[GRASS-dev] matplotlib example script
michael.barton at asu.edu
Thu Jul 24 22:01:32 EDT 2008
On Jul 24, 2008, at 6:03 PM, Glynn Clements wrote:
> Michael Barton wrote:
>>>> This script replicates the functionality of
>>>> d.histogram, but makes a much nicer looking plot. It also has more
>>>> options, although I've included only a very few of the formatting
>>>> possibilities here. The script sends the output from r.stats into 9
>>>> lines of code to produce the histogram with formatting options.
>>>> of it is done by 4 lines. This can be run from the command line and
>>>> does not require a GUI to be installed. It writes to a PNG file,
>>>> could easily be set to create a TclTk or wxPython interactive
>>>> as a user-selectable option.
>>> Before we start using MatPlotLib extensively, we need to figure out
>>> how to handle output format selection so that all script can work
>>> any backend, and the scripts can be used alongside d.* commands
>>> without the caller needing to distingiush between them.
>>> Or, at least, we need to figure out an interface that will allow
>>> us to
>>> do that later without having to modify large numbers of scripts.
>>> somthing like a grass.plot module which hides the details behind
>>> begin() and end() methods, so the scripts themselves don't reference
>>> specific format types.
>> I agree. One possibility is to use the ps backend if you are indeed
>> planning to switch the output to postscript. In this example, I just
>> wanted to show that TclTk, wxPython, Qt or other GUI is not required.
> Well, the general idea is to support as wide a range of backends as
> possible. Essentially, we want something similar to the d.* commands,
> which will output to a variety of backends, even those which are yet
> to be invented.
> Also, if we can't find any better way to integrate d.* commands and
> matplotlib, we may end up adding a d.graph backend to matplotlib.
>>>> for i in range(cells):
>>> Ouch. This is going to cause problems (i.e. fail) for large maps
>>> for moderately-sized maps, it will be slow). As it stands, this
>>> *isn't* a substitute for d.histogram.
>> Well, I was worried about that too. However, even with the 10m DEM in
>> spearfish, the main time is spent in running r.stats. The rest of the
>> code takes no appreciable time to run. I should try it on a big
>> ASTER or Landsat ETM file and see how long it takes.
> $ g.region rast=elevation.10m
> $ time r.stats -Acn elevation.10m >/dev/null
> r.stats complete.
> real 0m1.233s
> user 0m1.220s
> sys 0m0.013s
> time stuff/histogram_mpldemo.py input=elevation.10m
> r.stats complete.
> real 0m5.058s
> user 0m4.886s
> sys 0m0.163s
> Note that the time taken to get to the "r.stats complete" point
> includes the above loop to insert "cells" copies of "val" in
> Also, r.stats alone is only using one core, while the script will be
> using both (one running the script, another running r.stats
> concurrently). With a single core (or if the other core(s) are busy),
> it would be worse.
>>> As axes.hist() just calls numpy.histogram() then uses axes.bar() (or
>>> axes.barh()) to plot the result, you may as well just use axes.bar()
>>> directly on the value,count pairs emitted by r.stats.
>>> If you specifically want to bin the data, it would be better to
>>> add an option to r.stats, or to bin the data in the script as it is
>>> being read, rather than read an entire raster map into a Python
>> I agree about r.stats. Wouldn't binning in the script take as long as
>> the current method?
> Even if it takes just as long, you're less likely to have it fail
> because "plotlist" consumed all available RAM. As it stands, plotlist
> will have one entry for every non-null cell in the raster.
> When processing "bulk" data, anything that uses a fixed amount of
> memory (e.g. one integer per bin) is preferable to using memory
> proportional to the size of the input.
> Hence the recommendation to iterate over the lines of r.stats' output
> rather than read it all into a list then iterate over the list.
I'll give that a try.
>>>> if len(fcolor.split(':')) == 3:
>>>> #rgb color
>>>> r = float(fcolor.split(':'))
>>>> g = float(fcolor.split(':'))
>>>> b = float(fcolor.split(':'))
>>>> #translate to mpl rgb format
>>>> r = r / 255
>>>> g = g / 255
>>>> b = b / 255
>>>> fcolor = (r,g,b)
>>> This should probably be made into a library function; it would also
>>> need the named colours (lib/gis/named_colr.c).
>> Yes. And it might be one in MatPlotLib. It has some color function,
>> but I haven't explored them yet. Do the grass color names have html
>> equivalents? If so, we don't need /lib/gis/named_colr.c.
> I suspect that we want our own code here. Eventually there may be
> Python scripts which don't use matplotlib (i.e. non-d.* scripts) but
> which still need to parse colours.
> I've added this to grass.py:
> def parse_color(val, dflt = None):
> if val in named_colors:
> return named_colors[val]
> vals = val.split(':')
> if len(vals) == 3:
> return tuple(float(v) / 255 for v in vals)
> return dflt
> [along with the named_colors dictionary.]
I'd added it as a method in the script, but can dispense with that now.
More information about the grass-dev