如何让Matplotlib散点图图例尺寸固定在0-100范围?
问题
使用Matplotlib绘制散点图时,希望图例固定展示代表[0,25,50,75,100]的点尺寸,但scatter.legend_elements()函数会基于实际数据范围生成归一化的图例值。当前数据中Percentage变量范围仅为0-15,需要实现无论该变量实际范围如何,图例始终显示0-100的尺寸对应关系。
原代码如下:
import sys def make_scatter_plot_by_tissue(df, size_legend="auto"): #sort df by Percentage df=df.sort_values(by=['Percentage'], ascending=False) genes = df.Genes.unique() if len(genes) > 1: sys.stderr.write("check there is only one gene\n") else: gene = genes[0] plt.figure(figsize = (20,20)) scatter_plot = plt.scatter(df['Genes'], df['Groups'], s=df['Percentage'], c=df['Average rank'], # size of points based on percentage cmap='Reds', alpha=0.7) # Add a colorbar to show the mapping of colors to values cbar = plt.colorbar(scatter_plot) cbar.set_label('Average Rank', fontsize=20) #set the cbar legend range to be 0-5000 plt.clim(0, 5000) #set the cbar label font size cbar.ax.tick_params(labelsize=20) # code based on this https://stackoverflow.com/a/58485655/1735942 # Create a custom legend with circles representing the dot sizes # how to make the num range between 0-100 no matter the range of Percentage variable? size_legend = plt.legend(*scatter_plot.legend_elements(prop="sizes", num="auto"), loc='center left', title='Percentage', bbox_to_anchor=(1.30, .5), fontsize=15) # Set the title for the size legend size_legend.set_title('Percentage') size_legend.get_title().set_fontsize('20') # Display the plot plt.yticks(fontsize=15) plt.xticks(fontsize=15, rotation=90) plt.xlabel('Genes', fontsize=20) plt.ylabel('Tissue type', fontsize=20) title_string=f"Tissue expression summmary {gene}" plt.title(title_string, fontsize=20) plt.show()
解决方案
放弃legend_elements()的自动生成逻辑,手动创建固定范围的尺寸图例:
- 定义目标图例值:
target_sizes = [0,25,50,75,100] - 为每个目标值创建对应大小的散点标记(利用
matplotlib.lines.Line2D生成圆形标记) - 手动关联标记与标签,创建自定义图例
修改后的完整代码
import sys import matplotlib.pyplot as plt from matplotlib.lines import Line2D def make_scatter_plot_by_tissue(df, size_legend="auto"): # sort df by Percentage df = df.sort_values(by=['Percentage'], ascending=False) genes = df.Genes.unique() if len(genes) > 1: sys.stderr.write("check there is only one gene\n") else: gene = genes[0] plt.figure(figsize=(20,20)) scatter_plot = plt.scatter(df['Genes'], df['Groups'], s=df['Percentage'], c=df['Average rank'], cmap='Reds', alpha=0.7) # 处理颜色条 cbar = plt.colorbar(scatter_plot) cbar.set_label('Average Rank', fontsize=20) plt.clim(0, 5000) cbar.ax.tick_params(labelsize=20) # 创建固定范围的尺寸图例 target_sizes = [0,25,50,75,100] # 生成图例标记:每个标记对应目标尺寸,样式匹配散点图 legend_markers = [ Line2D([0], [0], marker='o', color='w', markerfacecolor='red', markersize=pow(s, 0.5), alpha=0.7, label=str(s)) for s in target_sizes ] # 创建图例 size_legend = plt.legend(handles=legend_markers, loc='center left', title='Percentage', bbox_to_anchor=(1.30, .5), fontsize=15) size_legend.get_title().set_fontsize('20') # 设置图表其他属性 plt.yticks(fontsize=15) plt.xticks(fontsize=15, rotation=90) plt.xlabel('Genes', fontsize=20) plt.ylabel('Tissue type', fontsize=20) plt.title(f"Tissue expression summary {gene}", fontsize=20) plt.show()
说明
- 用
Line2D生成圆形标记时,markersize取尺寸值的平方根,因为Matplotlib中scatter的s参数代表点的面积,而markersize代表点的直径,以此匹配视觉大小 - 标记的颜色、透明度与原散点图保持一致,确保视觉统一
- 目标尺寸列表可根据需求自由调整,不受实际数据范围影响
内容的提问来源于stack exchange,提问作者aindap
相关产品推荐
相关产品推荐

