|
From: Ted D. <ted...@jp...> - 2005-03-11 23:33:04
|
Jeez John if you're going to do this much work for a simple information
request I may start sending you "questions" about my normal job. (thank you
very much!)
Thanks for the code - it's going to save us a ton of time. We're going to
take the track2 demo and extend/refine/document it to be a function similar
to barh. We'll have to think about the x data input for this function a
little bit since it really needs to be something like
x= [ [ (start1,stop1), (start2,stop2), ... ],
[ (start1,stop1), (start2,stop2), ... ],
...
]
which might be a little complicated for someone to set up correctly.
Thanks,
Ted
At 02:33 PM 3/11/2005, John Hunter wrote:
> >>>>> "Ted" == Ted Drain <ted...@jp...> writes:
>
> Ted> We have some data that we'd like to plot and I'd like to know
> Ted> if matplotlib (MPL) supports this directly (I don't think it
> Ted> does) or where we should start looking to implement this
> Ted> capability.
>
>All the core functionality is there already -- you just have to plug
>the pieces together.
>
> Ted> We want to plot time intervals in a similar way to a
> Ted> horizontal bar graph. In this case, the data is when a
> Ted> spacecraft is in view of a ground station. So for a list of
> Ted> ground stations (the y axis), we have lists of start and stop
> Ted> times that represent the view periods. So we need to:
>
> Ted> - show the list of ground stations (i.e. arbitrary labels)
> Ted> along the Y axis like you would on a bar chart.
>
> Ted> - draw sets of rectangles at the right y location with the
> Ted> length determined by the x data (in user controllable line
> Ted> styles, colors, and fills).
>
>This is mostly available in barh, which by default has the left side
>of the bar at 0 but optionally allows you to specify the left as an
>array. So you can use barh to plot intervals with the left side
>specfied by the 'left' arg and the bar width specified by the 'x' arg.
>The return value is a list of Rectangles, which you can customize (set
>the facecolor, edgecolor, edgewidth, transparency, etc). See
>track1.py, attached below for an example.
>
>Note that you can use any mpl function with dates, as long as you set
>the tick formatters and locators correctly; this is also illustrated
>in the example code.
>
> Ted> - optionally label the start and stop points of each interval
> Ted> with the X value for that point (in this case a date/time).
> Ted> Ideally, the user would have the option of specifying a
> Ted> location relative to the bar for each end point like this
> Ted> (none, high, mid, low):
>
> Ted> High High |-----------| Mid | BAR | Mid |-----------| Low Low
>
>This requires you to compute the bar locations for the x, y, width,
>height coords of the rectangles. You can then add text with
>text(x,y,s) if you have computed y to be the bottom, center or top of
>the bar. track1.py also illustrates this; but see track2.py for
>examples of setting the horizontal and vertical alignment of the text,
>which should vary with High, Low or Mid for the best looking graphs.
>
> Ted> I don't think I can currently do this in MPL so I'd like to
> Ted> here ideas from John and anyone else on which classes I
> Ted> should start looking at any suggestions on how this should
> Ted> work.
>
>For real work, it helps to create custom classes to manage some of
>these layout details. I did this in track2.py, which creates a custom
>class derived from Rectangle that contains two Text instances
>labelstart and labelstop. This design makes more sense, since the
>View object knows it's left, bottom, width, height etc so it makes it
>easier to do layout. The example shows how to use mpl connections to
>toggle labels on and off.
>
>In any case, the two mpl classes you want to study are
>matplotlib.patches.Rectangle and matplotlib.text.Text, and you may
>want to take a close look at matplotlib.axes.Axes.barh method.
>
>Sometimes it's easier to write an example than it is to explain how to
>use everything together. If you can think of a nice way to wrap some
>of the functionality into reusable pieces, that would be great.
>
>JDH
>
>
>####################
># Begin track1.py #
>####################
>
>from matplotlib.dates import date2num
>from matplotlib.dates import HourLocator, DateFormatter
>from matplotlib.mlab import rand
>from matplotlib.numerix import arange
>from datetime import datetime
>from pylab import figure, show
>
>N = 7
>labels = ['S%d'%i for i in range(N)]
>colors = ('red', 'green', 'purple', 'brown', 'yellow', 'black', 'blue')
>
>t0 = date2num(datetime.now())
>start = t0 + rand(N) # add random days in seconds
>locator = HourLocator(arange(0,24,2)) # ticks every 2 hours
>formatter = DateFormatter('%H') # hour
>
>ylocs = arange(N) # ylocs of the bar, arbitrary
>
>duration = rand(N)*0.2 # random durations in fraction of day
>
>fig = figure()
>ax = fig.add_subplot(111)
>ax.xaxis.set_major_formatter(formatter)
>ax.xaxis.set_major_locator(locator)
>
>height = 0.5 # the height of the bar, arbitrary
>bars = ax.barh(duration, ylocs, height=height, left=start)
>ax.set_yticks(ylocs)
>ax.set_yticklabels(labels)
>
>for bar, color in zip(bars, colors):
> bar.set_facecolor(color)
>
># define some location arrays for labeling
>left = start
>right = left + duration
>top = ylocs + height/2.
>bottom = ylocs - height/2.
>center = ylocs
>
>
>
># label the 4th bar on top right
>ind = 3
>note = 'hi mom'
>x = right[ind]
>y = top[ind]
>ax.text(x,y,note)
>#ax.set_xlim((min(left), max(right)+2))
>ax.grid(True)
>ax.set_title('Time windows when craft visible by station')
>ax.set_xlabel('Time (h)')
>
>show()
>
>####################
># End track1.py #
>####################
>
>
>####################
># Begin track2.py #
>####################
>
>from matplotlib.artist import Artist
>from matplotlib.dates import date2num
>from matplotlib.dates import HourLocator, DateFormatter
>from matplotlib.patches import Rectangle
>from matplotlib.mlab import rand
>from matplotlib.numerix import arange
>from datetime import datetime
>
>import pylab
>
>class View(Rectangle):
> """
> A view of when a craft is visible defined by a start and stop time
> (days as float) with labeling capability.
>
> A rectangle will be drawn
> """
> def __init__(self, ax, ind, station, start, stop, timefmt='%H:%M',
> timeloc='top', height=0.5, **kwargs):
> """
> ax is an axes instance -- the class will add required Artists
> to to axes
>
> ind is the station number for yaxis positions -- the rectangles
> will be
> drawn with vertical centers at ind with a height height.
>
> station is a string label
>
> start and stop will be the left and right side of the
> rectangles
> """
> # for rects, x,y is lower left but we want ind to be the
> # center
> Rectangle.__init__(self, (start, ind-height/2), stop-start,
> height, **kwargs)
> ax.add_patch(self)
> self.ind = ind
> self.station = station
>
> self.timefmt = timefmt
> self.formatter = DateFormatter(timefmt)
>
> self.labelstart = ax.text(start, 0, self.formatter(start),
> horizontalalignment='right')
> self.labelstop = ax.text(stop, 0, self.formatter(stop),
> horizontalalignment='left')
>
> self.labelstart.set_visible(False)
> self.labelstop.set_visible(False)
> if timeloc is not None:
> if timeloc == 'top':
> y = ind + height/2.
> valign = 'bottom'
> elif timeloc == 'bottom':
> y = ind - height/2.
> valign = 'top'
> elif timeloc == 'center':
> y = ind
> valign = 'center'
>
> self.labelstart.set_visible(True)
> self.labelstop.set_visible(True)
>
> self.labelstart.set_y(y)
> self.labelstop.set_y(y)
>
> self.labelstart.set_verticalalignment(valign)
> self.labelstop.set_verticalalignment(valign)
>
>
>
>
>N = 8
>t0 = date2num(datetime.now())
>start = t0 + rand(N) # add random days in seconds
>locator = HourLocator(arange(0,24,2)) # ticks every 2 hours
>formatter = DateFormatter('%H') # hour
>
>duration = rand(N)*0.2 # random durations in fraction of day
>stop = start + duration
>fig = pylab.figure()
>ax = fig.add_subplot(111)
>ax.xaxis.set_major_formatter(formatter)
>ax.xaxis.set_major_locator(locator)
>
>views = []
>for ind, x1, x2 in zip(range(1,N+1), start, stop):
> view = View(ax, ind, 'S%d'%ind, x1, x2, timeloc='center')
> # Now call any Rectangle function on view instance to customize rect,
> # and any Text prop on view.labelstart and view.labelstop
> views.append(view)
>
>
>yticks = [view.ind for view in views]
>ylabels = [view.station for view in views]
>
>ax.set_yticks(yticks)
>ax.set_yticklabels(ylabels)
>
>def toggle_labels(event):
> if event.key != 't': return
> toggle_labels.on = not toggle_labels.on
> for view in views:
> view.labelstart.set_visible(toggle_labels.on)
> view.labelstop.set_visible(toggle_labels.on)
> pylab.draw()
>toggle_labels.on = True
>
># use canvas.mpl_connect in API
>pylab.connect('key_press_event', toggle_labels)
>
>ax.autoscale_view() # this is normally called by a plot command
>
>ax.set_xlim((min(start)-.1, max(stop)+.1))
>ax.set_ylim((0,N+1))
>ax.set_title("Press 't' to toggle labels")
>ax.set_xlabel('Time (hours)')
>ax.grid(True)
>pylab.show()
>
>
>####################
># End track2.py #
>####################
>
>
>
>
>-------------------------------------------------------
>SF email is sponsored by - The IT Product Guide
>Read honest & candid reviews on hundreds of IT Products from real users.
>Discover which products truly live up to the hype. Start reading now.
>http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
>_______________________________________________
>Matplotlib-users mailing list
>Mat...@li...
>https://lists.sourceforge.net/lists/listinfo/matplotlib-users
Ted Drain Jet Propulsion Laboratory ted...@jp...
|