|
From: John H. <jd...@gm...> - 2007-03-20 23:52:16
|
On 3/20/07, Eric Firing <ef...@ha...> wrote:
> You accidentally whacked out the new Axes.matshow, so I put it back.
Oops, sorry.
> I also noticed a few decorators--gasp!--in axes.py. I presume you will
> want them replaced by old-style syntax to preserve 2.3 compatibility,
> but I will leave that to you. (After about the 10th or so time of
> reading a bit about decorators, I think I understand them enough for
> simple use cases; apart from that ugly and utterly unpythonic @ symbol,
> maybe they are not as bad as I thought.)
>
> The curmudgeon in me has to wonder whether the snazzy unit support is
> really a good thing; this is partly a question of where the boundary of
> a plotting library should be. The simpler view (classic mpl) is that
> the role of mpl is to do a good job plotting numbers and labeling
> things, and the role of the user or application programmer is to supply
> the numbers and labels. I am not sure that enough is gained by enabling
> unit conversion and automatic axis labeling inside a plot command to
> compensate for the added complexity. My hesitation probably reflects
> the facts (1) that I don't see any *compelling* use cases in the sort
> of work I do, (2) I am not familiar with whatever use cases motivated
> this, (3) I haven't thought about it much yet, and (4) I may be a bit
> unimaginative.
>
> I will try to take a closer look, both at the changes and at the
> questions you raise in your message, tomorrow.
I too have been concerned by the complexity of this implementation --
I think it is trying to support too many paradigms, for example,
sequences of hetergeneous units. I have dramatically simplified the
code, and moved almost everything out of Axes. I have also made
"units" an rc param so that if units is not enabled, there is a dummy
do nothing units manager so you'll only pay for a few extra do nothing
function calls. Take a look at the code again when you get a minute,
I think you'll be more satisfied at the reduced complexity.
I've also cleaned up the examples to hopefully make clearer the
potential use cases. Eg, for radian plotting
from basic_units import radians, degrees
from pylab import figure, show, nx
x = nx.arange(0, 15, 0.01) * radians
fig = figure()
ax = fig.add_subplot(211)
ax.plot(x, nx.cos(x), xunits=radians)
ax.set_xlabel('radians')
ax = fig.add_subplot(212)
ax.plot(x, nx.cos(x), xunits=degrees)
ax.set_xlabel('degrees')
show()
and see attached screenshot. One of the things this implementation
buys you is the units writer can provide a mapping from types to
locators and formatters -- notice in the attached screenshot how you
get the fancy tick locating and formatting. This enables a matplotlib
application developer to alter the default ticking and formatting
outside of the code base.
Here is another use case, working with native datetimes -- note that
we get to use native dates in plot and set_xlim
import date_support # set up the date converters
import datetime
from pylab import figure, show, nx
xmin = datetime.date(2007,1,1)
xmax = datetime.date.today()
xdates = [xmin]
while 1:
thisdate = xdates[-1] + datetime.timedelta(days=1)
xdates.append(thisdate)
if thisdate>=xmax: break
fig = figure()
fig.subplots_adjust(bottom=0.2)
ax = fig.add_subplot(111)
ax.plot(xdates, nx.mlab.rand(len(xdates)), 'o')
ax.set_xlim(datetime.date(2007,2,1), datetime.date(2007,3,1))
for label in ax.get_xticklabels():
label.set_rotation(30)
label.set_ha('right')
show()
Some of the features were inspired by some real use cases that the JPL
has encountered in developing their monty application for ground
tracking of orbiting spacecraft. The basic problem is this. Imagine
you are a large C++ shop with a lot of legacy code and a python
interface, and you've decided to jettison your internal plotting
library for matplotlib. Your users work at a enhanced python shell
and have all of the legacy functionality and objects and want to so
something like
>>> plot(o)
where o is one of these legacy objects. They may not know a lot of
matplotlib, but can do plot. Asking them to learn about tickers and
formatters and conversion to arrays etc may be a non-starter for many
of these users. You could wrap all of the bits of matplotlib that you
need and do the conversion under the hood for your users, but then you
will always be trying to keep up with the mpl changes. You can't
really change the objects to suit mpl because too much legacy code
depends on them. What the proposed changes allow the developer to do
is write a converter class and register their types with a unit
manager and mpl will do the conversions in the right place. In the
current implementation (heavily revised) this happens when the Axes
adds the artist to itself, which provides a finite number of points of
entry.
Here is what the converter code in date_support in the units example
directory (used in the demo above). Note that this pretty much
replaces all of the current plot_date functionality, but happens
outside mpl and doesn't require the user to think about date2num
import matplotlib
matplotlib.rcParams['units'] = True
import matplotlib.units as units
import matplotlib.dates as dates
import matplotlib.ticker as ticker
import basic_units
import datetime
class DateConverter(units.ConversionInterface):
def tickers(x, unit=None):
'return major and minor tick locators and formatters'
majloc = dates.AutoDateLocator()
minloc = ticker.NullLocator()
majfmt = dates.AutoDateFormatter(majloc)
minfmt = ticker.NullFormatter()
return majloc, minloc, majfmt, minfmt
tickers = staticmethod(tickers)
def convert_to_value(value, unit):
return dates.date2num(value)
convert_to_value = staticmethod(convert_to_value)
units.manager.converters[datetime.date] = DateConverter()
And I've gotten the units.py module down to a digestable 105 lines of
code!
I haven't finished porting all of the artists yet, eg there is work
left to do in collections and text, but lines, patches and regular
polygon collections are working, and there are more examples.
See if you find the new interface less onerous. There is still work
to do if we want to support this kind of thing -- one of the hard
parts is to modify the various plotting functions to try and get the
original data into the primitive objects, which the current approach
is building around.
I've also gotten rid of all the decorators and properties. The code
is not python2.3 compatible.
JDH
|