利用python绘制连接从属关系弦图

本文介绍了一种在R语言工具包不足的情况下,如何用Python实现绘制脑区网络与节点关系的弦图,包括数据构建、贝塞尔曲线的使用以及详细代码示例。
摘要由CSDN通过智能技术生成

 前言

        弦图是一种较为实用的可视化图,它可以展示出各部分之间的关系。通常用于生信领域,探求个物种之间的相互作用与关系,利用R语言中的工具包可轻松画出。

        然而,对于脑的研究来说,R语言的弦图绘制工具包略有不足,比如大脑中存在多个脑区,而每个脑区又属于不同的网络,存在一个系列包含的关系,故R语言弦图无法满足这一要求。此外,python的弦图绘制工具包收费,对于学生党来说不太友好,故我写了一个绘制网络与节点的关系弦图。其代码包含两个步骤:1、外侧的圆环绘制(网络区域);2、内侧各节点连接曲线绘制。

原理及代码

        首先构建你的数据,一个对称矩阵,这里的示例数据为一个69*69的连接矩阵。

        接下来,需要创建一个类,规定内侧的连接曲线绘制方法,这里采用贝塞斯曲线,相较于直线或其他线来说,更加美观。

# 调用工具包
from matplotlib.font_manager import FontProperties
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
# 写一个贝塞斯曲线的类:
class BezierCurve:
    def __init__(self, control_points):    # 其包含了后续绘制图中所需的节点坐标
        self.control_points = np.array(control_points)
    def evaluate(self, t):    #  在给定参数t下计算曲线上的点的坐标
        n = len(self.control_points) - 1
        return np.sum([self.control_points[i] * self.bernstein_poly(i, n, t) for i in range(n + 1)], axis=0)
    def bernstein_poly(self, i, n, t):    # 计算贝塞尔基函数的值
        return np.math.comb(n, i) * (t ** i) * ((1 - t) ** (n - i))

       下一步是对数据进行绘制,分别是内侧个节点的连接,以及外侧个节点的上层网络。由于连接有正有负,故分为值>0和值<0两步:

# 曲线绘制代码:
def draw_chord_plot(df):    # 首先规定了基础的网络大小、色彩、字号等
    plt.rcParams.update({'font.size': 30})
    class_sizes = [12,15,13,10,5,6,8]
    class_names = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
    custom_colors = ['#008F7A','#0089BA', '#2C73D2', '#845EC2', '#FF6F91', '#FF9671', '#FFC75F']
    custom_cmap = ListedColormap(custom_colors)
    cmap = custom_cmap
    colors = [cmap(i) for i in range(len(class_sizes))]
    plt.figure(figsize=(20, 16))
    plt.pie(class_sizes, labels=class_names, startangle=0, colors=colors, wedgeprops=dict(width=0.5, linewidth=15, edgecolor='white'), textprops={'fontsize': 30})
    centre_circle = plt.Circle((0, 0),0.9, fc='white')
    fig = plt.gcf()
    fig.gca().add_artist(centre_circle)
    sorted_values = df.values.flatten()
    sorted_values.sort()
    for i in range(69):    # 绘制正连接曲线
        for j in range(i + 1, 69):
            value = df.iloc[i, j]
            if value > 0:
                angle_i = i * 360 / 69
                angle_j = j * 360 / 69
                x_i, y_i = 0.87 * np.cos(np.radians(angle_i)), 0.87 * np.sin(np.radians(angle_i))
                x_j, y_j = 0.87 * np.cos(np.radians(angle_j)), 0.87 * np.sin(np.radians(angle_j))
                # 使用自定义的贝塞尔曲线
                bezier_curve = BezierCurve([(x_i, y_i), (0,0),(x_j, y_j)])
                t_values = np.linspace(0, 1, 90)
                curve_points = np.array([bezier_curve.evaluate(t) for t in t_values])
                # 线条粗细和颜色
                color = '#D86161'
                # 线条粗细和颜色
                max_line_width = 10
                linewidths = max_line_width * np.concatenate((np.linspace(1, 0.1, 45), np.linspace(0.1, 1, 45)))
                # 添加曲线
                for t in range(1, len(curve_points)):
                    plt.plot([curve_points[t - 1, 0], curve_points[t, 0]],
                             [curve_points[t - 1, 1], curve_points[t, 1]],
                             color=color, linewidth=linewidths[t], alpha=1)
    for i in range(69):    # 绘制负连接曲线
        for j in range(i + 1, 69):
            value = df.iloc[i, j]
            if value < 0:
                angle_i = i * 360 / 69
                angle_j = j * 360 / 69
                x_i, y_i = 0.87 * np.cos(np.radians(angle_i)), 0.87 * np.sin(np.radians(angle_i))
                x_j, y_j = 0.87 * np.cos(np.radians(angle_j)), 0.87 * np.sin(np.radians(angle_j))
                # 使用自定义的贝塞尔曲线
                bezier_curve = BezierCurve([(x_i, y_i), (0,0),(x_j, y_j)])
                t_values = np.linspace(0, 1, 90)
                curve_points = np.array([bezier_curve.evaluate(t) for t in t_values])
                # 线条粗细和颜色
                color = '#6D9AEF'
                max_line_width = 10
                linewidths = max_line_width * np.concatenate((np.linspace(1, 0.1, 45), np.linspace(0.1, 1, 45)))
                for t in range(1, len(curve_points)):
                    plt.plot([curve_points[t - 1, 0], curve_points[t, 0]],
                             [curve_points[t - 1, 1], curve_points[t, 1]],
                             color=color, linewidth=linewidths[t], alpha=1)
    # 外周圆环图例
    class_names = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
    legend_handles = [Line2D([0], [0], marker='o', color='w', markerfacecolor=c, markersize=30, label=l)
                      for c, l in zip(colors, class_names)]
    plt.legend(handles=legend_handles, bbox_to_anchor=(0.95, 0.8), loc='upper left',frameon=False)
    plt.axis('equal')

        最后就是带入示例数据至以上代码:

df = pd.read_csv('示例文件')
draw_chord_plot(df)
plt.savefig('保存文件')
plt.show()

        代码最终绘制成图如下:

  • 13
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值