python-3.x - 如何在极坐标图中弯曲文本?

标签 python-3.x numpy matplotlib rendering polar-coordinates

您好Matplotlib专家,

如何在matplotlib极坐标图中弯曲文本?在下面的尝试中,我的代码分别旋转每个字符,但是这样做会删除每种字体的自然间距。有人可以描述在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()

Polar plot with ugly spacing

在下面的链接中,Thomas的答案似乎仅适用于笛卡尔坐标,而我目前的尝试应类似于Daan。

Curved text rendering in matplotlib

最佳答案

正如@Makdous上面所建议的,Curved text rendering in matplotlib是该问题的不错的实现。我仔细阅读了代码,您是对的,它是在笛卡尔坐标中,但是我认为您可以对它们进行一些修改,并使用以下公式使其起作用:
Cartestian to Polar conversions
您还可以使用我编写的这一行函数:

from typing import Tuple
from math import sqrt, degrees, atan2
def cartesian_to_polar(x: float, y: float)-> Tuple[float, float]:
    return sqrt(x**2 + y ** 2), degrees(atan2(y,x))
或者,如果您具有极坐标,并且希望使其与其他响应中链接的脚本一起使用,则可以使用以下方法:
from math import cos, sin, radians
def polar_to_cartesian(r: float, theta: float)-> Tuple[float, float]:
    return r * cos(radians(theta)), r * sin(radians(theta))

根据实现方式的不同,可以将其输入您拥有的坐标中,然后将其适当转换为直角坐标并运行链接的脚本,然后将点转换回极坐标并进行绘制。

关于python-3.x - 如何在极坐标图中弯曲文本?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61844673/

相关文章:

python - 无法启动docker虚拟机: ImportError: cannot import name 'format_lazy' from 'django.utils.text' (Python Error)

python - 任何人都可以详细解释 cv 和 cv2 有何不同以及是什么让 cv2 比 cv 更好更快?

python - 确定两个列表/数组的混洗索引

python - 如何更改感兴趣区域的 pyplot 背景颜色?

python - 如何根据字典中的键设置 Xticks

matplotlib - 如何在 matplotlib 中制作依赖 slider

python - 这个异步 aiohttp 代码有什么问题?

python-3.x - Pandas :如何使 value_counts() 超过阈值

python - "Merging"具有共同维度的 numpy 数组

python-3.x - 如何在 Pytorch 中创建自己的损失函数?