如何在极坐标图中弯曲文本?

use*_*442 9 rendering numpy matplotlib python-3.x polar-coordinates

你好 Matplotlib 专家,

如何在 matplotlib 极坐标图中曲线文本?在我下面的尝试中,我的代码单独旋转每个字符,但这样做会删除每个字体的自然间距。有人可以描述传递ax.textmatplotlib的解决方案吗?

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()
Run Code Online (Sandbox Code Playgroud)

具有丑陋间距的极坐标图

在下面的链接中,托马斯的回答似乎只适用于笛卡尔坐标,我目前的尝试应该类似于大安。

matplotlib 中的曲线文本渲染

vic*_*oom 1

正如 @Makdous 上面所建议的,matplotlib 中的曲线文本渲染是该问题的一个很好的实现。我通读了代码,你是对的,它是在笛卡尔坐标中,但我认为你可以稍微修改它并使用这些公式让它工作:

笛卡尔坐标到极坐标转换

您还可以使用我编写的这一行函数:

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))
Run Code Online (Sandbox Code Playgroud)

或者,如果您有极坐标并希望使其与其他响应中链接的脚本一起使用,您可以使用以下命令:

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))

Run Code Online (Sandbox Code Playgroud)

根据您实现它的方式,您可以将其输入您拥有的坐标,然后将其适当转换以到达笛卡尔坐标并运行链接的脚本,然后将点转换回极坐标并绘制它。