From: Rune V. S. <rv...@gm...> - 2010-03-23 15:33:32
|
Hello, I am having some issues generating pie charts, when some of the slices become very small, their labels will draw on top of each other, making it impossible to distinguish between them. And I am trying to avoid using a legend. Does anyone know if there is a way to properly position labels of pie charts to avoid overlapping. (By for example distributing them vertically with lines pointing to their respective slices) Similar to what is done here: http://chart.apis.google.com/chart?cht=p&chd=s:Uf9a&chs=250x100&chl=January|February|March|April -- Regards Rune V. Sjoen |
From: Jae-Joon L. <lee...@gm...> - 2010-03-23 16:41:47
Attachments:
new_piechart.png
|
This should be doable using the annotation. Here is a simple cook-up I just did. it uses a naive algorithm to place the labels, but I guess it gives you an idea how things work. a screenshot is attached. Regards, -JJ from pylab import * # make a square figure and axes figure(1, figsize=(6,6)) ax = axes([0.1, 0.1, 0.8, 0.8]) labels = 'Frogs', 'Hogs', 'Dogs', 'Logs' fracs = [15,30,45, 10] explode=(0, 0.05, 0, 0) p = pie(fracs, explode=explode, shadow=True) title('Raining Hogs and Dogs', bbox={'facecolor':'0.8', 'pad':5}) for p1, l1 in zip(p[0], labels): r = p1.r dr = r*0.1 t1, t2 = p1.theta1, p1.theta2 theta = (t1+t2)/2. xc, yc = r/2.*cos(theta/180.*pi), r/2.*sin(theta/180.*pi) x1, y1 = (r+dr)*cos(theta/180.*pi), (r+dr)*sin(theta/180.*pi) if x1 > 0 : x1 = r+2*dr ha, va = "left", "center" tt = -180 cstyle="angle,angleA=0,angleB=%f"%(theta,) else: x1 = -(r+2*dr) ha, va = "right", "center" tt = 0 cstyle="angle,angleA=0,angleB=%f"%(theta,) annotate(l1, (xc, yc), xycoords="data", xytext=(x1, y1), textcoords="data", ha=ha, va=va, arrowprops=dict(arrowstyle="-", connectionstyle=cstyle, patchB=p1)) show() |
From: Jae-Joon L. <lee...@gm...> - 2010-03-24 18:05:19
|
You should not use "angle" style if you change the x,y position (this is due to the algorithm of how the line connecting two points are create). Try something like below instead. if foo: if theta - foo < 10: print >>sys.stderr, "Overlapping, offsetting a little bit" y1 = y1 + 0.1 if x1 > 0 : cstyle="arc,angleA=180,armA=30,armB=10,angleB=%f"%(-theta,) else: cstyle="arc,angleA=0,armA=30,armB=10,angleB=%f"%(theta,) There is not much documentation of how each algorithm works (it is beyond my english skill). They are loosely based on the latex pstrick package and the screenshot in the following link may be useful to get some idea though. http://matplotlib.sourceforge.net/users/annotations_guide.html#annotating-with-arrow Regards, -JJ 2010/3/24 Rune V. Sjøen <rv...@gm...>: > Hello again, and thank you very much for the answer, suddenly it all got > much clearer to me. The only 'issue' I am having is (from screenshot) what > happens to the line pointing to Logs when I try to offset it a little bit on > the Y axis. It looks like either the angleA or angleB is wrong, but I don't > see and reason why it would be as the X coordinates does not change. > > Another thing I do not quite understand is what that patchB does. > > figure(1, figsize=(6,6)) > ax = axes([0.1, 0.1, 0.8, 0.8]) > > labels = 'Frogs', 'Hogs', 'Dogs', 'Logs' > fracs = [45, 135 ,1, 1] > > p = pie(fracs) > > foo = None > for p1, l1 in zip(p[0], labels): > > r = p1.r > dr = r*0.1 > t1, t2 = p1.theta1, p1.theta2 > theta = (t1+t2)/2. > > xc = cos(theta/180.*pi)*r > yc = sin(theta/180.*pi)*r > x1 = cos(theta/180.*pi)*(r+dr) > y1 = sin(theta/180.*pi)*(r+dr) > > if x1 > 0 : > x1 = r+2*dr > ha, va = "left", "center" > cstyle="angle,angleA=180,angleB=%f"%(-theta,) > print >> sys.stderr, ha, ",A,", va > else: > x1 = -(r+2*dr) > ha, va = "right", "center" > cstyle="angle,angleA=0,angleB=%f"%(theta,) > print >> sys.stderr, ha, ",B,", va > > if foo: > if theta - foo < 10: > print >>sys.stderr, "Overlapping, offsetting a little > bit" > y1 = y1 + 0.1 > foo = theta > > annotate(l1, > (xc, yc), xycoords="data", > xytext=(x1, y1), textcoords="data", ha=ha, va=va, > arrowprops=dict(arrowstyle="-", > connectionstyle=cstyle, > patchB=p1)) > > - Rune > > 2010/3/23 Jae-Joon Lee <lee...@gm...> >> >> This should be doable using the annotation. Here is a simple cook-up I >> just did. it uses a naive algorithm to place the labels, but I guess >> it gives you an idea how things work. >> a screenshot is attached. >> >> Regards, >> >> -JJ >> >> >> from pylab import * >> >> # make a square figure and axes >> figure(1, figsize=(6,6)) >> ax = axes([0.1, 0.1, 0.8, 0.8]) >> >> labels = 'Frogs', 'Hogs', 'Dogs', 'Logs' >> fracs = [15,30,45, 10] >> >> explode=(0, 0.05, 0, 0) >> p = pie(fracs, explode=explode, shadow=True) >> title('Raining Hogs and Dogs', bbox={'facecolor':'0.8', 'pad':5}) >> >> for p1, l1 in zip(p[0], labels): >> r = p1.r >> dr = r*0.1 >> t1, t2 = p1.theta1, p1.theta2 >> theta = (t1+t2)/2. >> >> xc, yc = r/2.*cos(theta/180.*pi), r/2.*sin(theta/180.*pi) >> x1, y1 = (r+dr)*cos(theta/180.*pi), (r+dr)*sin(theta/180.*pi) >> if x1 > 0 : >> x1 = r+2*dr >> ha, va = "left", "center" >> tt = -180 >> cstyle="angle,angleA=0,angleB=%f"%(theta,) >> else: >> x1 = -(r+2*dr) >> ha, va = "right", "center" >> tt = 0 >> cstyle="angle,angleA=0,angleB=%f"%(theta,) >> >> annotate(l1, >> (xc, yc), xycoords="data", >> xytext=(x1, y1), textcoords="data", ha=ha, va=va, >> arrowprops=dict(arrowstyle="-", >> connectionstyle=cstyle, >> patchB=p1)) >> >> show() > > |
From: Rune V. S. <rv...@gm...> - 2010-03-28 11:14:51
|
Hello again, and thanks. I did not have a chance to look at this until now but using arc instead of angle worked out great. 2010/3/24 Jae-Joon Lee <lee...@gm...> > You should not use "angle" style if you change the x,y position (this > is due to the algorithm of how the line connecting two points are > create). > > Try something like below instead. > > if foo: > if theta - foo < 10: > print >>sys.stderr, "Overlapping, offsetting a little bit" > y1 = y1 + 0.1 > if x1 > 0 : > cstyle="arc,angleA=180,armA=30,armB=10,angleB=%f"%(-theta,) > else: > cstyle="arc,angleA=0,armA=30,armB=10,angleB=%f"%(theta,) > > There is not much documentation of how each algorithm works (it is > beyond my english skill). They are loosely based on the latex pstrick > package and the screenshot in the following link may be useful to get > some idea though. > > > http://matplotlib.sourceforge.net/users/annotations_guide.html#annotating-with-arrow > > Regards, > > -JJ > > > 2010/3/24 Rune V. Sjøen <rv...@gm...>: > > Hello again, and thank you very much for the answer, suddenly it all got > > much clearer to me. The only 'issue' I am having is (from screenshot) > what > > happens to the line pointing to Logs when I try to offset it a little bit > on > > the Y axis. It looks like either the angleA or angleB is wrong, but I > don't > > see and reason why it would be as the X coordinates does not change. > > > > Another thing I do not quite understand is what that patchB does. > > > > figure(1, figsize=(6,6)) > > ax = axes([0.1, 0.1, 0.8, 0.8]) > > > > labels = 'Frogs', 'Hogs', 'Dogs', 'Logs' > > fracs = [45, 135 ,1, 1] > > > > p = pie(fracs) > > > > foo = None > > for p1, l1 in zip(p[0], labels): > > > > r = p1.r > > dr = r*0.1 > > t1, t2 = p1.theta1, p1.theta2 > > theta = (t1+t2)/2. > > > > xc = cos(theta/180.*pi)*r > > yc = sin(theta/180.*pi)*r > > x1 = cos(theta/180.*pi)*(r+dr) > > y1 = sin(theta/180.*pi)*(r+dr) > > > > if x1 > 0 : > > x1 = r+2*dr > > ha, va = "left", "center" > > cstyle="angle,angleA=180,angleB=%f"%(-theta,) > > print >> sys.stderr, ha, ",A,", va > > else: > > x1 = -(r+2*dr) > > ha, va = "right", "center" > > cstyle="angle,angleA=0,angleB=%f"%(theta,) > > print >> sys.stderr, ha, ",B,", va > > > > if foo: > > if theta - foo < 10: > > print >>sys.stderr, "Overlapping, offsetting a little > > bit" > > y1 = y1 + 0.1 > > foo = theta > > > > annotate(l1, > > (xc, yc), xycoords="data", > > xytext=(x1, y1), textcoords="data", ha=ha, va=va, > > arrowprops=dict(arrowstyle="-", > > connectionstyle=cstyle, > > patchB=p1)) > > > > - Rune > > > > 2010/3/23 Jae-Joon Lee <lee...@gm...> > >> > >> This should be doable using the annotation. Here is a simple cook-up I > >> just did. it uses a naive algorithm to place the labels, but I guess > >> it gives you an idea how things work. > >> a screenshot is attached. > >> > >> Regards, > >> > >> -JJ > >> > >> > >> from pylab import * > >> > >> # make a square figure and axes > >> figure(1, figsize=(6,6)) > >> ax = axes([0.1, 0.1, 0.8, 0.8]) > >> > >> labels = 'Frogs', 'Hogs', 'Dogs', 'Logs' > >> fracs = [15,30,45, 10] > >> > >> explode=(0, 0.05, 0, 0) > >> p = pie(fracs, explode=explode, shadow=True) > >> title('Raining Hogs and Dogs', bbox={'facecolor':'0.8', 'pad':5}) > >> > >> for p1, l1 in zip(p[0], labels): > >> r = p1.r > >> dr = r*0.1 > >> t1, t2 = p1.theta1, p1.theta2 > >> theta = (t1+t2)/2. > >> > >> xc, yc = r/2.*cos(theta/180.*pi), r/2.*sin(theta/180.*pi) > >> x1, y1 = (r+dr)*cos(theta/180.*pi), (r+dr)*sin(theta/180.*pi) > >> if x1 > 0 : > >> x1 = r+2*dr > >> ha, va = "left", "center" > >> tt = -180 > >> cstyle="angle,angleA=0,angleB=%f"%(theta,) > >> else: > >> x1 = -(r+2*dr) > >> ha, va = "right", "center" > >> tt = 0 > >> cstyle="angle,angleA=0,angleB=%f"%(theta,) > >> > >> annotate(l1, > >> (xc, yc), xycoords="data", > >> xytext=(x1, y1), textcoords="data", ha=ha, va=va, > >> arrowprops=dict(arrowstyle="-", > >> connectionstyle=cstyle, > >> patchB=p1)) > >> > >> show() > > > > > |