1
2 """
3 Defines CMapMenu, a wx submenu containing colormaps.
4
5 === Example ===
6
7 The following defines a context menu with mapper::
8
9 import wx
10 import cmapmenu
11
12 ...
13 def onContextMenu(self,event):
14 popup = wx.Menu()
15 item = popup.Append(wx.ID_ANY,'&Save image', 'Save image as PNG')
16 wx.EVT_MENU(self, item.GetId(), self.onSaveImage)
17 item = popup.Append(wx.ID_ANY,'&Grid on/off', 'Toggle grid lines')
18 wx.EVT_MENU(self, item.GetId(), self.onGridToggle)
19 item = popup.AppendMenu(wx.ID_ANY, "Colourmaps",
20 CMapMenu(self, self.mapper, self.canvas))
21
22 The assumption is that mapper and canvas are attributes of the panel for
23 which the context menu is defined. When the new colour map is selected,
24 the mapper will be reset and the figure redrawn.
25
26 Sometimes you will want to do more than just update the mapper for the
27 current canvas. You may for example want to record the new colormap name
28 in the application settings file so that it will be there when the
29 application is reloaded. To do this, call CMapMenu(callback=self.OnColormap).
30 This will call the method OnColormap with the parameter name giving the
31 name of the colormap.
32 """
33 __all__ = ['CMapMenu']
34
35 import sys
36 import wx
37 import numpy
38 from matplotlib import cm
39
41 """
42 Convert a colormap to a bitmap showing a colorbar for the colormap.
43
44 Orientation can be vertical or horizontal (only looks at the first letter).
45 """
46
47 V = colormap(numpy.linspace(0,1,length),bytes=True)
48 if orientation[0].lower() == 'h':
49 V = numpy.tile(V,(thickness,1))
50 bitmap = wx.BitmapFromBufferRGBA(length,thickness,V)
51 elif orientation[0].lower() == 'v':
52 V = numpy.tile(V,(1,thickness))
53 bitmap = wx.BitmapFromBufferRGBA(thickness,length,V)
54 else:
55 raise ValueError,"expected orientation [V]ertical or [H]orizontal"
56 return bitmap
57
59 """
60 Iterate over the available colormaps
61 """
62 maps = [name
63 for name in cm.datad.keys()
64 if not name.endswith("_r")]
65 maps.sort()
66 return maps
67
69 """
70 Colormaps grouped by source.
71 """
72 mlab = ['autumn','winter','spring','summer',
73 'gray','bone','copper','pink',
74 'cool','hot',
75 'hsv','jet','spectral',
76
77 'prism','flag']
78 mlab_r = [m+'_r' for m in mlab]
79 brewer = ['Accent','Dark2',
80 'Spectral',
81 'Paired',
82 'Blues','Greens','Greys','Oranges','Purples','Reds',
83 'Pastel1','Pastel2',
84 'Set1','Set2','Set3',
85 'BrBG','BuGn','BuPu','GnBu',
86 'OrRd',
87 'PiYG','PRGn','PuBu','PuBuGn',
88 'PuOr','PuRd',
89 'RdBu','RdGy','RdPu',
90 'RdYlBu','RdYlGn',
91 'YlGn','YlGnBu','YlOrBr','YlOrRd',
92 ]
93 brewer_r = [m+'_r' for m in brewer]
94 gist = ['gist_ncar','gist_rainbow',
95 'gist_stern','gist_earth',
96 'gist_gray','gist_heat',
97
98 ]
99 gist_r = [m+'_r' for m in gist]
100
101 return gist + [None] + mlab + [None] + brewer
102
104 """
105 Add keyword arguments to the event callback.
106 """
107 return lambda evt: callback(evt,**kw)
109 """
110 Menu tree binding to a list of colormaps.
111 """
114 """
115 Define a context menu for selecting colormaps.
116
117 Need a window to use as the event handler.
118 If mapper is defined, it will be updated with the new colormap.
119 If canvas is defined, it will update on idle.
120 """
121 wx.Menu.__init__(self)
122
123
124 bar_length = 32 if not sys.platform in ['darwin'] else 16
125 bar_height = 16
126 self.mapper,self.canvas,self.callback = mapper,canvas,callback
127 self.selected = None
128 self.mapid = {}
129 for name in grouped_colormaps():
130 if name is None:
131 self.AppendSeparator()
132 else:
133 item = wx.MenuItem(self, wx.ID_ANY, name)
134 map = cm.get_cmap(name)
135 icon = colorbar_bitmap(map,bar_length,thickness=bar_height)
136 item.SetBitmap(icon)
137 self.AppendItem(item)
138 window.Bind(wx.EVT_MENU,
139 event_callback(self._OnSelect, name=name),
140 id=item.GetId())
141
143 """
144 When selected, record the name, update the mapper and invoke the
145 callback.
146 """
147 self.selected = name
148 if self.mapper:
149 self.mapper.set_cmap(cm.get_cmap(name))
150 if self.canvas:
151 self.canvas.draw_idle()
152 if self.callback:
153 self.callback(name)
154
156
157 class ChangeCM(object):
158 def __init__(self,im):
159 self.im = im
160 def __call__(self, m):
161 self.im.set_cmap(m.get_cmap())
162 self.im.set_clim(m.get_clim())
163
164
165 from matplotlib.image import FigureImage
166 from matplotlib.figure import Figure
167 from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as Canvas
168 class Frame(wx.Frame):
169 def __init__(self):
170 wx.Frame.__init__(self, parent=None, title="Colourmap Selection")
171
172 self.figure = Figure(dpi=80, figsize=(2,2))
173 self.canvas = Canvas(self, -1, self.figure)
174 self.axes = self.figure.gca()
175 x = y = numpy.linspace(-3,3,80)
176 X,Y = numpy.meshgrid(x,y)
177 V = numpy.sin(Y**2+X**2)
178 self.mapper = FigureImage(self.figure)
179 im = self.axes.pcolor(x,y,V,shading='flat')
180 try:
181 cb = self.mapper.callbacksSM.connect('changed', ChangeCM(im))
182 except AttributeError:
183 self.mapper.add_observer(im)
184
185
186 sizer = wx.BoxSizer(wx.VERTICAL)
187 sizer.Add(self.canvas,1,wx.EXPAND)
188 self.SetSizer(sizer)
189
190 self.canvas.Bind(wx.EVT_RIGHT_DOWN, self.OnContext)
191
192
193 def OnContext(self, evt):
194 popup = wx.Menu()
195 item = popup.Append(wx.ID_ANY,'&Grid on/off', 'Toggle grid lines')
196 wx.EVT_MENU(self, item.GetId(), self.OnGridToggle)
197 cmapmenu = CMapMenu(self, callback = self.OnColormap,
198 mapper=self.mapper, canvas=self.canvas)
199 item = popup.AppendMenu(wx.ID_ANY, "Colourmaps", cmapmenu)
200 self.PopupMenu(popup, evt.GetPositionTuple())
201 def OnColormap(self, name):
202 print "Selected colormap",name
203 def OnGridToggle(self, event):
204 self.axes.grid()
205 self.canvas.draw_idle()
206
207 app = wx.App(redirect=False)
208 Frame().Show()
209 app.MainLoop()
210
211
212 if __name__ == "__main__": demo()
213