左心室靶心

该示例演示了如何为美国心脏协会(AHA)推荐的左心室创建17段模型。

左心室靶心示例

  1. import numpy as np
  2. import matplotlib as mpl
  3. import matplotlib.pyplot as plt
  4. def bullseye_plot(ax, data, segBold=None, cmap=None, norm=None):
  5. """
  6. Bullseye representation for the left ventricle.
  7. Parameters
  8. ----------
  9. ax : axes
  10. data : list of int and float
  11. The intensity values for each of the 17 segments
  12. segBold: list of int, optional
  13. A list with the segments to highlight
  14. cmap : ColorMap or None, optional
  15. Optional argument to set the desired colormap
  16. norm : Normalize or None, optional
  17. Optional argument to normalize data into the [0.0, 1.0] range
  18. Notes
  19. -----
  20. This function create the 17 segment model for the left ventricle according
  21. to the American Heart Association (AHA) [1]_
  22. References
  23. ----------
  24. .. [1] M. D. Cerqueira, N. J. Weissman, V. Dilsizian, A. K. Jacobs,
  25. S. Kaul, W. K. Laskey, D. J. Pennell, J. A. Rumberger, T. Ryan,
  26. and M. S. Verani, "Standardized myocardial segmentation and
  27. nomenclature for tomographic imaging of the heart",
  28. Circulation, vol. 105, no. 4, pp. 539-542, 2002.
  29. """
  30. if segBold is None:
  31. segBold = []
  32. linewidth = 2
  33. data = np.array(data).ravel()
  34. if cmap is None:
  35. cmap = plt.cm.viridis
  36. if norm is None:
  37. norm = mpl.colors.Normalize(vmin=data.min(), vmax=data.max())
  38. theta = np.linspace(0, 2 * np.pi, 768)
  39. r = np.linspace(0.2, 1, 4)
  40. # Create the bound for the segment 17
  41. for i in range(r.shape[0]):
  42. ax.plot(theta, np.repeat(r[i], theta.shape), '-k', lw=linewidth)
  43. # Create the bounds for the segments 1-12
  44. for i in range(6):
  45. theta_i = np.deg2rad(i * 60)
  46. ax.plot([theta_i, theta_i], [r[1], 1], '-k', lw=linewidth)
  47. # Create the bounds for the segments 13-16
  48. for i in range(4):
  49. theta_i = np.deg2rad(i * 90 - 45)
  50. ax.plot([theta_i, theta_i], [r[0], r[1]], '-k', lw=linewidth)
  51. # Fill the segments 1-6
  52. r0 = r[2:4]
  53. r0 = np.repeat(r0[:, np.newaxis], 128, axis=1).T
  54. for i in range(6):
  55. # First segment start at 60 degrees
  56. theta0 = theta[i * 128:i * 128 + 128] + np.deg2rad(60)
  57. theta0 = np.repeat(theta0[:, np.newaxis], 2, axis=1)
  58. z = np.ones((128, 2)) * data[i]
  59. ax.pcolormesh(theta0, r0, z, cmap=cmap, norm=norm)
  60. if i + 1 in segBold:
  61. ax.plot(theta0, r0, '-k', lw=linewidth + 2)
  62. ax.plot(theta0[0], [r[2], r[3]], '-k', lw=linewidth + 1)
  63. ax.plot(theta0[-1], [r[2], r[3]], '-k', lw=linewidth + 1)
  64. # Fill the segments 7-12
  65. r0 = r[1:3]
  66. r0 = np.repeat(r0[:, np.newaxis], 128, axis=1).T
  67. for i in range(6):
  68. # First segment start at 60 degrees
  69. theta0 = theta[i * 128:i * 128 + 128] + np.deg2rad(60)
  70. theta0 = np.repeat(theta0[:, np.newaxis], 2, axis=1)
  71. z = np.ones((128, 2)) * data[i + 6]
  72. ax.pcolormesh(theta0, r0, z, cmap=cmap, norm=norm)
  73. if i + 7 in segBold:
  74. ax.plot(theta0, r0, '-k', lw=linewidth + 2)
  75. ax.plot(theta0[0], [r[1], r[2]], '-k', lw=linewidth + 1)
  76. ax.plot(theta0[-1], [r[1], r[2]], '-k', lw=linewidth + 1)
  77. # Fill the segments 13-16
  78. r0 = r[0:2]
  79. r0 = np.repeat(r0[:, np.newaxis], 192, axis=1).T
  80. for i in range(4):
  81. # First segment start at 45 degrees
  82. theta0 = theta[i * 192:i * 192 + 192] + np.deg2rad(45)
  83. theta0 = np.repeat(theta0[:, np.newaxis], 2, axis=1)
  84. z = np.ones((192, 2)) * data[i + 12]
  85. ax.pcolormesh(theta0, r0, z, cmap=cmap, norm=norm)
  86. if i + 13 in segBold:
  87. ax.plot(theta0, r0, '-k', lw=linewidth + 2)
  88. ax.plot(theta0[0], [r[0], r[1]], '-k', lw=linewidth + 1)
  89. ax.plot(theta0[-1], [r[0], r[1]], '-k', lw=linewidth + 1)
  90. # Fill the segments 17
  91. if data.size == 17:
  92. r0 = np.array([0, r[0]])
  93. r0 = np.repeat(r0[:, np.newaxis], theta.size, axis=1).T
  94. theta0 = np.repeat(theta[:, np.newaxis], 2, axis=1)
  95. z = np.ones((theta.size, 2)) * data[16]
  96. ax.pcolormesh(theta0, r0, z, cmap=cmap, norm=norm)
  97. if 17 in segBold:
  98. ax.plot(theta0, r0, '-k', lw=linewidth + 2)
  99. ax.set_ylim([0, 1])
  100. ax.set_yticklabels([])
  101. ax.set_xticklabels([])
  102. # Create the fake data
  103. data = np.array(range(17)) + 1
  104. # Make a figure and axes with dimensions as desired.
  105. fig, ax = plt.subplots(figsize=(12, 8), nrows=1, ncols=3,
  106. subplot_kw=dict(projection='polar'))
  107. fig.canvas.set_window_title('Left Ventricle Bulls Eyes (AHA)')
  108. # Create the axis for the colorbars
  109. axl = fig.add_axes([0.14, 0.15, 0.2, 0.05])
  110. axl2 = fig.add_axes([0.41, 0.15, 0.2, 0.05])
  111. axl3 = fig.add_axes([0.69, 0.15, 0.2, 0.05])
  112. # Set the colormap and norm to correspond to the data for which
  113. # the colorbar will be used.
  114. cmap = mpl.cm.viridis
  115. norm = mpl.colors.Normalize(vmin=1, vmax=17)
  116. # ColorbarBase derives from ScalarMappable and puts a colorbar
  117. # in a specified axes, so it has everything needed for a
  118. # standalone colorbar. There are many more kwargs, but the
  119. # following gives a basic continuous colorbar with ticks
  120. # and labels.
  121. cb1 = mpl.colorbar.ColorbarBase(axl, cmap=cmap, norm=norm,
  122. orientation='horizontal')
  123. cb1.set_label('Some Units')
  124. # Set the colormap and norm to correspond to the data for which
  125. # the colorbar will be used.
  126. cmap2 = mpl.cm.cool
  127. norm2 = mpl.colors.Normalize(vmin=1, vmax=17)
  128. # ColorbarBase derives from ScalarMappable and puts a colorbar
  129. # in a specified axes, so it has everything needed for a
  130. # standalone colorbar. There are many more kwargs, but the
  131. # following gives a basic continuous colorbar with ticks
  132. # and labels.
  133. cb2 = mpl.colorbar.ColorbarBase(axl2, cmap=cmap2, norm=norm2,
  134. orientation='horizontal')
  135. cb2.set_label('Some other units')
  136. # The second example illustrates the use of a ListedColormap, a
  137. # BoundaryNorm, and extended ends to show the "over" and "under"
  138. # value colors.
  139. cmap3 = mpl.colors.ListedColormap(['r', 'g', 'b', 'c'])
  140. cmap3.set_over('0.35')
  141. cmap3.set_under('0.75')
  142. # If a ListedColormap is used, the length of the bounds array must be
  143. # one greater than the length of the color list. The bounds must be
  144. # monotonically increasing.
  145. bounds = [2, 3, 7, 9, 15]
  146. norm3 = mpl.colors.BoundaryNorm(bounds, cmap3.N)
  147. cb3 = mpl.colorbar.ColorbarBase(axl3, cmap=cmap3, norm=norm3,
  148. # to use 'extend', you must
  149. # specify two extra boundaries:
  150. boundaries=[0] + bounds + [18],
  151. extend='both',
  152. ticks=bounds, # optional
  153. spacing='proportional',
  154. orientation='horizontal')
  155. cb3.set_label('Discrete intervals, some other units')
  156. # Create the 17 segment model
  157. bullseye_plot(ax[0], data, cmap=cmap, norm=norm)
  158. ax[0].set_title('Bulls Eye (AHA)')
  159. bullseye_plot(ax[1], data, cmap=cmap2, norm=norm2)
  160. ax[1].set_title('Bulls Eye (AHA)')
  161. bullseye_plot(ax[2], data, segBold=[3, 5, 6, 11, 12, 16],
  162. cmap=cmap3, norm=norm3)
  163. ax[2].set_title('Segments [3,5,6,11,12,16] in bold')
  164. plt.show()

下载这个示例