Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strange pie graph cut off

I'm creating a gauge using matplotlib pie as the foundation:

import matplotlib.pyplot as plt
import math    

theta = 0.2

group_size=[10,10,10,10,10,50]

mid = [18,54,90,126,162]

from textwrap import wrap
labels=['1','2','3','4','5','']
labels = [ '\n'.join(wrap(l, 9)) for l in labels ]

fig, ax = plt.subplots()

ax.axis('equal')
pie3 = ax.pie(group_size, radius=2.2, colors=['k'] ,startangle=180,counterclock=False)

my_circle=plt.Circle( (0,0), 0.4, color='white')
p=plt.gcf()
p.gca().add_artist(my_circle)

pie4 = ax.pie([10,10,10,10,10,50], radius=2,  labeldistance=0.9, labels=labels,
              startangle=180,rotatelabels =True,counterclock=False)

plt.setp(pie4[1], rotation_mode="anchor", ha="center", va="center")
for tx in pie4[1]:
    font = tx.get_fontsize()
    tx.set_fontsize(12)
    rot = tx.get_rotation()
    tx.set_rotation(rot+90+(1-rot//180)*180)

for pie_wedge in pie3[0]:
    pie_wedge.set_edgecolor('white')

for pie_wedge in pie4[0]:
    pie_wedge.set_edgecolor('white')
    pie_wedge.set_linewidth(4)

#arrow bottom circle
ax.add_patch(Circle((0, 0), radius=0.15, facecolor='k',zorder=12))
ax.add_patch(Circle((0, 0), radius=0.13, facecolor='w',zorder=13))

ax.arrow(0, 0, 1.7 * np.sin(math.radians(theta*180-90)), 1.7 * np.cos(math.radians(theta*180-90)), \
                 width=0.15, head_width=0.15, head_length=0.2, fc='k', ec='k')

theta2 = 0.45

ax.arrow(0, 0, 1.7 * np.sin(math.radians(theta2*180-90)), 1.7 * np.cos(math.radians(theta2*180-90)), \
                 width=0.15, head_width=0.15, head_length=0.2, fc='k', ec='k',zorder=20)

Now the problem is my gauge arrow (in red) seems to get cut off at the top if it is sitting between 2 and 4. Almost as if there is an imaginary line between the left corner of the 2 wedge and the right corner of the 4 wedge. As you can see with the black arrow, no issue there.

enter image description here

Does anyone know what is happening here? I suspect a possible figsize issue?

like image 684
AToe Avatar asked Nov 08 '22 07:11

AToe


1 Answers

I think you're basically right in assuming it's a figsize issue, or at least, a frame size issue. As you have it, you are plotting your pie chart beyond the borders of the figure (this border is the "imaginary line" that you speak of in your question). The arrows don't know how to deal with this, and just get cut off where the frame would be. One way to fix this is to plot your pie graph with a radius of 1 (instead of 2, as you had it), so that it is all within the limits of the matplotlib frame, and then just divide the arrow lengths and other arrow parameters by 2 or thereabouts, to scale everything accordingly. Here is basically what I did to modify your code, to get you going (I put in comments in #### CAPS LOCK #### where I changed things):

from matplotlib.patches import Circle
import matplotlib.pyplot as plt
import math    

theta = 0.2

group_size=[10,10,10,10,10,50]

mid = [18,54,90,126,162]

from textwrap import wrap
labels=['1','2','3','4','5','']
labels = [ '\n'.join(wrap(l, 9)) for l in labels ]

fig, ax = plt.subplots()

ax.axis('equal')
### CHANGED RADIUS HERE ###
pie3 = ax.pie(group_size,radius=1, colors=['k'] ,startangle=180,counterclock=False)

my_circle=plt.Circle( (0,0), 0.4, color='white')
p=plt.gcf()
p.gca().add_artist(my_circle)

### CHANGED RADIUS HERE ###
pie4 = ax.pie([10,10,10,10,10,50], radius=0.9,  labeldistance=0.85, labels=labels,
              startangle=180,rotatelabels =True,counterclock=False)

plt.setp(pie4[1], rotation_mode="anchor", ha="center", va="center")
for tx in pie4[1]:
    font = tx.get_fontsize()
    tx.set_fontsize(12)
    rot = tx.get_rotation()
    tx.set_rotation(rot+90+(1-rot//180)*180)

for pie_wedge in pie3[0]:
    pie_wedge.set_edgecolor('white')

### DIVIDED LINEWIDTH BY 2 FOR SCALING ###
for pie_wedge in pie4[0]:
    pie_wedge.set_edgecolor('white')
    pie_wedge.set_linewidth(2)

#arrow bottom circle
### DIVIDED RADIUS BY 2 FOR SCALING ###
ax.add_patch(Circle((0, 0), radius=0.15/2, facecolor='k',zorder=12))
ax.add_patch(Circle((0, 0), radius=0.13/2, facecolor='w',zorder=13))

### DIVIDED SOME PARAMETERS BY 2.2 FOR SCALING ####
ax.arrow(0, 0, 1.7/2.2 * np.sin(math.radians(theta*180-90)), 1.7/2.2 * np.cos(math.radians(theta*180-90)), \
                 width=0.15/2, head_width=0.15/2, head_length=0.2/2, fc='k', ec='k')

theta2 = 0.45

### DIVIDED SOME PARAMETERS BY 2.2 FOR SCALING ####
ax.arrow(0, 0, 1.7/2.2 * np.sin(math.radians(theta2*180-90)), 1.7/2.2 * np.cos(math.radians(theta2*180-90)), \
                 width=0.15/2, head_width=0.15/2, head_length=0.2/2, fc='k', ec='k')

#### TIGHT LAYOUT MAKES SENSE HERE ####
plt.tight_layout()

enter image description here

like image 175
sacuL Avatar answered Nov 15 '22 12:11

sacuL