Seaborn FacetGrid - 在最后一个子图之后放置单个颜色条
Posted
技术标签:
【中文标题】Seaborn FacetGrid - 在最后一个子图之后放置单个颜色条【英文标题】:Seaborn FacetGrid - Place single colorbar after last subplot 【发布时间】:2018-09-27 06:43:10 【问题描述】:我正在尝试将颜色条添加到 3 个 seaborn 地块的网格中。我可以将颜色条添加到 3 个单独的图中,或者在第三个图旁边挤压一个颜色条。我想在第三个图之后有一个颜色条,而不改变最后一个图的大小。
我从这个答案中得到了很多好主意,但无法解决我的确切问题:SO Question/Answer
这是我当前的代码:
import seaborn as sns
def masked_vs_unmasked_facets(output_dir, merged_df, target_col, thresholds):
# defining the maximal values, to make the plot square
z_min = merged_df[['z_full', 'z_masked']].min(axis=0, skipna=True).min(skipna=True)
z_max = merged_df[['z_full', 'z_masked']].max(axis=0, skipna=True).max(skipna=True)
z_range_value = max(abs(z_min), abs(z_max))
# Setting the column values to create the facet grid
for i, val in enumerate(thresholds):
merged_df.loc[merged_df.info_score_masked > val, 'PlotSet'] = i
# Start the actual plots
g = sns.FacetGrid(merged_df, col='PlotSet', size=8)
def facet_scatter(x, y, c, **kwargs):
kwargs.pop("color")
plt.scatter(x, y, c=c, **kwargs)
# plt.colorbar() for multiple colourbars
vmin, vmax = 0, 1
norm=plt.Normalize(vmin=vmin, vmax=vmax)
g = (g.map(facet_scatter, 'z_full', 'z_masked', 'info_score_masked', norm=norm, cmap='viridis'))
ax = g.axes[0]
for ax in ax:
ax.set_xlim([-z_range_value * 1.1, z_range_value * 1.1])
ax.set_ylim([-z_range_value * 1.1, z_range_value * 1.1])
ax.plot(ax.get_xlim(), ax.get_ylim(), ls="--", c=".3")
plt.colorbar() # Single squashed colorbar
plt.show()
masked_vs_unmasked_facets(output_dir, masking_results, 'info_score_masked', [0, 0.7, 0.9])
单个颜色条,但第三个情节被压扁 多个颜色条,但很拥挤
【问题讨论】:
你读过***.com/questions/13784201/… 谢谢 - 差不多了。我现在可以在单独的轴上看到颜色条,因此第三个图不再被压扁。现在的问题是当我保存绘图时颜色栏没有被保存。关于我如何解决这个问题的任何提示?目前,我正在考虑使用subplots_adjust
。我会将此添加到我的答案中。
【参考方案1】:
根据@ImportanceOfBeingEarnest 的建议,我发现我需要向 facetgrid 添加另一组轴,然后将这些轴分配给颜色栏。为了将这个额外的元素保存到绘图中,我使用bbox_extra_artist
kwarg 作为紧密边界框。另一个小的添加是一个小子句,用于捕获我的一个方面没有数据的边缘情况。在这种情况下,我附加了一个空行,其中包含一个类别的单个实例,因此每个类别始终至少有 1 行。
import seaborn as sns
def masked_vs_unmasked_facets(output_dir, merged_df, target_col, thresholds):
z_min = merged_df[['z_full', 'z_masked']].min(axis=0, skipna=True).min(skipna=True)
z_max = merged_df[['z_full', 'z_masked']].max(axis=0, skipna=True).max(skipna=True)
z_range_value = max(abs(z_min), abs(z_max))
for i, val in enumerate(thresholds):
merged_df.loc[merged_df.info_score_masked > val, 'PlotSet'] = i
# Catch instances where there are no values in category, to ensure all facets are drawn each time
if i not in merged_df['PlotSet'].unique():
dummy_row = pd.DataFrame(columns=merged_df.columns, data='PlotSet': [i])
merged_df = merged_df.append(dummy_row)
g = sns.FacetGrid(merged_df, col='PlotSet', size=8)
def facet_scatter(x, y, c, **kwargs):
kwargs.pop("color")
plt.scatter(x, y, c=c, **kwargs)
vmin, vmax = 0, 1
norm=plt.Normalize(vmin=vmin, vmax=vmax)
g = (g.map(facet_scatter, 'z_full', 'z_masked', 'info_score_masked', norm=norm, cmap='viridis'))
titles = ["Correlation for all masked / unmasked z-score with above ".format(target_col, threshold) for threshold in thresholds]
axs = g.axes.flatten()
for i, ax in enumerate(axs):
ax.set_title(titles[i])
ax.set_xlim([-z_range_value * 1.1, z_range_value * 1.1])
ax.set_ylim([-z_range_value * 1.1, z_range_value * 1.1])
ax.plot(ax.get_xlim(), ax.get_ylim(), ls="--", c=".3")
cbar_ax = g.fig.add_axes([1.015,0.13, 0.015, 0.8])
plt.colorbar(cax=cbar_ax)
# extra_artists used here
plt.savefig(os.path.join(output_dir, 'masked_vs_unmasked_scatter_final.png'), bbox_extra_artists=(cbar_ax,), bbox_inches='tight')
masked_vs_unmasked_facets(output_dir, masking_results, 'info_score_masked', [0, 0.7, 0.9])
这给了我:
【讨论】:
以上是关于Seaborn FacetGrid - 在最后一个子图之后放置单个颜色条的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Seaborn 创建 FacetGrid 堆叠条形图?
如何在 seaborn 的 facetgrid 中设置可读的 xticks?
在 seaborn 中的特定位置画一条线/注释 Facetgrid
Python Seaborn:在 Facetgrid 中绘制多个 distplot