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):
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()
I am currently facing challenges in resolving the following issues:
- 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:
- 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.
CodePudding user response:
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()