【问题标题】:matplotlib sharex with colorbar not working带有颜色条的matplotlib sharex不起作用
【发布时间】:2018-03-23 12:32:22
【问题描述】:

我有 2 个子图 - 1 个散点图和一个条形图,我想要一个共享的 x 轴。散点图有一个颜色条。由于两个图的轴不重合,sharex 似乎不适用于此。 我的代码:

fig, (ax, ax2) = plt.subplots(2,1, gridspec_kw = {'height_ratios':[13,2]},figsize=(15,12), sharex=True)

df_plotdata.plot(kind='scatter', ax=ax, x='index_cancer', y='index_g', s=df_plotdata['freq1']*50, c=df_plotdata['freq2'], cmap=cmap)

df2.plot(ax=ax2, x='index_cancer', y='freq', kind = 'bar')

【问题讨论】:

  • 我意识到彩条是问题所在。尝试移动颜色条似乎不起作用。我似乎也无法摆脱它。
  • Sharex 表示轴限制相同并且轴是同步的。这并不意味着它们彼此重叠。这完全取决于您如何创建颜色条。如果人们只是在问题中提供minimal reproducible examples,可以复制和更改以轻松回答他们的问题,那不是很好吗?

标签: python pandas matplotlib subplot colorbar


【解决方案1】:

Sharex 表示坐标区限制相同并且坐标区是同步的。这并不意味着它们彼此重叠。这完全取决于您如何创建颜色条。

pandas scatterplot 创建的颜色条,就像 matplotlib 中的任何标准颜色条一样,是通过删除与其相关的轴的部分空间而创建的。因此,该轴小于网格中的其他轴。

您拥有的选项包括:

  • 将网格的其他轴缩小与散点图轴相同的量。
    这可以通过使用第一个轴的位置并相应地设置第二个轴的位置来完成,使用ax.get_position()ax.set_postion()

    import matplotlib.pyplot as plt
    import pandas as pd
    import numpy as np
    import itertools as it
    
    xy = list( it.product( range(10), range(10) ) )
    df = pd.DataFrame( xy, columns=['x','y'] )
    df['score'] = np.random.random( 100 )
    
    kw = {'height_ratios':[13,2]}
    fig, (ax,ax2) = plt.subplots(2,1,  gridspec_kw=kw, sharex=True)
    
    df.plot(kind='scatter', x='x',  y='y', c='score', s=100, cmap="PuRd",
              ax=ax, colorbar=True)
    df.groupby("x").mean().plot(kind = 'bar', y='score',ax=ax2, legend=False)
    
    ax2.legend(bbox_to_anchor=(1.03,0),loc=3)
    
    pos = ax.get_position()
    pos2 = ax2.get_position()
    ax2.set_position([pos.x0,pos2.y0,pos.width,pos2.height])
    
    plt.show()
    

  • 创建一个包含颜色条轴的网格。
    在这种情况下,您可以创建一个 4 x 4 的网格并将颜色条添加到它的右上轴。这需要将散点图提供给fig.colorbar(),并为颜色条指定一个坐标轴,

    fig.colorbar(ax.collections[0], cax=cax)       
    

    然后删除不需要的右下轴 (ax.axis("off"))。如果需要,您仍然可以通过ax2.get_shared_x_axes().join(ax, ax2) 共享坐标轴。

    import matplotlib.pyplot as plt
    import pandas as pd
    import numpy as np
    import itertools as it
    
    
    xy = list( it.product( range(10), range(10) ) )
    df = pd.DataFrame( xy, columns=['x','y'] )
    df['score'] = np.random.random( 100 )
    
    kw = {'height_ratios':[13,2], "width_ratios":[95,5]}
    fig, ((ax, cax),(ax2,aux)) = plt.subplots(2,2,  gridspec_kw=kw)
    
    df.plot(kind='scatter', x='x',  y='y', c='score', s=80, cmap="PuRd",
             ax=ax,colorbar=False)
    df.groupby("x").mean().plot(kind = 'bar', y='score',ax=ax2, legend=False)
    
    fig.colorbar(ax.collections[0], cax=cax, label="score")
    aux.axis("off")
    ax2.legend(bbox_to_anchor=(1.03,0),loc=3)
    ax2.get_shared_x_axes().join(ax, ax2)
    ax.tick_params(axis="x", labelbottom=0)
    ax.set_xlabel("")
    
    plt.show()
    

【讨论】:

    【解决方案2】:

    根据 ImportanceOfBeingErnest 的回答,以下两个函数将对齐轴:

    def align_axis_x(ax, ax_target):
        """Make x-axis of `ax` aligned with `ax_target` in figure"""
        posn_old, posn_target = ax.get_position(), ax_target.get_position()
        ax.set_position([posn_target.x0, posn_old.y0, posn_target.width, posn_old.height])
    
    def align_axis_y(ax, ax_target):
        """Make y-axis of `ax` aligned with `ax_target` in figure"""
        posn_old, posn_target = ax.get_position(), ax_target.get_position()
        ax.set_position([posn_old.x0, posn_target.y0, posn_old.width, posn_target.height])
    

    【讨论】:

      【解决方案3】:

      使用 Matplotlib 工具包(包含在 Matplotlib 中)

      我想添加一个替代当前答案的方法,即使用 Matplotlib 工具包中的函数 make_axes_locatable。默认情况下,这会优化空间的使用。如果您有一个包含多个此类子图的复杂子图配置(例如,使用 gridspec),则会产生很大的不同。

      使用示例

      import matplotlib.pyplot as plt
      import pandas as pd
      import numpy as np
      import itertools as it
      from mpl_toolkits.axes_grid1 import make_axes_locatable
      
      # create some data
      xy = list(it.product(range(16), range(16)))
      df = pd.DataFrame(xy, columns=["x", "y"])
      df["bubles"] = np.random.random(256)
      
      # create figure and main axis
      fig = plt.figure(figsize=(10,6))
      ax = plt.gca()
      
      # create a divider from make_axes_locatable
      divider = make_axes_locatable(ax)
      
      # append a new axis on the bottom whose size is 15% of the size of the main ax
      bax = divider.append_axes("bottom", size="15%", pad=.05)
      
      # append axis on the right for colourbar (size = 5%)
      cax = divider.append_axes("right", size="5%", pad=.05)
      
      cm = "plasma" # defining colourmap
      sm = plt.cm.ScalarMappable(cmap=cm)
      
      # plotting on main axis
      p1 = df.plot(kind='scatter', x='x',  y='y', c='bubles', s=df["bubles"]*200, cmap=cm,
                ax=ax, colorbar=False)
      
      # attaching colourbar to the axis at the right
      plt.colorbar(sm, cax=cax)
      
      # plotting on the adjascent axis (bottom)
      p2 = df.groupby("x").mean().plot(kind = 'bar', y='bubles',ax=bax, legend=False)
      
      # synchronizing plots on the x-axis
      p2.sharex(p1)
      
      # inserting some legend
      bax.legend(bbox_to_anchor=(1.03,0),loc=3)
      
      plt.show()
      

      上面的代码生成如下图:

      在下面的 GIF 中查看sharex 对两个 x 轴同步的影响:

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-04-05
        • 1970-01-01
        • 2011-07-26
        • 2021-06-03
        • 2017-05-13
        • 1970-01-01
        相关资源
        最近更新 更多