From: matthew a. <ma...@ca...> - 2004-01-05 01:44:09
|
Hi I'm writing a small script to plot my data, and I'd like to use a command line option to allow the same plot to be either displayed with GTK or output to postscript. This means I have to switch matplotlib backends within the script. Now by the time I know what option the user has chosen, I'm in a function: def plotThings(options): matplotlib.use(options.plotbackend) from matplotlib.matlab import * plot(...) ... and python complains SyntaxWarning: import * only allowed at module level It still works, but I think I'm on thin ice. And it doesn't work if I do: def main(): # ... parse options ... matplotlib.use(options.plotbackend) from matplotlib.matlab import * plotThings(options) SyntaxWarning: import * only allowed at module level NameError: global name 'plot' is not defined The matplotlib docs say you need to specify the backend before importing matplotlib.matlab. But this seems a bit restrictive: what if I want to display a plot on screen, and then output the same plot to postscript and print it? Normally imports are done only once at the top of a file, but I'd like to be able to switch backends anywhere. What are your thoughts on this issue? I've been using matplotlib for a while. It's the best python plotting tool I reckon. Thanks for contributing to free software. Cheers and thanks, Matthew. |
From: matthew a. <ma...@ca...> - 2004-01-05 04:45:23
|
Well I just answered my own question. As the docs point out, you can use the -dPS option to turn on the postscript backend. So to use this in harmony with my scripts I needed to: a) break out the plotting into a separate application called using command line options (conveniently I had already done this) b) tell my option parser about the -d option: import matplotlib from matplotlib.matlab import * # ... def main(): # ... parser.add_option("-d", dest="plotbackend", default="GTK", choices=matplotlib._knownBackends.keys(), help="Graphics backend to use to generate plots.") # ... c) use options.plotbackend in my own code to tell whether to savefig('something.ps') It's a bit awkward, but workable. Cheers, Matthew. On Mon, 5 Jan 2004, matthew arnison wrote: > Hi > > I'm writing a small script to plot my data, and I'd like to use a command > line option to allow the same plot to be either displayed with GTK or > output to postscript. > > This means I have to switch matplotlib backends within the script. > > Now by the time I know what option the user has chosen, I'm in a function: > > def plotThings(options): > matplotlib.use(options.plotbackend) > from matplotlib.matlab import * > > plot(...) > ... > > and python complains > > SyntaxWarning: import * only allowed at module level > > It still works, but I think I'm on thin ice. And it doesn't work if I do: > > def main(): > # ... parse options ... > > matplotlib.use(options.plotbackend) > from matplotlib.matlab import * > > plotThings(options) > > SyntaxWarning: import * only allowed at module level > NameError: global name 'plot' is not defined > > The matplotlib docs say you need to specify the backend before importing > matplotlib.matlab. But this seems a bit restrictive: what if I want to > display a plot on screen, and then output the same plot to postscript and > print it? Normally imports are done only once at the top of a file, but > I'd like to be able to switch backends anywhere. > > What are your thoughts on this issue? > > I've been using matplotlib for a while. It's the best python plotting tool > I reckon. Thanks for contributing to free software. > > Cheers and thanks, > Matthew. > > > ------------------------------------------------------- > This SF.net email is sponsored by: IBM Linux Tutorials. > Become an expert in LINUX or just sharpen your skills. Sign up for IBM's > Free Linux Tutorials. Learn everything from the bash shell to sys admin. > Click now! http://ads.osdn.com/?ad_id=1278&alloc_id=3371&op=click > _______________________________________________ > Matplotlib-users mailing list > Mat...@li... > https://lists.sourceforge.net/lists/listinfo/matplotlib-users > |
From: John H. <jdh...@ac...> - 2004-01-05 16:03:55
|
>>>>> "matthew" == matthew arnison <ma...@ca...> writes: matthew> The matplotlib docs say you need to specify the backend matthew> before importing matplotlib.matlab. But this seems a bit matthew> restrictive: what if I want to display a plot on screen, matthew> and then output the same plot to postscript and print it? matthew> Normally imports are done only once at the top of a file, matthew> but I'd like to be able to switch backends anywhere. The reason you need to specify the backend first is because everything from making a figure window to mapping an RGB tuple to a color is backend dependent. The matlab interface wouldn't know what to do with the 'figure' command without knowing its backend. What I think would be useful would be able to instantiate any backend figure with a figure instance from another backend. Eg a backend factory which did something like figPS = backend_factory(fig, 'PS') figGD = backend_factory(fig, 'GD') Ie, you could initialize a figure in any backend with an instance from another figure. This probably will never work perfectly across all backends, primarily because the GTK and WX backends both have a mainloop that they enter and it would be difficult to run both at the same time (though perhaps possible with GUI thread). But in most cases you wouldn't want too. But there is no reason you shouldn't be able to create a PS figure or a GD figure to save. I've been meaning to add a 'PS' extension checker in the savefig command that would enable you to save to PS from any backend. Is this primarily what you need to switch backends for? John Hunter |
From: matthew a. <ma...@ca...> - 2004-01-05 22:57:49
|
On Mon, 5 Jan 2004, John Hunter wrote: > >>>>> "matthew" == matthew arnison <ma...@ca...> writes: > > matthew> The matplotlib docs say you need to specify the backend > matthew> before importing matplotlib.matlab. But this seems a bit > matthew> restrictive: what if I want to display a plot on screen, > matthew> and then output the same plot to postscript and print it? > matthew> Normally imports are done only once at the top of a file, > matthew> but I'd like to be able to switch backends anywhere. > > But there is no reason you shouldn't be able to create a PS figure or > a GD figure to save. I've been meaning to add a 'PS' extension > checker in the savefig command that would enable you to save to PS > from any backend. > > Is this primarily what you need to switch backends for? Yes that's the sweet spot. Presumably the Save button on the GTK/WX GUI just calls savefig()? In which case you'd be able to save postscript from there too, which would be popular too I think. Another thing that would be handy is a simple cross-platform recipe (or function call?) for spawning persistent plot windows that don't block execution of the calling script. It may have been on this list (I should really search before asking) but it should be in the matplotlib docs I think. Oh yeah, and a default keyboard shortcut (or three! Esc, Q, Ctrl-Q) for quitting the plot window. And, being able to put the legend outside the plot area (either within a subplot, or outside all the subplots if the legend is the same for all). A big legend tends to cover up the data. Cheers, Matthew. |
From: John H. <jdh...@ac...> - 2004-01-07 14:54:16
|
>>>>> "matthew" == matthew arnison <ma...@ca...> writes: >> But there is no reason you shouldn't be able to create a PS >> figure or a GD figure to save. I've been meaning to add a 'PS' >> extension checker in the savefig command that would enable you >> to save to PS from any backend. >> >> Is this primarily what you need to switch backends for? matthew> Yes that's the sweet spot. matthew> Presumably the Save button on the GTK/WX GUI just calls matthew> savefig()? In which case you'd be able to save postscript matthew> from there too, which would be popular too I think. I've made some changes to the GTK backend that enable save to a ps figure, either by calling savefig('somefile.ps') or using a file with the ps extension from the save figure dialog. It's not too pretty internally but it works (more or less). Consider this a preliminary functional implementation with known bugs that will be hammered out later. The problem in implementing this is that the AxisText instances (axis and tick labels, title) are backend dependent. As Jeremy noted when he did the wx backend, this is different than the way other objects (lines, patches) are handled. With some refactoring this can be made more elegant. The other problem is that the default fonts are different between the backends, so you'll get a lot of warnings like "Falling back on default font". This is another problem we need to clear up -- ie, we need a set of shared fontnames between backends. Finally, a 'gotcha' that you need to watch out for is that text references in scripts will be destroyed by calling a postscript savefig (because of the way text instance conversions are handled). So if you did ax = subplot(111) plot(something) labels = ax.get_xticklabels() savefig('somefile.ps') set(labels, 'color', 'r') savefig('somefile.png') The color change would not take effect because the text references have been changed. Moral of story: do not change figure text properties after calling savefig for a ps figure with text instances obtained before the savefig call. Other than that it should work. Let me know. I've updated CVS but be forewarned: CVS mirrors sometime take a while to update. JDH |
From: matthew a. <ma...@ca...> - 2004-01-07 23:27:47
Attachments:
subplot_demo.py
|
That's great. It's interesting to read your discussion of backend switching issues. It's something that gnuplot deals with very poorly indeed, which is what motivated me to seek out matplotlib. I.e. in gnuplot you can freely switch backends, but the line styles are set differently (and sometimes very awkwardly: X resources for instance!) for each backend. Anyway, I tried out what's in CVS. As you say, it mostly works. I had trouble though with my (rather complicated) 2x2 subplot script. The worst problem is that when I use the Save button to save as .ps, the output is sized too large to fit on the page: only the lower left subplot is fully visible. There are various other layout problems, which I managed to reproduce in the attached hacked version of subplot_demo.py, but unfortunately I couldn't reproduce the problem above outside of my script. Other problems: * when saving from the GTK window into a .ps file, the lines are not clipped by the edge of the plot area: see the top left plot in the attached code * xaxis and yaxis labels often land on top of adjacent subplot titles and plot areas in savefig('blah.ps') output (I've had trouble with this in the -dPS output too) Also, I tried to save as file.eps, but the save dialog complained and only accepts .ps. Presumably this is an easy fix? Cheers, Matthew. On Wed, 7 Jan 2004, John Hunter wrote: > I've made some changes to the GTK backend that enable save to a ps > figure, either by calling > > savefig('somefile.ps') > > or using a file with the ps extension from the save figure dialog. > > It's not too pretty internally but it works (more or less). Consider > this a preliminary functional implementation with known bugs that will > be hammered out later. > > The problem in implementing this is that the AxisText instances (axis > and tick labels, title) are backend dependent. As Jeremy noted when > he did the wx backend, this is different than the way other objects > (lines, patches) are handled. With some refactoring this can be made > more elegant. > > The other problem is that the default fonts are different between the > backends, so you'll get a lot of warnings like "Falling back on > default font". This is another problem we need to clear up -- ie, we > need a set of shared fontnames between backends. > > Finally, a 'gotcha' that you need to watch out for is that text > references in scripts will be destroyed by calling a postscript > savefig (because of the way text instance conversions are handled). > > So if you did > > ax = subplot(111) > plot(something) > labels = ax.get_xticklabels() > savefig('somefile.ps') > set(labels, 'color', 'r') > savefig('somefile.png') > > The color change would not take effect because the text references > have been changed. Moral of story: do not change figure text > properties after calling savefig for a ps figure with text instances > obtained before the savefig call. > > Other than that it should work. Let me know. I've updated CVS but be > forewarned: CVS mirrors sometime take a while to update. > > JDH > |
From: John H. <jdh...@ac...> - 2004-01-26 21:38:53
|
>>>>> "matthew" == matthew arnison <ma...@ca...> writes: matthew> * when saving from the GTK window into a .ps file, the matthew> lines are not clipped by the edge of the plot area: see matthew> the top left plot in the attached code I've made a number of changes to matplotlib to improve the PS functionality -- those of you who are interested should take this version for a test drive and let me know of any problems so I can fix them for the next release. http://nitace.bsd.uchicago.edu:8080/files/share/matplotlib-0.42g.tar.gz Note WX is not working (but will be soon) with this snapshot so wx users please do not download. Added: * I think I've fixed all the backend switching problems, you can now output PS from the GTK backend by adding the PS extension. This will be available in WX soon. Let me know if you find any lingering bugs. * EPS (at long last!). Just use an 'eps' extension and the bounding box will be added to the PS output. matthew> * xaxis and yaxis labels often land on top of adjacent matthew> subplot titles and plot areas in savefig('blah.ps') matthew> output (I've had trouble with this in the -dPS output matthew> too) Yep, axes don't communicate with one another for text layout. A few things which you can do to help 1) Turn off redundant x labels. If 2 subplots use the same x axis, turn off the tick labels in all but the lower one with set(gca(), 'xticklabels', []) 2) Make the tick labels and titles smaller t = get(gca(), 'xticklabels') set(t, 'fontsize', 8) t = title('my title') set(t, 'fontsize', 10) 3) control the placement of the title manually t = title('my title') t.set_y(0.95) 1.0 is the top of the y axis. 1.02 is the default. Numbers less than 1 will be below the y axis. Eg, to make the title top aligned and below the top of the y axis, do t = title('my title', verticalalignment='top') t.set_y(0.99) I'm open to suggestions for changing the defaults (eg making the default fonts smaller) if people are having these kinds of problems regularly. JDH |