如何在极坐标图中绘制文本曲线?

问题描述 投票:0回答:1

如何在 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()

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

matplotlib 中的曲线文本渲染

python numpy matplotlib rendering polar-coordinates
1个回答
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))

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

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

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

© www.soinside.com 2019 - 2024. All rights reserved.