Python matplotlib 3D散点图颜色图例仅显示首个颜色问题
问题描述
需要创建同时带有尺寸、颜色两类图例的3D散点图,但实际生成的颜色图例仅展示颜色列表中的第一个颜色,无法正确显示所有分类对应的颜色。
复现代码
import matplotlib.pyplot as plt import matplotlib.colors # Visualizing 5-D mix data using bubble charts # leveraging the concepts of hue, size and depth fig = plt.figure(figsize=(8, 6)) ax = fig.add_subplot(111, projection='3d') t = fig.suptitle('Wine Residual Sugar - Alcohol Content - Acidity - Total Sulfur Dioxide - Type', fontsize=14) xs = [1,2,3,5,4] ys = [6,7,3,5,4] zs = [1,5,3,9,4] data_points = [(x, y, z) for x, y, z in zip(xs, ys, zs)] ss = [100,200,390,500,400] colors = ['red','red','blue','yellow','yellow'] scatter = ax.scatter(xs, ys, zs, alpha=0.4, c=colors, s=ss) ax.set_xlabel('Residual Sugar') ax.set_ylabel('Alcohol') ax.set_zlabel('Fixed Acidity') legend1 = ax.legend(*scatter.legend_elements()[0], loc="upper right", title="Classes", labels=colors, bbox_to_anchor=(1.5, 1),prop={'size': 20}) ax.add_artist(legend1) # produce a legend with a cross section of sizes from the scatter handles, labels = scatter.legend_elements(prop="sizes", alpha=0.6) legend2 = ax.legend(handles, labels, loc="upper right", title="Sizes", bbox_to_anchor=(1.5, 0.5), prop={'size': 20})
实际异常运行效果

问题原因
scatter.legend_elements()默认是为数值型连续颜色映射设计的,当直接传入字符串格式的分类颜色列表时,该方法无法自动识别去重后的分类条目,仅会生成单个颜色的图例元素,手动传入全量颜色作为labels参数还会出现句柄和标签匹配错位的问题,最终导致颜色图例显示异常。
修改方案
不要使用scatter.legend_elements()生成分类颜色的图例,手动对颜色分类去重后,单独创建对应颜色的图例句柄即可。
修改后完整代码
import matplotlib.pyplot as plt from matplotlib.lines import Line2D # Visualizing 5-D mix data using bubble charts # leveraging the concepts of hue, size and depth fig = plt.figure(figsize=(8, 6)) ax = fig.add_subplot(111, projection='3d') t = fig.suptitle('Wine Residual Sugar - Alcohol Content - Acidity - Total Sulfur Dioxide - Type', fontsize=14) xs = [1,2,3,5,4] ys = [6,7,3,5,4] zs = [1,5,3,9,4] data_points = [(x, y, z) for x, y, z in zip(xs, ys, zs)] ss = [100,200,390,500,400] colors = ['red','red','blue','yellow','yellow'] scatter = ax.scatter(xs, ys, zs, alpha=0.4, c=colors, s=ss) ax.set_xlabel('Residual Sugar') ax.set_ylabel('Alcohol') ax.set_zlabel('Fixed Acidity') # 手动生成分类颜色图例 # 如需固定分类顺序,可手动指定unique_colors列表,例如 unique_colors = ['red', 'blue', 'yellow'] unique_colors = list(dict.fromkeys(colors)) # 按首次出现顺序去重 color_handles = [ Line2D([0], [0], marker='o', color='w', markerfacecolor=c, markersize=15, alpha=0.4) for c in unique_colors ] legend1 = ax.legend( color_handles, unique_colors, loc="upper right", title="Classes", bbox_to_anchor=(1.5, 1), prop={'size': 20} ) ax.add_artist(legend1) # 尺寸图例保留原有逻辑即可 handles, labels = scatter.legend_elements(prop="sizes", alpha=0.6) legend2 = ax.legend(handles, labels, loc="upper right", title="Sizes", bbox_to_anchor=(1.5, 0.5), prop={'size': 20}) plt.show()
修改说明
- 使用
dict.fromkeys(colors)对颜色列表按首次出现顺序去重,避免set去重导致顺序随机的问题 - 通过
Line2D手动创建每个分类颜色对应的图例标记,匹配散点的透明度、样式 - 尺寸图例的原有逻辑不需要调整,不受颜色图例修改的影响
内容的提问来源于stack exchange,提问作者phw
相关产品推荐
相关产品推荐

