添加散点图后小提琴图被挤压至一侧,求正确叠加绘制方法
问题描述
希望创建带有自定义标记的双小提琴图,目前已成功绘制出小提琴图,但添加各类标记的散点图后,小提琴图的布局被破坏(小提琴图的阴影被挤到左侧),需要实现两者的正确叠加绘制。
原代码:
def plot_psd(centralised_frequencies,centralised_psds,distributed_frequencies,distributed_psds): fig,ax=plt.subplots(1,1,figsize=(10,5)) add_label(ax.violinplot(centralised_psds,side='high',showmeans=False,showmedians=False,showextrema=False), "Centralised Control") ax.set_xticklabels(centralised_frequencies) add_label(ax.violinplot(distributed_psds,side='low',showmeans=False,showmedians=False,showextrema=False), "Distributed Control") ax.set_xticklabels(distributed_frequencies) ax.scatter(centralised_frequencies,np.mean(centralised_psds,1),marker=markers.CARETLEFTBASE,color='r') ax.scatter(centralised_frequencies,np.min(centralised_psds,1),marker=markers.TICKLEFT,color='r') ax.scatter(centralised_frequencies,np.max(centralised_psds,1),marker=markers.TICKLEFT,color='r') ax.scatter(distributed_frequencies,np.mean(distributed_psds,1),marker=markers.CARETRIGHTBASE,color='b') ax.scatter(distributed_frequencies,np.min(distributed_psds,1),marker=markers.TICKRIGHT,color='b') ax.scatter(distributed_frequencies,np.max(distributed_psds,1),marker=markers.TICKRIGHT,color='b') ax.legend(*zip(*labels)) ax.set_xlabel("Frequency (Hz)") ax.set_ylabel("PSD*Freq") ax.set_xlabel("Frequency (Hz)") ax.set_ylabel("PSD*Freq") ax.set_title("Centralised Control") ax.set_title("Distributed Control") fig.savefig("6_Results/clean_data/psd.png") plt.clf() plt.close()
问题原因
- x轴位置不匹配:
violinplot默认的小提琴位置是从1开始的整数序列(1、2、3...),但散点图使用实际的frequency数值作为x坐标,导致x轴范围被拉宽,小提琴图被挤压到左侧区域。 - 重复设置轴属性:两次调用
set_xticklabels、set_xlabel、set_ylabel、set_title,后一次会覆盖前一次的设置,造成无效操作。
解决方法
步骤1:统一小提琴图与散点图的x轴位置
假设centralised_frequencies和distributed_frequencies的数值完全一致(双小提琴对应同一频率位置),调用violinplot时指定positions参数为频率值,让小提琴图的位置与散点图的x坐标对齐。
步骤2:清理重复的轴设置
删除重复的set_xlabel、set_ylabel、set_title调用,保留一次正确设置。
修正后的代码
import matplotlib.pyplot as plt import matplotlib.markers as markers import numpy as np # 假设add_label是你定义的用于给小提琴图添加图例的函数 labels = [] def add_label(violin, label): color = violin['bodies'][0].get_facecolor().flatten() labels.append((plt.Line2D([0], [0], marker='o', color='w', markerfacecolor=color, markersize=10), label)) def plot_psd(centralised_frequencies,centralised_psds,distributed_frequencies,distributed_psds): # 确保两个频率数组一致,否则双小提琴无法对应同一位置 assert np.array_equal(centralised_frequencies, distributed_frequencies), "频率数组必须一致" fig, ax = plt.subplots(1,1,figsize=(10,5)) # 绘制中央控制的小提琴图,指定positions为频率值 add_label(ax.violinplot(centralised_psds, positions=centralised_frequencies, side='high', showmeans=False, showmedians=False, showextrema=False), "Centralised Control") # 绘制分布式控制的小提琴图,使用相同的positions add_label(ax.violinplot(distributed_psds, positions=distributed_frequencies, side='low', showmeans=False, showmedians=False, showextrema=False), "Distributed Control") # 设置x轴刻度标签 ax.set_xticks(centralised_frequencies) ax.set_xticklabels(centralised_frequencies) # 绘制散点标记:均值、最值 # 中央控制相关标记 ax.scatter(centralised_frequencies, np.mean(centralised_psds,1), marker=markers.CARETLEFTBASE, color='r') ax.scatter(centralised_frequencies, np.min(centralised_psds,1), marker=markers.TICKLEFT, color='r') ax.scatter(centralised_frequencies, np.max(centralised_psds,1), marker=markers.TICKLEFT, color='r') # 分布式控制相关标记 ax.scatter(distributed_frequencies, np.mean(distributed_psds,1), marker=markers.CARETRIGHTBASE, color='b') ax.scatter(distributed_frequencies, np.min(distributed_psds,1), marker=markers.TICKRIGHT, color='b') ax.scatter(distributed_frequencies, np.max(distributed_psds,1), marker=markers.TICKRIGHT, color='b') # 设置图例、轴标签和标题 ax.legend(*zip(*labels)) ax.set_xlabel("Frequency (Hz)") ax.set_ylabel("PSD*Freq") ax.set_title("Centralised vs Distributed Control PSD Comparison") fig.savefig("6_Results/clean_data/psd.png") plt.clf() plt.close()
额外说明
如果你的centralised_frequencies和distributed_frequencies是不同的分类(非同一频率对比),则需要调整小提琴图的位置为连续整数,同时将散点图的x坐标替换为对应的整数索引,再设置xticklabels为频率值。例如:
# 生成整数位置 positions = np.arange(1, len(centralised_frequencies)+1) # 小提琴图使用positions ax.violinplot(centralised_psds, positions=positions, side='high', ...) # 散点图x坐标用positions ax.scatter(positions, np.mean(centralised_psds,1), ...) # 设置刻度标签 ax.set_xticks(positions) ax.set_xticklabels(centralised_frequencies)
内容的提问来源于stack exchange,提问作者Zedonkay
相关产品推荐
相关产品推荐

