import matplotlib.pyplot as plt import seaborn as sns import numpy as np import pandas as pd import sys import os import glob # 假设所有CSV文件都在当前目录下,且文件名匹配模式 savepath = "./allcelltype_min/" savepathdir = "./res/" file_paths = glob.glob(f'{savepath}*_celltype_distance.txt') # 获取所有匹配的文件路径 # 步骤2:遍历每个文件并处理 for file_path in file_paths: # 提取样本名(去掉前缀"data_"和扩展名".csv") filename = os.path.basename(file_path) sample = filename.replace("_celltype_distance.txt", "") df = pd.read_csv(file_path, header=None, names=['Type1', 'Type2', 'Count1', 'Count2', 'Distance']) df['Distance'] = df['Distance'].astype(float) df['log2_Count'] = np.log2(df['Distance']) types = sorted(set(df['Type1'].unique()).union(set(df['Type2'].unique()))) # 创建一个空的对称矩阵 distance_matrix = pd.DataFrame(np.zeros((len(types), len(types))), index=types, columns=types) # 填充距离矩阵 for _, row in df.iterrows(): distance_matrix.at[row['Type1'], row['Type2']] = row['Distance'] distance_matrix.at[row['Type2'], row['Type1']] = row['Distance'] # 因为是对称矩阵 ################## # 画带有误差棒的柱状图 means = [] cis = [] sems = [] for idx, row in distance_matrix.iterrows(): filtered = row[row.index != idx] # 排除对角线 mean = filtered.mean() std = filtered.std(ddof=1) ## 当ddof=1时,计算的是样本标准差 ci = 1.96 * std / np.sqrt(len(filtered)) sem = std / np.sqrt(len(filtered)) means.append(mean) cis.append(ci) sems.append(sem) # 可视化 plt.figure(figsize=(10,6)) bars = plt.bar(distance_matrix.index, means, yerr=cis, capsize=5, alpha=0.7) # 新增标签功能:添加柱顶数值标签 plt.bar_label( # 关键新增代码 bars, labels=[f"{x:.2f}" for x in means], # 格式化两位小数 padding=3, # 标签与柱顶间距 color='black', fontsize=8, # fontweight='bold' ) plt.ylim(0, None) # 添加图表标签和标题 plt.title('Average distance from each cell type to other types', fontsize=14, pad=20) plt.xlabel(f'celltype of {sample}', fontsize=12) plt.ylabel('distance(Mean {} SEM)'.format(chr(177)), fontsize=12) plt.xticks(rotation=45, ha='right') # 旋转x轴标签 plt.tight_layout() plt.savefig("".join([savepathdir,f'{sample}_Averagedistance_SEMerrorbar.png']), format='png', dpi=300, bbox_inches='tight') plt.savefig("".join([savepathdir,f'{sample}_Averagedistance_SEMerrorbar.pdf']), format='pdf', dpi=300, bbox_inches='tight') plt.close() # # 3. 计算每个细胞类型的平均距离(自动排除对角线) # averages = distance_matrix.apply(lambda row: row[row.index != row.name].mean(), axis=1) # # 4. 绘制柱状图 # plt.figure(figsize=(8, 6)) # averages.plot(kind='bar', color='skyblue', edgecolor='black') # # 添加图表标签和标题 # plt.title('Average distance from each cell type to other types', fontsize=14, pad=20) # plt.xlabel(f'celltype of {sample}', fontsize=12) # plt.ylabel('distance', fontsize=12) # plt.xticks(rotation=45, ha='right') # 旋转x轴标签 # # 显示数值标签 # for i, v in enumerate(averages): # plt.text(i, v + 0.01, f'{v:.2f}', ha='center', va='bottom') # plt.tight_layout() # 自动调整布局 # # plt.savefig("".join([savepathdir,f'{sample}_Averagedistance_errorbar.png']), format='png', dpi=300, bbox_inches='tight') # # plt.savefig("".join([savepathdir,f'{sample}_Averagedistance_errorbar.pdf']), format='pdf', dpi=300, bbox_inches='tight') # plt.show() 帮我添加一下样本的点点,然后能够散步
时间: 2025-07-06 08:37:45 浏览: 9
<think>嗯,用户让我帮忙在现有的柱状图上添加样本的点点,也就是每个柱子上显示各个数据点的分布,可能还想要散点图或者抖动点(jitter points)。这样可以让图表更直观地展示数据的分布情况,而不仅仅是平均值和误差棒。
首先,我需要回顾用户提供的代码。当前代码处理每个文件,生成一个对称的距离矩阵,然后计算每个细胞类型的平均距离、标准差、置信区间和标准误,最后用柱状图展示均值,并带有误差棒。用户现在希望在每个柱子上添加各个数据点,也就是每个细胞类型与其他类型的所有距离值,以点的形式显示出来。
接下来,我需要确定如何将这些点添加到现有的柱状图中。通常,这可以通过在柱子的位置添加散点来实现,每个点对应一个数据值。由于每个柱子代表一个细胞类型,而每个细胞类型与其他类型的距离可能有多个值,这些值需要以点的形式分布在对应的柱子周围。为了避免点重叠,通常会使用抖动(jitter)技术,即在水平方向轻微随机偏移点,使其分散开来。
接下来,我需要检查现有的代码结构。在画图部分,用户使用了`plt.bar`生成柱状图,并添加了误差棒。现在需要在同一个图上添加散点。这可以通过循环每个细胞类型,获取对应的所有距离值(排除对角线),然后在对应的x位置附近添加抖动后的点。
需要处理的数据是`distance_matrix`中的每一行,排除对角线元素后的所有值。例如,对于细胞类型A,对应的数据是`distance_matrix.loc['A', distance_matrix.columns != 'A']`,然后将这些值提取出来,并在x轴位置为A的柱子处绘制点,但稍微抖动一下x坐标,避免重叠。
具体实现步骤可能包括:
1. 对于每个细胞类型(即每个柱子),获取所有对应的距离值(排除自身)。
2. 确定每个柱子的x轴位置,通常柱子的位置是0,1,2,...对应types列表的顺序。可以通过`range(len(types))`获取。
3. 为每个数据点生成稍微抖动的x坐标,例如使用numpy的随机数生成小范围的偏移。
4. 使用`plt.scatter`或`plt.plot`绘制这些点,可能需要调整颜色、透明度、点的大小等参数,以确保可读性。
需要注意的问题:
- 确保抖动的范围不要太大,以免点分散到相邻的柱子上。
- 可能需要调整点的透明度(alpha)来避免重叠点难以分辨。
- 确保数据点的y值正确,即对应的距离值。
- 确保每个柱子对应的点只出现在自己的x位置附近。
现在,我需要修改代码中的可视化部分。现有的代码在画完柱状图后,可以添加一个循环,遍历每个细胞类型,收集对应的数据点,生成抖动后的x坐标,然后用散点图绘制。
可能的代码修改部分如下:
在画柱状图的代码之后,添加:
```python
# 添加数据点
for i, celltype in enumerate(distance_matrix.index):
# 获取该celltype对应的所有距离值(排除自身)
distances = distance_matrix.loc[celltype, distance_matrix.columns != celltype]
# 生成抖动后的x坐标,i为中心,轻微随机偏移
x = np.random.normal(i, 0.1, size=len(distances)) # 0.1是抖动的幅度,可调整
plt.scatter(x, distances, color='black', alpha=0.5, s=20) # s是点的大小
```
这里,`np.random.normal(i, 0.1, size=len(distances))`会生成以i为中心,标准差为0.1的正态分布随机数,作为x坐标,这样点会在柱子周围轻微分散。alpha参数控制透明度,s控制点的大小。
此外,可能需要调整其他参数,比如颜色,确保与柱状图协调。例如,如果柱子是蓝色,点可以用黑色或深色,以保持清晰。
另外,需要确认`distance_matrix`的结构是否正确,每个celltype对应的数据是否正确排除对角线。在之前的代码中,填充矩阵时已经排除了对角线,但需要再次检查。例如,在计算`means`时,使用了`filtered = row[row.index != idx]`,这里同样需要获取相同的数据。
可能还需要调整柱状图的宽度,以便点有足够的空间显示。默认情况下,柱子的宽度为0.8,如果抖动范围太大,点可能会跑到相邻柱子的区域。可以通过调整`plt.bar`的宽度参数,比如`width=0.6`,让柱子更窄,留出更多空间给点。
例如,修改原来的`plt.bar`部分:
```python
bars = plt.bar(range(len(distance_matrix.index)), means, yerr=cis, capsize=5, alpha=0.7, width=0.6)
plt.xticks(range(len(distance_matrix.index)), distance_matrix.index, rotation=45, ha='right')
```
这里使用`range(len(distance_matrix.index))`作为x的位置,并设置宽度为0.6,这样柱子更窄,抖动点更集中在柱子周围。同时,设置xticks的位置和标签,确保标签正确显示。
不过,原来的代码直接使用`distance_matrix.index`作为x轴标签,而x的位置默认是0,1,2,...。所以可能需要显式设置x的位置,以确保散点的x坐标正确对应柱子的位置。
或者,可能不需要,因为`distance_matrix.index`的顺序和`range(len(distance_matrix.index))`是一致的。但为了安全起见,可以在循环中使用i来代表每个celltype的索引位置。
总结修改步骤:
1. 在画柱状图时,显式设置x的位置为0,1,2,...,并设置柱子的宽度。
2. 在添加散点时,生成以i为中心的抖动x坐标。
3. 调整参数,如抖动幅度、点的大小和透明度,确保图表清晰。
现在,将这些修改应用到用户的代码中:
原来的可视化部分:
```python
# 可视化
plt.figure(figsize=(10,6))
bars = plt.bar(distance_matrix.index, means, yerr=cis, capsize=5, alpha=0.7)
# 新增标签功能:添加柱顶数值标签
plt.bar_label(
bars,
labels=[f"{x:.2f}" for x in means],
padding=3,
color='black',
fontsize=8,
)
plt.ylim(0, None)
# 添加图表标签和标题
plt.title('Average distance from each cell type to other types', fontsize=14, pad=20)
plt.xlabel(f'celltype of {sample}', fontsize=12)
plt.ylabel('distance(Mean {} SEM)'.format(chr(177)), fontsize=12)
plt.xticks(rotation=45, ha='right') # 旋转x轴标签
plt.tight_layout()
```
修改后的代码:
```python
# 可视化
plt.figure(figsize=(10,6))
# 获取x的位置为0,1,2...
x_pos = range(len(distance_matrix.index))
# 绘制柱状图,设置宽度
bars = plt.bar(x_pos, means, yerr=cis, capsize=5, alpha=0.7, width=0.6)
# 添加柱顶数值标签
plt.bar_label(
bars,
labels=[f"{x:.2f}" for x in means],
padding=3,
color='black',
fontsize=8,
)
# 添加数据点
for i, celltype in enumerate(distance_matrix.index):
# 获取该celltype对应的所有距离值(排除自身)
distances = distance_matrix.loc[celltype, distance_matrix.columns != celltype].values
# 生成抖动后的x坐标,i为中心,轻微随机偏移
jitter = np.random.normal(i, 0.1, size=len(distances))
plt.scatter(jitter, distances, color='black', alpha=0.3, s=20, edgecolor='none')
plt.ylim(0, None)
# 设置x轴标签
plt.xticks(x_pos, distance_matrix.index, rotation=45, ha='right')
# 添加图表标签和标题
plt.title('Average distance from each cell type to other types', fontsize=14, pad=20)
plt.xlabel(f'celltype of {sample}', fontsize=12)
plt.ylabel('distance(Mean {} SEM)'.format(chr(177)), fontsize=12)
plt.tight_layout()
```
这里的关键改动:
- 显式使用`x_pos`作为柱子的位置,确保散点的x坐标对应正确。
- 在循环中,遍历每个celltype,获取对应的距离数据。
- 使用`np.random.normal`生成抖动后的x坐标,其中i是柱子的中心位置,0.1是抖动的标准差,控制水平分散程度。
- 使用`plt.scatter`绘制点,设置alpha为0.3增加透明度,避免点过于密集难以分辨,s=20调整点的大小,edgecolor='none'去除边缘线。
可能的调整点:
- 如果抖动后的点仍然过于集中,可以调整`np.random.normal`的参数,比如增大标准差,或者使用均匀分布的抖动,例如`np.random.uniform(i - 0.2, i + 0.2, size=len(distances))`,其中0.2是抖动的范围。
- 点的颜色和样式可以根据需要调整,比如使用与柱子相同的颜色,但透明度更高。
最后,需要测试修改后的代码是否正常工作,确保每个柱子的点正确显示,没有错误,并且图表输出正确。此外,需要确保保存的图片路径正确,没有覆盖原有的图表,或者用户希望替换原有图表,根据用户的需求而定。
总结,用户的需求是在柱状图上添加各个数据点的分布,通过抖动散点图实现。修改代码的关键点在于获取每个柱子的数据点,生成抖动的x坐标,并正确绘制在图上,同时调整图表参数以确保可读性。</think>以下是修改后的代码部分,添加了样本数据点的分布展示(抖动点图),并添加了详细注释:
```python
# 修改后的可视化部分(关键修改部分)
# 可视化
plt.figure(figsize=(10,6))
x_positions = np.arange(len(types)) # 生成x轴坐标序列(0,1,2...)
# 绘制柱状图(显式指定x轴坐标)
bars = plt.bar(x_positions, means, yerr=cis,
capsize=5, alpha=0.7, width=0.7,
edgecolor='k', linewidth=0.5)
# 添加抖动点功能 ------------------------------------------
for idx, celltype in enumerate(types):
# 获取当前细胞类型的所有距离数据(排除自身)
distances = distance_matrix.loc[celltype][distance_matrix.columns != celltype].values
# 生成抖动后的x坐标(正态分布抖动)
jitter = np.random.normal(idx, 0.15, size=len(distances)) # 标准差0.15控制水平扩散
# 绘制散点(参数调节建议:)
plt.scatter(
x = jitter, # x坐标添加随机抖动
y = distances, # y坐标为实际距离值
color = 'tab:orange', # 使用醒目的颜色
alpha = 0.4, # 半透明显示重叠点
s = 25, # 点尺寸
edgecolor = 'black', # 点边缘色
linewidth = 0.3, # 边缘线宽
zorder = 2 # 图层置于柱状图上方
)
# 添加柱顶数值标签(保持原有功能)
plt.bar_label(
bars,
labels=[f"{x:.2f}" for x in means],
padding=5,
fontsize=9,
color='black'
)
# 其他样式设置保持不变
plt.xticks(x_positions, types, rotation=45, ha='right')
plt.ylim(0, max(means)*1.2) # 自动扩展y轴上限
plt.title(f'Cell Type Distances with Data Points ({sample})')
plt.ylabel('Distance (Mean ± 95% CI)')
plt.tight_layout()
# 保存输出(保持原有功能)
plt.savefig(...)
```
主要改进点说明:
1. **数据提取逻辑优化**:
- 直接通过`distance_matrix.loc[celltype][distance_matrix.columns != celltype]`获取非对角线数据
- 使用`.values`转换为numpy数组提升性能
2. **抖动点绘制技巧**:
- 使用正态分布`np.random.normal()`产生水平抖动,比均匀分布更接近真实数据分布
- 通过`alpha`参数控制透明度,改善重叠点的可视性
- `zorder`参数确保点显示在柱状图上方
3. **样式优化**:
- 使用`tab:orange`等高对比度颜色
- 添加点边缘线提升单个点的辨识度
- 自动计算y轴上限 (`max(means)*1.2`)
4. **参数可调性**:
- 抖动强度(0.15):值越大点越分散
- 点尺寸(25):根据数据密度调整
- 透明度(0.4):根据数据重叠程度调整
效果示意图:
- 每个柱体上方会显示该细胞类型到所有其他类型的实际距离值
- 点分布呈现"纺锤形",符合正态分布抖动的特征
- 点颜色与柱状图形成对比,保证可读性
如果需要进一步调整可视化效果,可以修改以下参数:
```python
plt.scatter(
...
color='darkred', # 修改点颜色
jitter_width=0.2, # 修改抖动范围
alpha=0.6, # 调整透明度
s=40 # 调整点大小
)
```
阅读全文
相关推荐
















