Reputation: 363
I am trying to curve text on a polar chart in matplotlib.
Here is an example of my case:
import matplotlib.pyplot as plt
import numpy as np
text = ["Electoral Process", "Political Pluralism", "Rule of Law",
"Freedom of expression", "Freedom of believe"]
no_labels =len(text)
angle_size = int(360/no_labels)
#define the number of angles in degrees and convert it to radians
theta = [i/180*np.pi for i in range(0, 360,angle_size) ]
#where to put the labels on the radial axis
radius = [1]*no_labels
#Find the mid point of each angle
mid_point =[i/180*np.pi for i in range(int(angle_size/2), 360, angle_size)]
fig, ax = plt.subplots(subplot_kw={'projection': 'polar'},figsize=(10, 6), facecolor="white")
ax.set_theta_zero_location('N')
ax.set_theta_direction(-1)
ax.set_xticklabels([]) #remove the original xlabels
ax.set_yticklabels([]) #remove the original ylabels
# Arrange the grid into number of sales equal parts in degrees
lines = plt.thetagrids(range(0, 360, int(360/len(text))))
#Place the text in the midle of each pie
for m, r, t in zip(mid_point,radius, text):
ax.annotate(t, xy=[m, r], fontsize=12, ha="center", va="center", )
Which generates this:
I have found other posts that do that, but I dont understand the code so I am trying to build it from scratch. This is what I got so far:
import numpy as np
import matplotlib as mpl
text = ["Electoral Process", "Political Pluralism", "Rule of Law",
"Freedom of expression", "Freedom of believe"]
no_labels =len(text)
angle_size = int(360/no_labels)
#define the number of angles in degrees and convert it to radians
theta = [i/180*np.pi for i in range(0, 360,angle_size) ]
#where to put the labels on the radial axis
radius = [1]*no_labels
#Find the mid point of each angle
mid_point =[i/180*np.pi for i in range(int(angle_size/2), 360, angle_size)]
fig,ax=plt.subplots(subplot_kw={'projection': 'polar'},figsize=(10,6), dpi=100)
# Arrange the grid into number of sales equal parts in degrees
lines = plt.thetagrids(range(0, 360, int(360/len(text))))
ax.set_theta_zero_location('N')
ax.set_theta_direction(-1)
ax.set_xticklabels([]) #remove the original xlabels
ax.set_yticklabels([]) #remove the original ylabels
#start with one label
start_text = theta[0]
text2=["ELECTORAL PROCESS"]
spacing=len(text[0])+4
end_text = theta[1]
x= np.linspace(start_text, end_text, spacing)
y= [1, 0.5]
for txt in text2:
print(txt)
for a,tx in zip(x,txt):
ax.text(a, 1.05 ,tx,rotation=-28, fontsize= 8, ha="center", va= "center"),
print(a,tx)
Now I have to iterate it for every label, rotate each letter to follow the curve (using a hardcoded angle at the moment) and also write upwards or downwards depending on where the code is and it seems like I might be complicating things.
Anyone has done this using "simple code" or can explain how the code below works?
Similar problem but dont understand the code
Upvotes: 0
Views: 276
Reputation: 363
Thanks to @aradhna I managed to fix the code. (Thanks a million) Here it is!
import numpy as np
import matplotlib.pyplot as plt
text = ["Electoral Process", "Political Pluralism", "Rule of Law",
"Freedom of expression", "Freedom of believe"]
no_labels =len(text)
angle_size = int(360/no_labels)
#define the number of angles in degrees and convert it to radians
theta = [i/180*np.pi for i in range(0, 360,angle_size) ]
#Find the mid point of each angle
mid_point =[i/180*np.pi for i in range(int(angle_size/2), 360, angle_size)]
fig,ax=plt.subplots(subplot_kw={'projection': 'polar'},figsize=(10,6), dpi=100)
# Arrange the grid into number of text
lines = plt.thetagrids(range(0, 360, int(360/len(text))))
ax.set_theta_zero_location('N')
ax.set_theta_direction(-1)
ax.set_xticklabels([]) #remove the original xlabels
ax.set_yticklabels([]) #remove the original ylabels
for txt, midpoint in zip(text, mid_point):
#count nr letters divide by 2 convert to radians and substract from midpoiint
center_pos = midpoint-np.deg2rad(len(txt)/2+4)
#print(midpoint, text, a)
for i in range(len(txt)):
#print(txt[i], midpoint, a)
ax.text(center_pos, 1.04 ,txt[i].capitalize(),rotation=-np.rad2deg(center_pos), fontsize= 8, ha="center", va= "center")
center_pos += 0.032 #adds radians to the next275 letter
Here is the result:
Upvotes: 1
Reputation: 91
This is a very hard question and this is what I got after 2 hours of coding (I could not do better).
# Import modules
import numpy as np
import matplotlib.pyplot as plt
# ------------------------------------ #
# Define the figure
fig = plt.figure(figsize=(16,16))
# Setting the axes projection as polar
ax = fig.add_subplot(111, projection='polar')
# List that stores
# - the text to be displayed
# - the distance, r, from the center
# - the angle at which to display the text
#
# data = [["text", r, theta in deg], [...], ...]
# The r and theta have to be hardcoded
#
data = [["Electoral Process", 1.02, 65.0], ["Political Pluralism", 1.04, -5.0], ["Rule of Law", 1.06, -95.0],
["Freedom of expression", 1.06, 215.0], ["Freedom of believe", 1.06, 137.0]]
# Arrange the grid into number of sales equal parts in degrees
lines = plt.thetagrids(range(0, 360, int(360/len(data))))
# Iterate through each text
for text, r, theta in data:
# Convert to radians
theta = np.deg2rad(theta)
# Iterate through each letter
for i in range(len(text)):
# Display the letter
#
# The angle of rotation is -(90 deg - theta).
# This makes a right angle triangle. We must rotate the text towards Center.
# Please draw it on paper, with the angle, theta, to get why the equation is correct.
#
# text[i]
# |
# |
# Center ----------------|
#
plt.text(theta, r, text[i], rotation=-(90-np.rad2deg(theta)), fontsize=16)
# Decrement theta for the next letter
theta -= 0.06 # Arbirary value
# Remove tick labels
ax.set_xticklabels([])
ax.set_yticklabels([])
# Display the plot
plt.show()
I hope this helps you.
Upvotes: 1