77467


線グラフと棒グラフを個別に表示する方法はできました。  
これらを同じグラフに描画する方法がわかりません。

環境:  
Anaconda-Navigator  
Jupyter Notebook 6.3.0

線グラフ:

[code]

    import matplotlib.pyplot as plt
    import numpy as np
    import pandas as pd
    import seaborn as sns
    
    df = pd.DataFrame(
        {
            'name': ['A', 'B', 'C', 'D', 'E'],
            'value': [10000, 5000, 1000, 500, 100]
        }
    )
        
    df['accumulative_ratio'] = df['value'].cumsum() / df['value'].sum()
    
    df['accumulative_ratio'].plot.line(color='darkblue')
    
[/code]

棒グラフ:

[code]

    df['value'].plot.bar(color='darkblue')
    
[/code]

[maplotlibの棒グラフに累積比率を追加する -
Qiita](https://qiita.com/messefor/items/aa2fc73e3046cc63de72)  
をみようみまねで試しているのですが、下記でエラーです。

[code]

    import matplotlib.pyplot as plt
    import numpy as np
    import pandas as pd
    import seaborn as sns
    
    df = pd.DataFrame(
        {
            'name': ['A', 'B', 'C', 'D', 'E'],
            'value': [10000, 5000, 1000, 500, 100]
        }
    )    
    
    df['accumulative_ratio'] = df['value'].cumsum() / df['value'].sum()
    
    fig, ax = plt.subplots()
    
    bar = ax.bar(left=x_idx,
                 height=df['value'],
                 align='center',
                 tick_label=df['name'],
                 alpha=0.7
                 )
    
[/code]

エラー：

[code]

    TypeError                                 Traceback (most recent call last)
    <ipython-input-25-face40da5000> in <module>
         16 fig, ax = plt.subplots()
         17 
    ---> 18 bar = ax.bar(left=x_idx,
         19              height=df['value'],
         20              align='center',
    
    ~/opt/anaconda3/lib/python3.8/site-packages/matplotlib/__init__.py in inner(ax, data, *args, **kwargs)
       1445     def inner(ax, *args, data=None, **kwargs):
       1446         if data is None:
    -> 1447             return func(ax, *map(sanitize_sequence, args), **kwargs)
       1448 
       1449         bound = new_sig.bind(ax, *args, **kwargs)
    
    TypeError: bar() missing 1 required positional argument: 'x'
    
[/code]

正直、 `plt.subplots()` から何か2つ（`fig`と`ax`）をもらっているようですが、いまいち使い方がピンと来ていません。

また参考資料リンク先に

> 第2軸に累積の折れ線グラフを追加  
>  ax2 = ax.twinx()

とありますが、重ねない場合は、`df['accumulative_ratio'].plot.line(color='darkblue')`というように、`line`を使えばいけたので`twinx()`を別途呼び出すなどの、お作法が必要な理由等がよくわかっていません。

どのようにすれば、グラフを重ねて表示できますか？


CC BY-SA 4.0
2021-06-10T14:05:52.767
77465
2021-06-10T19:21:17.570
2021-06-10T16:25:54.227
3060
9008
question
python pandas matplotlib
累積比率（線グラフ）を棒グラフに重ねる方法がわかりません


データフレームの内容を見ますと、`df.value` の範囲は `[100, 10000]` で `df.accumulative_ratio` は  
`[0, 1.0]` となっています。つまりスケールが大幅に異なっている、という事です。実際には `df.accumulative_ratio`
もプロットされているのですが、`X` 軸とほぼ重なっています。

[code]

    >>> df
      name  value  accumulative_ratio
    0    A  10000            0.602410
    1    B   5000            0.903614
    2    C   1000            0.963855
    3    D    500            0.993976
    4    E    100            1.000000
    
[/code]

というわけで `df.accumulative_ratio` のプロットに `secondary_y=True` を指定します。

[code]

    import matplotlib.pyplot as plt
    import matplotlib.ticker as ticker
    import pandas as pd
    import seaborn as sns
    
    df = pd.DataFrame({
       'name': ['A', 'B', 'C', 'D', 'E'],
      'value': [10000, 5000, 1000, 500, 100]
    })
    
    # set graph style
    sns.set_style(sns.axes_style(style='darkgrid'))
    sns.set_palette('muted')
    sns.set_color_codes('dark')
    
    # set accumulative ratio
    df['accumulative_ratio'] = df['value'].cumsum() / df['value'].sum()
    
    # plotting
    ax_val = df['value'].plot.bar(
      width=0.8, color='#789ad9', alpha=0.7, label='value')
    ax_acc = df['accumulative_ratio'].plot.line(
      ls='--', marker='o', color='red', secondary_y=True, label='acc. ratio')
    
    # annotation
    for i, v in enumerate(df.value):
      ax_val.text(i, v, v, ha='center', color='darkblue')
    for i, v in enumerate(df.accumulative_ratio):
      ax_acc.text(i, v*1.01, f'{v:.2f}', ha='center', color='red')
    
    # value axes attributes
    ax_val.set_xlabel('Group')
    ax_val.set_ylabel('Value')
    ax_val.set_xticklabels(df.name)
    ax_val.grid(True)
    
    # accumulative ratio axes attributes
    ax_acc.set_ylabel('Accumulative ratio')
    ax_acc.yaxis.set_major_locator(ticker.MultipleLocator(0.1))
    ax_acc.grid(False)
    
    # title
    plt.suptitle('Example of barplot with secondary axis', fontsize=18)
    
    # legend
    plt.legend(
      *[sum(l, []) for l in zip(
        ax_val.get_legend_handles_labels(),
        ax_acc.get_legend_handles_labels())],
      loc='center right', frameon=False
    )
    
    # show
    plt.show()
    
[/code]

[![figure](https://i.stack.imgur.com/hNxz8.png)](https://i.stack.imgur.com/hNxz8.png)


CC BY-SA 4.0
2021-06-10T15:16:28.437
77467
2021-06-10T19:21:17.570
2021-06-10T19:21:17.570
77465
answer


#### 棒グラフのエラーについて

記事が古いか何かで, APIが古くなってる可能性があります

[code]

    bar = ax.bar(left=x_idx,
                 height=df['value'],
                 align='center',
                 tick_label=df['name'],
                 alpha=0.7
                 )
    
[/code]

… これを  
この様に書き換えればよいかも

[code]

    bar = ax.bar(df['name'], df['value'], align='center', alpha=0.7)
    
[/code]

* * *

#### グラフ重ね合わせについて

複数のグラフを同時の場合
[subplots](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.subplots.html)
を用いて `ax` あるいは複数の ax (`axes`) を準備し, そこに描画することに

[code]

    # using the variable ax for single a Axes
    fig, ax = plt.subplots()
    
    # using the variable axs for multiple Axes
    fig, axes = plt.subplots(2, 2)
    
[/code]

今回の場合は, ひとつだけ用意し, 毎回 `ax` に対し描画することになります


CC BY-SA 4.0
2021-06-10T15:45:48.337
77468
2021-06-10T15:45:48.337
43025
77465
answer