这是我在 stackoverflow 上的第一篇文章,所以请保持温和。
这是我的问题: 我在一个网站上找到了一个非常好的 python 脚本,我不得不稍微修改一下以满足我的需要,现在我想再次修改它,但我不知道如何修改
先上代码
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
def bullseye_plot(ax, data, segBold=None, cmap=None, norm=None):
"""
Bullseye representation for the left ventricle.
Parameters
----------
ax : axes
data : list of int and float
The intensity values for each of the 17 segments
segBold: list of int, optional
A list with the segments to highlight
cmap : ColorMap or None, optional
Optional argument to set the desired colormap
norm : Normalize or None, optional
Optional argument to normalize data into the [0.0, 1.0] range
Notes
-----
This function create the 17 segment model for the left ventricle according
to the American Heart Association (AHA) [1]_
References
----------
.. [1] M. D. Cerqueira, N. J. Weissman, V. Dilsizian, A. K. Jacobs,
S. Kaul, W. K. Laskey, D. J. Pennell, J. A. Rumberger, T. Ryan,
and M. S. Verani, "Standardized myocardial segmentation and
nomenclature for tomographic imaging of the heart",
Circulation, vol. 105, no. 4, pp. 539-542, 2002.
"""
if segBold is None:
segBold = []
linewidth = 2
data = np.array(data).ravel()
if cmap is None:
cmap = plt.cm.viridis
if norm is None:
norm = mpl.colors.Normalize(vmin=data.min(), vmax=data.max())
theta = np.linspace(0, 2*np.pi, 768)
r = np.linspace(0, 1, 4)
# Create the bound for the segment 17
for i in range(r.shape[0]):
ax.plot(theta, np.repeat(r[i], theta.shape), '-k', lw=linewidth)
# Create the bounds for the segments 1-12
for i in range(6):
theta_i = i*60*np.pi/180
ax.plot([theta_i, theta_i], [r[1], 1], '-k', lw=linewidth)
# Create the bounds for the segments 13-16
for i in range(4):
theta_i = i*90*np.pi/180 - 45*np.pi/180
ax.plot([theta_i, theta_i], [r[0], r[1]], '-k', lw=linewidth)
# Fill the segments 1-6
r0 = r[2:4]
r0 = np.repeat(r0[:, np.newaxis], 128, axis=1).T
for i in range(6):
# First segment start at 60 degrees
theta0 = theta[i*128:i*128+128] + 60*np.pi/180
theta0 = np.repeat(theta0[:, np.newaxis], 2, axis=1)
z = np.ones((128, 2))*data[i]
ax.pcolormesh(theta0, r0, z, cmap=cmap, norm=norm)
if i+1 in segBold:
ax.plot(theta0, r0, '-k', lw=linewidth+2)
ax.plot(theta0[0], [r[2], r[3]], '-k', lw=linewidth+1)
ax.plot(theta0[-1], [r[2], r[3]], '-k', lw=linewidth+1)
# Fill the segments 7-12
r0 = r[1:3]
r0 = np.repeat(r0[:, np.newaxis], 128, axis=1).T
for i in range(6):
# First segment start at 60 degrees
theta0 = theta[i*128:i*128+128] + 60*np.pi/180
theta0 = np.repeat(theta0[:, np.newaxis], 2, axis=1)
z = np.ones((128, 2))*data[i+6]
ax.pcolormesh(theta0, r0, z, cmap=cmap, norm=norm)
if i+7 in segBold:
ax.plot(theta0, r0, '-k', lw=linewidth+2)
ax.plot(theta0[0], [r[1], r[2]], '-k', lw=linewidth+1)
ax.plot(theta0[-1], [r[1], r[2]], '-k', lw=linewidth+1)
# Fill the segments 13-16
r0 = r[0:2]
r0 = np.repeat(r0[:, np.newaxis], 192, axis=1).T
for i in range(4):
# First segment start at 45 degrees
theta0 = theta[i*192:i*192+192] + 45*np.pi/180
theta0 = np.repeat(theta0[:, np.newaxis], 2, axis=1)
z = np.ones((192, 2))*data[i+12]
ax.pcolormesh(theta0, r0, z, cmap=cmap, norm=norm)
if i+13 in segBold:
ax.plot(theta0, r0, '-k', lw=linewidth+2)
ax.plot(theta0[0], [r[0], r[1]], '-k', lw=linewidth+1)
ax.plot(theta0[-1], [r[0], r[1]], '-k', lw=linewidth+1)
ax.set_ylim([0, 1])
ax.set_yticklabels([])
ax.set_xticklabels([])
# Create the fake data
data = np.array(range(17)) + 1
# Make a figure and axes with dimensions as desired.
fig, ax = plt.subplots(figsize=(12, 8), nrows=1, ncols=1,
subplot_kw=dict(projection='polar'))
fig.canvas.set_window_title('Left Ventricle Bulls Eyes (AHA)')
# Set the colormap and norm to correspond to the data for which
# the colorbar will be used.
cmap = mpl.cm.viridis
norm = mpl.colors.Normalize(vmin=1, vmax=17)
# Create the 17 segment model
bullseye_plot(ax, data, cmap=cmap, norm=norm)
ax.set_title('Bulls Eye (AHA)')
plt.show()
它生成我们所说的 bulleye map ,查看生成的输出: Bulleye map
我想做的事情很容易解释:
-我想在每个段中适本地添加一个或两个数字(最大)(在这张图片中,有 16 个段)。
-根据数字的值(当只有一个数字时),我希望能够将每个段关联到不同的阴影/颜色。例如,如果我有“2”,则相关段的颜色将为红色。如果我有“4”,相关段的颜色也可能是红色但更暗。类似的东西。
如果这样的事情不可能,至少我希望根据与给定段关联的数字使用不同的颜色。
我不太了解 python,所以我不知道该怎么做,而且我的问题非常具体,以至于我真的不知道在哪里寻找答案。 如果您能帮助我,我将不胜感激。
PS:另外,如果您认为代码可以以某种方式改进(或者有一些无用的部分),请告诉我。
提前谢谢你。
PS:为了表彰第一个代码的作者,这里是原文链接 How to generate bulleye map
到目前为止,我用 Latex 做了类似的事情,这是我在每个段有 2 个数字时获得的图片。我希望它能让我更容易地“描绘”出我想要的东西。 Bulleye map - LateX version
更新:通过结合接受的答案和原始脚本中的一些想法,我终于得到了我想要的。 这是脚本
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
def bullseye_plot(ax, data, segBold=None, cmap=None, norm=None, labels=[], labelProps={}):
if segBold is None:
segBold = []
linewidth = 2
data = np.array(data).ravel()
if cmap is None:
cmap = plt.cm.viridis
if norm is None:
norm = mpl.colors.Normalize(vmin=data.min(), vmax=data.max())
theta = np.linspace(0, 2*np.pi, 768)
r = np.linspace(0, 1, 4)
# Create the bound for the segment 17
for i in range(r.shape[0]):
ax.plot(theta, np.repeat(r[i], theta.shape), '-k', lw=linewidth)
# Create the bounds for the segments 1-12
for i in range(6):
theta_i = i*60*np.pi/180
ax.plot([theta_i, theta_i], [r[1], 1], '-k', lw=linewidth)
# Create the bounds for the segments 13-16
for i in range(4):
theta_i = i*90*np.pi/180 - 45*np.pi/180
ax.plot([theta_i, theta_i], [r[0], r[1]], '-k', lw=linewidth)
# Fill the segments 1-6
r0 = r[2:4]
r0 = np.repeat(r0[:, np.newaxis], 128, axis=1).T
for i in range(6):
# First segment start at 60 degrees
theta0 = theta[i*128:i*128+128] + 60*np.pi/180
theta0 = np.repeat(theta0[:, np.newaxis], 2, axis=1)
z = np.ones((128, 2))*data[i]
ax.pcolormesh(theta0, r0, z, cmap=cmap, norm=norm)
if labels:
ax.annotate(labels[i], xy=(theta0[0,0]+30*np.pi/180,np.mean(r[2:4])), ha='center', va='center', **labelProps)
if i+1 in segBold:
ax.plot(theta0, r0, '-k', lw=linewidth+2)
ax.plot(theta0[0], [r[2], r[3]], '-k', lw=linewidth+1)
ax.plot(theta0[-1], [r[2], r[3]], '-k', lw=linewidth+1)
# Fill the segments 7-12
r0 = r[1:3]
r0 = np.repeat(r0[:, np.newaxis], 128, axis=1).T
for i in range(6):
# First segment start at 60 degrees
theta0 = theta[i*128:i*128+128] + 60*np.pi/180
theta0 = np.repeat(theta0[:, np.newaxis], 2, axis=1)
z = np.ones((128, 2))*data[i+6]
ax.pcolormesh(theta0, r0, z, cmap=cmap, norm=norm)
if labels:
ax.annotate(labels[i+6], xy=(theta0[0,0]+30*np.pi/180,np.mean(r[1:3])), ha='center', va='center', **labelProps)
if i+7 in segBold:
ax.plot(theta0, r0, '-k', lw=linewidth+2)
ax.plot(theta0[0], [r[1], r[2]], '-k', lw=linewidth+1)
ax.plot(theta0[-1], [r[1], r[2]], '-k', lw=linewidth+1)
# Fill the segments 13-16
r0 = r[0:2]
r0 = np.repeat(r0[:, np.newaxis], 192, axis=1).T
for i in range(4):
# First segment start at 45 degrees
theta0 = theta[i*192:i*192+192] + 45*np.pi/180
theta0 = np.repeat(theta0[:, np.newaxis], 2, axis=1)
z = np.ones((192, 2))*data[i+12]
ax.pcolormesh(theta0, r0, z, cmap=cmap, norm=norm)
if labels:
ax.annotate(labels[i+12], xy=(theta0[0,0]+45*np.pi/180,np.mean(r[0:2])), ha='center', va='center', **labelProps)
if i+13 in segBold:
ax.plot(theta0, r0, '-k', lw=linewidth+2)
ax.plot(theta0[0], [r[0], r[1]], '-k', lw=linewidth+1)
ax.plot(theta0[-1], [r[0], r[1]], '-k', lw=linewidth+1)
ax.set_ylim([0, 1])
ax.set_yticklabels([])
ax.set_xticklabels([])
# Create the fake data
labels = ['1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'10',
'11',
'12',
'13',
'14',
'15',
'16']
data=[]
for i in range(len(labels)):
x=int(labels[i])
data.append(x)
# Make a figure and axes with dimensions as desired.
fig, ax = plt.subplots(figsize=(8, 8), nrows=1, ncols=1,
subplot_kw=dict(projection='polar'))
fig.canvas.set_window_title('Left Ventricle Bulls Eyes (AHA)')
# Create the axis for the colorbars
axl = fig.add_axes([0.14, 0.15, 0.2, 0.05])
# Set the colormap and norm to correspond to the data for which
# the colorbar will be used.
cmap = mpl.cm.viridis
norm = mpl.colors.Normalize(vmin=min(data), vmax=max(data))
# ColorbarBase derives from ScalarMappable and puts a colorbar
# in a specified axes, so it has everything needed for a
# standalone colorbar. There are many more kwargs, but the
# following gives a basic continuous colorbar with ticks
# and labels.
cb1 = mpl.colorbar.ColorbarBase(axl, cmap=cmap, norm=norm,
orientation='horizontal')
cb1.set_label('Some Units')
# Create the 16 segment model
bullseye_plot(ax, data, cmap=cmap, norm=norm, labels=labels, labelProps={'size':15, "weight":'bold'})
ax.set_title('Bulls Eye (AHA)')
plt.show()
至于结果,就在这里 Final result
最佳答案
我修改了代码以在单元格的(近似)中心添加标签。您可以传递一个标签数组(作为字符串)和一个 any parameters accepted by matplotlib's Text 的字典。调整标签的外观。
至于单元格的颜色,它们是由data
和colormap决定的。
在您的原始代码中,您有一个线性颜色图 (viridis
)。相反,您可以使用 ListedColormap
生成您自己的颜色条,并将每种颜色映射到数据中的特定值。
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
def bullseye_plot(ax, data, segBold=None, cmap=None, norm=None, labels=[], labelProps={}):
"""
Bullseye representation for the left ventricle.
Parameters
----------
ax : axes
data : list of int and float
The intensity values for each of the 17 segments
segBold: list of int, optional
A list with the segments to highlight
cmap : ColorMap or None, optional
Optional argument to set the desired colormap
norm : Normalize or None, optional
Optional argument to normalize data into the [0.0, 1.0] range
Notes
-----
This function create the 17 segment model for the left ventricle according
to the American Heart Association (AHA) [1]_
References
----------
.. [1] M. D. Cerqueira, N. J. Weissman, V. Dilsizian, A. K. Jacobs,
S. Kaul, W. K. Laskey, D. J. Pennell, J. A. Rumberger, T. Ryan,
and M. S. Verani, "Standardized myocardial segmentation and
nomenclature for tomographic imaging of the heart",
Circulation, vol. 105, no. 4, pp. 539-542, 2002.
"""
if segBold is None:
segBold = []
linewidth = 2
data = np.array(data).ravel()
if cmap is None:
cmap = plt.cm.viridis
if norm is None:
norm = mpl.colors.Normalize(vmin=data.min(), vmax=data.max())
theta = np.linspace(0, 2*np.pi, 768)
r = np.linspace(0, 1, 4)
# Create the bound for the segment 17
for i in range(r.shape[0]):
ax.plot(theta, np.repeat(r[i], theta.shape), '-k', lw=linewidth)
# Create the bounds for the segments 1-12
for i in range(6):
theta_i = i*60*np.pi/180
ax.plot([theta_i, theta_i], [r[1], 1], '-k', lw=linewidth)
# Create the bounds for the segments 13-16
for i in range(4):
theta_i = i*90*np.pi/180 - 45*np.pi/180
ax.plot([theta_i, theta_i], [r[0], r[1]], '-k', lw=linewidth)
# Fill the segments 1-6
r0 = r[2:4]
r0 = np.repeat(r0[:, np.newaxis], 128, axis=1).T
for i in range(6):
# First segment start at 60 degrees
theta0 = theta[i*128:i*128+128] + 60*np.pi/180
theta0 = np.repeat(theta0[:, np.newaxis], 2, axis=1)
z = np.ones((128, 2))*data[i]
ax.pcolormesh(theta0, r0, z, cmap=cmap, norm=norm)
if labels:
ax.annotate(labels[i], xy=(theta0[0,0]+30*np.pi/180,np.mean(r[2:4])), ha='center', va='center', **labelProps)
if i+1 in segBold:
ax.plot(theta0, r0, '-k', lw=linewidth+2)
ax.plot(theta0[0], [r[2], r[3]], '-k', lw=linewidth+1)
ax.plot(theta0[-1], [r[2], r[3]], '-k', lw=linewidth+1)
# Fill the segments 7-12
r0 = r[1:3]
r0 = np.repeat(r0[:, np.newaxis], 128, axis=1).T
for i in range(6):
# First segment start at 60 degrees
theta0 = theta[i*128:i*128+128] + 60*np.pi/180
theta0 = np.repeat(theta0[:, np.newaxis], 2, axis=1)
z = np.ones((128, 2))*data[i+6]
ax.pcolormesh(theta0, r0, z, cmap=cmap, norm=norm)
if labels:
ax.annotate(labels[i+6], xy=(theta0[0,0]+30*np.pi/180,np.mean(r[1:3])), ha='center', va='center', **labelProps)
if i+7 in segBold:
ax.plot(theta0, r0, '-k', lw=linewidth+2)
ax.plot(theta0[0], [r[1], r[2]], '-k', lw=linewidth+1)
ax.plot(theta0[-1], [r[1], r[2]], '-k', lw=linewidth+1)
# Fill the segments 13-16
r0 = r[0:2]
r0 = np.repeat(r0[:, np.newaxis], 192, axis=1).T
for i in range(4):
# First segment start at 45 degrees
theta0 = theta[i*192:i*192+192] + 45*np.pi/180
theta0 = np.repeat(theta0[:, np.newaxis], 2, axis=1)
z = np.ones((192, 2))*data[i+12]
ax.pcolormesh(theta0, r0, z, cmap=cmap, norm=norm)
if labels:
ax.annotate(labels[i+12], xy=(theta0[0,0]+45*np.pi/180,np.mean(r[0:2])), ha='center', va='center', **labelProps)
if i+13 in segBold:
ax.plot(theta0, r0, '-k', lw=linewidth+2)
ax.plot(theta0[0], [r[0], r[1]], '-k', lw=linewidth+1)
ax.plot(theta0[-1], [r[0], r[1]], '-k', lw=linewidth+1)
ax.set_ylim([0, 1])
ax.set_yticklabels([])
ax.set_xticklabels([])
# Create the fake data
data = [1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4]
labels = ['label 1',
'label 2',
'label 3',
'label 4',
'label 5',
'label 6',
'label 7',
'label 8',
'label 9',
'label 10',
'label 11',
'label 12',
'label 13',
'label 14',
'label 15',
'label 16',
'label 17']
# Make a figure and axes with dimensions as desired.
fig, ax = plt.subplots(figsize=(8, 8), nrows=1, ncols=1,
subplot_kw=dict(projection='polar'))
fig.canvas.set_window_title('Left Ventricle Bulls Eyes (AHA)')
# Set the colormap and norm to correspond to the data for which
# the colorbar will be used.
cmap = mpl.colors.ListedColormap(['xkcd:dusty purple',
'xkcd:light aquamarine',
'xkcd:pale salmon',
'xkcd:dusty orange',
'xkcd:sapphire',
'xkcd:azure'])
norm = mpl.colors.Normalize(vmin=1, vmax=6)
# Create the 17 segment model
bullseye_plot(ax, data, cmap=cmap, norm=norm, labels=labels, labelProps={'size':15, "weight":'bold'})
ax.set_title('Bulls Eye (AHA)')
plt.show()
关于python - 在用 python 生成的图形中添加一些数字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53629554/