File: matplotlib_support.py

package info (click to toggle)
gamera 1:3.4.3-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, buster, sid
  • size: 15,912 kB
  • sloc: xml: 122,324; cpp: 50,730; python: 35,044; ansic: 258; makefile: 114; sh: 101
file content (291 lines) | stat: -rw-r--r-- 10,853 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
#
# Copyright (C) 2001-2005 Ichiro Fujinaga, Michael Droettboom,
#                         and Karl MacMillan
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#

from sys import stderr

try:
   import matplotlib
#    if (not hasattr(matplotlib, '__version__') or
#        matplotlib.__version__ not in ("0.73.1", "0.84", "0.90.1")):
#       print >>stderr, "WARNING: The version of matplotlib you have installed has not been officially"
#       print >>stderr, "tested with Gamera.  It may work fine, or you may experience strange"
#       print >>stderr, "problems using the matplotlib functionality.  Please include the"
#       print >>stderr, "version of your matplotlib (%s) in any bug reports to the Gamera" % (matplotlib.__version__)
#       print >>stderr, "developers.\n"
   try:
      matplotlib.use("WXAgg")
      from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
      from matplotlib.backends import backend_wxagg as underlying_backend
   except ImportError:
      matplotlib.use("WX")
      from matplotlib.backends.backend_wx import FigureCanvasWx as FigureCanvas
      from matplotlib.backends import backend_wx as underlying_backend
   from matplotlib.backends import backend_wx
   from matplotlib import backend_bases
   from matplotlib.figure import Figure
   from matplotlib._pylab_helpers import Gcf
   import wx
   from gamera.gui import toolbar, gui_util, gamera_icons
except ImportError:
   def plot(*args, **kwargs):
      raise RuntimeError("Plotting is not supported because the optional matplotlib library\n"
                       "could not be found.\n\n"
                       "Download and install matplotlib from matplotlib.sourceforge.net,\n"
                       "then restart Gamera to have plotting support.")
   show_figure = plot
   matplotlib_installed = False
else:
   cursord = backend_wx.cursord
   
   class GameraPlotToolbar(backend_bases.NavigationToolbar2, toolbar.ToolBar):
      def __init__(self, parent, canvas):
         self.canvas = canvas
         self._idle = True
         self.statbar = None
         toolbar.ToolBar.__init__(self, parent)
         backend_bases.NavigationToolbar2.__init__(self, canvas)
         
      def _init_toolbar(self):
         load_bitmap = backend_wx._load_bitmap
         self.AddSimpleTool(10, gamera_icons.getIconHomeBitmap(),
                            'Reset original view', self.home)
         self.AddSimpleTool(20, gamera_icons.getIconBackBitmap(),
                            'Back navigational view', self.back)
         self.AddSimpleTool(30, gamera_icons.getIconForwardBitmap(),
                            'Forward navigational view', self.forward)
         self.AddSeparator()
         self.pan_button = self.AddSimpleTool(40, gamera_icons.getIconMoveBitmap(),
                                              'Pan/zoom mode', self.pan, True)
         self.zoom_button = self.AddSimpleTool(50, gamera_icons.getIconZoomViewBitmap(),
                                               'Zoom to rectangle', self.zoom, True)
         self.AddSeparator()
         self.AddSimpleTool(60, gamera_icons.getIconSaveBitmap(),
                            'Save plot contents to file', self.save)
         self.AddSimpleTool(70, gamera_icons.getIconPrinterBitmap(),
                            'Print', self.print_plot)
         
      def save(self, evt):
         filename = gui_util.save_file_dialog(self, self.canvas._get_imagesave_wildcards())
         if filename is not None:
            self.canvas.print_figure(filename)

      def print_plot(self, evt):
         printout = backend_wx.PrintoutWx(self.canvas)
         dialog_data = wx.PrintDialogData()
         if wx.VERSION < (2, 5):
            dialog_data.EnableHelp(False)
            dialog_data.EnablePageNumbers(False)
            dialog_data.EnableSelection(False)
         printer = wx.Printer(dialog_data)
         if not printer.Print(self, printout, True):
            if printer.GetLastError() == wx.PRINTER_ERROR:
               gui_util.message("A printing error occurred.")

      def zoom(self, evt):
         if evt.GetIsDown():
            self.pan_button.SetValue(False)
         else:
            self.zoom_button.SetValue(True)
         backend_bases.NavigationToolbar2.zoom(self, evt)
         
      def pan(self, evt):
         if evt.GetIsDown():
            self.zoom_button.SetValue(False)
         else:
            self.pan_button.SetValue(True)
         backend_bases.NavigationToolbar2.pan(self, evt)


      # This is all verbatim from backend_wx.py, which for various
      # multiple-ineheritance-related reasons can not just be directly
      # imported

      def set_cursor(self, cursor):
         cursor = wx.StockCursor(cursord[cursor])
         self.canvas.SetCursor( cursor )

      def release(self, event):
         try: del self.lastrect
         except AttributeError: pass

      def dynamic_update(self):
         d = self._idle
         self._idle = False
         if d:
            self.canvas.draw()
            self._idle = True

      def draw_rubberband(self, event, x0, y0, x1, y1):
         'adapted from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/189744'
         canvas = self.canvas
         dc = wx.ClientDC(canvas)
         
         # Set logical function to XOR for rubberbanding
         dc.SetLogicalFunction(wx.XOR)
         
         # Set dc brush and pen
         # Here I set brush and pen to white and grey respectively
         # You can set it to your own choices
         
         # The brush setting is not really needed since we
         # dont do any filling of the dc. It is set just for 
         # the sake of completion.
         
         wbrush = wx.Brush(wx.Colour(255,255,255), wx.TRANSPARENT)
         wpen = wx.Pen(wx.Colour(200, 200, 200), 1, wx.SOLID)
         dc.SetBrush(wbrush)
         dc.SetPen(wpen)
         
         dc.ResetBoundingBox()
         dc.BeginDrawing()
         height = self.canvas.figure.bbox.height()
         y1 = height - y1
         y0 = height - y0
         
         if y1<y0: y0, y1 = y1, y0
         if x1<y0: x0, x1 = x1, x0
         
         w = x1 - x0
         h = y1 - y0
         
         rect = int(x0), int(y0), int(w), int(h)
         try: lastrect = self.lastrect
         except AttributeError: pass
         else: dc.DrawRectangle(*lastrect)  #erase last
         self.lastrect = rect
         dc.DrawRectangle(*rect)
         dc.EndDrawing()

      def set_status_bar(self, statbar):
         self.statbar = statbar

      def set_message(self, s):
         if self.statbar is not None: self.statbar.set_function(s)

   class GameraPlotDropTarget(wx.PyDropTarget):
      def __init__(self, figure):
         wx.PyDropTarget.__init__(self)
         self.df = wx.CustomDataFormat("Vector")
         self.data = wx.CustomDataObject(self.df)
         self.SetDataObject(self.data)
         self.figure = figure

      def OnEnter(self, *args):
         return wx.DragCopy
      
      def OnDrop(self, *args):
         return True
      
      def OnDragOver(self, *args):
         return wx.DragCopy
   
      def OnData(self, x, y, d):
         if self.GetData():
            data = eval(self.data.GetData())
            self.figure.axes[0].plot(data)
         return d

   class GameraPlotFrame(wx.Frame):
      def __init__(self, num, figure):
         self.num = num
         wx.Frame.__init__(self, None, -1, 'matplotlib Plot', size=(550, 350))
         self.figure = figure
         self.canvas = FigureCanvas(self, -1, self.figure)
         self.canvas.SetDropTarget(GameraPlotDropTarget(self.figure))
         statbar = backend_wx.StatusBarWx(self)
         self.SetStatusBar(statbar)
         self.toolbar = GameraPlotToolbar(self, self.canvas)
         self.toolbar.set_status_bar(statbar)

         box = wx.BoxSizer(wx.VERTICAL)
         box.Add(self.toolbar, 0, wx.EXPAND)
         box.Add(self.canvas, 1, wx.EXPAND)
         self.SetSizer(box)
         self.Fit()
         self.figmgr = GameraFigureManager(self.canvas, num, self)

      def GetToolBar(self):
         return self.toolbar

      def get_figure_manager(self):
         return self.figmgr

   _plot_num = 0
   def plot(*args):
      # Having inf values in the array raises a cryptic error
      # message from matplotlib
      inf = 1e300
      line = args[0]
      for x in line:
         if x > inf or x < -inf:
            raise ValueError("Line contains 'inf' or '-inf' values which can not be plotted.")

      figure = Figure()
      axis = figure.add_subplot(111)
      axis.plot(*args)
      show_figure(figure)
      return figure

   def show_figure(figure):
      display = GameraPlotFrame(0, figure)
      display.Show()
      return display

   # Everything below here is just to support pylab mode
   def show():
       for figwin in Gcf.get_all_fig_managers():
           figwin.frame.Show()
           figwin.canvas.realize()
           figwin.canvas.draw()

   def new_figure_manager(num, *args, **kwargs):
       # in order to expose the Figure constructor to the pylab
       # interface we need to create the figure here
       fig = Figure(*args, **kwargs)
       frame = GameraPlotFrame(num, fig)
       figmgr = frame.get_figure_manager()
       figmgr.canvas.realize()
       figmgr.frame.Show()
       return figmgr

   class GameraFigureManager(backend_bases.FigureManagerBase):
      def __init__(self, canvas, num, frame):
         backend_bases.FigureManagerBase.__init__(self, canvas, num)
         self.frame = frame
         self.window = frame
         self.tb = frame.GetToolBar()
         
         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 destroy(self, *args):
         self.frame.Destroy()
         self.canvas.Destroy()        
         import wx
         wx.WakeUpIdle()

   from matplotlib import backends
   backends.show = show
   backends.new_figure_manager = new_figure_manager

   matplotlib_installed = True
   
__all__ = "plot show_figure".split()