color_palettes = { 1: {'cmap': plt.cm.viridis_r, 'max_val_color': '#c00000', 'median_color': 'black', 'outer_dash_color': '#c00000', 'inner_dash_color': '#0000FF'}, 2: {'cmap': plt.cm.Blues, 'max_val_color': '#00008B', 'median_color': 'black', 'outer_dash_color': '#00008B', 'inner_dash_color': '#1E90FF'}, 3: {'cmap': plt.cm.YlOrRd, 'max_val_color': '#8B0000', 'median_color': 'black', 'outer_dash_color': '#FF4500', 'inner_dash_color': '#DAA520'}, 4: {'cmap': plt.cm.Greys, 'max_val_color': 'black', 'median_color': 'black', 'outer_dash_color': '#363636', 'inner_dash_color': '#808080'}, 5: {'cmap': plt.cm.Spectral_r, 'max_val_color': '#D73027', 'median_color': 'black', 'outer_dash_color': '#D73027', 'inner_dash_color': '#4575B4'}, 6: {'cmap': plt.cm.cividis, 'max_val_color': '#2A788E', 'median_color': 'black', 'outer_dash_color': '#2A788E', 'inner_dash_color': '#FDE725'}, 7: {'cmap': plt.cm.plasma, 'max_val_color': '#7A0403', 'median_color': 'black', 'outer_dash_color': '#7A0403', 'inner_dash_color': '#F0F921'}, 8: {'cmap': plt.cm.inferno, 'max_val_color': '#570A0F', 'median_color': 'black', 'outer_dash_color': '#570A0F', 'inner_dash_color': '#FCFFA4'}, 9: {'cmap': plt.cm.magma, 'max_val_color': '#420A68', 'median_color': 'black', 'outer_dash_color': '#420A68', 'inner_dash_color': '#F0F921'}, 10: {'cmap': plt.cm.twilight_shifted, 'max_val_color': '#000060', 'median_color': 'black', 'outer_dash_color': '#000060', 'inner_dash_color': '#F0F0D0'}, 11: {'cmap': plt.cm.Pastel1, 'max_val_color': '#A65628', 'median_color': 'black', 'outer_dash_color': '#A65628', 'inner_dash_color': '#377EB8'}, 12: {'cmap': plt.cm.Paired, 'max_val_color': '#E31A1C', 'median_color': 'black', 'outer_dash_color': '#E31A1C', 'inner_dash_color': '#1F78B4'}, 13: {'cmap': plt.cm.Accent, 'max_val_color': '#3B3B3B', 'median_color': 'black', 'outer_dash_color': '#3B3B3B', 'inner_dash_color': '#7FC97F'}, 14: {'cmap': plt.cm.Set3, 'max_val_color': '#4C4C4C', 'median_color': 'black', 'outer_dash_color': '#4C4C4C', 'inner_dash_color': '#8DD3C7'}, 15: {'cmap': plt.cm.ocean, 'max_val_color': '#0000A0', 'median_color': 'white', 'outer_dash_color': '#0000A0', 'inner_dash_color': '#90FFFF'}, 16: {'cmap': plt.cm.terrain, 'max_val_color': '#333333', 'median_color': 'black', 'outer_dash_color': '#333333', 'inner_dash_color': '#A0A0A0'}, 17: {'cmap': plt.cm.gist_stern, 'max_val_color': '#FF0000', 'median_color': 'black', 'outer_dash_color': '#FF0000', 'inner_dash_color': '#00FFFF'}, 18: {'cmap': plt.cm.gist_earth, 'max_val_color': '#A67C52', 'median_color': 'black', 'outer_dash_color': '#A67C52', 'inner_dash_color': '#274488'}, 19: {'cmap': plt.cm.coolwarm, 'max_val_color': '#B2182B', 'median_color': 'black', 'outer_dash_color': '#B2182B', 'inner_dash_color': '#2166AC'}, 20: {'cmap': plt.cm.BrBG, 'max_val_color': '#8C510A', 'median_color': 'black', 'outer_dash_color': '#8C510A', 'inner_dash_color': '#01665E'}}
# ===================== 库导入 =====================import matplotlib.pyplot as pltimport numpy as npimport pandas as pdimport os# 绘图字体与格式设置plt.rcParams['font.family'] = ['Times New Roman']plt.rcParams['axes.unicode_minus'] = Falseplt.rcParams['pdf.fonttype'] = 42plt.rcParams['ps.fonttype'] = 42# ===================== 配色方案=====================color_palettes = { 1: {'cmap': plt.cm.viridis_r, 'max_val_color': '#c00000', 'median_color': 'black', 'outer_dash_color': '#c00000', 'inner_dash_color': '#0000FF'},}# 选择配色方案selected_palette = 1selected_scheme = color_palettes[selected_palette]# ===================== 自动创建输出文件夹 =====================save_dir = "图表"os.makedirs(save_dir, exist_ok=True)# ===================== 数据读取函数 =====================def load_data_from_excel(filename): df = pd.read_excel(filename) categories = df.columns.tolist() data_raw = [df[col].dropna().values for col in categories] return data_raw, categories# ===================== 绘图函数 =====================def draw_radial_violin_plot(data_raw, categories, color_scheme): medians = [np.median(d) for d in data_raw] max_vals = [np.max(d) for d in data_raw] n_categories = len(categories) # 提取配色 cmap = color_scheme['cmap'] max_val_color = color_scheme['max_val_color'] median_color = color_scheme['median_color'] outer_dash_color = color_scheme['outer_dash_color'] inner_dash_color = color_scheme['inner_dash_color'] # 角度设置 angles = np.linspace(np.deg2rad(10), np.deg2rad(170), n_categories) data_plot = [d + 0.012 for d in data_raw] # 初始化极坐标图 fig, ax = plt.subplots(figsize=(12, 7), subplot_kw={'projection': 'polar'}) # 绘制小提琴图 violin_parts = ax.violinplot( data_plot, positions=angles, widths=0.2, quantiles=[[0.25, 0.5, 0.75]] * n_categories, showextrema=False ) # 自定义样式 colors = cmap(np.linspace(0.1, 0.9, n_categories)) for i, pc in enumerate(violin_parts['bodies']): pc.set_facecolor(colors[i]) pc.set_edgecolor('black') pc.set_alpha(1) violin_parts['cquantiles'].set_edgecolor('black') lines = violin_parts['cquantiles'].get_segments() new_widths = [1.5 if i % 3 == 1 else 1 for i in range(len(lines))] violin_parts['cquantiles'].set_linewidths(new_widths) # 坐标轴设置 ax.set_ylim(-0.01, 0.08) ax.set_rticks([]) ax.set_yticklabels([]) ax.grid(False) ax.set_theta_zero_location('E') ax.set_theta_direction(1) ax.set_thetamin(0) ax.set_thetamax(360) ax.set_xticklabels([]) ax.spines['polar'].set_visible(False) # 标注 for i in range(n_categories): ang_rad = angles[i] ang_deg = np.degrees(ang_rad) rot_tan = ang_deg - 90 rot_rad = ang_deg - 180 ax.text(ang_rad, 0.075, categories[i], ha='center', va='center', fontsize=12, fontweight='bold', rotation=rot_tan) ax.text(ang_rad, 0.065, f'{max_vals[i]:.3f}', ha='center', va='center', fontsize=9, color=max_val_color, rotation=rot_tan) ax.text(ang_rad, 0.005, f'{medians[i]:.3f}', ha='center', va='center', fontsize=9, color=median_color, rotation=rot_rad) # 弧线 arc_angs = np.linspace(np.deg2rad(10), np.deg2rad(170), 100) ax.plot(arc_angs, [0.07]*100, 'k-', lw=1) ax.plot(arc_angs, [0.06]*100, color=outer_dash_color, ls='--', lw=1.5) ax.plot(arc_angs, [0.01]*100, color=inner_dash_color, ls='--', lw=1.5) ax.plot(arc_angs, [0.009]*100, 'k-', lw=1) plt.tight_layout() save_path = os.path.join(save_dir, f"violin_{selected_palette}.png") plt.savefig(save_path, dpi=300, bbox_inches='tight') plt.close(fig)# ===================== 主程序 =====================if __name__ == "__main__": # 读取根目录下的 data.xlsx raw_data, CATEGORIES = load_data_from_excel("data.xlsx") # 绘图 draw_radial_violin_plot(raw_data, CATEGORIES, selected_scheme)