COLOR_SCHEMES = { 1: ["#050505", "#183454", "#316896", "#5992c2", "#adc5e0", "#f6f6f8", "#fad69d", "#e28d32", "#b84d12", "#7c1206"], # 方案 1: Nature/Cell 经典红蓝黑蓝橙渐变(极高对比度) 2: ["#053061", "#2166ac", "#4393c3", "#92c5de", "#d1e5f0", "#f7f7f7", "#fddbc7", "#f4a582", "#d6604d", "#b2182b"], # 方案 2: PNAS/Science 标准经典红蓝渐变(深蓝-浅白-深红) 3: ["#440154", "#482878", "#3e4989", "#31688e", "#26828e", "#1f9e89", "#35b779", "#6ece58", "#b5de2b", "#fde725"], # 方案 3: Viridis 视角友好配色(全色盲/弱视感知均匀,Nature推荐) 4: ["#000004", "#180f3d", "#400f74", "#6c1b7d", "#992d7f", "#c5407e", "#ed5969", "#fa8775", "#fbb984", "#fcfdbf"], # 方案 4: Magma 高亮对比配色(深紫至亮黄,适合强信号差异) 5: ["#0d0887", "#350498", "#5c01a6", "#8002a0", "#9c179e", "#bd3786", "#d8576b", "#ed7953", "#fb9f3a", "#f0f921"], # 方案 5: Plasma 鲜艳对比配色(紫蓝至橙黄,适合单细胞差异表达) 6: ["#9e0142", "#d53e4f", "#f46d43", "#fdae61", "#fee08b", "#e6f598", "#abdda4", "#66c2a5", "#3288bd", "#5e4fa2"], # 方案 6: Spectral 经典光谱全彩配色(适合多组分/多模块展示) 7: ["#3b4cc0", "#5977e3", "#7b9ff9", "#9ebeff", "#c0d4f5", "#f2f2f2", "#fbe3d5", "#f7f79c", "#e88067", "#b40426"], # 方案 7: Coolwarm 经典冷暖双色(蓝-白-红,学术论文通用) 8: ["#ffffd9", "#edf8b1", "#c7e9b4", "#7fcdbb", "#41b6c4", "#1d91c0", "#225ea8", "#253494", "#081d58", "#02092c"], # 方案 8: YlGnBu 黄绿蓝渐变(适用于无负值单向连续数值梯度) 9: ["#ffffcc", "#ffedd1", "#fed976", "#feb24c", "#fd8d3c", "#fc4e2a", "#e31a1c", "#bd0026", "#800026", "#4a0018"], # 方案 9: YlOrRd 黄橙红渐变(适用于信号强度/通路激活梯度) 10: ["#00204d", "#00326d", "#1f467d", "#3b5b8c", "#56729c", "#7289ab", "#90a2bb", "#b0bdcb", "#d1d9db", "#ffea46"], # 方案 10: Cividis 视力友好渐变(针对色盲校准,无视觉失真) 11: ["#08519c", "#3182bd", "#6baed6", "#9ecae1", "#c6dbef", "#eff3ff", "#fee5d9", "#fcae91", "#fb6a4a", "#cb181d"], # 方案 11: EMBO Red-Blue 双色平衡(EMBO Journal标准表达量梯度) 12: ["#2d004b", "#542788", "#8073ac", "#b2abd2", "#d8daeb", "#f7f7f7", "#fee0b6", "#fdb863", "#e08214", "#b35806"], # 方案 12: Cell Press 经典橙紫(Cell期刊特有双色渐变) 13: ["#00441b", "#2a7044", "#529d6f", "#84c69b", "#bfe5cc", "#f4f4f4", "#f8d1d8", "#eb9aa8", "#d25a74", "#9e1b42"], # 方案 13: Teal-Rose 青灰玫瑰红(高级学术莫兰迪风格) 14: ["#543005", "#8c510a", "#bf812d", "#dfc27d", "#f6e8c3", "#f5f5f5", "#c7edd9", "#80cdc1", "#35978f", "#01665e"], # 方案 14: Brown-BlueGreen 棕绿蓝平衡(适用于环境基因组与生态多组学) 15: ["#8e0152", "#c51b7d", "#de77ae", "#f1b6da", "#fde0ef", "#f7f7f7", "#e6f5d0", "#b8e186", "#7fbc41", "#276419"], # 方案 15: PiYG 粉白绿(用于差异基因表达中的上下调显著性展示) 16: ["#40004b", "#762a83", "#9970ab", "#c2a5cf", "#e7d4e8", "#f7f7f7", "#d9f0d3", "#a6dba0", "#5aae61", "#1b7837"], # 方案 16: Purple-Green 紫绿渐变(高质量学术期刊通用差异比较) 17: ["#f7fbff", "#deebf7", "#c6dbef", "#9ecae1", "#6baed6", "#4292c6", "#2171b5", "#08519c", "#08306b", "#021536"], # 方案 17: Blues 经典单色系蓝色(适用于表达量/浓度基础热图) 18: ["#fcfbfd", "#efedf5", "#dadaeb", "#bcbddc", "#9e9ac8", "#807dba", "#6a51a3", "#54278f", "#3f007d", "#1d003f"], # 方案 18: Purples 经典单色系紫色(适用于蛋白质组学/单细胞强度分布) 19: ["#fff5f0", "#fee0d2", "#fcbba1", "#fc9272", "#fb6a4a", "#ef3b2c", "#cb181d", "#a50f15", "#67000d", "#340005"], # 方案 19: Reds 经典单色系红色(适用于通路富集分值/信号强度) 20: ["#000000", "#1a1a1a", "#333333", "#4d4d4d", "#666666", "#808080", "#999999", "#b3b3b3", "#cccccc", "#ffffff"] # 方案 20: Grayscale 单色黑白灰(适用于无彩印要求的经典图书/专利出版)}
import osimport pandas as pdimport numpy as npimport matplotlib.pyplot as pltimport matplotlib.gridspec as gridspecfrom matplotlib.colors import LinearSegmentedColormapfrom scipy.cluster.hierarchy import linkage, dendrogram# 符合主流期刊标准的专业科研配色方案字典COLOR_SCHEMES = { 1: ["#050505", "#183454", "#316896", "#5992c2", "#adc5e0", "#f6f6f8", "#fad69d", "#e28d32", "#b84d12", "#7c1206"], # 方案 1: Nature/Cell 经典红蓝黑蓝橙渐变(极高对比度)}# 选择配色方案(可通过修改此处的数字切换 1-20)SELECTED_SCHEME = 4colors = COLOR_SCHEMES[SELECTED_SCHEME]cmap = LinearSegmentedColormap.from_list("custom_heatmap", colors, N=256)output_dir = "图表"os.makedirs(output_dir, exist_ok=True)excel_path = "data.xlsx"df = pd.read_excel(excel_path)genes = df["Gene"].tolist()sample_cols = [c for c in df.columns if c != "Gene"]matrix = df.set_index("Gene")[sample_cols]control_cols = [c for c in sample_cols if "siControl" in c]kdm5a_cols = [c for c in sample_cols if "siKDM5A" in c]# 从数据中动态计算每列的真实均值control_means = matrix[control_cols].mean(axis=0).valueskdm5a_means = matrix[kdm5a_cols].mean(axis=0).values# 层次聚类树row_linkage = linkage(matrix.values, method='average', metric='euclidean')fig = plt.figure(figsize=(7.2, 6.2), dpi=300)gs = gridspec.GridSpec( nrows=3, ncols=4, width_ratios=[0.5, 1.2, 1.2, 1.3], height_ratios=[0.3, 0.6, 5.0], wspace=0.12, hspace=0.06)# 顶部分组标签ax_hdr_ctrl = fig.add_subplot(gs[0, 1])ax_hdr_ctrl.set_facecolor("#b3b3b3")ax_hdr_ctrl.text(0.5, 0.5, "siControl", ha='center', va='center', fontsize=13, fontweight='bold', color='#222222')ax_hdr_ctrl.set_xticks([])ax_hdr_ctrl.set_yticks([])ax_hdr_kdm = fig.add_subplot(gs[0, 2])ax_hdr_kdm.set_facecolor("#f1dfa3")ax_hdr_kdm.text(0.5, 0.5, "siKDM5A", ha='center', va='center', fontsize=13, fontweight='bold', fontstyle='italic', color='#222222')ax_hdr_kdm.set_xticks([])ax_hdr_kdm.set_yticks([])ax_hdr_txt = fig.add_subplot(gs[0, 3])ax_hdr_txt.axis('off')ax_hdr_txt.text(0.02, 0.5, "siRNA", ha='left', va='center', fontsize=13, fontweight='bold')# 顶部柱状图(根据数据自动计算绘制)ax_bar_ctrl = fig.add_subplot(gs[1, 1])ax_bar_ctrl.bar(np.arange(len(control_cols)), control_means, color="#808080", edgecolor='#333333', width=0.6, linewidth=0.8)ax_bar_ctrl.set_ylim(-1.1, 0.6)ax_bar_ctrl.set_yticks([-0.5, 0, 0.5])ax_bar_ctrl.tick_params(labelsize=9)ax_bar_ctrl.set_xticks([])ax_bar_kdm = fig.add_subplot(gs[1, 2])ax_bar_kdm.bar(np.arange(len(kdm5a_cols)), kdm5a_means, color="#e5c467", edgecolor='#333333', width=0.6, linewidth=0.8)ax_bar_kdm.set_ylim(-1.1, 0.6)ax_bar_kdm.set_yticks([])ax_bar_kdm.set_xticks([])ax_bar_lbl = fig.add_subplot(gs[1, 3])ax_bar_lbl.axis('off')ax_bar_lbl.text(0.02, 0.4, "Mean\nz-score", ha='left', va='center', fontsize=10, fontweight='bold', linespacing=1.0)ax_hdr_ctrl.text(-0.55, 1.25, "e", transform=ax_hdr_ctrl.transAxes, fontsize=18, fontweight='bold', ha='right', va='bottom')# 聚类树ax_dendro = fig.add_subplot(gs[2, 0])dendro = dendrogram(row_linkage, orientation='left', ax=ax_dendro, link_color_func=lambda k: '#222222', above_threshold_color='#222222', no_labels=True)ax_dendro.axis('off')# 热图 siControlax_hm_ctrl = fig.add_subplot(gs[2, 1])ax_hm_ctrl.imshow(matrix[control_cols].values, aspect='auto', cmap=cmap, vmin=-2, vmax=2)ax_hm_ctrl.set_xticks([])ax_hm_ctrl.set_yticks([])for spine in ax_hm_ctrl.spines.values(): spine.set_visible(False)# 热图 siKDM5Aax_hm_kdm = fig.add_subplot(gs[2, 2])im_kdm = ax_hm_kdm.imshow(matrix[kdm5a_cols].values, aspect='auto', cmap=cmap, vmin=-2, vmax=2)ax_hm_kdm.set_xticks([])ax_hm_kdm.set_yticks(np.arange(len(genes)))ax_hm_kdm.set_yticklabels(genes, fontsize=11, fontweight='regular')ax_hm_kdm.yaxis.tick_right()ax_hm_kdm.tick_params(axis='y', length=0, pad=6)for spine in ax_hm_kdm.spines.values(): spine.set_visible(False)# 色阶条 (Colorbar)ax_right_space = fig.add_subplot(gs[2, 3])ax_right_space.axis('off')cbar_ax = fig.add_axes([0.77, 0.22, 0.035, 0.28])cbar = fig.colorbar(im_kdm, cax=cbar_ax, orientation='vertical')cbar.set_ticks([-2, -1, 0, 1, 2])cbar.ax.tick_params(direction='in', color='white', length=4, width=1.2, left=True, right=True, labelsize=11)cbar.ax.set_yticklabels(['-2', '-1', '0', '1', '2'], color='black')cbar.outline.set_visible(False)cbar.ax.set_title("z-score", fontsize=11, fontweight='bold', pad=10, loc='left')# 保存带方案编号的文件名output_png = os.path.join(output_dir, f"heatmap_scheme_{SELECTED_SCHEME}.png")plt.savefig(output_png, bbox_inches='tight', dpi=300)plt.close()