Matplotlib: Rotating labels on lower half of pie chart and repositioning text labels

Question:

I am using the following code to create the attached visualization:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.textpath import TextPath
from matplotlib.patches import PathPatch

fig = plt.figure(figsize=(6, 6))
ax = fig.add_axes([0, 0, 1, 1], aspect=1)
size = 0.1

params = [
    "Parameter 1", "Parameter 2","Parameter 3","Parameter 4","Parameter 5","Parameter 6",
    "Parameter 7","Parameter 8","Parameter 9","Parameter 10","Parameter 11","Parameter 12"
]

# Simple pie
ax.pie(np.ones(12), radius=1, colors=["#F5F5F5"] * len(params), wedgeprops=dict(width=size, edgecolor="w"))

# Rotated and transformed label
def plot_curved_text(text, angle, radius=1, scale=0.005):
    "credits: Nicolas P. Rougier"
    path = TextPath((0, 0), text, size=10)
    path.vertices.flags.writeable = True
    V = path.vertices
    xmin, xmax = V[:, 0].min(), V[:, 0].max()
    ymin, ymax = V[:, 1].min(), V[:, 1].max()
    V -= (xmin + xmax) / 2, (ymin + ymax) / 2
    V *= scale
    for i in range(len(V)):
        a = angle - V[i, 0]
        V[i, 0] = (radius + V[i, 1]) * np.cos(a)
        V[i, 1] = (radius + V[i, 1]) * np.sin(a)
    patch = PathPatch(path, facecolor="k", linewidth=0)
    ax.add_artist(patch)

for val, label in zip(
    np.linspace(0.5, 11.5, 12),
    params
):
    plot_curved_text(label, val * 2 * np.pi / 12, 1 - 0.5 * size)

plt.show()

enter image description here

I am currently facing challenges in resolving the following issues:

  1. I am seeking a solution to rotate the labels applied on the lower half of a circle/pie (parameters 7 to 12) in the opposite direction, in order to achieve a similar appearance to that of the labels parameters 5 to 9, as depicted in the attached visual below:

enter image description here

  1. Additionally, using the current code, the parameter 1 is added to the right-hand side, however, my desired outcome is for it to be located at the top, as illustrated in point 1 visual

If anyone could provide assistance in addressing these two concerns, it would be greatly appreciated.

Asked By: slothfulwave612

||

Answers:

To let the pie start with 0 at the top, add 90 degrees to ax.pie(..., startangle=90). To do the same with the texts, the angle past to plot_curved_text should be increased by pi / 2.

Multiplying the x and y coordinates of the vertices of the path by -1 puts the text upside down. The sign of the sin of the rotation angle is the easiest way to know whether or not to rotate the text. (Adding an epsilon avoids problems when the angle would be zero.)

As the positions of the individual letter are already in numpy format, the for loop can be simplified via a vectorized call.

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.textpath import TextPath
from matplotlib.patches import PathPatch

# Rotated and transformed label
def plot_curved_text(text, angle, radius=1, scale=0.005):
    path = TextPath((0, 0), text, size=10)
    path.vertices.flags.writeable = True
    V = path.vertices
    xmin, xmax = V[:, 0].min(), V[:, 0].max()
    ymin, ymax = V[:, 1].min(), V[:, 1].max()
    V -= (xmin + xmax) / 2, (ymin + ymax) / 2
    V *= scale * np.sign(np.sin(angle) + 1e-100)
    a = angle - V[:, 0]
    V[:, 0] = (radius + V[:, 1]) * np.cos(a)
    V[:, 1] = (radius + V[:, 1]) * np.sin(a)

    patch = PathPatch(path, facecolor="k", linewidth=0)
    ax.add_artist(patch)

fig = plt.figure(figsize=(6, 6))
ax = fig.add_axes([0, 0, 1, 1], aspect=1)

size = 0.1
params = ["Parameter 1", "Parameter 2", "Parameter 3", "Parameter 4", "Parameter 5", "Parameter 6", "Parameter 7",
          "Parameter 8", "Parameter 9", "Parameter 10", "Parameter 11", "Parameter 12"]
# Simple pie
ax.pie(np.ones(12), radius=1, startangle=90, colors=["#F5F5F5"] * len(params), wedgeprops=dict(width=size, edgecolor="w"))

for val, label in zip(np.linspace(0.5, 11.5, 12), params):
    plot_curved_text(label, val * 2*np.pi/12 + np.pi/2, 1 - 0.5*size)

plt.show()

pie chart with rotated texts

Answered By: JohanC
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.