我正在制作一张极 map ,其中的扁虱并不均匀地分布在圆圈周围.有几个非常好的问答对处理均匀分布的答案,它们都使用divide up the circle方法.E.g. this.

我想知道是否有可能使用标签中烘焙的转换来按我想要的方式旋转文本.

我可以做到这一点,但我不知道如何正确地锚定它.执行此操作的代码如下:

for tick in plt.xticks()[1]:
    tick._transform = tick._transform + mpl.transforms.Affine2D().rotate_deg_around(0, 0, 10)

其输出如下所示:

enter image description here

鉴于我想要这样的输出:

enter image description here

(摘自上述链接的问题)

显然,我需要90度旋转,而不是10度,但90度旋转会让它脱离画布.

这种方法可行吗,或者我需要重新判断我的战略吗?

完整的代码块如下所示:

import random

import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np

one_person = {
    "Human": {
        "Collaboration": 4,
        "Growth Mindset": 3,
        "Inclusion": 5,
        "Project and Studio Life": 2,
    },
    "Tectonics": {
        "Office Manual and Procedures": 3,
        "Documentation Standards": 3,
        "Site Stage Services": 2,
        "External and Public Domain Works": 2,
        "Structure": 3,
        "Enclosure": 2,
        "Waterproofing (int. and ext.)": 3,
        "Interiors": 1,
        "Structure and Services": 2,
    },
    "Technology": {
        "Bluebeam": 2,
        "Confluence": 3,
        "Drawing on screens": 0,
        "dRofus": 0,
        "Excel": 2,
        "Grasshopper": 1,
        "InDesign": 2,
        "Outlook": 2,
        "Python": 5,
        "Rhino": 1,
        "Teams": 2,
        "Timesheets and expenses": 3,
    },
    "Regenerative": {
        "REgenerative Design": 3,
        "Materials and Embodied Carbon practice": 1,
        "Materials and Embodied Carbon analysis": 2,
        "Energy": 3,
        "Resilience": 1,
        "Rating Systems": 2,
    },
    "Design": {
        "Predesign - Briefing, Stakeholder Engagement & Establishing Project Values": 2,
        "Predesign - Feasibility Studies And Strategic Organisational Planning": 3,
        "Initiating Design": 2,
        "Conserving Design": 3,
        "Design Communication - Written": 2,
        "Design Communication - Visual": 4,
        "Design Communication - Verbal": 3,
    },
    "Connecting with country": {"Connecting with Country": 2},
}
colours = [
    "b",  # blue.
    "g",  # green.
    "r",  # red.
    "c",  # cyan.
    "m",  # magenta.
    "y",  # yellow.
    "k",  # black.
    # "w",  # white.
]


def draw_radar(data, colour_letters, person_name=""):
    """Draw the graph.

    Based substanitally on this SO thread:
    https://stackoverflow.com/questions/60563106/complex-polar-plot-in-matplotlib
    """
    # not really sure why -1, but if you don't you get an empty segment
    num_areas = len(data) - 1
    running_total = 0
    thetas = {}
    for key, value in data.items():
        this_area_num_points = len(value)
        this_area_theta = ((2 * np.pi) / num_areas) / (this_area_num_points)
        thetas[key] = []
        for i in range(len(value)):
            thetas[key].append((i * this_area_theta) + running_total)
        running_total += (2 * np.pi) / num_areas

    labels = []
    for key, value in data.items():
        for area, score in value.items():
            labels.append(f"{score} {key}: {area}")

    for name, theta_list in thetas.items():
        individual_scores = list(data[name].values())
        colour = random.choice(colour_letters)
        if len(theta_list) > 1:
            plt.polar(theta_list, individual_scores, c=colour, label=name)
        elif len(theta_list) == 1:
            plt.scatter(theta_list, individual_scores, c=colour, label=name)
    plt.yticks(np.arange(-5, 5), [""] * 5 + list(range(5)))
    plt.xticks(
        np.concatenate(tuple(list(thetas.values()))),
        labels,
        transform_rotates_text=True,
    )
    for tick in plt.xticks()[1]:
        tick._transform = tick._transform + mpl.transforms.Affine2D().rotate_deg_around(
            0, 0, 10
        )
    if person_name:
        plt.title = f"Competency for {person_name}"
    plt.savefig("radar.png")


draw_radar(one_person, colours)

推荐答案

Rather than using Matplotlib transforms, you can use ax.get_xticklabels(), & then iteratively set the rotation of each label with label.set_rotation(θ) ¹

?其中,Angular θ是从与每个标签相关联的极轴数据中得出的;它实际上等同于极轴图中的x维.

例如,修改您提供的代码,如下所示:

import random

import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np

one_person = {
    "Human": {
        "Collaboration": 4,
        "Growth Mindset": 3,
        "Inclusion": 5,
        "Project and Studio Life": 2,
    },
    "Tectonics": {
        "Office Manual and Procedures": 3,
        "Documentation Standards": 3,
        "Site Stage Services": 2,
        "External and Public Domain Works": 2,
        "Structure": 3,
        "Enclosure": 2,
        "Waterproofing (int. and ext.)": 3,
        "Interiors": 1,
        "Structure and Services": 2,
    },
    "Technology": {
        "Bluebeam": 2,
        "Confluence": 3,
        "Drawing on screens": 0,
        "dRofus": 0,
        "Excel": 2,
        "Grasshopper": 1,
        "InDesign": 2,
        "Outlook": 2,
        "Python": 5,
        "Rhino": 1,
        "Teams": 2,
        "Timesheets and expenses": 3,
    },
    "Regenerative": {
        "REgenerative Design": 3,
        "Materials and Embodied Carbon practice": 1,
        "Materials and Embodied Carbon analysis": 2,
        "Energy": 3,
        "Resilience": 1,
        "Rating Systems": 2,
    },
    "Design": {
        "Predesign - Briefing, Stakeholder Engagement & Establishing Project Values": 2,
        "Predesign - Feasibility Studies And Strategic Organisational Planning": 3,
        "Initiating Design": 2,
        "Conserving Design": 3,
        "Design Communication - Written": 2,
        "Design Communication - Visual": 4,
        "Design Communication - Verbal": 3,
    },
    "Connecting with country": {"Connecting with Country": 2},
}
colours = [
    "b",  # blue.
    "g",  # green.
    "r",  # red.
    "c",  # cyan.
    "m",  # magenta.
    "y",  # yellow.
    "k",  # black.
]


def draw_radar(data, colour_letters, person_name=""):
    """Draw the graph.

    Based substanitally on this SO thread:
    https://stackoverflow.com/questions/60563106/complex-polar-plot-in-matplotlib
    """

    fig, ax = plt.subplots(
        subplot_kw={"projection": "polar"}, figsize=(10, 10)
    )
    num_areas = len(data) - 1
    running_total = 0
    thetas = {}
    for key, value in data.items():
        this_area_num_points = len(value)
        this_area_theta = ((2 * np.pi) / num_areas) / (this_area_num_points)
        thetas[key] = []
        for i in range(len(value)):
            thetas[key].append((i * this_area_theta) + running_total)
        running_total += (2 * np.pi) / num_areas

    labels = []
    for key, value in data.items():
        for area, score in value.items():
            labels.append(f"{score} {key}: {area}")

    for name, theta_list in thetas.items():
        individual_scores = list(data[name].values())
        colour = colour_letters.pop()  # random.choice(colour_letters)
        if len(theta_list) > 1:
            ax.plot(theta_list, individual_scores, c=colour, label=name)
        elif len(theta_list) == 1:
            ax.scatter(theta_list, individual_scores, c=colour, label=name)
    ax.set_yticks(np.arange(-5, 5), [""] * 5 + list(range(5)))
    ax.set_xticks(
        np.concatenate(tuple(list(thetas.values()))), labels,
    )

    plt.gcf().canvas.draw()
    max_label_len = max(list(map(len, labels)))
    t_labels = []
    for label in ax.get_xticklabels():
        x, y = label.get_position()
        text = label.get_text()
        angle = x
        y_adjust = (len(text) / max_label_len) * 0.8
        if text.endswith("Country"):
            x_adjust = 0.05
            angle += 0.05
        else:
            x_adjust = 0
        lab = ax.text(
            x + x_adjust,
            y - y_adjust,
            label.get_text(),
            transform=label.get_transform(),
            ha=label.get_ha(),
            va=label.get_va(),
        )
        if np.cos(angle) < 0:
            angle = angle + np.pi
        angle = np.rad2deg(angle)
        lab.set_rotation(angle)
        t_labels.append(lab)
    ax.set_xticklabels([])
    plt.show()


draw_radar(one_person, colours)

results in: Matplotlib polar plot with 'theta' angle-specific rotated tick labels

您可能需要调整以下各项的设置:

  1. figsize(在定义figax图形和轴对象时),并且相应地,
  2. y_adjust系数(上面设置为0.8).

一般的逻辑是 for each 极轴数据值找到绘制的theta角,然后将该角值本身用作标签文本的刻度特定旋转.这np.cos个代码判断并适当地将标签倒置.并且每个标签基于其归一化标签文本长度(相对于最大长度标签)向外移动(即,y维上的负向)一定量,导致所有标签或多或少精确地位于圆圈之外(即,文本标签越长,它必须移动的越多).

此外,还有一个标签(以‘Country’结尾)与另一个标签重叠-对于那个标签,我自定义将其向上移动,并略微弯曲其刻度标签旋转的Angular ,以反映它实际上属于/应该指向极图上与其正下方的刻度标签数据具有相同角的数据.

Python相关问答推荐

单击cookie按钮,但结果不一致

Flask:如何在完整路由代码执行之前返回验证

来自ARIMA结果的模型方程

强制venv在bin而不是收件箱文件夹中创建虚拟环境

将行从一个DF添加到另一个DF

Python无法在已导入的目录中看到新模块

比较两个二元组列表,NP.isin

Python 3.12中的通用[T]类方法隐式类型检索

删除所有列值,但判断是否存在任何二元组

为什么sys.exit()不能与subproccess.run()或subprocess.call()一起使用

Polars:用氨纶的其他部分替换氨纶的部分

对所有子图应用相同的轴格式

如何在给定的条件下使numpy数组的计算速度最快?

基于索引值的Pandas DataFrame条件填充

如果值发生变化,则列上的极性累积和

从嵌套的yaml创建一个嵌套字符串,后面跟着点

为什么np. exp(1000)给出溢出警告,而np. exp(—100000)没有给出下溢警告?

dask无groupby(ddf. agg([min,max])?''''

如何使用使用来自其他列的值的公式更新一个rabrame列?

OpenCV轮廓.很难找到给定图像的所需轮廓