From: Steve C. <ste...@ya...> - 2004-05-08 04:42:37
|
John, I've just started using the new tick locating, formatting and date plotting and noticed if you want to show day of month, month and year its quite easy to end up with major and minor tick labels overwriting each other. Is there a way to draw the major tick label underneath the minor tick label so they're not competing for the same space? Something like this: Minor label (day of month) 3 10 18 24 31 7 14 22 28 6 13 20 27 Major label (month, year) Jan 2000 Feb 2000 Mar 2000 Regards, Steve |
From: John H. <jdh...@ac...> - 2004-05-08 13:09:56
|
>>>>> "Steve" == Steve Chaplin <ste...@ya...> writes: Steve> John, I've just started using the new tick locating, Steve> formatting and date plotting and noticed if you want to Steve> show day of month, month and year its quite easy to end up Steve> with major and minor tick labels overwriting each other. Steve> Is there a way to draw the major tick label underneath the Steve> minor tick label so they're not competing for the same Steve> space? There are a few ways to go here. First of all, with no change to the code, you can set the tick positions of the minor tick labels as follow. I'm just winging this code so apologies if there is a minor mistake somewhere ax = subplot(111) #your plot here for tick in ax.xaxis.get_minor_ticks(): tick.label1.set_y(-0.1) Note that the y coord of the x tick label is in axes coordinates, where 0 is the bottom and 1 is the top of the axes, so -0.1 is 10% below the bottom of the axes. label1 and label2 are the bottom and top label text.Text instances (this is a recent feature to support left/right labeling or top/bottom tick labeling) so you can call any of the Text methods on them. Note this code only affects the current ticks, so if you were doing interactive navigation and zoomed out, thereby creating new minor ticks, the new minor ticks would have their default locations (but I can fix this fairly easily by updating the copy properties function that transfers old tick properties to new ones when ticks are created during interaction). There is an additional consideration. Currently, the tick drawing code will skip a minor tick if a major tick has already been drawn at that exact location. In axis.py there is a line in the axis drawing code that reads if seen.has_key(loc): continue where seen is a dict that has a key if the tick location loc was drawn by the major tick drawing code. We could add an attribute, something like forceDraw, to the tick and modify this code so that you could do if not tick.forceDraw and seen.has_key(loc): continue and in your code for tick in ax.xaxis.get_minor_ticks(): tick.forceDraw = True tick.label1.set_y(-0.1) Let me know how this works for you. We could automate this a bit if you think it's worthwhile, eg by setting a 'draw under' flag for the minor ticks, getting the bounding boxes of the major ticks in the axis drawing code, and setting the offsets automagically. This would have the dual advantages of working in the presence of changes in font size, interaction, etc. The question is whether it's sufficiently common to justify the extra work or if the manual control approach above suffices. If you want to add this feature, I can get you some additional pointers to code showing how to get the bounding box of all the major tick labels and using this to control the positioning of the minor tick labels. JDH |
From: Al S. <a.d...@wo...> - 2004-05-09 00:13:19
|
One way to avoid having the minor ticklabels collide with the major ones is to put them on separate lines as illustrated in the original post. Supporting multi-line text (embedded '\n's in ticklabels) would permit this. All you would have to do is begin the minor ticklabels with one or more '\n's. How is this coming along? -Al On Sat, 2004-05-08 at 08:47, John Hunter wrote: > >>>>> "Steve" == Steve Chaplin <ste...@ya...> writes: > > Steve> John, I've just started using the new tick locating, > Steve> formatting and date plotting and noticed if you want to > Steve> show day of month, month and year its quite easy to end up > Steve> with major and minor tick labels overwriting each other. > Steve> Is there a way to draw the major tick label underneath the > Steve> minor tick label so they're not competing for the same > Steve> space? > > There are a few ways to go here. First of all, with no change to the > code, you can set the tick positions of the minor tick labels as > follow. I'm just winging this code so apologies if there is a minor > mistake somewhere > > ax = subplot(111) > > #your plot here > for tick in ax.xaxis.get_minor_ticks(): > tick.label1.set_y(-0.1) > > Note that the y coord of the x tick label is in axes coordinates, > where 0 is the bottom and 1 is the top of the axes, so -0.1 is 10% > below the bottom of the axes. label1 and label2 are the bottom and > top label text.Text instances (this is a recent feature to support > left/right labeling or top/bottom tick labeling) so you can call any > of the Text methods on them. > > Note this code only affects the current ticks, so if you were doing > interactive navigation and zoomed out, thereby creating new minor > ticks, the new minor ticks would have their default locations (but I > can fix this fairly easily by updating the copy properties function > that transfers old tick properties to new ones when ticks are created > during interaction). > > There is an additional consideration. Currently, the tick drawing > code will skip a minor tick if a major tick has already been drawn at > that exact location. In axis.py there is a line in the axis drawing > code that reads > > if seen.has_key(loc): continue > > where seen is a dict that has a key if the tick location loc was drawn > by the major tick drawing code. We could add an attribute, something > like forceDraw, to the tick and modify this code so that you could do > > if not tick.forceDraw and seen.has_key(loc): continue > > and in your code > > for tick in ax.xaxis.get_minor_ticks(): > tick.forceDraw = True > tick.label1.set_y(-0.1) > > Let me know how this works for you. > > We could automate this a bit if you think it's worthwhile, eg by > setting a 'draw under' flag for the minor ticks, getting the bounding > boxes of the major ticks in the axis drawing code, and setting the > offsets automagically. This would have the dual advantages of working > in the presence of changes in font size, interaction, etc. The > question is whether it's sufficiently common to justify the extra work > or if the manual control approach above suffices. If you want to add > this feature, I can get you some additional pointers to code showing > how to get the bounding box of all the major tick labels and using > this to control the positioning of the minor tick labels. > > JDH > > > ------------------------------------------------------- > This SF.Net email is sponsored by Sleepycat Software > Learn developer strategies Cisco, Motorola, Ericsson & Lucent use to > deliver higher performing products faster, at low TCO. > http://www.sleepycat.com/telcomwpreg.php?From=osdnemail3 > _______________________________________________ > Matplotlib-users mailing list > Mat...@li... > https://lists.sourceforge.net/lists/listinfo/matplotlib-users |
From: John H. <jdh...@ac...> - 2004-05-09 02:01:09
|
>>>>> "Al" == Al Schapira <a.d...@wo...> writes: Al> One way to avoid having the minor ticklabels collide with the Al> major ones is to put them on separate lines as illustrated in Al> the original post. Supporting multi-line text (embedded '\n's Al> in ticklabels) would permit this. All you would have to do is Al> begin the minor ticklabels with one or more '\n's. How is Al> this coming along? I've laid the groundwork for it, by factoring the text instances out of the backends. Now the backends just are asked to draw plain old strings at a given location, size, rotation etc. Before they were asked to draw matplotlib text instances, which means if the string contained new lines and the backend couldn't handle them, you were hosed. Under the new framework, the Text class will newline split the strings, and layout the separate strings. This will buy you newline separated strings on all backends with rotation for those that support arbitrary rotation (gd, agg, ps) So the short answer is: it's close. Depending on how the other things that I'm working on go, maybe next week, maybe a little later. JDH |
From: Steve C. <ste...@ya...> - 2004-05-09 05:58:13
|
On Sat, 2004-05-08 at 20:47, John Hunter wrote: > ax = subplot(111) > > #your plot here > for tick in ax.xaxis.get_minor_ticks(): > tick.label1.set_y(-0.1) > Thanks for the advice, but I tried this and the tick labels disappeared completely. I then tried tick.label1.set_y(0.0) which I would expect to leave the labels at the same place, but the labels disappeared also. I had a look at matplotlib.dates and found what looks like a problem/limitation. This is my understanding, which may be completely wrong. The python 'time' module (and epochtime) limits years to 1970-2038. The 'egenix' and python 'datetime' modules support a much larger range of years ('datetime supports years from 1-9999). matplotlib.dates converter classes supports 'epochtime', 'datetime' and 'egenix' date formats. However, internally it uses epochtime for all dates and so limits all years to the range 1970-2038, even though 'datetime' and 'egeinx' themselves support much more that this. I think there is a lot of data available before 1970 that people might like to plot. Taking stock data as an example, Yahoo has data going back to 1962 for some companies. Regards Steve |
From: John H. <jdh...@ac...> - 2004-05-10 12:58:51
|
>>>>> "Steve" == Steve Chaplin <ste...@ya...> writes: Steve> On Sat, 2004-05-08 at 20:47, John Hunter wrote: >> ax = subplot(111) >> >> #your plot here for tick in ax.xaxis.get_minor_ticks(): >> tick.label1.set_y(-0.1) >> Steve> Thanks for the advice, but I tried this and the tick labels Steve> disappeared completely. I then tried tick.label1.set_y(0.0) Steve> which I would expect to leave the labels at the same place, Steve> but the labels disappeared also. Doh! There's a reason I try to never post untested code. I wrongly assumed the location were in relative axes coords but they are not. I use reference values (matplotlib.transforms.RRef - think mutable floats or a c pointer to a float) in some instances to specify locations. I define binary operations on these so I can specify locations like 3 points to the left of the x axis minimum, and have these locations update automagically under figure resizes and dpi changes - see http://matplotlib.sf.net/matplotlib.transforms.html. This is what I do for x tick label locations - they are specified in number of points below the minimum of the axes bounding rectangle. Here is how to properly change that location (tested this time!) from matplotlib.transforms import RRef from matplotlib.matlab import * ax = subplot(111) plot([1,2,3]) points = 20 for tick in ax.xaxis.get_major_ticks(): y = ax.bbox.y.get_refmin() - ax.dpi*RRef(points/72.0) tick.label1.set_y(y) show() ax.bbox.y.get_refmin(), ax.dpi and RRef(points/72.0) are all RRefs, as is y. A word of warning. I'm totally rewriting the transform architecture from the ground up as we speak, so whatever you do here is likely to change with the next release. Of course there will be an analogous way to do it and if you remind me I'll let you know what it is - or you can check the code in XAxis.py to see how it specifies tick locations. In any case there will be release notes detailing the changes. Steve> I had a look at matplotlib.dates and found what looks like Steve> a problem/limitation. This is my understanding, which may Steve> be completely wrong. The python 'time' module (and Steve> epochtime) limits years to 1970-2038. The 'egenix' and Steve> python 'datetime' modules support a much larger range of Steve> years ('datetime supports years from 1-9999). Steve> matplotlib.dates converter classes supports 'epochtime', Steve> 'datetime' and 'egenix' date formats. However, internally Steve> it uses epochtime for all dates and so limits all years to Steve> the range 1970-2038, even though 'datetime' and 'egeinx' Steve> themselves support much more that this. Steve> I think there is a lot of data available before 1970 that Steve> people might like to plot. Taking stock data as an example, Steve> Yahoo has data going back to 1962 for some companies. Absolutely right. It ought to use datetime for everything if python2.3 is available. It's not a top priority for me right now since I'm up to my elbows with the new transformation code, optimized line and patch collection drawing, porting mathtext to PS and handling newline separated strings, but I agree it is an important fix; I added it to the priorities list. JDH |