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... |