You can subscribe to this list here.
2003 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(1) |
Nov
(33) |
Dec
(20) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2004 |
Jan
(7) |
Feb
(44) |
Mar
(51) |
Apr
(43) |
May
(43) |
Jun
(36) |
Jul
(61) |
Aug
(44) |
Sep
(25) |
Oct
(82) |
Nov
(97) |
Dec
(47) |
2005 |
Jan
(77) |
Feb
(143) |
Mar
(42) |
Apr
(31) |
May
(93) |
Jun
(93) |
Jul
(35) |
Aug
(78) |
Sep
(56) |
Oct
(44) |
Nov
(72) |
Dec
(75) |
2006 |
Jan
(116) |
Feb
(99) |
Mar
(181) |
Apr
(171) |
May
(112) |
Jun
(86) |
Jul
(91) |
Aug
(111) |
Sep
(77) |
Oct
(72) |
Nov
(57) |
Dec
(51) |
2007 |
Jan
(64) |
Feb
(116) |
Mar
(70) |
Apr
(74) |
May
(53) |
Jun
(40) |
Jul
(519) |
Aug
(151) |
Sep
(132) |
Oct
(74) |
Nov
(282) |
Dec
(190) |
2008 |
Jan
(141) |
Feb
(67) |
Mar
(69) |
Apr
(96) |
May
(227) |
Jun
(404) |
Jul
(399) |
Aug
(96) |
Sep
(120) |
Oct
(205) |
Nov
(126) |
Dec
(261) |
2009 |
Jan
(136) |
Feb
(136) |
Mar
(119) |
Apr
(124) |
May
(155) |
Jun
(98) |
Jul
(136) |
Aug
(292) |
Sep
(174) |
Oct
(126) |
Nov
(126) |
Dec
(79) |
2010 |
Jan
(109) |
Feb
(83) |
Mar
(139) |
Apr
(91) |
May
(79) |
Jun
(164) |
Jul
(184) |
Aug
(146) |
Sep
(163) |
Oct
(128) |
Nov
(70) |
Dec
(73) |
2011 |
Jan
(235) |
Feb
(165) |
Mar
(147) |
Apr
(86) |
May
(74) |
Jun
(118) |
Jul
(65) |
Aug
(75) |
Sep
(162) |
Oct
(94) |
Nov
(48) |
Dec
(44) |
2012 |
Jan
(49) |
Feb
(40) |
Mar
(88) |
Apr
(35) |
May
(52) |
Jun
(69) |
Jul
(90) |
Aug
(123) |
Sep
(112) |
Oct
(120) |
Nov
(105) |
Dec
(116) |
2013 |
Jan
(76) |
Feb
(26) |
Mar
(78) |
Apr
(43) |
May
(61) |
Jun
(53) |
Jul
(147) |
Aug
(85) |
Sep
(83) |
Oct
(122) |
Nov
(18) |
Dec
(27) |
2014 |
Jan
(58) |
Feb
(25) |
Mar
(49) |
Apr
(17) |
May
(29) |
Jun
(39) |
Jul
(53) |
Aug
(52) |
Sep
(35) |
Oct
(47) |
Nov
(110) |
Dec
(27) |
2015 |
Jan
(50) |
Feb
(93) |
Mar
(96) |
Apr
(30) |
May
(55) |
Jun
(83) |
Jul
(44) |
Aug
(8) |
Sep
(5) |
Oct
|
Nov
(1) |
Dec
(1) |
2016 |
Jan
|
Feb
|
Mar
(1) |
Apr
|
May
|
Jun
(2) |
Jul
|
Aug
(3) |
Sep
(1) |
Oct
(3) |
Nov
|
Dec
|
2017 |
Jan
|
Feb
(5) |
Mar
|
Apr
|
May
|
Jun
|
Jul
(3) |
Aug
|
Sep
(7) |
Oct
|
Nov
|
Dec
|
2018 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(2) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
|
1
(3) |
2
(4) |
3
(5) |
4
(3) |
5
|
6
|
7
(2) |
8
(4) |
9
(6) |
10
|
11
(7) |
12
(8) |
13
(2) |
14
(2) |
15
(5) |
16
(14) |
17
(13) |
18
(8) |
19
|
20
|
21
|
22
(2) |
23
(7) |
24
(7) |
25
(8) |
26
(7) |
27
(2) |
28
(1) |
29
|
30
|
|
|
|
|
From: John H. <jd...@gm...> - 2008-09-17 12:03:32
|
On Wed, Sep 17, 2008 at 1:44 PM, Ryan May <rm...@gm...> wrote: > Hi, > > Is anyone else seeing some odd messages when trying to use SVN right > now? Here's what I see: > I just did an svn up w/o incident JDH |
From: John H. <jd...@gm...> - 2008-09-17 12:01:16
|
On Wed, Sep 17, 2008 at 1:30 PM, Jae-Joon Lee <lee...@gm...> wrote: > Hi, > > I uploaded my patch. > > https://sourceforge.net/tracker/index.php?func=detail&aid=2116614&group_id=80706&atid=560722 Hi Jae Joon -- thanks for uploading this. I have read through it once and it looks pretty good -- thanks for doing the extra work to properly document the kwargs using the auto-property infrastructure. One request: could you submit the entire patch including the examples as a single 'svn diff'? Then I can more easily apply it and test it. Thanks, JDH |
From: Ryan M. <rm...@gm...> - 2008-09-17 11:44:38
|
Hi, Is anyone else seeing some odd messages when trying to use SVN right now? Here's what I see: >svn up Error validating server certificate for 'https://matplotlib.svn.sourceforge.net:443': - The certificate is not issued by a trusted authority. Use the fingerprint to validate the certificate manually! Certificate information: - Hostname: *.svn.sourceforge.net - Valid: from Tue, 09 Oct 2007 14:15:07 GMT until Mon, 08 Dec 2008 15:15:07 GMT - Issuer: Equifax Secure Certificate Authority, Equifax, US - Fingerprint: fb:75:6c:40:58:ae:21:8c:63:dd:1b:7b:6a:7d:bb:8c:74:36:e7:8a (R)eject, accept (t)emporarily or accept (p)ermanently? ^Csvn: OPTIONS of 'https://matplotlib.svn.sourceforge.net/svnroot/matplotlib/trunk/matplotlib': Server certificate verification failed: issuer is not trusted (https://matplotlib.svn.sourceforge.net) Thoughts? Ryan -- Ryan May Graduate Research Assistant School of Meteorology University of Oklahoma |
From: Jae-Joon L. <lee...@gm...> - 2008-09-17 11:31:00
|
Hi, I uploaded my patch. https://sourceforge.net/tracker/index.php?func=detail&aid=2116614&group_id=80706&atid=560722 I added a FancyBboxPatch class in the patches.py. And changed text.Text class to support it. Two examples are attached with this email. I hope I have put enough documentation, but if anything is not clear, just let me know. Also see if the current interfaces are acceptable. I only have placed two kind of boxstyles. I'll add more eventually. Regards, -JJ On Fri, Sep 12, 2008 at 5:21 PM, John Hunter <jd...@gm...> wrote: > On Fri, Sep 12, 2008 at 2:46 PM, Jae-Joon Lee <lee...@gm...> wrote: >> Thanks John, >> >> I think I'd better use a sf patch initially so that you or others can >> review and improve it. I'll definitely need some help with >> documentation as my English can be horrible sometime. On the other >> hand, it would be much easier for me to do some maintenance work if I >> can commit the changes directly. So, my sf id is "leejjoon" and it >> will be great if you add me as a developer. > > OK, I added you as a developer, but you continue posting your patches > here and we will be happy to review and comment on them as we have > time. > > >> I guess this fancy box thing can be used with other artist objects >> also, although the legend object is an only object I can think of now. >> And my personal inclination is put those support code into patches.py >> and have a patch class around it, i.e., a FancyBoxPatch class which is >> initialized with bbox-like object and draw a fancy box around the >> given bbox. And let the Text and the Legend class use this >> FancyBoxPatch. In the current matplotlib, both the Text and the Legend >> class uses the Patch class for drawing a bbox. So how do you think? > > Yes, if you can generalize it to a Patch instance this will be more > useful and then matplotlib.patches will be the place for it. > I notice that your current TextBoxArtist does not actually derive from > matplotlib.artist.Artist. If you intend it to be an Artist, you > should explictly inherit and implement draw and other required methods > (eg get_children if your Artist contains other artists) > >> What I also want to see in matplotlib is a fancy annotation. I have >> some working code (although I'm planning some major code >> reorganization) and willing to contribute it if there is an interest >> (see the attached example). As you can easily guess, the fancy >> annotation share some of its core with the fancy box. So if you're >> also willing to include the fancy annotation things in matplotlib, >> I'll put some more effort in the code reorganization so that it can >> nicely fit in the current matplotlib classes. > > These examples look very nice too! Send in a patch when you have > everything organized. > > JDH > |
From: Gregor T. <gre...@gm...> - 2008-09-17 01:08:05
|
John Hunter schrieb: >> Second, I am using interactive mode and WXAgg in windows. So my startup >> script does this: >> import matplotlib as _mpl >> _mpl.use('WXAgg') >> import pylab as _p >> _p.ion() >> Before, when I would then type >> gca().plot([1,2,1]) >> > > I would not expect a draw here, since draw only happens on pylab > commands. Eg _p.plot should trigger a draw, but not gca().plot > because the latter is an axes method. I don't really know why it > would have worked before, if it did. I would be pretty surprised if > it did, actually. > Older versions of the wx and wxagg backend indeed unnecessarily rerendered the figure (triggered a draw) very often - with every paint event. This has been fixed. Gregor |
From: Gael V. <gae...@no...> - 2008-09-16 23:56:14
|
Hi, Nice and ambitious project :). I am happy to hear Michael mentioning traits as a way forward on this task. I have the feeling that the approach that was taken by Mayavi2 to put an UI on top of VTK could be of good inspiration for such a project. Althought Mayavi is not the perfect UI (some of its dialog are not great), I think it has been fairly successful at taking a huge library like VTK (900 classes) and exposing its functionality in an application, with dialogs to edit the objects. For this purpose, traits where paramount. The ability not only to create dialogs automatically, but also to handle the notifications created by modifying the objects was invaluable. And very recently, trapping these notifications has allowed us to create automatic script generation from UI operations. Traits also gives in the long run a possibility to have multiple backends behind these dialogs, althought this is clearly more work, as only Wx and Qt4 are currently implemented. For matplotlib, one way forward would be to have one or more traited-aware backend, that would be using mixin objects, inheriting both from the core of MatPlotlib, and from HasTraits. The difficulty would probably be generating the callbacks. Traits wouldn't solve all the problems with GUI creation (unless it was used everywhere, and everything was done in the traits way), but I think it would make this ambitious task easier. Good luck, I am looking forward to exciting development on this side! Gaël On Tue, Sep 16, 2008 at 01:47:04AM +0200, Heinrich Acker wrote: > Hello everybody, > after happily using matplotlib for a while and writing a larger application for it with wxPython as the GUI toolkit, I recently tried to add a function to matplotlib itself. It is the possibility to interactively edit a plot, such that attributes of objects in a figure can be changed from the plot itself, in contrast to using a shell such as IPython. > This is of course inspired by Matlab and other tools. There are two ways to do this: > 1. Provide graphical picking of objects, and dialogs and/or context menus to change attributes of the selected object(s). Advantages: most intuitive, perhaps also fastest to operate. Disadvantages: picking itself sometimes does not work well, and you can't click on what you don't see or know of. > 2. Provide an 'object browser', i.e. a dialog that shows the tree of objects, where the user can select object(s), then inspect all attributes in another part of the dialog, and change them replacing content there. Advantages: delivers insight into the object structure, everything is easily found and selected. Disadvantages: often requires much more clicks, especially for simple changes. > Since the feature was always essential for me in Matlab, I naturally would like to have both solutions available concurrently, but when I tried to implement it, I decided for (2) because I wanted to know more about the object structure at first. > What I have right now is the 'object browser' in the WX backend, but without the actual editing feature, it is only possible to look at the objects and attributes. At this point I saw that I don't know matplotlib well enough to complete the editing myself. I'm overwhelmed by the variety of objects, attributes, methods, and distribution of items over the object tree. > I'm posting this because I would like to > * know if anybody is interested in this feature, too (couldn't find anything through searching the list). > * work together with you to make this something useful. > * get information about an appropriate way to integrate this into matplotlib (where to place the functions, etc.). > * finally see it integrated into a release, if possible. > Attached are a modified backend_wx.py of 0.98.3, and an icon for the toolbar2, to be included into ...\mpl-data\images. With these files, the icon appears on the toolbar2, and when clicked on, a dialog pops up. It shows the object tree on the left hand side, where items can be expanded, collapsed, and selected. For the selected object, the result of str(object.__dict__) is displayed on the right hand side. That's all ... only a start. > What's your opinion? > Regards, > Heinrich Acker > from __future__ import division > """ > backend_wx.py > A wxPython backend for matplotlib, based (very heavily) on > backend_template.py and backend_gtk.py > Author: Jeremy O'Donoghue (je...@o-...) > Derived from original copyright work by John Hunter > (jdh...@ac...) > Copyright (C) Jeremy O'Donoghue & John Hunter, 2003-4 > License: This work is licensed under a PSF compatible license. A copy > should be included with this source code. > """ > """ > KNOWN BUGS - > - Mousewheel (on Windows) only works after menu button has been pressed > at least once > - Mousewheel on Linux (wxGTK linked against GTK 1.2) does not work at all > - Vertical text renders horizontally if you use a non TrueType font > on Windows. This is a known wxPython issue. Work-around is to ensure > that you use a TrueType font. > - Pcolor demo puts chart slightly outside bounding box (approx 1-2 pixels > to the bottom left) > - Outputting to bitmap more than 300dpi results in some text being incorrectly > scaled. Seems to be a wxPython bug on Windows or font point sizes > 60, as > font size is correctly calculated. > - Performance poorer than for previous direct rendering version > - TIFF output not supported on wxGTK. This is a wxGTK issue > - Text is not anti-aliased on wxGTK. This is probably a platform > configuration issue. > - If a second call is made to show(), no figure is generated (#866965) > Not implemented: > - Printing > Fixed this release: > - Bug #866967: Interactive operation issues fixed [JDH] > - Bug #866969: Dynamic update does not function with backend_wx [JOD] > Examples which work on this release: > --------------------------------------------------------------- > | Windows 2000 | Linux | > | wxPython 2.3.3 | wxPython 2.4.2.4 | > --------------------------------------------------------------| > - alignment_test.py | TBE | OK | > - arctest.py | TBE | (3) | > - axes_demo.py | OK | OK | > - axes_props.py | OK | OK | > - bar_stacked.py | TBE | OK | > - barchart_demo.py | OK | OK | > - color_demo.py | OK | OK | > - csd_demo.py | OK | OK | > - dynamic_demo.py | N/A | N/A | > - dynamic_demo_wx.py | TBE | OK | > - embedding_in_gtk.py | N/A | N/A | > - embedding_in_wx.py | OK | OK | > - errorbar_demo.py | OK | OK | > - figtext.py | OK | OK | > - histogram_demo.py | OK | OK | > - interactive.py | N/A (2) | N/A (2) | > - interactive2.py | N/A (2) | N/A (2) | > - legend_demo.py | OK | OK | > - legend_demo2.py | OK | OK | > - line_styles.py | OK | OK | > - log_demo.py | OK | OK | > - logo.py | OK | OK | > - mpl_with_glade.py | N/A (2) | N/A (2) | > - mri_demo.py | OK | OK | > - mri_demo_with_eeg.py | OK | OK | > - multiple_figs_demo.py | OK | OK | > - pcolor_demo.py | OK | OK | > - psd_demo.py | OK | OK | > - scatter_demo.py | OK | OK | > - scatter_demo2.py | OK | OK | > - simple_plot.py | OK | OK | > - stock_demo.py | OK | OK | > - subplot_demo.py | OK | OK | > - system_monitor.py | N/A (2) | N/A (2) | > - text_handles.py | OK | OK | > - text_themes.py | OK | OK | > - vline_demo.py | OK | OK | > --------------------------------------------------------------- > (2) - Script uses GTK-specific features - cannot not run, > but wxPython equivalent should be written. > (3) - Clipping seems to be broken. > """ > cvs_id = '$Id: backend_wx.py 5935 2008-07-31 14:10:18Z mdboom $' > import sys, os, os.path, math, StringIO, weakref, warnings > # Debugging settings here... > # Debug level set here. If the debug level is less than 5, information > # messages (progressively more info for lower value) are printed. In addition, > # traceback is performed, and pdb activated, for all uncaught exceptions in > # this case > _DEBUG = 5 > if _DEBUG < 5: > import traceback, pdb > _DEBUG_lvls = {1 : 'Low ', 2 : 'Med ', 3 : 'High', 4 : 'Error' } > try: > import wx > backend_version = wx.VERSION_STRING > except: > print >>sys.stderr, "Matplotlib backend_wx requires wxPython be installed" > sys.exit() > #!!! this is the call that is causing the exception swallowing !!! > #wx.InitAllImageHandlers() > def DEBUG_MSG(string, lvl=3, o=None): > if lvl >= _DEBUG: > cls = o.__class__ > # Jeremy, often times the commented line won't print but the > # one below does. I think WX is redefining stderr, damned > # beast > #print >>sys.stderr, "%s- %s in %s" % (_DEBUG_lvls[lvl], string, cls) > print "%s- %s in %s" % (_DEBUG_lvls[lvl], string, cls) > def debug_on_error(type, value, tb): > """Code due to Thomas Heller - published in Python Cookbook (O'Reilley)""" > traceback.print_exc(type, value, tb) > print > pdb.pm() # jdh uncomment > class fake_stderr: > """Wx does strange things with stderr, as it makes the assumption that there > is probably no console. This redirects stderr to the console, since we know > that there is one!""" > def write(self, msg): > print "Stderr: %s\n\r" % msg > #if _DEBUG < 5: > # sys.excepthook = debug_on_error > # WxLogger =wx.LogStderr() > # sys.stderr = fake_stderr > # Event binding code changed after version 2.5 > if wx.VERSION_STRING >= '2.5': > def bind(actor,event,action,**kw): > actor.Bind(event,action,**kw) > else: > def bind(actor,event,action,id=None): > if id is not None: > event(actor, id, action) > else: > event(actor,action) > import matplotlib > from matplotlib import verbose > from matplotlib.backend_bases import RendererBase, GraphicsContextBase,\ > FigureCanvasBase, FigureManagerBase, NavigationToolbar2, \ > cursors > from matplotlib._pylab_helpers import Gcf > from matplotlib.artist import Artist > from matplotlib.cbook import exception_to_str, is_string_like, is_writable_file_like > from matplotlib.figure import Figure > from matplotlib.path import Path > from matplotlib.text import _process_text_args, Text > from matplotlib.transforms import Affine2D > from matplotlib.widgets import SubplotTool > from matplotlib import rcParams > # the True dots per inch on the screen; should be display dependent > # see http://groups.google.com/groups?q=screen+dpi+x11&hl=en&lr=&ie=UTF-8&oe=UTF-8&safe=off&selm=7077.26e81ad5%40swift.cs.tcd.ie&rnum=5 for some info about screen dpi > PIXELS_PER_INCH = 75 > def error_msg_wx(msg, parent=None): > """ > Signal an error condition -- in a GUI, popup a error dialog > """ > dialog =wx.MessageDialog(parent = parent, > message = msg, > caption = 'Matplotlib backend_wx error', > style=wx.OK | wx.CENTRE) > dialog.ShowModal() > dialog.Destroy() > return None > def raise_msg_to_str(msg): > """msg is a return arg from a raise. Join with new lines""" > if not is_string_like(msg): > msg = '\n'.join(map(str, msg)) > return msg > class RendererWx(RendererBase): > """ > The renderer handles all the drawing primitives using a graphics > context instance that controls the colors/styles. It acts as the > 'renderer' instance used by many classes in the hierarchy. > """ > #In wxPython, drawing is performed on a wxDC instance, which will > #generally be mapped to the client aread of the window displaying > #the plot. Under wxPython, the wxDC instance has a wx.Pen which > #describes the colour and weight of any lines drawn, and a wxBrush > #which describes the fill colour of any closed polygon. > fontweights = { > 100 : wx.LIGHT, > 200 : wx.LIGHT, > 300 : wx.LIGHT, > 400 : wx.NORMAL, > 500 : wx.NORMAL, > 600 : wx.NORMAL, > 700 : wx.BOLD, > 800 : wx.BOLD, > 900 : wx.BOLD, > 'ultralight' : wx.LIGHT, > 'light' : wx.LIGHT, > 'normal' : wx.NORMAL, > 'medium' : wx.NORMAL, > 'semibold' : wx.NORMAL, > 'bold' : wx.BOLD, > 'heavy' : wx.BOLD, > 'ultrabold' : wx.BOLD, > 'black' : wx.BOLD > } > fontangles = { > 'italic' : wx.ITALIC, > 'normal' : wx.NORMAL, > 'oblique' : wx.SLANT } > # wxPython allows for portable font styles, choosing them appropriately > # for the target platform. Map some standard font names to the portable > # styles > # QUESTION: Is it be wise to agree standard fontnames across all backends? > fontnames = { 'Sans' : wx.SWISS, > 'Roman' : wx.ROMAN, > 'Script' : wx.SCRIPT, > 'Decorative' : wx.DECORATIVE, > 'Modern' : wx.MODERN, > 'Courier' : wx.MODERN, > 'courier' : wx.MODERN } > def __init__(self, bitmap, dpi): > """ > Initialise a wxWindows renderer instance. > """ > DEBUG_MSG("__init__()", 1, self) > if wx.VERSION_STRING < "2.8": > raise RuntimeError("matplotlib no longer supports wxPython < 2.8 for the Wx backend.\nYou may, however, use the WxAgg backend.") > self.width = bitmap.GetWidth() > self.height = bitmap.GetHeight() > self.bitmap = bitmap > self.fontd = {} > self.dpi = dpi > self.gc = None > def flipy(self): > return True > def offset_text_height(self): > return True > def get_text_width_height_descent(self, s, prop, ismath): > """ > get the width and height in display coords of the string s > with FontPropertry prop > """ > #return 1, 1 > if ismath: s = self.strip_math(s) > if self.gc is None: > gc = self.new_gc() > else: > gc = self.gc > gfx_ctx = gc.gfx_ctx > font = self.get_wx_font(s, prop) > gfx_ctx.SetFont(font, wx.BLACK) > w, h, descent, leading = gfx_ctx.GetFullTextExtent(s) > return w, h, descent > def get_canvas_width_height(self): > 'return the canvas width and height in display coords' > return self.width, self.height > def handle_clip_rectangle(self, gc): > new_bounds = gc.get_clip_rectangle() > if new_bounds is not None: > new_bounds = new_bounds.bounds > gfx_ctx = gc.gfx_ctx > if gfx_ctx._lastcliprect != new_bounds: > gfx_ctx._lastcliprect = new_bounds > if new_bounds is None: > gfx_ctx.ResetClip() > else: > gfx_ctx.Clip(new_bounds[0], self.height - new_bounds[1] - new_bounds[3], > new_bounds[2], new_bounds[3]) > #@staticmethod > def convert_path(gfx_ctx, tpath): > wxpath = gfx_ctx.CreatePath() > for points, code in tpath.iter_segments(): > if code == Path.MOVETO: > wxpath.MoveToPoint(*points) > elif code == Path.LINETO: > wxpath.AddLineToPoint(*points) > elif code == Path.CURVE3: > wxpath.AddQuadCurveToPoint(*points) > elif code == Path.CURVE4: > wxpath.AddCurveToPoint(*points) > elif code == Path.CLOSEPOLY: > wxpath.CloseSubpath() > return wxpath > convert_path = staticmethod(convert_path) > def draw_path(self, gc, path, transform, rgbFace=None): > gc.select() > self.handle_clip_rectangle(gc) > gfx_ctx = gc.gfx_ctx > transform = transform + Affine2D().scale(1.0, -1.0).translate(0.0, self.height) > tpath = transform.transform_path(path) > wxpath = self.convert_path(gfx_ctx, tpath) > if rgbFace is not None: > gfx_ctx.SetBrush(wx.Brush(gc.get_wxcolour(rgbFace))) > gfx_ctx.DrawPath(wxpath) > else: > gfx_ctx.StrokePath(wxpath) > gc.unselect() > def draw_text(self, gc, x, y, s, prop, angle, ismath): > """ > Render the matplotlib.text.Text instance > None) > """ > if ismath: s = self.strip_math(s) > DEBUG_MSG("draw_text()", 1, self) > gc.select() > self.handle_clip_rectangle(gc) > gfx_ctx = gc.gfx_ctx > font = self.get_wx_font(s, prop) > color = gc.get_wxcolour(gc.get_rgb()) > gfx_ctx.SetFont(font, color) > w, h, d = self.get_text_width_height_descent(s, prop, ismath) > x = int(x) > y = int(y-h) > if angle == 0.0: > gfx_ctx.DrawText(s, x, y) > else: > rads = angle / 180.0 * math.pi > xo = h * math.sin(rads) > yo = h * math.cos(rads) > gfx_ctx.DrawRotatedText(s, x - xo, y - yo, rads) > gc.unselect() > def new_gc(self): > """ > Return an instance of a GraphicsContextWx, and sets the current gc copy > """ > DEBUG_MSG('new_gc()', 2, self) > self.gc = GraphicsContextWx(self.bitmap, self) > self.gc.select() > self.gc.unselect() > return self.gc > def get_gc(self): > """ > Fetch the locally cached gc. > """ > # This is a dirty hack to allow anything with access to a renderer to > # access the current graphics context > assert self.gc != None, "gc must be defined" > return self.gc > def get_wx_font(self, s, prop): > """ > Return a wx font. Cache instances in a font dictionary for > efficiency > """ > DEBUG_MSG("get_wx_font()", 1, self) > key = hash(prop) > fontprop = prop > fontname = fontprop.get_name() > font = self.fontd.get(key) > if font is not None: > return font > # Allow use of platform independent and dependent font names > wxFontname = self.fontnames.get(fontname, wx.ROMAN) > wxFacename = '' # Empty => wxPython chooses based on wx_fontname > # Font colour is determined by the active wx.Pen > # TODO: It may be wise to cache font information > size = self.points_to_pixels(fontprop.get_size_in_points()) > font =wx.Font(int(size+0.5), # Size > wxFontname, # 'Generic' name > self.fontangles[fontprop.get_style()], # Angle > self.fontweights[fontprop.get_weight()], # Weight > False, # Underline > wxFacename) # Platform font name > # cache the font and gc and return it > self.fontd[key] = font > return font > def points_to_pixels(self, points): > """ > convert point measures to pixes using dpi and the pixels per > inch of the display > """ > return points*(PIXELS_PER_INCH/72.0*self.dpi/72.0) > class GraphicsContextWx(GraphicsContextBase): > """ > The graphics context provides the color, line styles, etc... > This class stores a reference to a wxMemoryDC, and a > wxGraphicsContext that draws to it. Creating a wxGraphicsContext > seems to be fairly heavy, so these objects are cached based on the > bitmap object that is passed in. > The base GraphicsContext stores colors as a RGB tuple on the unit > interval, eg, (0.5, 0.0, 1.0). wxPython uses an int interval, but > since wxPython colour management is rather simple, I have not chosen > to implement a separate colour manager class. > """ > _capd = { 'butt': wx.CAP_BUTT, > 'projecting': wx.CAP_PROJECTING, > 'round': wx.CAP_ROUND } > _joind = { 'bevel': wx.JOIN_BEVEL, > 'miter': wx.JOIN_MITER, > 'round': wx.JOIN_ROUND } > _dashd_wx = { 'solid': wx.SOLID, > 'dashed': wx.SHORT_DASH, > 'dashdot': wx.DOT_DASH, > 'dotted': wx.DOT } > _cache = weakref.WeakKeyDictionary() > def __init__(self, bitmap, renderer): > GraphicsContextBase.__init__(self) > #assert self.Ok(), "wxMemoryDC not OK to use" > DEBUG_MSG("__init__()", 1, self) > dc, gfx_ctx = self._cache.get(bitmap, (None, None)) > if dc is None: > dc = wx.MemoryDC() > dc.SelectObject(bitmap) > gfx_ctx = wx.GraphicsContext.Create(dc) > gfx_ctx._lastcliprect = None > self._cache[bitmap] = dc, gfx_ctx > self.bitmap = bitmap > self.dc = dc > self.gfx_ctx = gfx_ctx > self._pen = wx.Pen('BLACK', 1, wx.SOLID) > gfx_ctx.SetPen(self._pen) > self._style = wx.SOLID > self.renderer = renderer > def select(self): > """ > Select the current bitmap into this wxDC instance > """ > if sys.platform=='win32': > self.SelectObject(self.bitmap) > self.IsSelected = True > def unselect(self): > """ > Select a Null bitmasp into this wxDC instance > """ > if sys.platform=='win32': > self.SelectObject(wx.NullBitmap) > self.IsSelected = False > def set_foreground(self, fg, isRGB=None): > """ > Set the foreground color. fg can be a matlab format string, a > html hex color string, an rgb unit tuple, or a float between 0 > and 1. In the latter case, grayscale is used. > """ > # Implementation note: wxPython has a separate concept of pen and > # brush - the brush fills any outline trace left by the pen. > # Here we set both to the same colour - if a figure is not to be > # filled, the renderer will set the brush to be transparent > # Same goes for text foreground... > DEBUG_MSG("set_foreground()", 1, self) > self.select() > GraphicsContextBase.set_foreground(self, fg, isRGB) > self._pen.SetColour(self.get_wxcolour(self.get_rgb())) > self.gfx_ctx.SetPen(self._pen) > self.unselect() > def set_graylevel(self, frac): > """ > Set the foreground color. fg can be a matlab format string, a > html hex color string, an rgb unit tuple, or a float between 0 > and 1. In the latter case, grayscale is used. > """ > DEBUG_MSG("set_graylevel()", 1, self) > self.select() > GraphicsContextBase.set_graylevel(self, frac) > self._pen.SetColour(self.get_wxcolour(self.get_rgb())) > self.gfx_ctx.SetPen(self._pen) > self.unselect() > def set_linewidth(self, w): > """ > Set the line width. > """ > DEBUG_MSG("set_linewidth()", 1, self) > self.select() > if w>0 and w<1: w = 1 > GraphicsContextBase.set_linewidth(self, w) > lw = int(self.renderer.points_to_pixels(self._linewidth)) > if lw==0: lw = 1 > self._pen.SetWidth(lw) > self.gfx_ctx.SetPen(self._pen) > self.unselect() > def set_capstyle(self, cs): > """ > Set the capstyle as a string in ('butt', 'round', 'projecting') > """ > DEBUG_MSG("set_capstyle()", 1, self) > self.select() > GraphicsContextBase.set_capstyle(self, cs) > self._pen.SetCap(GraphicsContextWx._capd[self._capstyle]) > self.gfx_ctx.SetPen(self._pen) > self.unselect() > def set_joinstyle(self, js): > """ > Set the join style to be one of ('miter', 'round', 'bevel') > """ > DEBUG_MSG("set_joinstyle()", 1, self) > self.select() > GraphicsContextBase.set_joinstyle(self, js) > self._pen.SetJoin(GraphicsContextWx._joind[self._joinstyle]) > self.gfx_ctx.SetPen(self._pen) > self.unselect() > def set_linestyle(self, ls): > """ > Set the line style to be one of > """ > DEBUG_MSG("set_linestyle()", 1, self) > self.select() > GraphicsContextBase.set_linestyle(self, ls) > try: > self._style = GraphicsContextWx._dashd_wx[ls] > except KeyError: > self._style = wx.LONG_DASH# Style not used elsewhere... > # On MS Windows platform, only line width of 1 allowed for dash lines > if wx.Platform == '__WXMSW__': > self.set_linewidth(1) > self._pen.SetStyle(self._style) > self.gfx_ctx.SetPen(self._pen) > self.unselect() > def get_wxcolour(self, color): > """return a wx.Colour from RGB format""" > DEBUG_MSG("get_wx_color()", 1, self) > if len(color) == 3: > r, g, b = color > r *= 255 > g *= 255 > b *= 255 > return wx.Colour(red=int(r), green=int(g), blue=int(b)) > else: > r, g, b, a = color > r *= 255 > g *= 255 > b *= 255 > a *= 255 > return wx.Colour(red=int(r), green=int(g), blue=int(b), alpha=int(a)) > class FigureCanvasWx(FigureCanvasBase, wx.Panel): > """ > The FigureCanvas contains the figure and does event handling. > In the wxPython backend, it is derived from wxPanel, and (usually) lives > inside a frame instantiated by a FigureManagerWx. The parent window probably > implements a wx.Sizer to control the displayed control size - but we give a > hint as to our preferred minimum size. > """ > keyvald = { > wx.WXK_CONTROL : 'control', > wx.WXK_SHIFT : 'shift', > wx.WXK_ALT : 'alt', > wx.WXK_LEFT : 'left', > wx.WXK_UP : 'up', > wx.WXK_RIGHT : 'right', > wx.WXK_DOWN : 'down', > wx.WXK_ESCAPE : 'escape', > wx.WXK_F1 : 'f1', > wx.WXK_F2 : 'f2', > wx.WXK_F3 : 'f3', > wx.WXK_F4 : 'f4', > wx.WXK_F5 : 'f5', > wx.WXK_F6 : 'f6', > wx.WXK_F7 : 'f7', > wx.WXK_F8 : 'f8', > wx.WXK_F9 : 'f9', > wx.WXK_F10 : 'f10', > wx.WXK_F11 : 'f11', > wx.WXK_F12 : 'f12', > wx.WXK_SCROLL : 'scroll_lock', > wx.WXK_PAUSE : 'break', > wx.WXK_BACK : 'backspace', > wx.WXK_RETURN : 'enter', > wx.WXK_INSERT : 'insert', > wx.WXK_DELETE : 'delete', > wx.WXK_HOME : 'home', > wx.WXK_END : 'end', > wx.WXK_PRIOR : 'pageup', > wx.WXK_NEXT : 'pagedown', > wx.WXK_PAGEUP : 'pageup', > wx.WXK_PAGEDOWN : 'pagedown', > wx.WXK_NUMPAD0 : '0', > wx.WXK_NUMPAD1 : '1', > wx.WXK_NUMPAD2 : '2', > wx.WXK_NUMPAD3 : '3', > wx.WXK_NUMPAD4 : '4', > wx.WXK_NUMPAD5 : '5', > wx.WXK_NUMPAD6 : '6', > wx.WXK_NUMPAD7 : '7', > wx.WXK_NUMPAD8 : '8', > wx.WXK_NUMPAD9 : '9', > wx.WXK_NUMPAD_ADD : '+', > wx.WXK_NUMPAD_SUBTRACT : '-', > wx.WXK_NUMPAD_MULTIPLY : '*', > wx.WXK_NUMPAD_DIVIDE : '/', > wx.WXK_NUMPAD_DECIMAL : 'dec', > wx.WXK_NUMPAD_ENTER : 'enter', > wx.WXK_NUMPAD_UP : 'up', > wx.WXK_NUMPAD_RIGHT : 'right', > wx.WXK_NUMPAD_DOWN : 'down', > wx.WXK_NUMPAD_LEFT : 'left', > wx.WXK_NUMPAD_PRIOR : 'pageup', > wx.WXK_NUMPAD_NEXT : 'pagedown', > wx.WXK_NUMPAD_PAGEUP : 'pageup', > wx.WXK_NUMPAD_PAGEDOWN : 'pagedown', > wx.WXK_NUMPAD_HOME : 'home', > wx.WXK_NUMPAD_END : 'end', > wx.WXK_NUMPAD_INSERT : 'insert', > wx.WXK_NUMPAD_DELETE : 'delete', > } > def __init__(self, parent, id, figure): > """ > Initialise a FigureWx instance. > - Initialise the FigureCanvasBase and wxPanel parents. > - Set event handlers for: > EVT_SIZE (Resize event) > EVT_PAINT (Paint event) > """ > FigureCanvasBase.__init__(self, figure) > # Set preferred window size hint - helps the sizer (if one is > # connected) > l,b,w,h = figure.bbox.bounds > w = int(math.ceil(w)) > h = int(math.ceil(h)) > wx.Panel.__init__(self, parent, id, size=wx.Size(w, h)) > def do_nothing(*args, **kwargs): > warnings.warn('could not find a setinitialsize function for backend_wx; please report your wxpython version=%s to the matplotlib developers list'%backend_version) > pass > # try to find the set size func across wx versions > try: > getattr(self, 'SetInitialSize') > except AttributeError: > self.SetInitialSize = getattr(self, 'SetBestFittingSize', do_nothing) > if not hasattr(self,'IsShownOnScreen'): > self.IsShownOnScreen = getattr(self, 'IsVisible', lambda *args: True) > # Create the drawing bitmap > self.bitmap =wx.EmptyBitmap(w, h) > DEBUG_MSG("__init__() - bitmap w:%d h:%d" % (w,h), 2, self) > # TODO: Add support for 'point' inspection and plot navigation. > self._isDrawn = False > bind(self, wx.EVT_SIZE, self._onSize) > bind(self, wx.EVT_PAINT, self._onPaint) > bind(self, wx.EVT_ERASE_BACKGROUND, self._onEraseBackground) > bind(self, wx.EVT_KEY_DOWN, self._onKeyDown) > bind(self, wx.EVT_KEY_UP, self._onKeyUp) > bind(self, wx.EVT_RIGHT_DOWN, self._onRightButtonDown) > bind(self, wx.EVT_RIGHT_DCLICK, self._onRightButtonDown) > bind(self, wx.EVT_RIGHT_UP, self._onRightButtonUp) > bind(self, wx.EVT_MOUSEWHEEL, self._onMouseWheel) > bind(self, wx.EVT_LEFT_DOWN, self._onLeftButtonDown) > bind(self, wx.EVT_LEFT_DCLICK, self._onLeftButtonDown) > bind(self, wx.EVT_LEFT_UP, self._onLeftButtonUp) > bind(self, wx.EVT_MOTION, self._onMotion) > bind(self, wx.EVT_LEAVE_WINDOW, self._onLeave) > bind(self, wx.EVT_IDLE, self._onIdle) > self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) > self.macros = {} # dict from wx id to seq of macros > self.Printer_Init() > def Destroy(self, *args, **kwargs): > wx.Panel.Destroy(self, *args, **kwargs) > def Copy_to_Clipboard(self, event=None): > "copy bitmap of canvas to system clipboard" > bmp_obj = wx.BitmapDataObject() > bmp_obj.SetBitmap(self.bitmap) > wx.TheClipboard.Open() > wx.TheClipboard.SetData(bmp_obj) > wx.TheClipboard.Close() > def Printer_Init(self): > """initialize printer settings using wx methods""" > self.printerData = wx.PrintData() > self.printerData.SetPaperId(wx.PAPER_LETTER) > self.printerData.SetPrintMode(wx.PRINT_MODE_PRINTER) > self.printerPageData= wx.PageSetupDialogData() > self.printerPageData.SetMarginBottomRight((25,25)) > self.printerPageData.SetMarginTopLeft((25,25)) > self.printerPageData.SetPrintData(self.printerData) > self.printer_width = 5.5 > self.printer_margin= 0.5 > def Printer_Setup(self, event=None): > """set up figure for printing. The standard wx Printer > Setup Dialog seems to die easily. Therefore, this setup > simply asks for image width and margin for printing. """ > dmsg = """Width of output figure in inches. > The current aspect ration will be kept.""" > dlg = wx.Dialog(self, -1, 'Page Setup for Printing' , (-1,-1)) > df = dlg.GetFont() > df.SetWeight(wx.NORMAL) > df.SetPointSize(11) > dlg.SetFont(df) > x_wid = wx.TextCtrl(dlg,-1,value="%.2f" % self.printer_width, size=(70,-1)) > x_mrg = wx.TextCtrl(dlg,-1,value="%.2f" % self.printer_margin,size=(70,-1)) > sizerAll = wx.BoxSizer(wx.VERTICAL) > sizerAll.Add(wx.StaticText(dlg,-1,dmsg), > 0, wx.ALL | wx.EXPAND, 5) > sizer = wx.FlexGridSizer(0,3) > sizerAll.Add(sizer, 0, wx.ALL | wx.EXPAND, 5) > sizer.Add(wx.StaticText(dlg,-1,'Figure Width'), > 1, wx.ALIGN_LEFT|wx.ALL, 2) > sizer.Add(x_wid, > 1, wx.ALIGN_LEFT|wx.ALL, 2) > sizer.Add(wx.StaticText(dlg,-1,'in'), > 1, wx.ALIGN_LEFT|wx.ALL, 2) > sizer.Add(wx.StaticText(dlg,-1,'Margin'), > 1, wx.ALIGN_LEFT|wx.ALL, 2) > sizer.Add(x_mrg, > 1, wx.ALIGN_LEFT|wx.ALL, 2) > sizer.Add(wx.StaticText(dlg,-1,'in'), > 1, wx.ALIGN_LEFT|wx.ALL, 2) > btn = wx.Button(dlg,wx.ID_OK, " OK ") > btn.SetDefault() > sizer.Add(btn, 1, wx.ALIGN_LEFT, 5) > btn = wx.Button(dlg,wx.ID_CANCEL, " CANCEL ") > sizer.Add(btn, 1, wx.ALIGN_LEFT, 5) > dlg.SetSizer(sizerAll) > dlg.SetAutoLayout(True) > sizerAll.Fit(dlg) > if dlg.ShowModal() == wx.ID_OK: > try: > self.printer_width = float(x_wid.GetValue()) > self.printer_margin = float(x_mrg.GetValue()) > except: > pass > if ((self.printer_width + self.printer_margin) > 7.5): > self.printerData.SetOrientation(wx.LANDSCAPE) > else: > self.printerData.SetOrientation(wx.PORTRAIT) > dlg.Destroy() > return > def Printer_Setup2(self, event=None): > """set up figure for printing. Using the standard wx Printer > Setup Dialog. """ > if hasattr(self, 'printerData'): > data = wx.PageSetupDialogData() > data.SetPrintData(self.printerData) > else: > data = wx.PageSetupDialogData() > data.SetMarginTopLeft( (15, 15) ) > data.SetMarginBottomRight( (15, 15) ) > dlg = wx.PageSetupDialog(self, data) > if dlg.ShowModal() == wx.ID_OK: > data = dlg.GetPageSetupData() > tl = data.GetMarginTopLeft() > br = data.GetMarginBottomRight() > self.printerData = wx.PrintData(data.GetPrintData()) > dlg.Destroy() > def Printer_Preview(self, event=None): > """ generate Print Preview with wx Print mechanism""" > po1 = PrintoutWx(self, width=self.printer_width, > margin=self.printer_margin) > po2 = PrintoutWx(self, width=self.printer_width, > margin=self.printer_margin) > self.preview = wx.PrintPreview(po1,po2,self.printerData) > if not self.preview.Ok(): print "error with preview" > self.preview.SetZoom(50) > frameInst= self > while not isinstance(frameInst, wx.Frame): > frameInst= frameInst.GetParent() > frame = wx.PreviewFrame(self.preview, frameInst, "Preview") > frame.Initialize() > frame.SetPosition(self.GetPosition()) > frame.SetSize((850,650)) > frame.Centre(wx.BOTH) > frame.Show(True) > self.gui_repaint() > def Printer_Print(self, event=None): > """ Print figure using wx Print mechanism""" > pdd = wx.PrintDialogData() > # SetPrintData for 2.4 combatibility > pdd.SetPrintData(self.printerData) > pdd.SetToPage(1) > printer = wx.Printer(pdd) > printout = PrintoutWx(self, width=int(self.printer_width), > margin=int(self.printer_margin)) > print_ok = printer.Print(self, printout, True) > if wx.VERSION_STRING >= '2.5': > if not print_ok and not printer.GetLastError() == wx.PRINTER_CANCELLED: > wx.MessageBox("""There was a problem printing. > Perhaps your current printer is not set correctly?""", > "Printing", wx.OK) > else: > if not print_ok: > wx.MessageBox("""There was a problem printing. > Perhaps your current printer is not set correctly?""", > "Printing", wx.OK) > printout.Destroy() > self.gui_repaint() > def draw_idle(self): > """ > Delay rendering until the GUI is idle. > """ > DEBUG_MSG("draw_idle()", 1, self) > self._isDrawn = False # Force redraw > # Create a timer for handling draw_idle requests > # If there are events pending when the timer is > # complete, reset the timer and continue. The > # alternative approach, binding to wx.EVT_IDLE, > # doesn't behave as nicely. > if hasattr(self,'_idletimer'): > self._idletimer.Restart(50) > else: > self._idletimer = wx.FutureCall(50,self._onDrawIdle) > # FutureCall is a backwards-compatible alias; > # CallLater became available in 2.7.1.1. > def _onDrawIdle(self, *args, **kwargs): > if wx.GetApp().Pending(): > self._idletimer.Restart(50, *args, **kwargs) > else: > del self._idletimer > # GUI event or explicit draw call may already > # have caused the draw to take place > if not self._isDrawn: > self.draw(*args, **kwargs) > def draw(self, drawDC=None): > """ > Render the figure using RendererWx instance renderer, or using a > previously defined renderer if none is specified. > """ > DEBUG_MSG("draw()", 1, self) > self.renderer = RendererWx(self.bitmap, self.figure.dpi) > self.figure.draw(self.renderer) > self._isDrawn = True > self.gui_repaint(drawDC=drawDC) > def flush_events(self): > wx.Yield() > def start_event_loop(self, timeout=0): > """ > Start an event loop. This is used to start a blocking event > loop so that interactive functions, such as ginput and > waitforbuttonpress, can wait for events. This should not be > confused with the main GUI event loop, which is always running > and has nothing to do with this. > Call signature:: > start_event_loop(self,timeout=0) > This call blocks until a callback function triggers > stop_event_loop() or *timeout* is reached. If *timeout* is > <=0, never timeout. > Raises RuntimeError if event loop is already running. > """ > if hasattr(self, '_event_loop'): > raise RuntimeError("Event loop already running") > id = wx.NewId() > timer = wx.Timer(self, id=id) > if timeout > 0: > timer.Start(timeout*1000, oneShot=True) > bind(self, wx.EVT_TIMER, self.stop_event_loop, id=id) > # Event loop handler for start/stop event loop > self._event_loop = wx.EventLoop() > self._event_loop.Run() > timer.Stop() > def stop_event_loop(self, event=None): > """ > Stop an event loop. This is used to stop a blocking event > loop so that interactive functions, such as ginput and > waitforbuttonpress, can wait for events. > Call signature:: > stop_event_loop_default(self) > """ > if hasattr(self,'_event_loop'): > if self._event_loop.IsRunning(): > self._event_loop.Exit() > del self._event_loop > def _get_imagesave_wildcards(self): > 'return the wildcard string for the filesave dialog' > default_filetype = self.get_default_filetype() > filetypes = self.get_supported_filetypes_grouped() > sorted_filetypes = filetypes.items() > sorted_filetypes.sort() > wildcards = [] > extensions = [] > filter_index = 0 > for i, (name, exts) in enumerate(sorted_filetypes): > ext_list = ';'.join(['*.%s' % ext for ext in exts]) > extensions.append(exts[0]) > wildcard = '%s (%s)|%s' % (name, ext_list, ext_list) > if default_filetype in exts: > filter_index = i > wildcards.append(wildcard) > wildcards = '|'.join(wildcards) > return wildcards, extensions, filter_index > def gui_repaint(self, drawDC=None): > """ > Performs update of the displayed image on the GUI canvas, using the > supplied device context. If drawDC is None, a ClientDC will be used to > redraw the image. > """ > DEBUG_MSG("gui_repaint()", 1, self) > if self.IsShownOnScreen(): > if drawDC is None: > drawDC=wx.ClientDC(self) > drawDC.BeginDrawing() > drawDC.DrawBitmap(self.bitmap, 0, 0) > drawDC.EndDrawing() > #wx.GetApp().Yield() > else: > pass > filetypes = FigureCanvasBase.filetypes.copy() > filetypes['bmp'] = 'Windows bitmap' > filetypes['jpeg'] = 'JPEG' > filetypes['jpg'] = 'JPEG' > filetypes['pcx'] = 'PCX' > filetypes['png'] = 'Portable Network Graphics' > filetypes['tif'] = 'Tagged Image Format File' > filetypes['tiff'] = 'Tagged Image Format File' > filetypes['xpm'] = 'X pixmap' > def print_figure(self, filename, *args, **kwargs): > # Use pure Agg renderer to draw > FigureCanvasBase.print_figure(self, filename, *args, **kwargs) > # Restore the current view; this is needed because the > # artist contains methods rely on particular attributes > # of the rendered figure for determining things like > # bounding boxes. > if self._isDrawn: > self.draw() > def print_bmp(self, filename, *args, **kwargs): > return self._print_image(filename, wx.BITMAP_TYPE_BMP, *args, **kwargs) > def print_jpeg(self, filename, *args, **kwargs): > return self._print_image(filename, wx.BITMAP_TYPE_JPEG, *args, **kwargs) > print_jpg = print_jpeg > def print_pcx(self, filename, *args, **kwargs): > return self._print_image(filename, wx.BITMAP_TYPE_PCX, *args, **kwargs) > def print_png(self, filename, *args, **kwargs): > return self._print_image(filename, wx.BITMAP_TYPE_PNG, *args, **kwargs) > def print_tiff(self, filename, *args, **kwargs): > return self._print_image(filename, wx.BITMAP_TYPE_TIF, *args, **kwargs) > print_tif = print_tiff > def print_xpm(self, filename, *args, **kwargs): > return self._print_image(filename, wx.BITMAP_TYPE_XPM, *args, **kwargs) > def _print_image(self, filename, filetype, *args, **kwargs): > origBitmap = self.bitmap > l,b,width,height = self.figure.bbox.bounds > width = int(math.ceil(width)) > height = int(math.ceil(height)) > self.bitmap = wx.EmptyBitmap(width, height) > renderer = RendererWx(self.bitmap, self.figure.dpi) > gc = renderer.new_gc() > self.figure.draw(renderer) > # Now that we have rendered into the bitmap, save it > # to the appropriate file type and clean up > if is_string_like(filename): > if not self.bitmap.SaveFile(filename, filetype): > DEBUG_MSG('print_figure() file save error', 4, self) > raise RuntimeError('Could not save figure to %s\n' % (filename)) > elif is_writable_file_like(filename): > if not self.bitmap.ConvertToImage().SaveStream(filename, filetype): > DEBUG_MSG('print_figure() file save error', 4, self) > raise RuntimeError('Could not save figure to %s\n' % (filename)) > # Restore everything to normal > self.bitmap = origBitmap > # Note: draw is required here since bits of state about the > # last renderer are strewn about the artist draw methods. Do > # not remove the draw without first verifying that these have > # been cleaned up. The artist contains() methods will fail > # otherwise. > if self._isDrawn: > self.draw() > self.Refresh() > def get_default_filetype(self): > return 'png' > def _onPaint(self, evt): > """ > Called when wxPaintEvt is generated > """ > DEBUG_MSG("_onPaint()", 1, self) > drawDC = wx.PaintDC(self) > if not self._isDrawn: > self.draw(drawDC=drawDC) > else: > self.gui_repaint(drawDC=drawDC) > evt.Skip() > def _onEraseBackground(self, evt): > """ > Called when window is redrawn; since we are blitting the entire > image, we can leave this blank to suppress flicker. > """ > pass > def _onSize(self, evt): > """ > Called when wxEventSize is generated. > In this application we attempt to resize to fit the window, so it > is better to take the performance hit and redraw the whole window. > """ > DEBUG_MSG("_onSize()", 2, self) > # Create a new, correctly sized bitmap > self._width, self._height = self.GetClientSize() > self.bitmap =wx.EmptyBitmap(self._width, self._height) > self._isDrawn = False > if self._width <= 1 or self._height <= 1: return # Empty figure > dpival = self.figure.dpi > winch = self._width/dpival > hinch = self._height/dpival > self.figure.set_size_inches(winch, hinch) > # Rendering will happen on the associated paint event > # so no need to do anything here except to make sure > # the whole background is repainted. > self.Refresh(eraseBackground=False) > def _get_key(self, evt): > keyval = evt.m_keyCode > if self.keyvald.has_key(keyval): > key = self.keyvald[keyval] > elif keyval <256: > key = chr(keyval) > else: > key = None > # why is wx upcasing this? > if key is not None: key = key.lower() > return key > def _onIdle(self, evt): > 'a GUI idle event' > evt.Skip() > FigureCanvasBase.idle_event(self, guiEvent=evt) > def _onKeyDown(self, evt): > """Capture key press.""" > key = self._get_key(evt) > evt.Skip() > FigureCanvasBase.key_press_event(self, key, guiEvent=evt) > def _onKeyUp(self, evt): > """Release key.""" > key = self._get_key(evt) > #print 'release key', key > evt.Skip() > FigureCanvasBase.key_release_event(self, key, guiEvent=evt) > def _onRightButtonDown(self, evt): > """Start measuring on an axis.""" > x = evt.GetX() > y = self.figure.bbox.height - evt.GetY() > evt.Skip() > self.CaptureMouse() > FigureCanvasBase.button_press_event(self, x, y, 3, guiEvent=evt) > def _onRightButtonUp(self, evt): > """End measuring on an axis.""" > x = evt.GetX() > y = self.figure.bbox.height - evt.GetY() > evt.Skip() > if self.HasCapture(): self.ReleaseMouse() > FigureCanvasBase.button_release_event(self, x, y, 3, guiEvent=evt) > def _onLeftButtonDown(self, evt): > """Start measuring on an axis.""" > x = evt.GetX() > y = self.figure.bbox.height - evt.GetY() > evt.Skip() > self.CaptureMouse() > FigureCanvasBase.button_press_event(self, x, y, 1, guiEvent=evt) > def _onLeftButtonUp(self, evt): > """End measuring on an axis.""" > x = evt.GetX() > y = self.figure.bbox.height - evt.GetY() > #print 'release button', 1 > evt.Skip() > if self.HasCapture(): self.ReleaseMouse() > FigureCanvasBase.button_release_event(self, x, y, 1, guiEvent=evt) > def _onMouseWheel(self, evt): > """Translate mouse wheel events into matplotlib events""" > # Determine mouse location > x = evt.GetX() > y = self.figure.bbox.height - evt.GetY() > # Convert delta/rotation/rate into a floating point step size > delta = evt.GetWheelDelta() > rotation = evt.GetWheelRotation() > rate = evt.GetLinesPerAction() > #print "delta,rotation,rate",delta,rotation,rate > step = rate*float(rotation)/delta > # Done handling event > evt.Skip() > # Mac is giving two events for every wheel event > # Need to skip every second one > if wx.Platform == '__WXMAC__': > if not hasattr(self,'_skipwheelevent'): > self._skipwheelevent = True > elif self._skipwheelevent: > self._skipwheelevent = False > return # Return without processing event > else: > self._skipwheelevent = True > # Convert to mpl event > FigureCanvasBase.scroll_event(self, x, y, step, guiEvent=evt) > def _onMotion(self, evt): > """Start measuring on an axis.""" > x = evt.GetX() > y = self.figure.bbox.height - evt.GetY() > evt.Skip() > FigureCanvasBase.motion_notify_event(self, x, y, guiEvent=evt) > def _onLeave(self, evt): > """Mouse has left the window; fake a motion event.""" > evt.Skip() > FigureCanvasBase.motion_notify_event(self, -1, -1, guiEvent=evt) > # The following functions and classes are for pylab compatibility > # mode (matplotlib.pylab) and implement figure managers, etc... > def _create_wx_app(): > """ > Creates a wx.PySimpleApp instance if a wx.App has not been created. > """ > wxapp = wx.GetApp() > if wxapp is None: > wxapp = wx.PySimpleApp() > wxapp.SetExitOnFrameDelete(True) > # retain a reference to the app object so it does not get garbage > # collected and cause segmentation faults > _create_wx_app.theWxApp = wxapp > def draw_if_interactive(): > """ > This should be overriden in a windowing environment if drawing > should be done in interactive python mode > """ > DEBUG_MSG("draw_if_interactive()", 1, None) > if matplotlib.is_interactive(): > figManager = Gcf.get_active() > if figManager is not None: > figManager.canvas.draw() > def show(): > """ > Current implementation assumes that matplotlib is executed in a PyCrust > shell. It appears to be possible to execute wxPython applications from > within a PyCrust without having to ensure that wxPython has been created > in a secondary thread (e.g. SciPy gui_thread). > Unfortunately, gui_thread seems to introduce a number of further > dependencies on SciPy modules, which I do not wish to introduce > into the backend at this point. If there is a need I will look > into this in a later release. > """ > DEBUG_MSG("show()", 3, None) > for figwin in Gcf.get_all_fig_managers(): > figwin.frame.Show() > if show._needmain and not matplotlib.is_interactive(): > # start the wxPython gui event if there is not already one running > wxapp = wx.GetApp() > if wxapp is not None: > # wxPython 2.4 has no wx.App.IsMainLoopRunning() method > imlr = getattr(wxapp, 'IsMainLoopRunning', lambda: False) > if not imlr(): > wxapp.MainLoop() > show._needmain = False > show._needmain = True > def new_figure_manager(num, *args, **kwargs): > """ > Create a new figure manager instance > """ > # in order to expose the Figure constructor to the pylab > # interface we need to create the figure here > DEBUG_MSG("new_figure_manager()", 3, None) > _create_wx_app() > FigureClass = kwargs.pop('FigureClass', Figure) > fig = FigureClass(*args, **kwargs) > frame = FigureFrameWx(num, fig) > figmgr = frame.get_figure_manager() > if matplotlib.is_interactive(): > figmgr.frame.Show() > return figmgr > class FigureFrameWx(wx.Frame): > def __init__(self, num, fig): > # On non-Windows platform, explicitly set the position - fix > # positioning bug on some Linux platforms > if wx.Platform == '__WXMSW__': > pos = wx.DefaultPosition > else: > pos =wx.Point(20,20) > l,b,w,h = fig.bbox.bounds > wx.Frame.__init__(self, parent=None, id=-1, pos=pos, > title="Figure %d" % num) > # Frame will be sized later by the Fit method > DEBUG_MSG("__init__()", 1, self) > self.num = num > statbar = StatusBarWx(self) > self.SetStatusBar(statbar) > self.canvas = self.get_canvas(fig) > self.canvas.SetInitialSize(wx.Size(fig.bbox.width, fig.bbox.height)) > self.sizer =wx.BoxSizer(wx.VERTICAL) > self.sizer.Add(self.canvas, 1, wx.TOP | wx.LEFT | wx.EXPAND) > # By adding toolbar in sizer, we are able to put it at the bottom > # of the frame - so appearance is closer to GTK version > self.toolbar = self._get_toolbar(statbar) > if self.toolbar is not None: > self.toolbar.Realize() > if wx.Platform == '__WXMAC__': > # Mac platform (OSX 10.3, MacPython) does not seem to cope with > # having a toolbar in a sizer. This work-around gets the buttons > # back, but at the expense of having the toolbar at the top > self.SetToolBar(self.toolbar) > else: > # On Windows platform, default window size is incorrect, so set > # toolbar width to figure width. > tw, th = self.toolbar.GetSizeTuple() > fw, fh = self.canvas.GetSizeTuple() > # By adding toolbar in sizer, we are able to put it at the bottom > # of the frame - so appearance is closer to GTK version. > # As noted above, doesn't work for Mac. > self.toolbar.SetSize(wx.Size(fw, th)) > self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND) > self.SetSizer(self.sizer) > self.Fit() > self.figmgr = FigureManagerWx(self.canvas, num, self) > bind(self, wx.EVT_CLOSE, self._onClose) > def _get_toolbar(self, statbar): > if matplotlib.rcParams['toolbar']=='classic': > toolbar = NavigationToolbarWx(self.canvas, True) > elif matplotlib.rcParams['toolbar']=='toolbar2': > toolbar = NavigationToolbar2Wx(self.canvas) > toolbar.set_status_bar(statbar) > else: > toolbar = None > return toolbar > def get_canvas(self, fig): > return FigureCanvasWx(self, -1, fig) > def get_figure_manager(self): > DEBUG_MSG("get_figure_manager()", 1, self) > return self.figmgr > def _onClose(self, evt): > DEBUG_MSG("onClose()", 1, self) > self.canvas.stop_event_loop() > Gcf.destroy(self.num) > #self.Destroy() > def GetToolBar(self): > """Override wxFrame::GetToolBar as we don't have managed toolbar""" > return self.toolbar > def Destroy(self, *args, **kwargs): > wx.Frame.Destroy(self, *args, **kwargs) > if self.toolbar is not None: > self.toolbar.Destroy() > wxapp = wx.GetApp() > if wxapp: > wxapp.Yield() > return True > class FigureManagerWx(FigureManagerBase): > """ > This class contains the FigureCanvas and GUI frame > It is instantiated by GcfWx whenever a new figure is created. GcfWx is > responsible for managing multiple instances of FigureManagerWx. > NB: FigureManagerBase is found in _pylab_helpers > public attrs > canvas - a FigureCanvasWx(wx.Panel) instance > window - a wxFrame instance - http://www.lpthe.jussieu.fr/~zeitlin/wxWindows/docs/wxwin_wxframe.html#wxframe > """ > def __init__(self, canvas, num, frame): > DEBUG_MSG("__init__()", 1, self) > FigureManagerBase.__init__(self, canvas, num) > self.frame = frame > self.window = frame > self.tb = frame.GetToolBar() > self.toolbar = self.tb # consistent with other backends > def notify_axes_change(fig): > 'this will be called whenever the current axes is changed' > if self.tb != None: self.tb.update() > self.canvas.figure.add_axobserver(notify_axes_change) > def showfig(*args): > frame.Show() > # attach a show method to the figure > self.canvas.figure.show = showfig > def destroy(self, *args): > DEBUG_MSG("destroy()", 1, self) > self.frame.Destroy() > #if self.tb is not None: self.tb.Destroy() > import wx > #wx.GetApp().ProcessIdle() > wx.WakeUpIdle() > def set_window_title(self, title): > self.window.SetTitle(title) > def resize(self, width, height): > 'Set the canvas size in pixels' > self.canvas.SetInitialSize(wx.Size(width, height)) > self.window.GetSizer().Fit(self.window) > # Identifiers for toolbar controls - images_wx contains bitmaps for the images > # used in the controls. wxWindows does not provide any stock images, so I've > # 'stolen' those from GTK2, and transformed them into the appropriate format. > #import images_wx > _NTB_AXISMENU =wx.NewId() > _NTB_AXISMENU_BUTTON =wx.NewId() > _NTB_X_PAN_LEFT =wx.NewId() > _NTB_X_PAN_RIGHT =wx.NewId() > _NTB_X_ZOOMIN =wx.NewId() > _NTB_X_ZOOMOUT =wx.NewId() > _NTB_Y_PAN_UP =wx.NewId() > _NTB_Y_PAN_DOWN =wx.NewId() > _NTB_Y_ZOOMIN =wx.NewId() > _NTB_Y_ZOOMOUT =wx.NewId() > #_NTB_SUBPLOT =wx.NewId() > _NTB_SAVE =wx.NewId() > _NTB_CLOSE =wx.NewId() > def _load_bitmap(filename): > """ > Load a bitmap file from the backends/images subdirectory in which the > matplotlib library is installed. The filename parameter should not > contain any path information as this is determined automatically. > Returns a wx.Bitmap object > """ > basedir = os.path.join(rcParams['datapath'],'images') > bmpFil... [truncated message content] |
From: John H. <jd...@gm...> - 2008-09-16 19:17:15
|
On Tue, Sep 16, 2008 at 9:00 PM, John Hunter <jd...@gm...> wrote: > Oops, wait, I answered too fast. The figure.dpi *was* already used in > the cache key and the renderer.dpi, which I just added, is not > guaranteed to exist (depending on the backend). I need to figure out > why the figure.dpi in the cache key is not sufficient .... OK, I see what is going on. Actually, nothing is broken (feature not bug, though admittedly confusing). In savefig, the renderer saves the display dpi, sets the savefig dpi on the figure and renderer (as necessary) instances, draws the figure, and then restores the display dpi. Outside of savefig therefore, all you see when calling get_window_extent is the display dpi. What you need to do is hook into the drawing so you can get the window extent when the canvas is drawn by savefig, when the savefig dpi is set. The script below shows that before and after savefig, you get the display dpi extent, but in the draw event you get the savefig dpi. If this is too onerous and you know you will be using an image backend, just set the rc figure and savefig dpi to be the same. import matplotlib as mpl mpl.use('agg') import matplotlib.pyplot as plt fig = plt.figure() t = plt.text(0.5, 0.6, 'testing') print 'before save window extent', t.get_window_extent().extents def ondraw(event): print 'on draw window extent', t.get_window_extent().extents fig.canvas.mpl_connect('draw_event', ondraw) fig.savefig('/tmp/t150.png', dpi=150) print 'after save window extent', t.get_window_extent().extents plt.show() JDH |
From: Eric F. <ef...@ha...> - 2008-09-16 19:17:10
|
John Hunter wrote: > On Tue, Sep 16, 2008 at 8:57 PM, John Hunter <jd...@gm...> wrote: >> On Tue, Sep 16, 2008 at 5:09 PM, Eric Firing <ef...@ha...> wrote: >> >>> I find this very confusing--the _renderer.dpi is not being used by >>> get_window_extent(). Is this the intended behavior? If so, I would >>> like to at least add a note to that effect to the get_window_extent >>> docstring >> No, this was definitely a bug. Because text layout is expensive, the >> text module caches the layout based on a cache key (see >> text.Text.get_prop_tup). We were using the renderer id, and lots of >> other stuff, but not the dpi, in the cache key. I just added the dpi, >> so it should work correctly now, though I have done no tests. Give >> r6098 a whirl and let me know. > > Oops, wait, I answered too fast. The figure.dpi *was* already used in > the cache key and the renderer.dpi, which I just added, is not > guaranteed to exist (depending on the backend). I need to figure out > why the figure.dpi in the cache key is not sufficient .... Maybe because backend_bases FigureCanvasBase.print_figure cleverly changes figure.dpi, prints, and then changes it back again? origDPI = self.figure.dpi origfacecolor = self.figure.get_facecolor() origedgecolor = self.figure.get_edgecolor() self.figure.dpi = dpi self.figure.set_facecolor(facecolor) self.figure.set_edgecolor(edgecolor) try: result = getattr(self, method_name)( filename, dpi=dpi, facecolor=facecolor, edgecolor=edgecolor, orientation=orientation, **kwargs) finally: self.figure.dpi = origDPI self.figure.set_facecolor(origfacecolor) self.figure.set_edgecolor(origedgecolor) self.figure.set_canvas(self) #self.figure.canvas.draw() ## seems superfluous return result Eric |
From: John H. <jd...@gm...> - 2008-09-16 19:01:01
|
On Tue, Sep 16, 2008 at 8:57 PM, John Hunter <jd...@gm...> wrote: > On Tue, Sep 16, 2008 at 5:09 PM, Eric Firing <ef...@ha...> wrote: > >> I find this very confusing--the _renderer.dpi is not being used by >> get_window_extent(). Is this the intended behavior? If so, I would >> like to at least add a note to that effect to the get_window_extent >> docstring > > No, this was definitely a bug. Because text layout is expensive, the > text module caches the layout based on a cache key (see > text.Text.get_prop_tup). We were using the renderer id, and lots of > other stuff, but not the dpi, in the cache key. I just added the dpi, > so it should work correctly now, though I have done no tests. Give > r6098 a whirl and let me know. Oops, wait, I answered too fast. The figure.dpi *was* already used in the cache key and the renderer.dpi, which I just added, is not guaranteed to exist (depending on the backend). I need to figure out why the figure.dpi in the cache key is not sufficient .... JDH |
From: John H. <jd...@gm...> - 2008-09-16 18:57:23
|
On Tue, Sep 16, 2008 at 5:09 PM, Eric Firing <ef...@ha...> wrote: > I find this very confusing--the _renderer.dpi is not being used by > get_window_extent(). Is this the intended behavior? If so, I would > like to at least add a note to that effect to the get_window_extent > docstring No, this was definitely a bug. Because text layout is expensive, the text module caches the layout based on a cache key (see text.Text.get_prop_tup). We were using the renderer id, and lots of other stuff, but not the dpi, in the cache key. I just added the dpi, so it should work correctly now, though I have done no tests. Give r6098 a whirl and let me know. JDH |
From: Eric F. <ef...@ha...> - 2008-09-16 18:35:15
|
Pierre GM wrote: > All, > What's the mechanism to submit tickets ? Pierre, There is a tracker, http://sourceforge.net/tracker/?group_id=80706&atid=560720 but it is better to start exactly as you have, with a message to this list. > > I just ran this rather obscure bug that has been reported on numpy/scipy: > when import matplotlib when python is started with the -OO flag, a TypeError > is raised: > File "/usr/lib64/python2.4/site-packages/matplotlib/figure.py", line 623, in > Figure > add_axes.__doc__ = add_axes.__doc__ % > (", ".join(get_projection_names()), '%(Axes)s') > TypeError: unsupported operand type(s) for %: 'NoneType' and 'tuple' Why would one want to use -OO when running matplotlib? Is it essential to be able to do this? > > (that's r6097). > > The trick is to use a command such as: > add_axes.__doc__ = ((add_axes.__doc__ or '') % > (", ".join(get_projection_names()), '%(Axes)s')) or None > everywhere needed. Clever, but it strikes me as a bit too ugly to sprinkle throughout mpl. Numpy has the same problem (via nosetester.py, if not elsewhere), so fixing mpl alone won't help. Eric |
From: Pierre GM <pgm...@gm...> - 2008-09-16 16:48:46
|
All, What's the mechanism to submit tickets ? I just ran this rather obscure bug that has been reported on numpy/scipy: when import matplotlib when python is started with the -OO flag, a TypeError is raised: File "/usr/lib64/python2.4/site-packages/matplotlib/figure.py", line 623, in Figure add_axes.__doc__ = add_axes.__doc__ % (", ".join(get_projection_names()), '%(Axes)s') TypeError: unsupported operand type(s) for %: 'NoneType' and 'tuple' (that's r6097). The trick is to use a command such as: add_axes.__doc__ = ((add_axes.__doc__ or '') % (", ".join(get_projection_names()), '%(Axes)s')) or None everywhere needed. Thx a lot in advance. |
From: Eric F. <ef...@ha...> - 2008-09-16 15:09:37
|
dpi settings are still a source of confusion. Suppose one wants to get the bounding boxes of strings in a png file, for use as clickable regions on a web site. Just use the get_window_extent() method of each text object after it has been drawn with savefig, right? Wrong! The gotcha is that get_window_extent() is always based on the "ordinary" dpi, not on the "savefig" dpi. In [1]:import matplotlib as mpl In [2]:mpl.use('agg') In [4]:import matplotlib.pyplot as plt In [5]:fig = plt.figure() In [6]:t = plt.text(0.5, 0.6, 'testing') In [7]:fig.savefig('/tmp/t50.png', dpi=50) In [9]:t.get_window_extent().extents Out[9]:array([ 328. , 278.4 , 356.046875, 287.4 ]) In [10]:fig.savefig('/tmp/t150.png', dpi=150) In [11]:t.get_window_extent().extents Out[11]:array([ 328. , 278.4 , 411.875, 302.4 ]) In [12]:t._renderer.dpi Out[12]:150 I find this very confusing--the _renderer.dpi is not being used by get_window_extent(). Is this the intended behavior? If so, I would like to at least add a note to that effect to the get_window_extent docstring. The obvious workaround is to always use "fig.savefig('figname.png', dpi=rcParams['figure.dpi']) in this sort of application. Eric |
From: John H. <jd...@gm...> - 2008-09-16 12:34:30
|
On Tue, Sep 16, 2008 at 2:14 PM, Jack Sankey <jac...@gm...> wrote: > Hello, > I couldn't find this in the API changes, but when I upgraded to the latest > matplotlib 0.98.2, I found (after much hair pulling) that > gca().plot([1,2,1], label='_anything') > will produce a plot and > gca().legend() > will not display the specified label. I had been using filenames starting > with underscores before and _nolabel_ to keep from showing a legend entry. > Is this a bug or has the philosophy changed to eliminate anything starting > with an underscore from the legend? I think if anything None or maybe "" > should be used for empty labels. I had to check the code to see why this was so, but we do exclude everything that starts with an underscore, even though we only document the '_nolegend_'. I suspect that this change was designed to support the autolabeling of lines when added without a label. In Axes.add_line: if not line.get_label(): line.set_label('_line%d'%len(self.lines)) but I don't recall why we added this bit of functionality. I'm not sure at this point if we should change the doc to reflect reality or change reality to reflect the doc, so perhaps someone using the auto-labeled line feature should chime in here. > Second, I am using interactive mode and WXAgg in windows. So my startup > script does this: > import matplotlib as _mpl > _mpl.use('WXAgg') > import pylab as _p > _p.ion() > Before, when I would then type > gca().plot([1,2,1]) I would not expect a draw here, since draw only happens on pylab commands. Eg _p.plot should trigger a draw, but not gca().plot because the latter is an axes method. I don't really know why it would have worked before, if it did. I would be pretty surprised if it did, actually. JDH |
From: Jack S. <jac...@gm...> - 2008-09-16 12:14:58
|
Hello, I couldn't find this in the API changes, but when I upgraded to the latest matplotlib 0.98.2, I found (after much hair pulling) that gca().plot([1,2,1], label='_anything') will produce a plot and gca().legend() will not display the specified label. I had been using filenames starting with underscores before and _nolabel_ to keep from showing a legend entry. Is this a bug or has the philosophy changed to eliminate anything starting with an underscore from the legend? I think if anything None or maybe "" should be used for empty labels. Second, I am using interactive mode and WXAgg in windows. So my startup script does this: import matplotlib as _mpl _mpl.use('WXAgg') import pylab as _p _p.ion() Before, when I would then type gca().plot([1,2,1]) a plot would appear showing the data. Now I just get a blank figure, and I have to type _p.draw() to see the data. I'm also not sure if this is a bug or a philosophy change, but I did find the old interactive mode was useful. Cheers, Jack |
From: Darren D. <dsd...@gm...> - 2008-09-16 11:22:33
|
I finally got around to installing the qt4 backend for traits. Switching on the experimental config package built around traits in matplotlib, I was really impressed with being able to do: from matplotlib import mplConfig mplConfig.configure_traits() which yielded a dialog for editing matplotlibs default settings. On Tuesday 16 September 2008 01:23:21 pm Michael Droettboom wrote: > As an aside -- it's come up a number of times that Enthought Traits may > be part of the solution to this. That is, if all of the major > properties of artist objects were defined as traits, the trait machinery > could automatically build dialog boxes to tweak various parameters etc. > That's a major undertaking to move all that code over to use Traits, and > may have performance implications, but that might have advantages in > terms of GUI independence, extensibility (adding more properties in the > future without having to update many locations), and lots of other > little tricky details that Traits has worked out over the years. > > I'm not saying that is *the* solution to this problem, but it's > definitely relevant and should be considered before running too far with > an ad-hoc solution. > > Mike > > Paul Kienzle wrote: > > On Tue, Sep 16, 2008 at 01:47:04AM +0200, Heinrich Acker wrote: > >> I'm posting this because I would like to > >> > >> * know if anybody is interested in [GUI plot editor] feature, > >> too (couldn't find anything through searching the list). > > > > I would like to see this capability in matplotlib. > > > >> * work together with you to make this something useful. > > > > Not in the short term. :-( > > > >> * get information about an appropriate way to integrate this > >> into matplotlib (where to place the functions, etc.). > > > > Try to follow the ideas of style sheets. If I want to change > > the fonts on one axis, I probably want to change them on both. > > Axes fonts are probably a bit smaller than the title font. > > > >> * finally see it integrated into a release, if possible. > > > > To get this integrated into the release you will need a way > > to support other backends. This means separating the > > structure of the interface from the backend which implements > > it. The alternative is to build up an interface using > > matplotlib defined widgets, but I think you will give you > > better results with less work. > > > > - Paul > > > > > > ------------------------------------------------------------------------- > > This SF.Net email is sponsored by the Moblin Your Move Developer's > > challenge Build the coolest Linux based applications with Moblin SDK & > > win great prizes Grand prize is a trip for two to an Open Source event > > anywhere in the world > > http://moblin-contest.org/redirect.php?banner_id=100&url=/ > > _______________________________________________ > > Matplotlib-devel mailing list > > Mat...@li... > > https://lists.sourceforge.net/lists/listinfo/matplotlib-devel |
From: Michael D. <md...@st...> - 2008-09-16 10:23:34
|
As an aside -- it's come up a number of times that Enthought Traits may be part of the solution to this. That is, if all of the major properties of artist objects were defined as traits, the trait machinery could automatically build dialog boxes to tweak various parameters etc. That's a major undertaking to move all that code over to use Traits, and may have performance implications, but that might have advantages in terms of GUI independence, extensibility (adding more properties in the future without having to update many locations), and lots of other little tricky details that Traits has worked out over the years. I'm not saying that is *the* solution to this problem, but it's definitely relevant and should be considered before running too far with an ad-hoc solution. Mike Paul Kienzle wrote: > On Tue, Sep 16, 2008 at 01:47:04AM +0200, Heinrich Acker wrote: > >> I'm posting this because I would like to >> >> * know if anybody is interested in [GUI plot editor] feature, >> too (couldn't find anything through searching the list). >> > > I would like to see this capability in matplotlib. > > >> * work together with you to make this something useful. >> > > Not in the short term. :-( > > >> * get information about an appropriate way to integrate this >> into matplotlib (where to place the functions, etc.). >> > > Try to follow the ideas of style sheets. If I want to change > the fonts on one axis, I probably want to change them on both. > Axes fonts are probably a bit smaller than the title font. > > >> * finally see it integrated into a release, if possible. >> > > To get this integrated into the release you will need a way > to support other backends. This means separating the > structure of the interface from the backend which implements > it. The alternative is to build up an interface using > matplotlib defined widgets, but I think you will give you > better results with less work. > > - Paul > > > ------------------------------------------------------------------------- > This SF.Net email is sponsored by the Moblin Your Move Developer's challenge > Build the coolest Linux based applications with Moblin SDK & win great prizes > Grand prize is a trip for two to an Open Source event anywhere in the world > http://moblin-contest.org/redirect.php?banner_id=100&url=/ > _______________________________________________ > Matplotlib-devel mailing list > Mat...@li... > https://lists.sourceforge.net/lists/listinfo/matplotlib-devel > -- Michael Droettboom Science Software Branch Operations and Engineering Division Space Telescope Science Institute Operated by AURA for NASA |
From: Paul K. <pki...@ni...> - 2008-09-16 10:16:51
|
On Tue, Sep 16, 2008 at 01:47:04AM +0200, Heinrich Acker wrote: > I'm posting this because I would like to > > * know if anybody is interested in [GUI plot editor] feature, > too (couldn't find anything through searching the list). I would like to see this capability in matplotlib. > * work together with you to make this something useful. Not in the short term. :-( > * get information about an appropriate way to integrate this > into matplotlib (where to place the functions, etc.). Try to follow the ideas of style sheets. If I want to change the fonts on one axis, I probably want to change them on both. Axes fonts are probably a bit smaller than the title font. > * finally see it integrated into a release, if possible. To get this integrated into the release you will need a way to support other backends. This means separating the structure of the interface from the backend which implements it. The alternative is to build up an interface using matplotlib defined widgets, but I think you will give you better results with less work. - Paul |
From: David M. K. <Dav...@ir...> - 2008-09-16 01:26:59
|
Hi, I would just undo what I have done rather than putting a lot of moved messages all over the place. I personally find the mix of matlab and non-matlab stuff in mlab confusing, but I will go with the group consensus. Cheers, David On Sun, 2008-09-14 at 12:08 -0500, John Hunter wrote: > On Sun, Sep 14, 2008 at 10:44 AM, David M. Kaplan <Dav...@ir...> wrote: > > > I also moved a bunch of functions having to do with numerics and > > geometry from cbook and mlab into a separate file called > > numerical_methods.py as was discussed a while back. This is fairly easy > > to undo if a problem, but this seems logical to me. > > Hi David, I don't mind a reorganization, but there are a few things > about this that I think we can improve upon. In this case, I think a > partial solution, moving some of the functions but not others with no > clear reason why some remain and some were moved, may be worse than > doing nothing since people won't know where to look when they need > something. I would be in favor of either putting everything in mlab, > which is my preference, or moving everything but the matlab > compatibility functions. One other possibility which we raised last > time is to put all the geometry functions in one place, eg in a "geom" > or "geometry" module and leave everything else in mlab. > > Two other points > > * the name numerical_methods is too long, let's find something nice and short > > * everything that gets moved should have the original function left > in place with a deprecation warning that points to the replcaement in > the help string and in the function call. The old function can just > forward the call onto the new function, but it is a bit tough for > regular users who may be relying on a function to just see it gone > with no idea where to look for the replacement. Also, include a mpl > version or date for any function deprecated so that we can know later > when to remove it, eg after one or two release cycles. As it is, we > have lots of deprecated functions with no obvious date or version > stamp when they were deprecated. > > Anyway, thanks for the fixes and I hope these suggestions aren't too onerous. > > JDH -- ********************************** David M. Kaplan Charge de Recherche 1 Institut de Recherche pour le Developpement Centre de Recherche Halieutique Mediterraneenne et Tropicale av. Jean Monnet B.P. 171 34203 Sete cedex France Phone: +33 (0)4 99 57 32 27 Fax: +33 (0)4 99 57 32 95 http://www.ur097.ird.fr/team/dkaplan/index.html ********************************** |
From: Heinrich A. <Hei...@we...> - 2008-09-15 16:47:15
|
Hello everybody, after happily using matplotlib for a while and writing a larger application for it with wxPython as the GUI toolkit, I recently tried to add a function to matplotlib itself. It is the possibility to interactively edit a plot, such that attributes of objects in a figure can be changed from the plot itself, in contrast to using a shell such as IPython. This is of course inspired by Matlab and other tools. There are two ways to do this: 1. Provide graphical picking of objects, and dialogs and/or context menus to change attributes of the selected object(s). Advantages: most intuitive, perhaps also fastest to operate. Disadvantages: picking itself sometimes does not work well, and you can't click on what you don't see or know of. 2. Provide an 'object browser', i.e. a dialog that shows the tree of objects, where the user can select object(s), then inspect all attributes in another part of the dialog, and change them replacing content there. Advantages: delivers insight into the object structure, everything is easily found and selected. Disadvantages: often requires much more clicks, especially for simple changes. Since the feature was always essential for me in Matlab, I naturally would like to have both solutions available concurrently, but when I tried to implement it, I decided for (2) because I wanted to know more about the object structure at first. What I have right now is the 'object browser' in the WX backend, but without the actual editing feature, it is only possible to look at the objects and attributes. At this point I saw that I don't know matplotlib well enough to complete the editing myself. I'm overwhelmed by the variety of objects, attributes, methods, and distribution of items over the object tree. I'm posting this because I would like to * know if anybody is interested in this feature, too (couldn't find anything through searching the list). * work together with you to make this something useful. * get information about an appropriate way to integrate this into matplotlib (where to place the functions, etc.). * finally see it integrated into a release, if possible. Attached are a modified backend_wx.py of 0.98.3, and an icon for the toolbar2, to be included into ...\mpl-data\images. With these files, the icon appears on the toolbar2, and when clicked on, a dialog pops up. It shows the object tree on the left hand side, where items can be expanded, collapsed, and selected. For the selected object, the result of str(object.__dict__) is displayed on the right hand side. That's all ... only a start. What's your opinion? Regards, Heinrich Acker |
From: Gael V. <gae...@no...> - 2008-09-15 16:41:40
|
On Mon, Sep 15, 2008 at 07:38:01PM -0400, Paul Kienzle wrote: > It does not poll. > draw_idle() triggers a timer with a 5ms delay. This timer is reset for > each draw_idle() call. At timeout the timer is restarted if there are more > events on the wx event queue, otherwise the graph is rendered. This means > you can do as many draw_idle commands as you want while processing your > data, but the expensive rendering will only happen once. OK, very nice. This is indeed a very efficient pattern for dealing with too agressive refresh. I've seen it used with a lot of success in many places. Thanks for enlighting me on this. I guess I could (should?) have looked at the code base. Gaël |
From: Paul K. <pki...@ni...> - 2008-09-15 16:38:12
|
On Mon, Sep 15, 2008 at 11:29:15PM +0200, Gael Varoquaux wrote: > On Mon, Sep 15, 2008 at 04:06:45PM -0400, Paul Kienzle wrote: > > Hi, > > > I tweaked the wx backend so that the idle delay is 5 ms rather than 50 ms. > > This allows the idle delay to kick in between mouse move events so > > the graph will be updated during a drag operation. > > > Users can override the idle delay using: > > > mpl.backends.backend_wx.IDLE_DELAY = n > > I don't know what the context is here, but if I understand it properly, > to be doing polling on a 5ms timescale is not very nice. This means a > wake up of the CPU every 5ms for this specific app. If everybody starts > doing that (I am looking at you, flash) my battery life goes down and my > laptop starts heating up. It does not poll. draw_idle() triggers a timer with a 5ms delay. This timer is reset for each draw_idle() call. At timeout the timer is restarted if there are more events on the wx event queue, otherwise the graph is rendered. This means you can do as many draw_idle commands as you want while processing your data, but the expensive rendering will only happen once. Note that the wx.EVT_IDLE event polls about once per second. The backend must always bind to wx.EVT_IDLE since mpl_connect doesn't tell it whether or not it wants to receive the events, so this can't be avoided. I'm including a demo program to check the idle event behaviour on any platform, and the output I get on OS X when starting the application, waiting a few seconds and moving the mouse. Wx is generating more events than I expect. Is there any reason to keep idle_event support? It would seems more useful to have timer+draw_idle. - Paul -- idle.py -- import time import pylab t0 = time.time() def idle(ev): print "idle event at time %.6f seconds"%(time.time()-t0) def mouse(ev): print "motion event at time %.6f seconds"%(time.time()-t0) pylab.plot([1,2,3]) pylab.gcf().canvas.mpl_connect('idle_event',idle) pylab.gcf().canvas.mpl_connect('motion_notify_event',mouse) pylab.show() -- output -- $ python idle.py idle event at time 0.564772 seconds idle event at time 0.565030 seconds idle event at time 0.565147 seconds idle event at time 1.565512 seconds idle event at time 1.565739 seconds idle event at time 2.566126 seconds idle event at time 2.566348 seconds idle event at time 3.566702 seconds idle event at time 3.566920 seconds idle event at time 4.567263 seconds idle event at time 4.567488 seconds idle event at time 5.567894 seconds idle event at time 5.568116 seconds idle event at time 6.568480 seconds idle event at time 6.568698 seconds motion event at time 6.945880 seconds idle event at time 6.946449 seconds idle event at time 6.946573 seconds idle event at time 6.946688 seconds motion event at time 6.963200 seconds idle event at time 6.963724 seconds idle event at time 6.963845 seconds idle event at time 6.963959 seconds motion event at time 6.978130 seconds idle event at time 6.978689 seconds idle event at time 6.978846 seconds idle event at time 6.978963 seconds motion event at time 6.996028 seconds idle event at time 6.996623 seconds idle event at time 6.996751 seconds idle event at time 6.996866 seconds |
From: Gael V. <gae...@no...> - 2008-09-15 14:29:27
|
On Mon, Sep 15, 2008 at 04:06:45PM -0400, Paul Kienzle wrote: > Hi, > I tweaked the wx backend so that the idle delay is 5 ms rather than 50 ms. > This allows the idle delay to kick in between mouse move events so > the graph will be updated during a drag operation. > Users can override the idle delay using: > mpl.backends.backend_wx.IDLE_DELAY = n I don't know what the context is here, but if I understand it properly, to be doing polling on a 5ms timescale is not very nice. This means a wake up of the CPU every 5ms for this specific app. If everybody starts doing that (I am looking at you, flash) my battery life goes down and my laptop starts heating up. Gaël |
From: Paul K. <pki...@ni...> - 2008-09-15 13:06:51
|
Hi, I tweaked the wx backend so that the idle delay is 5 ms rather than 50 ms. This allows the idle delay to kick in between mouse move events so the graph will be updated during a drag operation. Users can override the idle delay using: mpl.backends.backend_wx.IDLE_DELAY = n - Paul |
From: John H. <jd...@gm...> - 2008-09-14 17:08:14
|
On Sun, Sep 14, 2008 at 10:44 AM, David M. Kaplan <Dav...@ir...> wrote: > I also moved a bunch of functions having to do with numerics and > geometry from cbook and mlab into a separate file called > numerical_methods.py as was discussed a while back. This is fairly easy > to undo if a problem, but this seems logical to me. Hi David, I don't mind a reorganization, but there are a few things about this that I think we can improve upon. In this case, I think a partial solution, moving some of the functions but not others with no clear reason why some remain and some were moved, may be worse than doing nothing since people won't know where to look when they need something. I would be in favor of either putting everything in mlab, which is my preference, or moving everything but the matlab compatibility functions. One other possibility which we raised last time is to put all the geometry functions in one place, eg in a "geom" or "geometry" module and leave everything else in mlab. Two other points * the name numerical_methods is too long, let's find something nice and short * everything that gets moved should have the original function left in place with a deprecation warning that points to the replcaement in the help string and in the function call. The old function can just forward the call onto the new function, but it is a bit tough for regular users who may be relying on a function to just see it gone with no idea where to look for the replacement. Also, include a mpl version or date for any function deprecated so that we can know later when to remove it, eg after one or two release cycles. As it is, we have lots of deprecated functions with no obvious date or version stamp when they were deprecated. Anyway, thanks for the fixes and I hope these suggestions aren't too onerous. JDH |