如何在matplotlib polar plot中弯曲文本?在我下面的尝试中,我的代码单独旋转每个字符,但这样做会删除每个字体的自然间距。有人能描述一下在matplotlib中传递ax.text
的解决方案吗?
import numpy as np
import matplotlib as mpl
import matplotlib.pylab as plt
def curveText(text, height, minTheta, maxTheta, ax):
interval = np.arange(minTheta, maxTheta, .022)
if( maxTheta <= np.pi):
progression = interval[::-1]
rotation = interval[::-1] - np.arctan(np.tan(np.pi/2))
else:
progression = interval
rotation = interval - np.arctan(np.tan(np.pi/2)) - np.pi
## Render each letter individually
for i, rot, t in zip(progression, rotation, text):
ax.text(i, height, t, fontsize=11,rotation=np.degrees(rot), ha='center', va='center')
def buildCircularHeatMap( data=None, label=None, cmaps=None, categorymap=None, vmin=0, vmax=None ):
(xDim, yDim) = data.shape
if cmaps == None:
cmaps = [mpl.cm.get_cmap()] * yDim
BOTTOM = xDim / 100 * 120
#FONTSIZE = 1 if xDim/100*8 < 1 else xDim/100*8
theta = np.linspace(0.0, 2 * np.pi - 5 * np.pi/180, xDim, endpoint=False)
width = (2*np.pi - 5 * np.pi/180)/xDim
ax = plt.subplot(111, polar=True)
ax.grid(False)
ax.set_yticklabels([])
ax.set_xticklabels([])
categorysum = np.zeros(len(categorymap))
for x in label:
categorysum[int(float( x )) - 1] += 1
categorysum = categorysum/np.sum(categorysum)*2*np.pi
## Build Face Color Values
for i in range(yDim):
cmap_scalar = mpl.cm.ScalarMappable(cmap=cmaps[i])
cmap_scalar.set_clim(vmin=vmin, vmax=vmax)
facecolor = cmap_scalar.to_rgba(data[:,i])
_ = ax.text(2 * np.pi - 5 * np.pi/180, BOTTOM+i*10, str(i), fontsize=11, rotation=np.degrees(270))
bars = ax.bar(theta, np.ones(xDim)*10, width=width, bottom=BOTTOM+i*10)
for j, b in enumerate(bars):
b.set_facecolor( facecolor[j] )
## Build CCS Label
for th, l, bar in zip(theta, label, bars):
rot = np.arctan(np.tan(th))
ax.text(th,BOTTOM+yDim*10+bar.get_height()+5, l, rotation_mode='anchor',
rotation=np.degrees(rot), fontsize=11, ha='center', va='center')
## Build Category Label
categoryColor = np.asarray([int(float(c)) for c in label])
bars = ax.bar(theta, np.ones(xDim)*20, width=width, bottom=BOTTOM+yDim*10 + 30)
for j, b in enumerate(bars):
b.set_facecolor(np.asarray([0.0,0.0,0.0]))
if categoryColor[j] % 2 == 0:
b.set_alpha(0.07)
else:
b.set_alpha(0.0)
for i in range(len(categorymap)):
c = i + 1
t = theta[categoryColor==c]
mi = np.min(t)
ma = np.max(t)
rad = (ma-mi)/2+mi
curveText(categorymap[c], BOTTOM+yDim*10+40, mi, ma, ax)
if __name__ == "__main__":
categorymap={
1: "Infectious & parasitic dieases",
2: "Neoplasms",
3: "Endocrine; nutritional; and metabolic diseases and immunity disorders",
4: "Diseases of the blood and blood-forming organs",
5: "Mental Illness",
6: "Nervous system disorders",
7: "Circulatory disorders",
8: "Respiratory disorders",
9: "Digestive disorders",
10: "Genitourinary disorders",
11: "Complications of pregnancy; childbirth; and the puerperium",
12: "Skin and subcutaneous tissue disorder",
13: "Musculoskeletal system and connective tissue disorder",
14: "Congenital anomalies",
15: "Certain conditions originating in the perinatal period",
16: "Injury and poisoning",
17: "Ill-defined status",
18: "Unclassified"
}
data = np.random.standard_normal((180, 3))
colormaps = [mpl.cm.get_cmap("Reds"), mpl.cm.get_cmap("Oranges"), mpl.cm.get_cmap("Greens"), mpl.cm.get_cmap("Blues")]
labels = sorted([ '{:.2f}'.format(np.abs(i)) for i in np.random.random_sample(180) * 18 + 1 ])
fig = plt.figure(figsize=(11,11))
buildCircularHeatMap(data=data, label=labels, cmaps=colormaps, categorymap=categorymap)
plt.show()
在下面的链接中,托马斯的答案似乎只适用于carbohydrate坐标,我目前的尝试应该类似于Daan。
Curved text rendering in matplotlib
1条答案
按热度按时间zd287kbt1#
正如@Makdous上面所建议的,Curved text rendering in matplotlib是这个问题的一个很好的实现。我通读了代码,你是对的,它是在直角坐标系中,但我认为你可以稍微修改一下,并使用这些公式使其工作:
你也可以使用我写的一行函数:
或者,如果你有极坐标,并希望它与其他响应中链接的脚本一起工作,你可以使用这个:
根据您实现它的方式,您可以将它输入到您拥有的坐标中,然后适当地转换它以获得直角坐标并运行链接的脚本,然后将点转换回极坐标并绘制它。