我正在使用 python Seaborn 进行绘图:
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
import matplotlib.colors as c
from matplotlib.patches import Patch
from matplotlib.ticker import FixedLocator
data = {
'Sample1 stateA': np.random.randint(1, 11, 5),
'Sample1 stateB': np.random.randint(1, 11, 5),
'Sample1 stateC': np.random.randint(1, 11, 5),
'Sample2 stateA': np.random.randint(1, 11, 5),
'Sample2 stateB': np.random.randint(1, 11, 5),
'Sample2 stateC': np.random.randint(1, 11, 5),
}
# Create the DataFrame
df = pd.DataFrame(data)
# Plot
plt.figure(figsize=(12, 8))
ax = sns.heatmap(data
cbar=False,
linewidths=0.1,
linecolor='black',
annot=False,
vmin=1,
vmax=10
)
我想在 x 轴顶部和底部添加不同的标签,类似于以下内容: 底部标签:
xticks_labels = []
for i, label in enumerate(data.columns):
# Split sample name and condition
sample_name, condition = label.split(' ', 1)
xticks_labels.append(condition) # Only show condition name on the heatmap top
# Set the xticks to show the condition
ax.set_xticklabels(xticks_labels, rotation=90)
顶部标签,这个更加精细,因为我想将一个标签放在一组列的中心:
# Set the ticks for the sample
# Get the sample names in the order of the sample columns
# Create a secondary x-axis for the sample names
ax2 = ax.twiny()
sample_names = [item.split(" ")[0] for item in data.columns]
ax2.yaxis.tick_left()
ticks = []
labels = []
prev_label = None
for i, label in enumerate(sample_names):
if label != prev_label:
ticks.append(i)
labels.append(label)
prev_label = label
ticks.append(i + 1)
ax2.xaxis.set_minor_locator(FixedLocator(ticks))
ax2.xaxis.set_major_locator(FixedLocator([(t0 + t1) / 2 for t0, t1 in zip(ticks[:-1], ticks[1:])]))
ax2.set_xticklabels(labels, rotation=0)
ax2.tick_params(axis='both', which='major', length=0)
ax2.tick_params(axis='x', which='minor', length=60)
# Show ax2 on top so it doesn't get hidden
ax2.spines['top'].set_position(('outward', 40))
# Adjust the layout to make sure both sets of labels are visible
plt.tight_layout()
# Save the plot to a file
plt.savefig(heatmap_file, dpi=300, bbox_inches='tight')
如果我执行上述操作,为顶部标签创建辅助轴,我只能得到底部标签(辅助轴未显示)。
如果我尝试使用同一轴制作顶部标签(使用 ax 而不是 ax2,我可以看到顶部标签,但看不到底部):
ax.yaxis.tick_left()
ticks = []
labels = []
prev_label = None
for i, label in enumerate(sample_names):
if label != prev_label:
ticks.append(i)
labels.append(label)
prev_label = label
ticks.append(i + 1)
ax.xaxis.set_minor_locator(FixedLocator(ticks))
ax.xaxis.set_major_locator(FixedLocator([(t0 + t1) / 2 for t0, t1 in zip(ticks[:-1], ticks[1:])]))
ax.set_xticklabels(labels, rotation=0)
ax.tick_params(axis='both', which='major', length=0)
ax.tick_params(axis='x', which='minor', length=60)
# Show ax2 on top so it doesn't get hidden
ax.spines['top'].set_position(('outward', 40))
# Adjust the layout to make sure both sets of labels are visible
plt.tight_layout()
谢谢你。
如果我正确理解你的问题,我认为你选择绘制辅助轴使这个问题变得过于复杂,我会使用
ax.text()
的方法(顺便说一句,我不知道为什么辅助轴或主轴是不显示)。
试试这个,希望能成功:
# Bottom labels
xticks_labels = [label.split(' ', 1)[1] for label in df.columns]
ax.set_xticklabels(xticks_labels, rotation=90)
# Top labels
sample_names = [label.split(' ', 1)[0] for label in df.columns]
# Calculate the midpoint of each group of conditions for top labels
mid_points = []
for i in range(len(sample_names)):
if i == 0 or sample_names[i] != sample_names[i-1]:
start = i
if i == len(sample_names) - 1 or sample_names[i] != sample_names[i+1]:
mid_points.append((start + i) / 2)
# Add top labels using ax.text()
for i, midpoint in enumerate(mid_points):
ax.text(midpoint, -0.1, sample_names[midpoint], ha='center', va='center', transform=ax.get_xaxis_transform(), fontsize=12)