Mpl绘制心肌模型图方法二:Axes.bar + polar 坐标系

上一篇介绍了 AHA 的 左心室17段分割模型的定义,和用 axes.pie() 绘制该模型图的方法。

还可以用 matplotlib 的 axes.bar() + polar绘制该模型图,这种方法相对于 axes.pie() 方法更加灵活适用。

模型的元数据、完整的代码、高清成图请到资源中下载:

https://download.csdn.net/download/sinat_32570141/15196030

Axes.bar() + polar 实现

polar + bar 绘制圆环图官方示例

import matplotlib.pyplot as plt
import numpy as np

fig, ax = plt.subplots(subplot_kw=dict(polar=True))

size = 0.3
vals = np.array([[60., 32.], [37., 40.], [29., 10.]])
#normalize vals to 2 pi
valsnorm = vals/np.sum(vals)*2*np.pi
#obtain the ordinates of the bar edges
valsleft = np.cumsum(np.append(0, valsnorm.flatten()[:-1])).reshape(vals.shape)

cmap = plt.get_cmap("tab20c")
outer_colors = cmap(np.arange(3)*4)
inner_colors = cmap([1, 2, 5, 6, 9, 10])

ax.bar(x=valsleft[:, 0],
       width=valsnorm.sum(axis=1), bottom=1-size, height=size,
       color=outer_colors, edgecolor='w', linewidth=1, align="edge")

ax.bar(x=valsleft.flatten(),
       width=valsnorm.flatten(), bottom=1-2*size, height=size,
       color=inner_colors, edgecolor='w', linewidth=1, align="edge")

ax.set(title="Pie plot with `ax.bar` and polar coordinates")
ax.set_axis_off()

plt.savefig("assets/bar_pie.png",facecolor='w',dpi=150)
plt.show()

Mpl绘制心肌模型图方法二:Axes.bar + polar 坐标系_第1张图片

bar 转换为圆环图的原理

Axes.bar(self, x, 
         height, width=0.8, 
         bottom=None, *, 
         align='center', data=None, 
         **kwargs)
  • x, float 序列, bar 的 x-axis 上的位置;映射为圆环每段的开始角度。
  • height, float 序列, bar 的高度;映射为圆环每段的宽度(极径差)。
  • width,float 序列,bar 的宽度;映射为圆环每段的弧长;
  • color color
  • edgecolor or ec color or None or ‘auto’
  • facecolor or fc color or None

上面的圆环图还原成 bar 图如下:
Mpl绘制心肌模型图方法二:Axes.bar + polar 坐标系_第2张图片
bar 转换为 圆环图的过程实际就是将 bar弯曲成环状。首先要将 bar 在笛卡尔坐标系中的坐标、尺寸映射到 polar坐标系。

bar + polar 绘制心肌模型图

导入数据

import numpy as np
import pandas as pd

MS_df = pd.read_csv('17-Segment.csv')

数据格式如下:

MS_N MS_FullName MS Part Seg_Nu CA_Color CA Angle
0 1 basal anterior (segment 1) basal anterior segment 1 (66,148, 247) LAD 60
1 2 basal anteroseptal (segment 2) basal anteroseptal segment 2 (66,148, 247) LAD 60
2 3 basal inferoseptal (segment 3) basal inferoseptal segment 3 (254, 252, 82) RCA 60

定义颜色生成函数

# 将[0,255]整数表示的RGB颜色值转化为[0,1]浮点数表示的RGB值元组
def make_color(df_col):
    ca_rgb = []
    for i in df_col:
        temp = i.replace('(','').replace(')','')
        temp_rgb = tuple([(int(j)/255) for j in temp.split(',')])
        ca_rgb.append(temp_rgb)
    return ca_rgb        
ms = ('basal','mid','apical','apex')
ca = ('LAD','RCA','LCX')

生成绘制模型三部分的基础数据

x_basal = MS_df[MS_df['MS']=='basal']['Angle'].values.tolist()
x_mid = MS_df[MS_df['MS']=='mid']['Angle'].values.tolist()
x_apical = MS_df[MS_df['MS']=='apical']['Angle'].values.tolist()
x_apex = MS_df[MS_df['MS']=='apex']['Angle'].values.tolist()
c_basal = make_color(MS_df[MS_df['MS']=='basal']['CA_Color'])
c_mid = make_color(MS_df[MS_df['MS']=='mid']['CA_Color'])
c_apical = make_color(MS_df[MS_df['MS']=='apical']['CA_Color'])
c_apex = make_color(MS_df[MS_df['MS']=='apex']['CA_Color'])
l_basal = MS_df[MS_df['MS']=='basal']['MS_N'].values.tolist()
l_mid = MS_df[MS_df['MS']=='mid']['MS_N'].values.tolist()
l_apical = MS_df[MS_df['MS']=='apical']['MS_N'].values.tolist()
l_apex = MS_df[MS_df['MS']=='apex']['MS_N'].values.tolist()

自定义函数将bar数据映射到 polar 坐标系

笛卡尔坐标数据到 polar 坐标系的映射

# 生成绘制 bar 需要的 x, width
# x 是 bar 的位置,需要映射到 `[0, 2*np.pi]`区间
# width 是每个 bar 的宽度,sum(width) = 2*np.pi
# AHA 的 17-segment 模型图,环形从非 0 开始,所以需要一个偏移
# 偏移类似 axes.pie() 函数的 startangle 参数

def make_x_w(xdata, offset=60):
    bar_x = []
    bar_w = []
    for i, v in enumerate(xdata):
        ......
        ......        
    return bar_x, bar_w    

主图的绘制

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

fig = plt.figure(figsize=(6.4,4.8),
                 facecolor='w',
                 constrained_layout=False)

ax = plt.axes((0.125,0.15,0.75,0.775),polar=True)
axc = fig.add_axes([0.255, 0.11, 0.5, 0.04])

ax.set_axis_off()

size = 0.25 # rings 环极径差

# bars_basal 环
bars_basal = ax.bar(x=make_x_w(x_basal,60)[0],
       width=make_x_w(x_basal)[1], 
       bottom=1-size, 
       height=size,
       color=c_basal, 
       edgecolor='k', 
       linewidth=0.5, 
       align="edge"
      )

#bars_mid 环
.....

#bars_apical 环
....

#apex 段也可以通过 Circle 实现
circle = plt.Circle((0.0, 0.0), size, 
                    transform=ax.transData._b, 
                    fc=c_apex[0],
                    ec='k',
                    linewidth=0.5)
ax.add_artist(circle)

# 标记 17 段的函数
def autolabel(rects,l_seg):
    for i, rect in enumerate(rects):
        height = rect.get_height()
        ax.annotate('{}'.format(l_seg[i]),
                    xy=(rect.get_x() + rect.get_width() / 2, 
                        rects[i]._y0+0.125),
                    ha='center', va='center')

.....

ax.set(title="Draw AHA17-S module by bar + polar coordinates ")
plt.savefig('assets/bar_polar_bullseye.png',facecolor='w',dpi=200)

plt.show()

完成的图如下:
Mpl绘制心肌模型图方法二:Axes.bar + polar 坐标系_第3张图片

心肌模型图的 bar 图

上面的心肌模型图对应的 axes.bar 图如下:
Mpl绘制心肌模型图方法二:Axes.bar + polar 坐标系_第4张图片
有任何问题,欢迎到 python草堂QQ群:457079928 讨论交流。

你可能感兴趣的:(matplotlib,Python,python,matplotlib)