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 from mglutil.util.callback import CallBackFunction
28 from NetworkEditor.widgets import TkPortWidget, PortWidget
29 import Pmw,math,os
30 from matplotlib.colors import cnames
31 from matplotlib.lines import Line2D,lineStyles,TICKLEFT, TICKRIGHT, TICKUP, TICKDOWN
32 from matplotlib.transforms import Value
33 from matplotlib import rcParams
34 from mglutil.gui.BasicWidgets.Tk.thumbwheel import ThumbWheel
35 from Numeric import array
36 """
37 This module implements Vision nodes exposing matplotlib functionatility.
38
39 MPLBaseNE:
40 ---------
41 The class provides a base class for all nodes exposing matplotlib functionality
42
43 its purpose is to to create the attributes described below and implement
44 methods shared by all nodes.
45
46 Attributes:
47 self.figure = None: # node's figure object
48 # This attribute always points to the matplotlib Figure object which has
49 # a FigureCanvasTkAgg object in its .canvas attribute
50
51 # self.canvas FigureCanvasTkAgg
52
53 self.axes = None
54 # This attribute points to the matplotlib Axes instance used by this node
55
56 self.axes.figure # figure in which the axes is currently drawn
57
58 Methods:
59 def createFigure(self, master=None, width=None, height=None, dpi=None,
60 facecolor=None, edgecolor=None, frameon=None,
61 packOpts=None, toolbar=True):
62
63 # This method is used by all nodes if they need to create a Figure object
64 # from the matplotlib library and a FigureCanvasTkAgg object for this
65 # figure.
66
67 def setFigure(self, figure):
68 # This method place the node's axes object into the right Figure
69
70
71 def beforeRemovingFromNetwork(self):
72 # this method is called when a node is deleted from a network. Its job is
73 # to delete FigureCanvasTkAgg and Axes when appropriate.
74
75
76 MPLFigure:
77 -----------
78 The MPLFigure node allows the creation of a plotting area in which one
79 or more Axes can be added, where an Axes is a 2D graphical representation
80 of a data set (i.e. 2D plot). A 'master' can be apecified to embed the figure
81 in other panels. This node provides control over parameter that apply to the
82 MPLFigure such, width, height, dpi, etc.
83
84
85 Plotting Node:
86 -------------
87 Plotting nodes such as Histogram, Plot, Scatter, Pie, etc. take adtasets and
88 render them as 2D plots. They alwas own the axes.
89 If the data to be rendered is the only input to these nodes, they will create
90 a default Figure, add a default Plot2D to this figure, and draw the data in
91 this default 2D plot.
92 """
93
94 from Vision import UserLibBuild
95 from NetworkEditor.items import NetworkNode
96
97 import Tkinter
98 import matplotlib
99 import types
100 import weakref
101
102
103
104 matplotlib.use('TkAgg')
105
106 from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
107 from matplotlib.backends.backend_tkagg import NavigationToolbar2TkAgg
108 from matplotlib.figure import Figure as OriginalFigure
109 from matplotlib.axes import Axes, Subplot, PolarSubplot, PolarAxes
110 from matplotlib.pylab import *
111 from Vision.colours import get_colours
112 from Vision.posnegFill import posNegFill
113 from matplotlib import numerix
114 from matplotlib.artist import setp
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 from matplotlib.cbook import iterable, popd
153 try:
154 from matplotlib.dates import DayLocator, HourLocator, \
155 drange, date2num, timezone
156 except:
157 pass
158 try:
159 from pytz import common_timezones
160 except:
161 common_timezones=[]
162
163 locations={'best' : 0,
164 'upper right' : 1,
165 'upper left' : 2,
166 'lower left' : 3,
167 'lower right' : 4,
168 'right' : 5,
169 'center left' : 6,
170 'center right' : 7,
171 'lower center' : 8,
172 'upper center' : 9,
173 'center' : 10,}
174 colors={
175 'blue' : 'b',
176 'green' : 'g',
177 'red' : 'r',
178 'cyan' : 'c',
179 'magenta' :'m',
180 'yellow' :'y',
181 'black': 'k',
182 'white' : 'w',
183 }
184
185 markers= {
186 'square' : 's',
187 'circle' : 'o',
188 'triangle up' : '^',
189 'triangle right' : '>',
190 'triangle down' : 'v',
191 'triangle left' : '<',
192 'diamond' : 'd',
193 'pentagram' : 'p',
194 'hexagon' : 'h',
195 'octagon' : '8',
196 }
197
198 cmaps=['autumn','bone', 'cool','copper','flag','gray','hot','hsv','jet','pink', 'prism', 'spring', 'summer', 'winter']
199
201 styles={}
202 for ls in Line2D._lineStyles.keys():
203 styles[Line2D._lineStyles[ls][6:]]=ls
204 for ls in Line2D._markers.keys():
205 styles[Line2D._markers[ls][6:]]=ls
206
207 if styles.has_key('steps'):
208 del styles['steps']
209 for s in styles.keys():
210 if s =="nothing":
211 del styles['nothing']
212 if s[:4]=='tick':
213 del styles[s]
214 return styles
215
259
260
261
263 """Base class for node wrapping the maptlotlib objects
264
265 """
266 - def __init__(self, name='MPLBase', **kw):
267 kw['name'] = name
268 apply( NetworkNode.__init__, (self,), kw )
269
270 self.figure = None
271 self.axes = None
272
273
274
275
276 self.ownsMaster = False
277
278
280 ax = self.axes
281
282 if kw.has_key('left'):
283 rect = [kw['left'], kw['bottom'], kw['width'], kw['height']]
284 ax.set_position(rect)
285 if kw.has_key('frameon'):
286 ax.set_frame_on(kw['frameon'])
287
288 if kw.has_key("title"):
289 if type(kw['title'])==types.StringType:
290 ax.set_title(kw['title'])
291 else:
292 print 'Set title as Object'
293 if kw.has_key("xlabel"):
294 ax.set_xlabel(kw['xlabel'])
295 if kw.has_key("ylabel"):
296 ax.set_ylabel(kw['ylabel'])
297 if kw.has_key("xlimit"):
298 if kw['xlimit']!='':
299 ax.set_xlim(eval(kw['xlimit']))
300 if kw.has_key("ylimit"):
301 if kw['ylimit']!='':
302 ax.set_ylim(eval(kw['ylimit']))
303 if kw.has_key("xticklabels"):
304 if not kw['xticklabels']:
305 ax.set_xticklabels([])
306 if kw.has_key("yticklabels"):
307 if not kw['yticklabels']:
308 ax.set_yticklabels([])
309 if kw.has_key("axison"):
310 if kw['axison']:
311 ax.set_axis_on()
312 else:
313 ax.set_axis_off()
314 if kw.has_key("autoscaleon"):
315 if kw['autoscaleon']:
316 ax.set_autoscale_on(True)
317 else:
318 ax.set_autoscale_on(False)
319 if kw.has_key("adjustable"):
320 ax.set_adjustable(kw['adjustable'])
321 if kw.has_key("aspect"):
322 ax.set_aspect(kw['aspect'])
323 if kw.has_key("anchor"):
324 ax.set_anchor(kw['anchor'])
325
326 if kw.has_key("axisbelow"):
327 if kw['axisbelow']==1:
328 val=True
329 else:
330 val=False
331 rcParams['axes.axisbelow']=val
332 ax.set_axisbelow(val)
333
334 if kw.has_key("gridOn"):
335 if kw['gridOn']==1:
336 ax._gridOn=True
337 val=True
338 if kw.has_key('gridcolor'):
339 gcolor=kw['gridcolor']
340 else:
341 gcolor=rcParams['grid.color']
342 if kw.has_key('gridlinestyle'):
343 glinestyle=kw['gridlinestyle']
344 else:
345 glinestyle=rcParams['grid.linestyle']
346 if kw.has_key('gridlinewidth'):
347 glinewidth=kw['gridlinewidth']
348 else:
349 glinewidth=rcParams['grid.linewidth']
350 if kw.has_key('whichgrid'):
351 whichgrid=kw['whichgrid']
352 else:
353 whichgrid='major'
354 ax.grid(val,color=gcolor, linestyle=glinestyle, linewidth=glinewidth,which=whichgrid)
355 else:
356 val=False
357 ax.grid(val)
358
359 if kw.has_key("facecolor"):
360 ax.set_axis_bgcolor(kw['facecolor'])
361 if kw.has_key("edgecolor"):
362 ax.axesFrame.set_color(kw['edgecolor'])
363 if kw.has_key('zoomx'):
364
365 ax.zoomx(kw['zoomx'])
366
367 if kw.has_key('zoomy'):
368
369 ax.zoomy(kw['zoomy'])
370
371 if kw.has_key("xtick.color"):
372 for i in ax.xaxis.get_ticklabels():
373 i.set_color(kw['xtick.color'])
374 if kw.has_key("ytick.color"):
375 for i in ax.yaxis.get_ticklabels():
376 i.set_color(kw['ytick.color'])
377
378 if kw.has_key('xtick.labelrotation'):
379 for i in ax.xaxis.get_ticklabels():
380 i.set_rotation(float(kw['xtick.labelrotation']))
381 if kw.has_key('ytick.labelrotation'):
382 for i in ax.yaxis.get_ticklabels():
383 i.set_rotation(float(kw['ytick.labelrotation']))
384 if kw.has_key("xtick.labelsize"):
385 for i in ax.xaxis.get_ticklabels():
386 i.set_size(float(kw['xtick.labelsize']))
387 if kw.has_key("ytick.labelsize"):
388 for i in ax.yaxis.get_ticklabels():
389 i.set_size(float(kw['ytick.labelsize']))
390 if kw.has_key("linewidth"):
391 ax.axesFrame.set_linewidth(float(kw['linewidth']))
392
393
394 if kw.has_key("markeredgewidth"):
395 for i in ax.get_xticklines():
396 i.set_markeredgewidth(kw['markeredgewidth'])
397 for i in ax.get_yticklines():
398 i.set_markeredgewidth(kw['markeredgewidth'])
399
400 if kw.has_key("markeredgecolor"):
401 for i in ax.get_xticklines():
402 i.set_markeredgecolor(kw['markeredgecolor'])
403 for i in ax.get_yticklines():
404 i.set_markeredgecolor(kw['markeredgecolor'])
405
406 if kw.has_key("markerfacecolor"):
407 for i in ax.get_xticklines():
408 i.set_markerfacecolor(kw['markerfacecolor'])
409 for i in ax.get_yticklines():
410 i.set_markerfacecolor(kw['markerfacecolor'])
411
412
413 if kw.has_key("figpatch_linewidth"):
414 ax.figure.figurePatch.set_linewidth(kw['figpatch_linewidth'])
415 if kw.has_key("figpatch_facecolor"):
416 ax.figure.figurePatch.set_facecolor(kw['figpatch_facecolor'])
417 if kw.has_key("figpatch_edgecolor"):
418 ax.figure.figurePatch.set_edgecolor(kw['figpatch_edgecolor'])
419 if kw.has_key("figpatch_antialiased"):
420 ax.figure.figurePatch.set_antialiased(kw['figpatch_antialiased'])
421
422
423 if kw.has_key('text'):
424 for i in kw['text']:
425 if type(i)==types.DictType:
426 tlab=i['textlabel']
427 posx=i['posx']
428 posy=i['posy']
429 horizontalalignment=i['horizontalalignment']
430 verticalalignment=i['verticalalignment']
431 rotation=i['rotation']
432 ax.text(x=posx,y=posy,s=tlab,horizontalalignment=horizontalalignment,verticalalignment=verticalalignment,rotation=rotation,transform = ax.transAxes)
433 if kw.has_key("text.color"):
434 for t in ax.texts:
435 t.set_color(kw['text.color'])
436 if kw.has_key("text.usetex"):
437 rcParams['text.usetex']=kw['text.usetex']
438 if kw.has_key("text.dvipnghack"):
439 rcParams['text.dvipnghack']=kw['text.dvipnghack']
440 if kw.has_key("text.fontstyle"):
441 for t in ax.texts:
442 t.set_fontstyle(kw['text.fontstyle'])
443 if kw.has_key("text.fontangle"):
444 for t in ax.texts:
445 t.set_fontangle(kw['text.fontangle'])
446 if kw.has_key("text.fontvariant"):
447 for t in ax.texts:
448 t.set_fontvariant(kw['text.fontvariant'])
449 if kw.has_key("text.fontweight"):
450 for t in ax.texts:
451 t.set_fontweight(kw['text.fontweight'])
452 if kw.has_key("text.fontsize"):
453 for t in ax.texts:
454 t.set_fontsize(kw['text.fontsize'])
455
456
457 if kw.has_key("Font.fontfamily"):
458 for t in ax.texts:
459 t.set_family(kw['Font.fontfamily'])
460 if kw.has_key("Font.fontstyle"):
461 for t in ax.texts:
462 t.set_fontstyle(kw['Font.fontstyle'])
463 if kw.has_key("Font.fontangle"):
464 for t in ax.texts:
465 t.set_fontangle(kw['Font.fontangle'])
466 if kw.has_key("Font.fontvariant"):
467 for t in ax.texts:
468 t.set_fontvariant(kw['Font.fontvariant'])
469 if kw.has_key("Font.fontweight"):
470 for t in ax.texts:
471 t.set_fontweight(kw['Font.fontweight'])
472 if kw.has_key("Font.fontsize"):
473 for t in ax.texts:
474 t.set_fontsize(kw['Font.fontsize'])
475
476
477 if kw.has_key('legendlabel'):
478 if ',' in kw['legendlabel']:
479 x=kw['legendlabel'].split(",")
480 else:
481 x=(kw['legendlabel'],)
482 if kw.has_key('legend.isaxes'):
483 isaxes=kw['legend.isaxes']
484 else:
485 isaxes=rcParams['legend.isaxes']
486
487 if kw.has_key('legend.numpoints'):
488 numpoints=kw['legend.numpoints']
489 else:
490 numpoints=rcParams['legend.numpoints']
491
492 if kw.has_key('legend.pad'):
493 pad=kw['legend.pad']
494 else:
495 pad=rcParams['legend.pad']
496
497 if kw.has_key('legend.markerscale'):
498 markerscale=kw['legend.markerscale']
499 else:
500 markerscale=rcParams['legend.markerscale']
501 if kw.has_key('legend.labelsep'):
502 labelsep=kw['legend.labelsep']
503 else:
504 labelsep=rcParams['legend.labelsep']
505 if kw.has_key('legend.handlelen'):
506 handlelen=kw['legend.handlelen']
507 else:
508 handlelen=rcParams['legend.handlelen']
509 if kw.has_key('legend.handletextsep'):
510 handletextsep=kw['legend.handletextsep']
511 else:
512 handletextsep=rcParams['legend.handletextsep']
513 if kw.has_key('legend.axespad'):
514 axespad=kw['legend.axespad']
515 else:
516 axespad=rcParams['legend.axespad']
517 if kw.has_key('legend.shadow'):
518 shadow=kw['legend.shadow']
519 else:
520 shadow=rcParams['legend.shadow']
521 leg=self.axes.legend(tuple(x),loc=kw['legendlocation'],isaxes=isaxes,numpoints=numpoints,pad=pad,labelsep=labelsep,handlelen=handlelen,handletextsep=handletextsep,axespad=axespad,shadow=shadow,markerscale=markerscale)
522 if kw.has_key('legend.fontsize'):
523 setp(ax.get_legend().get_texts(),fontsize=kw['legend.fontsize'])
524
525
526 if kw.has_key('xtick.major.pad'):
527 for i in ax.xaxis.majorTicks:
528 i.set_pad(kw['xtick.major.pad'])
529 if kw.has_key('xtick.minor.pad'):
530 for i in ax.xaxis.minorTicks:
531 i.set_pad(kw['xtick.minor.pad'])
532 if kw.has_key('ytick.major.pad'):
533 for i in ax.yaxis.majorTicks:
534 i.set_pad(kw['ytick.major.pad'])
535 if kw.has_key('ytick.minor.pad'):
536 for i in ax.yaxis.minorTicks:
537 i.set_pad(kw['ytick.minor.pad'])
538 if kw.has_key('xtick.major.size'):
539 rcParams['xtick.major.size']=kw['xtick.major.size']
540 if kw.has_key('xtick.minor.size'):
541 rcParams['xtick.minor.size']=kw['xtick.minor.size']
542 if kw.has_key('xtick.direction'):
543 rcParams['xtick.direction']=kw['xtick.direction']
544 if kw.has_key('ytick.major.size'):
545 rcParams['ytick.major.size']=kw['ytick.major.size']
546 if kw.has_key('ytick.minor.size'):
547 rcParams['ytick.minor.size']=kw['ytick.minor.size']
548 if kw.has_key('ytick.direction'):
549 rcParams['ytick.direction']=kw['ytick.direction']
550
551
552
554
555 NetworkNode.beforeRemovingFromNetwork(self)
556
557 if self.axes:
558
559 self.axes.figure.delaxes(self.axes)
560 self.canvas._tkcanvas.master.destroy()
561 elif self.canvas:
562 self.canvas._tkcanvas.master.destroy()
563
564
566 """returns true if only he first port (i.e. data) has new data.
567 """
568
569
570
571 ports = self.inputPorts
572 if not ports[0].hasNewData():
573 return False
574 for p in self.inputPorts:
575 if p.hasNewData():
576 return False
577
578 return True
579
580
581
763
765 """This node creates a PIL image
766
767 Input:
768 plots - Matplotlib Axes objects
769 figwidth - width in inches
770 figheigh - height in inches
771 dpi - resolution; defaults to rc figure.dpi
772 facecolor - the background color; defaults to rc figure.facecolor
773 edgecolor - the border color; defaults to rc figure.edgecolor
774 faceAlpha - alpha value of background
775 edgeAlpha - alpha value of edge
776 frameon - boolean
777 hold - boolean
778 toolbar - boolean (init option only)
779 packOpts - string representation of packing options
780
781 Output:
782 canvas: MPLFigure Object
783
784 Todo:
785 legend
786 text
787 image ?
788 """
789
790 - def __init__(self, name='imageFigure', **kw):
791 kw['name'] = name
792 apply( MPLBaseNE.__init__, (self,), kw )
793
794 codeBeforeDisconnect = """def beforeDisconnect(self, c):
795 node1 = c.port1.node
796 node2 = c.port2.node
797 if node1.figure.axes:
798 node1.figure.delaxes(node1.axes)
799 node1.figure.add_axes(node1.axes)
800 """
801 ip = self.inputPortsDescr
802 ip.append(datatype='MPLAxes', required=False, name='plots',
803 singleConnection=False,
804 beforeDisconnect=codeBeforeDisconnect)
805 ip.append(datatype='float', required=False, name='width')
806 ip.append(datatype='float', required=False, name='height')
807 ip.append(datatype='int', required=False, name='dpi')
808 ip.append(datatype='colorsRGB', required=False, name='facecolor')
809 ip.append(datatype='colorsRGB', required=False, name='edgecolor')
810 ip.append(datatype='float', required=False, name='alphaFace')
811 ip.append(datatype='float', required=False, name='alphaEdge')
812 ip.append(datatype='boolean', required=False, name='frameon')
813 ip.append(datatype='boolean', required=False, name='hold')
814
815 op = self.outputPortsDescr
816 op.append(datatype='image', name='image')
817
818 self.widgetDescr['width'] = {
819 'class':'NEThumbWheel','master':'ParamPanel',
820 'width':75, 'height':21, 'oneTurn':2, 'type':'float',
821 'wheelPad':2, 'initialValue':6.4,
822 'labelCfg':{'text':'width in inches'} }
823
824 self.widgetDescr['height'] = {
825 'class':'NEThumbWheel','master':'ParamPanel',
826 'width':75, 'height':21, 'oneTurn':2, 'type':'float',
827 'wheelPad':2, 'initialValue':4.8,
828 'labelCfg':{'text':'height in inches'} }
829
830 self.widgetDescr['dpi'] = {
831 'class':'NEThumbWheel','master':'ParamPanel',
832 'width':75, 'height':21, 'oneTurn':10, 'type':'int',
833 'wheelPad':2, 'initialValue':80,
834 'labelCfg':{'text':'DPI'} }
835
836 self.widgetDescr['alphaFace'] = {
837 'class':'NEThumbWheel','master':'ParamPanel',
838 'width':75, 'height':21, 'oneTurn':1., 'type':'float',
839 'wheelPad':2, 'initialValue':0.5, 'min':0.0, 'max':1.0,
840 'labelCfg':{'text':'alpha Face'} }
841
842 self.widgetDescr['alphaEdge'] = {
843 'class':'NEThumbWheel','master':'ParamPanel',
844 'width':75, 'height':21, 'oneTurn':1., 'type':'float',
845 'wheelPad':2, 'initialValue':0.5, 'min':0.0, 'max':1.0,
846 'labelCfg':{'text':'alphaEdge'} }
847
848 self.widgetDescr['frameon'] = {
849 'class':'NECheckButton', 'master':'ParamPanel',
850 'initialValue':1, 'labelCfg':{'text':'frame'} }
851
852 self.widgetDescr['hold'] = {
853 'class':'NECheckButton', 'master':'ParamPanel',
854 'initialValue':0, 'labelCfg':{'text':'hold'} }
855
856 code = """def doit(self, plots=None, width=None, height=None, dpi=None, facecolor=None, edgecolor=None, alphaFace=0.5, alphaEdge=0.5, frameon=True, hold=False):
857 figure = self.figure
858 try:
859 self.canvas.renderer.clear()
860 except AttributeError:
861 pass
862 figure.clear()
863
864 # Powers of 2 image to be clean
865 if width>height:
866 htc = float(height)/width
867 w = 512
868 h = int(512*htc)
869 else:
870 wtc = float(width)/height
871 w = int(512*wtc)
872 h = 512
873
874 dpi = figure.get_dpi()
875
876
877 #figure.set_figsize_inches(width,height)
878 figure.set_figsize_inches(w / dpi, h / dpi)
879
880 for p in plots:
881 if hasattr(p,"figure"):
882 p.figure.set_figwidth(w / dpi)
883 p.figure.set_figheight(h / dpi)
884 figure.add_axes(p)
885 p.set_figure(figure)
886 p.axesPatch.set_alpha(alphaFace)
887
888 # configure dpi
889 if dpi is not None:
890 figure.set_dpi(dpi)
891
892 # configure facecolor
893 if facecolor is not None:
894 figure.set_facecolor(tuple(facecolor[0]))
895
896 # configure edgecolor
897 if edgecolor is not None:
898 figure.set_edgecolor(tuple(edgecolor[0]))
899
900 # configure frameon
901 if frameon is not None:
902 figure.set_frameon(frameon)
903
904 figure.hold(hold)
905
906 figure.figurePatch.set_alpha(alphaEdge)
907 self.canvas.draw() # force a draw
908
909 import Image
910 im = self.canvas.buffer_rgba(0,0)
911 ima = Image.frombuffer("RGBA", (w,h), im)
912 ima = ima.transpose(Image.FLIP_TOP_BOTTOM)
913
914 self.outputData(image=ima)
915 """
916 self.setFunction(code)
917
918
925
927 self.figure = Figure()
928 from matplotlib.backends.backend_agg import FigureCanvasAgg
929 self.canvas = FigureCanvasAgg(self.figure)
930
931
932
934 """Class for configuring the axes.
935 The following options can be set.
936 left,bottom,width,height ----allows to set the position of the axes.
937 frame on/off --- allows to on or off frame
938 hold on/off --- allows to on or off hold.When hold is True, subsequent plot commands will be added to
939 the current axes. When hold is False, the current axes and figure will be cleared on
940 the next plot command
941 title --- allows to set title of the figure
942 xlabel ---allows to set xlabel of the figure
943 ylabel ---allows to set ylabel of the figure
944 xlimit --- set autoscale off before setting xlimit.
945 y limit --- set autoscale off before setting ylimit.
946 xticklabels on/off --- allows to on or off xticklabels
947 yticklabels on/off --- allows to on or off yticklabels
948 axis on/off --- allows to on or off axis
949 autoscale on/off --- when on sets default axes limits ,when off sets limit from xlimit and ylimit entries.
950 """
951
952 - def __init__(self, name='Draw Area', **kw):
953 kw['name'] = name
954 apply( NetworkNode.__init__, (self,), kw )
955
956 ip = self.inputPortsDescr
957 ip.append(datatype='float', required=False, name='left')
958 ip.append(datatype='float', required=False, name='bottom')
959 ip.append(datatype='float', required=False, name='width')
960 ip.append(datatype='float', required=False, name='height')
961 ip.append(datatype='boolean', required=False, name='frameon')
962 ip.append(datatype='boolean', required=False, name='hold')
963 ip.append(datatype='string', required=False, name='title')
964 ip.append(datatype='string', required=False, name='xlabel')
965 ip.append(datatype='string', required=False, name='ylabel')
966 ip.append(datatype='string', required=False, name='xlimit')
967 ip.append(datatype='string', required=False, name='ylimit')
968 ip.append(datatype='boolean', required=False, name='xticklabels')
969 ip.append(datatype='boolean', required=False, name='yticklabels')
970 ip.append(datatype='boolean', required=False, name='axison')
971 ip.append(datatype='boolean', required=False, name='autoscaleon')
972 self.widgetDescr['left'] = {
973 'class':'NEThumbWheel','master':'ParamPanel',
974 'width':75, 'height':21, 'oneTurn':1., 'type':'float',
975 'labelGridCfg':{'sticky':'w'},
976 'wheelPad':2, 'initialValue':0.1,
977 'labelCfg':{'text':'left (0. to 1.)'} }
978
979 self.widgetDescr['bottom'] = {
980 'class':'NEThumbWheel','master':'ParamPanel',
981 'width':75, 'height':21, 'oneTurn':1., 'type':'float',
982 'labelGridCfg':{'sticky':'w'},
983 'wheelPad':2, 'initialValue':0.1,
984 'labelCfg':{'text':'bottom (0. to 1.)'} }
985
986 self.widgetDescr['width'] = {
987 'class':'NEThumbWheel','master':'ParamPanel',
988 'width':75, 'height':21, 'oneTurn':1., 'type':'float',
989 'labelGridCfg':{'sticky':'w'},
990 'wheelPad':2, 'initialValue':0.8,
991 'labelCfg':{'text':'width (0. to 1.)'} }
992
993 self.widgetDescr['height'] = {
994 'class':'NEThumbWheel','master':'ParamPanel',
995 'width':75, 'height':21, 'oneTurn':1., 'type':'float',
996 'labelGridCfg':{'sticky':'w'},
997 'wheelPad':2, 'initialValue':0.8,
998 'labelCfg':{'text':'height (0. to 1.0)'} }
999
1000 self.widgetDescr['frameon'] = {
1001 'class':'NECheckButton', 'master':'ParamPanel',
1002 'labelGridCfg':{'sticky':'w'},
1003 'initialValue':1, 'labelCfg':{'text':'frame'} }
1004
1005 self.widgetDescr['hold'] = {
1006 'class':'NECheckButton', 'master':'ParamPanel',
1007 'labelGridCfg':{'sticky':'w'},
1008 'initialValue':0, 'labelCfg':{'text':'hold'} }
1009
1010 self.widgetDescr['title'] = {
1011 'class':'NEEntry', 'master':'ParamPanel',
1012 'labelCfg':{'text':'title'},'labelGridCfg':{'sticky':'w'},
1013 'initialValue':'Figure:'}
1014
1015 self.widgetDescr['xlabel'] = {
1016 'class':'NEEntry', 'master':'ParamPanel',
1017 'labelCfg':{'text':'X label'},'labelGridCfg':{'sticky':'w'},
1018 'initialValue':'X'}
1019
1020 self.widgetDescr['ylabel'] = {
1021 'class':'NEEntry', 'master':'ParamPanel','labelGridCfg':{'sticky':'w'},
1022 'labelCfg':{'text':'Y label'},
1023 'initialValue':'Y'}
1024
1025 self.widgetDescr['xlimit'] = {
1026 'class':'NEEntry', 'master':'ParamPanel','labelGridCfg':{'sticky':'w'},
1027 'labelCfg':{'text':'X limit'},
1028 'initialValue':''}
1029
1030 self.widgetDescr['ylimit'] = {
1031 'class':'NEEntry', 'master':'ParamPanel','labelGridCfg':{'sticky':'w'},
1032 'labelCfg':{'text':'Y limit'},
1033 'initialValue':''}
1034
1035 self.widgetDescr['xticklabels'] = {
1036 'class':'NECheckButton', 'master':'ParamPanel','labelGridCfg':{'sticky':'w'},
1037 'initialValue':1, 'labelCfg':{'text':'xticklabels'} }
1038
1039 self.widgetDescr['yticklabels'] = {
1040 'class':'NECheckButton', 'master':'ParamPanel','labelGridCfg':{'sticky':'w'},'labelGridCfg':{'sticky':'w'},
1041 'initialValue':1, 'labelCfg':{'text':'yticklabels'} }
1042
1043
1044 self.widgetDescr['axison'] = {
1045 'class':'NECheckButton', 'master':'ParamPanel',
1046 'initialValue':1, 'labelCfg':{'text':'axis on'} }
1047 self.widgetDescr['autoscaleon'] = {
1048 'class':'NECheckButton', 'master':'ParamPanel','labelGridCfg':{'sticky':'w'},
1049 'initialValue':1, 'labelCfg':{'text':'autoscale on'} }
1050 op = self.outputPortsDescr
1051 op.append(datatype='MPLDrawArea', name='drawAreaDef')
1052
1053 code = """def doit(self, left=.1, bottom=.1,
1054 width=.8, height=.8, frameon=True, hold=False, title='Figure', xlabel='X',
1055 ylabel='Y', xlimit='',ylimit='',xticklabels=True,yticklabels=True,axison=True,autoscaleon=True):
1056
1057 kw = {'left':left, 'bottom':bottom, 'width':width, 'height':height,
1058 'frameon':frameon, 'hold':hold, 'title':title, 'xlabel':xlabel,
1059 'ylabel':ylabel, 'axison':axison, 'xticklabels': xticklabels,'yticklabels': yticklabels,'xlimit':xlimit,'ylimit':ylimit,'autoscaleon':autoscaleon}
1060
1061 self.outputData(drawAreaDef=kw)
1062 """
1063 self.setFunction(code)
1064
1065
1066 -class MPLMergeTextNE(NetworkNode):
1067 """Class for writting multiple labels in the axes.Takes input from Text
1068 nodes.
1069 """
1070 - def __init__(self, name='MergeText', **kw):
1071 kw['name'] = name
1072 apply( NetworkNode.__init__, (self,), kw )
1073 ip = self.inputPortsDescr
1074 ip.append(datatype='MPLDrawArea', required=False,name='textlist',singleConnection=False)
1075 op = self.outputPortsDescr
1076 op.append(datatype='MPLDrawArea', name='drawAreaDef')
1077 code = """def doit(self,textlist):
1078 kw={'text':textlist}
1079 self.outputData(drawAreaDef=kw)"""
1080 self.setFunction(code)
1081
1083 """Base class for plotting nodes"""
1084
1086
1087 self.figure = Figure()
1088 self.axes = self.figure.add_subplot( 111 )
1089 self.axes.node = weakref.ref(self)
1090
1091 master = Tkinter.Toplevel()
1092 master.title(self.name)
1093 self.canvas = FigureCanvasTkAgg(self.figure, master)
1094 self.figure.set_canvas(self.canvas)
1095
1096 packOptsDict = {'side':'top', 'fill':'both', 'expand':1}
1097 self.canvas.get_tk_widget().pack( *(), **packOptsDict )
1098 self.canvas._master.protocol('WM_DELETE_WINDOW',self.canvas._master.iconify)
1099 toolbar = NavigationToolbar2TkAgg(self.canvas, master)
1100
1102 newdrawAreaDef={}
1103 if drawAreaDef:
1104 if len(drawAreaDef)==1 and drawAreaDef[0]!=None:
1105 for d in drawAreaDef[0].keys():
1106 newdrawAreaDef[d]=drawAreaDef[0][d]
1107 elif len(drawAreaDef)>1:
1108 for dAD in drawAreaDef:
1109 if type(dAD)== types.DictType:
1110 for j in dAD.keys():
1111 newdrawAreaDef[j]=dAD[j]
1112 self.setDrawArea(newdrawAreaDef)
1113
1114 codeBeforeDisconnect ="""def beforeDisconnect(self,c):
1115 node=c.port2.node
1116 node.axes.clear()
1117 node.canvas.draw() """
1118
1119
1120
1121
1122
1123
1124
1125 -class FillNE(MPLPlottingNode):
1126 """plots filled polygons.
1127 x - list of x vertices
1128 y - list of y vertices
1129 fillcolor - color
1130 """
1131
1132 - def __init__(self, name='Fill', **kw):