source: sasview/plottools/src/danse/common/plottools/canvas.py @ 82a54b8

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 82a54b8 was 82a54b8, checked in by Mathieu Doucet <doucetm@…>, 13 years ago

adding plottools Part 2

  • Property mode set to 100644
File size: 8.4 KB
Line 
1"""
2This module implements a faster canvas for plotting.
3it ovewrites some matplolib methods to allow printing on sys.platform=='win32'
4"""
5import wx
6import sys
7from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg
8from matplotlib.backends.backend_wxagg import _convert_agg_to_wx_bitmap
9from matplotlib.backends.backend_agg import FigureCanvasAgg
10from matplotlib.backend_bases import MouseEvent, RendererBase
11from matplotlib.backends.backend_wx import GraphicsContextWx, PrintoutWx
12from matplotlib.backends.backend_wx import RendererWx
13
14
15def draw_image(self, x, y, im, bbox, clippath=None, clippath_trans=None):
16    """
17    Draw the image instance into the current axes;
18
19    :param x: is the distance in pixels from the left hand side of the canvas.
20    :param y: the distance from the origin.  That is, if origin is
21        upper, y is the distance from top.  If origin is lower, y
22        is the distance from bottom
23    :param im: the class`matplotlib._image.Image` instance
24    :param bbox: a class `matplotlib.transforms.Bbox` instance for clipping, or
25        None
26
27    """
28    pass
29#print "overriding select"
30def select(self): 
31    """
32    """
33    #print "in new select"
34    pass
35
36def unselect(self):
37    """
38    """
39    pass
40
41def OnPrintPage(self, page):
42    """
43    override printPage of matplotlib
44    """
45    self.canvas.draw()
46    dc        = self.GetDC()
47    try:
48        (ppw, pph) = self.GetPPIPrinter()      # printer's pixels per in
49    except:
50        ppw = 1
51        pph = 1
52    (pgw, pgh) = self.GetPageSizePixels()  # page size in pixels
53    (dcw, dch) = dc.GetSize()
54    (grw, grh) = self.canvas.GetSizeTuple()
55
56    # save current figure dpi resolution and bg color,
57    # so that we can temporarily set them to the dpi of
58    # the printer, and the bg color to white
59    bgcolor = self.canvas.figure.get_facecolor()
60    fig_dpi = self.canvas.figure.dpi
61
62    # draw the bitmap, scaled appropriately
63    vscale    = float(ppw) / fig_dpi
64
65    # set figure resolution,bg color for printer
66    self.canvas.figure.dpi = ppw
67    self.canvas.figure.set_facecolor('#FFFFFF')
68
69    renderer  = RendererWx(self.canvas.bitmap, self.canvas.figure.dpi)
70    self.canvas.figure.draw(renderer)
71    self.canvas.bitmap.SetWidth(  int(self.canvas.bitmap.GetWidth() * vscale))
72    self.canvas.bitmap.SetHeight( int(self.canvas.bitmap.GetHeight()* vscale))
73    self.canvas.draw()
74
75    # page may need additional scaling on preview
76    page_scale = 1.0
77    if self.IsPreview():   page_scale = float(dcw)/pgw
78
79    # get margin in pixels = (margin in in) * (pixels/in)
80    top_margin  = int(self.margin * pph * page_scale)
81    left_margin = int(self.margin * ppw * page_scale)
82
83    # set scale so that width of output is self.width inches
84    # (assuming grw is size of graph in inches....)
85    user_scale = (self.width * fig_dpi * page_scale)/float(grw)
86    dc.SetDeviceOrigin(left_margin, top_margin)
87    dc.SetUserScale(user_scale, user_scale)
88
89    # this cute little number avoid API inconsistencies in wx
90    try:
91        dc.DrawBitmap(self.canvas.bitmap, 0, 0)
92    except:
93        try:
94            dc.DrawBitmap(self.canvas.bitmap, (0, 0))
95        except:
96            pass
97
98    # restore original figure  resolution
99    self.canvas.figure.set_facecolor(bgcolor)
100    ## used to be self.canvas.figure.dpi.set( fig_dpi)
101    self.canvas.figure.dpi = fig_dpi
102    self.canvas.draw()
103    return True
104
105GraphicsContextWx.select = select
106GraphicsContextWx.unselect = unselect
107PrintoutWx.OnPrintPage = OnPrintPage
108RendererBase.draw_image = draw_image
109
110class FigureCanvas(FigureCanvasWxAgg):
111    """
112    Add features to the wx agg canvas for better support of AUI and
113    faster plotting.
114   
115    """
116
117    def __init__(self, *args, **kw):
118        super(FigureCanvas, self).__init__(*args, **kw)
119        self._isRendered = False
120       
121        # Create an timer for handling draw_idle requests
122        # If there are events pending when the timer is
123        # complete, reset the timer and continue.  The
124        # alternative approach, binding to wx.EVT_IDLE,
125        # doesn't behave as nicely.
126        self.idletimer = wx.CallLater(1, self._onDrawIdle)
127        # panel information
128        self.panel = None
129        self.resizing = False
130        self.xaxis = None
131        self.yaxis = None
132        # Support for mouse wheel
133        self.Bind(wx.EVT_MOUSEWHEEL, self._onMouseWheel)
134       
135    def set_panel(self, panel):
136        """
137        Set axes
138        """
139        # set panel
140        self.panel = panel
141        # set axes
142        self.xaxis = panel.subplot.xaxis
143        self.yaxis = panel.subplot.yaxis
144       
145    def draw_idle(self, *args, **kwargs):
146        """
147        Render after a delay if no other render requests have been made.
148        """
149        self.panel.subplot.grid(self.panel.grid_on)
150        self.idletimer.Restart(5, *args, **kwargs)  # Delay by 5 ms
151
152    def _onDrawIdle(self, *args, **kwargs):
153        """
154        """
155        if False and wx.GetApp().Pending():
156            self.idletimer.Restart(5, *args, **kwargs)
157        else:           
158            # Draw plot, changes resizing too
159            self.draw(*args, **kwargs)
160            self.resizing = False 
161           
162    def _get_axes_switch(self):   
163        """
164        """
165        # Check resize whether or not True
166        # This is for fast response when plot is being resized
167        if not self.resizing:
168            self.xaxis.set_visible(True)
169            self.yaxis.set_visible(True)
170            self.panel.schedule_full_draw('del')
171        else:
172            self.xaxis.set_visible(False)
173            self.yaxis.set_visible(False)
174            self.panel.schedule_full_draw('append')
175        # set the resizing back to default= False
176        self.set_resizing(False)
177       
178    def set_resizing(self, resizing=False): 
179        """
180        Setting the resizing
181        """ 
182        self.resizing = resizing
183        self.panel.set_resizing(False)
184       
185    def draw(self, drawDC=None):
186        """
187        Render the figure using agg.
188        """
189        # Only draw if window is shown, otherwise graph will bleed through
190        # on the notebook style AUI widgets.
191        fig = FigureCanvasWxAgg
192        if self.IsShownOnScreen():
193            self._isRendered = True
194            #self.panel.parent.refresh_floating(self.panel)
195            self._get_axes_switch()
196            #import time
197            #st = time.time()
198            try:
199                fig.draw(self)
200            except ValueError:
201                pass
202            #self.bitmap = _convert_agg_to_wx_bitmap(self.get_renderer(), None)
203            #self.gui_repaint(drawDC=drawDC)
204            #print "time", time.time() - st
205        else:
206            self._isRendered = False
207   
208    def _onMouseWheel(self, evt):
209        """Translate mouse wheel events into matplotlib events"""
210        # Determine mouse location
211        w, h = self.figure.canvas.get_width_height()
212        x = evt.GetX()
213        y = h - evt.GetY()
214
215        # Convert delta/rotation/rate into a floating point step size
216        delta = evt.GetWheelDelta() 
217        rotation = evt.GetWheelRotation()
218        rate = evt.GetLinesPerAction()
219        #print "delta,rotation,rate",delta,rotation,rate
220        step = rate * float(rotation) / delta
221
222        # Convert to mpl event
223        evt.Skip()
224        self.scroll_event(x, y, step, guiEvent=evt)
225
226    def scroll_event(self, x, y, step=1, guiEvent=None):
227        """
228        Backend derived classes should call this function on any
229        scroll wheel event.  x,y are the canvas coords: 0,0 is lower,
230        left.  button and key are as defined in MouseEvent
231       
232        """
233        button = 'up' if step >= 0 else 'down'
234        self._button = button
235        s = 'scroll_event'
236        event = MouseEvent(s, self, x, y, button, self._key, guiEvent=guiEvent)
237        setattr(event, 'step', step)
238        self.callbacks.process(s, event)
239        if step != 0:
240            self.panel.is_zoomed = True
241               
242    def _onRightButtonDown(self, evt):
243        """
244        Overload the right button down call back to avoid a problem
245        with the context menu over matplotlib plots on linux.
246       
247        :TODO: Investigate what the root cause of the problem is.
248       
249        """
250        if sys.platform == 'linux2':
251            evt.Skip()
252        else:
253            FigureCanvasWxAgg._onRightButtonDown(self, evt)
254            # This solves the focusing on rightclick.
255            # Todo: better design
256            self.panel.parent.set_plot_unfocus() 
257            self.panel.on_set_focus(None)
258       
259        return
Note: See TracBrowser for help on using the repository browser.