92848


axs[0, 1]の高さをaxs[0, 0]の高さに合わせ，axs[1, 0]の幅をaxs[0,
0]の幅に合わせるために，以下のコードを実行しました．しかし，添付画像のようにaxs[1, 0]とaxs[0, 0]の幅が合いません．

`img_ax.imshow(..., aspect="auto")`とすると幅は揃いますが，axs[0, 0]画像の比率が元画像と異なってしまいます．

元画像の比率を維持したまま，高さと幅を揃える方法はありますか？

[code]

    import numpy as np
    import matplotlib.pyplot as plt
    from PIL import Image
    
    fig=plt.figure(dpi=200, constrained_layout=True)
    axs:list[list[plt.Axes]] = fig.subplots(
        2, 2,
        gridspec_kw=dict(height_ratios=[3, 1],width_ratios=[3, 1])
    )
    axs[1][1].set_visible(False)
    
    im = Image.open("brightest.bmp").convert("L")
    img_ax=axs[0][0]
    img_ax.imshow(np.asarray(im)[::4,::4], cmap="gray", vmin=0, vmax=255)
    
[/code]

[![output figure
image](https://i.stack.imgur.com/zvq3G.png)](https://i.stack.imgur.com/zvq3G.png)


CC BY-SA 4.0
2022-12-16T13:26:38.297
92823
2022-12-17T16:19:08.233
50560
question
python python3 matplotlib
imshow を含んだ subplots 関数の width_ratios が効かない


スマートな方法とは言えないですが，`constrained_layout=False` に変更して出力を見ながら
`plt.subplots_adjust()` の設定値で余白を調整してみました。詳細は
[matplotlib.pyplot.subplots_adjust](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.subplots_adjust.html)
を参照ください。なお，デフォルト値は下記です。

[code]

    left=0.125, right=0.9, bottom=0.11, top=0.88,
    wspace=0.2, hspace=0.2
    
[/code]

私の環境（macOS13(M1), Python 3.10.8, matplotlib 3.6.2）では，`wspace=0.4, hspace=0.3`
で添付のレイアウトになりました。

[code]

    import numpy as np
    import matplotlib.pyplot as plt
    from PIL import Image
    
    fig = plt.figure(dpi=200, constrained_layout=False)  # modified                     
    axs: list[list[plt.Axes]] = fig.subplots(
        2, 2,
        gridspec_kw=dict(height_ratios=[3, 1], width_ratios=[3, 1]))
    axs[1][1].set_visible(False)
    
    im = Image.open("brightest.bmp").convert("L")
    img_ax = axs[0][0]
    img_ax.imshow(np.asarray(im)[::4, ::4], cmap="gray", vmin=0, vmax=255)
    
    plt.subplots_adjust(wspace=0.4, hspace=0.3)
    plt.show()
    
[/code]

[![レイアウトの画像](https://i.stack.imgur.com/iDDjo.png)](https://i.stack.imgur.com/iDDjo.png)


CC BY-SA 4.0
2022-12-17T10:40:18.160
92838
2022-12-17T10:40:18.160
54588
92823
answer


Delft Viewさんの方法を試してみました．  
たしかに，空白を調整することで幅を揃えることができました．しかし画像の縦横比と`height_ratios(width_ratios)`の組み合わせによっては写真のようにかなり不格好になってしまうこともわかりました．

[code]

    from PIL import Image
    import numpy as np
    import matplotlib.pyplot as plt
    fig = plt.figure(dpi=120)
    axs: list[list[plt.Axes]] = fig.subplots(
            2,2,gridspec_kw=dict(height_ratios=[4, 1],width_ratios=[4, 1])
        )
    axs[1][1].set_visible(False)
    
    # Image
    img_ax = axs[0][0]
    img_arr = np.random.rand(480, 480)*255
    img_ax.imshow(img_arr,cmap="gray",vmin=0,vmax=255)
    
    fig.subplots_adjust(wspace=1, hspace=0.2)
    
[/code]

[![test1](https://i.stack.imgur.com/35Ecw.png)](https://i.stack.imgur.com/35Ecw.png)

* * *

引き続きネットを調べてみた結果，良い解決策が見つかりました．([Colorbar with
AxesDivider](https://matplotlib.org/stable/gallery/axes_grid1/demo_colorbar_with_axes_divider.html))

`make_axes_locatable(img_ax)`により，`img_ax`に紐づいた`AxesDivider`が作られます．`append_axes()`により，指定した位置，サイズ，間隔で新たな`Axes`を`img_ax`に追加できました．

[code]

    from mpl_toolkits.axes_grid1 import make_axes_locatable # 追加インポート
    fig = plt.figure(dpi=120)
    img_ax: plt.Axes = fig.subplots(1,1)
    
    # Image
    img_arr = np.random.rand(480, 480)*255
    img_ax.imshow(img_arr,cmap="gray",vmin=0,vmax=255)
    
    # Right and bottom axes
    num_append = 1
    divider = make_axes_locatable(img_ax)
    for _ in range(num_append):
        right_ax = divider.append_axes("right", size="35%", pad=0.4)
        bottom_ax = divider.append_axes("bottom", size="35%", pad=0.4)
    
[/code]

[![画像の説明をここに入力](https://i.stack.imgur.com/5LfAp.png)](https://i.stack.imgur.com/5LfAp.png)

* * *

`num_append`を変更すると，追加する`Axes`を増やすことができます．  
例：`num_append=3`  
[![画像の説明をここに入力](https://i.stack.imgur.com/kvIq1.png)](https://i.stack.imgur.com/kvIq1.png)


CC BY-SA 4.0
2022-12-17T16:13:53.653
92848
2022-12-17T16:19:08.233
2022-12-17T16:19:08.233
50560
50560
92823
answer