source: sasview/src/sas/sasgui/guiframe/local_perspectives/plotting/boxSum.py @ 952ea1f

magnetic_scattrelease-4.2.2ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249
Last change on this file since 952ea1f was 7432acb, checked in by andyfaff, 7 years ago

MAINT: search+replace '!= None' by 'is not None'

  • Property mode set to 100644
File size: 26.8 KB
Line 
1"""
2    Boxsum Class: determine 2 rectangular area to compute
3    the sum of pixel of a Data.
4"""
5import math
6import wx
7from BaseInteractor import _BaseInteractor
8from sas.sasgui.guiframe.events import SlicerParamUpdateEvent
9from sas.sasgui.guiframe.events import EVT_SLICER_PARS
10from sas.sasgui.guiframe.events import StatusEvent
11
12
13class BoxSum(_BaseInteractor):
14    """
15        Boxsum Class: determine 2 rectangular area to compute
16        the sum of pixel of a Data.
17        Uses PointerInteractor , VerticalDoubleLine,HorizontalDoubleLine.
18        @param zorder:  Artists with lower zorder values are drawn first.
19        @param x_min: the minimum value of the x coordinate
20        @param x_max: the maximum value of the x coordinate
21        @param y_min: the minimum value of the y coordinate
22        @param y_max: the maximum value of the y coordinate
23
24    """
25    def __init__(self, base, axes, color='black', zorder=3, x_min=0.008,
26                 x_max=0.008, y_min=0.0025, y_max=0.0025):
27        """
28        """
29        _BaseInteractor.__init__(self, base, axes, color=color)
30        # # class initialization
31        # # list of Boxsmun markers
32        self.markers = []
33        self.axes = axes
34        # # connect the artist for the motion
35        self.connect = self.base.connect
36        # # when qmax is reached the selected line is reset the its previous value
37        self.qmax = min(self.base.data2D.xmax, self.base.data2D.xmin)
38        # # Define the boxsum limits
39        self.xmin = -1 * 0.5 * min(math.fabs(self.base.data2D.xmax),
40                                   math.fabs(self.base.data2D.xmin))
41        self.ymin = -1 * 0.5 * min(math.fabs(self.base.data2D.xmax),
42                                   math.fabs(self.base.data2D.xmin))
43        self.xmax = 0.5 * min(math.fabs(self.base.data2D.xmax),
44                              math.fabs(self.base.data2D.xmin))
45        self.ymax = 0.5 * min(math.fabs(self.base.data2D.xmax),
46                              math.fabs(self.base.data2D.xmin))
47        # # center of the boxSum
48        self.center_x = 0.0002
49        self.center_y = 0.0003
50        # # Number of points on the plot
51        self.nbins = 20
52        # # Define initial result the summation
53        self.count = 0
54        self.error = 0
55        self.total = 0
56        self.totalerror = 0
57        self.points = 0
58        # # Flag to determine if the current figure has moved
59        # # set to False == no motion , set to True== motion
60        self.has_move = False
61        # # Create Boxsum edges
62        self.horizontal_lines = HorizontalDoubleLine(self,
63                                                     self.base.subplot,
64                                                     color='blue',
65                                                     zorder=zorder,
66                                                     y=self.ymax,
67                                                     x=self.xmax,
68                                                     center_x=self.center_x,
69                                                     center_y=self.center_y)
70        self.horizontal_lines.qmax = self.qmax
71
72        self.vertical_lines = VerticalDoubleLine(self,
73                                                 self.base.subplot,
74                                                 color='black',
75                                                 zorder=zorder,
76                                                 y=self.ymax,
77                                                 x=self.xmax,
78                                                 center_x=self.center_x,
79                                                 center_y=self.center_y)
80        self.vertical_lines.qmax = self.qmax
81
82        self.center = PointInteractor(self,
83                                      self.base.subplot, color='grey',
84                                      zorder=zorder,
85                                      center_x=self.center_x,
86                                      center_y=self.center_y)
87        # # Save the name of the slicer panel associate with this slicer
88        self.panel_name = ""
89        # # Update and post slicer parameters
90        self.update()
91        self._post_data()
92        # # Bind to slice parameter events
93        self.base.Bind(EVT_SLICER_PARS, self._onEVT_SLICER_PARS)
94
95    def set_panel_name(self, name):
96        """
97            Store the name of the panel associated to this slicer
98            @param name: the name of this panel
99        """
100        self.panel_name = name
101
102    def _onEVT_SLICER_PARS(self, event):
103        """
104            receive an event containing parameters values to reset the slicer
105            @param event: event of type SlicerParameterEvent with params as
106            attribute
107        """
108        # # Post e message to declare what kind of event has being received
109        wx.PostEvent(self.base.parent,
110                     StatusEvent(status="Boxsum._onEVT_SLICER_PARS"))
111        event.Skip()
112        # # reset the slicer with the values contains the event.params dictionary
113        if event.type == self.__class__.__name__:
114            self.set_params(event.params)
115            self.base.update()
116
117    def set_layer(self, n):
118        """
119        Allow adding plot to the same panel
120        :param n: the number of layer
121        """
122        self.layernum = n
123        self.update()
124
125    def clear(self):
126        """
127        Clear the slicer and all connected events related to this slicer
128        """
129        self.clear_markers()
130        self.horizontal_lines.clear()
131        self.vertical_lines.clear()
132        self.center.clear()
133        self.base.connect.clearall()
134        self.base.Unbind(EVT_SLICER_PARS)
135
136    def update(self):
137        """
138        Respond to changes in the model by recalculating the profiles and
139        resetting the widgets.
140        """
141        # # check if the center point has moved and update the figure accordingly
142        if self.center.has_move:
143            self.center.update()
144            self.horizontal_lines.update(center=self.center)
145            self.vertical_lines.update(center=self.center)
146        # # check if the horizontal lines have moved and
147        # update the figure accordingly
148        if self.horizontal_lines.has_move:
149            self.horizontal_lines.update()
150            self.vertical_lines.update(y1=self.horizontal_lines.y1,
151                                       y2=self.horizontal_lines.y2,
152                                       height=self.horizontal_lines.half_height)
153        # # check if the vertical lines have moved and
154        # update the figure accordingly
155        if self.vertical_lines.has_move:
156            self.vertical_lines.update()
157            self.horizontal_lines.update(x1=self.vertical_lines.x1,
158                                         x2=self.vertical_lines.x2,
159                                         width=self.vertical_lines.half_width)
160
161    def save(self, ev):
162        """
163        Remember the roughness for this layer and the next so that we
164        can restore on Esc.
165        """
166        self.base.freeze_axes()
167        self.horizontal_lines.save(ev)
168        self.vertical_lines.save(ev)
169        self.center.save(ev)
170
171    def _post_data(self):
172        """
173        Get the limits of the boxsum and compute the sum of the pixel
174        contained in that region and the error on that sum
175        """
176        # # the region of the summation
177        x_min = self.horizontal_lines.x2
178        x_max = self.horizontal_lines.x1
179        y_min = self.vertical_lines.y2
180        y_max = self.vertical_lines.y1
181        # #computation of the sum and its error
182        from sas.sascalc.dataloader.manipulations import Boxavg
183        box = Boxavg(x_min=x_min, x_max=x_max, y_min=y_min, y_max=y_max)
184        self.count, self.error = box(self.base.data2D)
185        # Dig out number of points summed, SMK & PDB, 04/03/2013
186        from sas.sascalc.dataloader.manipulations import Boxsum
187        boxtotal = Boxsum(x_min=x_min, x_max=x_max, y_min=y_min, y_max=y_max)
188        self.total, self.totalerror, self.points = boxtotal(self.base.data2D)
189
190    def moveend(self, ev):
191        """
192            After a dragging motion this function is called to compute
193            the error and the sum of pixel of a given data 2D
194        """
195        self.base.thaw_axes()
196        # # compute error an d sum of data's pixel
197        self._post_data()
198        # # Create and event ( posted to guiframe)that  set the
199        # #current slicer parameter to a panel of name self.panel_name
200        self.type = self.__class__.__name__
201        params = self.get_params()
202        event = SlicerParamUpdateEvent(type=self.type,
203                                       params=params,
204                                       panel_name=self.panel_name)
205        wx.PostEvent(self.base.parent, event)
206
207    def restore(self):
208        """
209        Restore the roughness for this layer.
210        """
211        self.horizontal_lines.restore()
212        self.vertical_lines.restore()
213        self.center.restore()
214
215    def move(self, x, y, ev):
216        """
217        Process move to a new position, making sure that the move is allowed.
218        """
219        pass
220
221    def set_cursor(self, x, y):
222        """
223        """
224        pass
225
226    def get_params(self):
227        """
228        Store a copy of values of parameters of the slicer into a dictionary.
229        :return params: the dictionary created
230        """
231        params = {}
232        params["Width"] = math.fabs(self.vertical_lines.half_width) * 2
233        params["Height"] = math.fabs(self.horizontal_lines.half_height) * 2
234        params["center_x"] = self.center.x
235        params["center_y"] = self.center.y
236        params["num_points"] = self.points
237        params["avg"] = self.count
238        params["avg_error"] = self.error
239        params["sum"] = self.total
240        params["sum_error"] = self.totalerror
241        return params
242
243    def get_result(self):
244        """
245            return the result of box summation
246        """
247        result = {}
248        result["num_points"] = self.points
249        result["avg"] = self.count
250        result["avg_error"] = self.error
251        result["sum"] = self.total
252        result["sum_error"] = self.totalerror
253        return result
254
255    def set_params(self, params):
256        """
257        Receive a dictionary and reset the slicer with values contained
258        in the values of the dictionary.
259        :param params: a dictionary containing name of slicer parameters and values the user assigned to the slicer.
260        """
261        x_max = math.fabs(params["Width"]) / 2
262        y_max = math.fabs(params["Height"]) / 2
263
264        self.center_x = params["center_x"]
265        self.center_y = params["center_y"]
266        # update the slicer given values of params
267        self.center.update(center_x=self.center_x, center_y=self.center_y)
268        self.horizontal_lines.update(center=self.center,
269                                     width=x_max, height=y_max)
270        self.vertical_lines.update(center=self.center,
271                                   width=x_max, height=y_max)
272        # compute the new error and sum given values of params
273        self._post_data()
274
275    def freeze_axes(self):
276        """
277        """
278        self.base.freeze_axes()
279
280    def thaw_axes(self):
281        """
282        """
283        self.base.thaw_axes()
284
285    def draw(self):
286        """
287        """
288        self.base.draw()
289
290
291
292class PointInteractor(_BaseInteractor):
293    """
294    Draw a point that can be dragged with the marker.
295    this class controls the motion the center of the BoxSum
296    """
297    def __init__(self, base, axes, color='black', zorder=5, center_x=0.0,
298                 center_y=0.0):
299        """
300        """
301        _BaseInteractor.__init__(self, base, axes, color=color)
302        # # Initialization the class
303        self.markers = []
304        self.axes = axes
305        # center coordinates
306        self.x = center_x
307        self.y = center_y
308        # # saved value of the center coordinates
309        self.save_x = center_x
310        self.save_y = center_y
311        # # Create a marker
312        self.center_marker = self.axes.plot([self.x], [self.y], linestyle='',
313                                            marker='s', markersize=10,
314                                            color=self.color, alpha=0.6,
315                                            pickradius=5, label="pick",
316                                            zorder=zorder,
317                                            visible=True)[0]
318        # # Draw a point
319        self.center = self.axes.plot([self.x], [self.y],
320                                     linestyle='-', marker='',
321                                     color=self.color,
322                                     visible=True)[0]
323        # # Flag to determine the motion this point
324        self.has_move = False
325        # # connecting the marker to allow them to move
326        self.connect_markers([self.center_marker])
327        # # Update the figure
328        self.update()
329
330    def set_layer(self, n):
331        """
332            Allow adding plot to the same panel
333            @param n: the number of layer
334        """
335        self.layernum = n
336        self.update()
337
338    def clear(self):
339        """
340            Clear this figure and its markers
341        """
342        self.clear_markers()
343        try:
344            self.center.remove()
345            self.center_marker.remove()
346        except:
347            # Old version of matplotlib
348            for item in range(len(self.axes.lines)):
349                del self.axes.lines[0]
350
351    def update(self, center_x=None, center_y=None):
352        """
353            Draw the new roughness on the graph.
354        """
355        if center_x is not None:
356            self.x = center_x
357        if center_y is not None:
358            self.y = center_y
359        self.center_marker.set(xdata=[self.x], ydata=[self.y])
360        self.center.set(xdata=[self.x], ydata=[self.y])
361
362    def save(self, ev):
363        """
364        Remember the roughness for this layer and the next so that we
365        can restore on Esc.
366        """
367        self.save_x = self.x
368        self.save_y = self.y
369        self.base.freeze_axes()
370
371    def moveend(self, ev):
372        """
373        """
374        self.has_move = False
375        self.base.moveend(ev)
376
377    def restore(self):
378        """
379        Restore the roughness for this layer.
380        """
381        self.y = self.save_y
382        self.x = self.save_x
383
384    def move(self, x, y, ev):
385        """
386        Process move to a new position, making sure that the move is allowed.
387        """
388        self.x = x
389        self.y = y
390        self.has_move = True
391        self.base.base.update()
392
393    def set_cursor(self, x, y):
394        """
395        """
396        self.move(x, y, None)
397        self.update()
398
399class VerticalDoubleLine(_BaseInteractor):
400    """
401         Draw 2 vertical lines moving in opposite direction and centered on
402         a point (PointInteractor)
403    """
404    def __init__(self, base, axes, color='black', zorder=5, x=0.5, y=0.5,
405                 center_x=0.0, center_y=0.0):
406        """
407        """
408        _BaseInteractor.__init__(self, base, axes, color=color)
409        # # Initialization the class
410        self.markers = []
411        self.axes = axes
412        # # Center coordinates
413        self.center_x = center_x
414        self.center_y = center_y
415        # # defined end points vertical lignes and their saved values
416        self.y1 = y + self.center_y
417        self.save_y1 = self.y1
418
419        delta = self.y1 - self.center_y
420        self.y2 = self.center_y - delta
421        self.save_y2 = self.y2
422
423        self.x1 = x + self.center_x
424        self.save_x1 = self.x1
425
426        delta = self.x1 - self.center_x
427        self.x2 = self.center_x - delta
428        self.save_x2 = self.x2
429        # # save the color of the line
430        self.color = color
431        # # the height of the rectangle
432        self.half_height = math.fabs(y)
433        self.save_half_height = math.fabs(y)
434        # # the with of the rectangle
435        self.half_width = math.fabs(self.x1 - self.x2) / 2
436        self.save_half_width = math.fabs(self.x1 - self.x2) / 2
437        # # Create marker
438        self.right_marker = self.axes.plot([self.x1], [0], linestyle='',
439                                           marker='s', markersize=10,
440                                           color=self.color, alpha=0.6,
441                                           pickradius=5, label="pick",
442                                           zorder=zorder, visible=True)[0]
443
444        # # define the left and right lines of the rectangle
445        self.right_line = self.axes.plot([self.x1, self.x1], [self.y1, self.y2],
446                                         linestyle='-', marker='',
447                                         color=self.color, visible=True)[0]
448        self.left_line = self.axes.plot([self.x2, self.x2], [self.y1, self.y2],
449                                        linestyle='-', marker='',
450                                        color=self.color, visible=True)[0]
451        # # Flag to determine if the lines have moved
452        self.has_move = False
453        # # connection the marker and draw the pictures
454        self.connect_markers([self.right_marker])
455        self.update()
456
457    def set_layer(self, n):
458        """
459        Allow adding plot to the same panel
460        :param n: the number of layer
461        """
462        self.layernum = n
463        self.update()
464
465    def clear(self):
466        """
467        Clear this slicer  and its markers
468        """
469        self.clear_markers()
470        try:
471            self.right_marker.remove()
472            self.right_line.remove()
473            self.left_line.remove()
474        except:
475            # Old version of matplotlib
476            for item in range(len(self.axes.lines)):
477                del self.axes.lines[0]
478
479    def update(self, x1=None, x2=None, y1=None, y2=None, width=None,
480               height=None, center=None):
481        """
482        Draw the new roughness on the graph.
483        :param x1: new maximum value of x coordinates
484        :param x2: new minimum value of x coordinates
485        :param y1: new maximum value of y coordinates
486        :param y2: new minimum value of y coordinates
487        :param width: is the width of the new rectangle
488        :param height: is the height of the new rectangle
489        :param center: provided x, y  coordinates of the center point
490        """
491        # # save the new height, witdh of the rectangle if given as a param
492        if width is not None:
493            self.half_width = width
494        if height is not None:
495            self.half_height = height
496        # # If new  center coordinates are given draw the rectangle
497        # #given these value
498        if center is not None:
499            self.center_x = center.x
500            self.center_y = center.y
501            self.x1 = self.half_width + self.center_x
502            self.x2 = -self.half_width + self.center_x
503            self.y1 = self.half_height + self.center_y
504            self.y2 = -self.half_height + self.center_y
505
506            self.right_marker.set(xdata=[self.x1], ydata=[self.center_y])
507            self.right_line.set(xdata=[self.x1, self.x1],
508                                ydata=[self.y1, self.y2])
509            self.left_line.set(xdata=[self.x2, self.x2],
510                               ydata=[self.y1, self.y2])
511            return
512        # # if x1, y1, y2, y3 are given draw the rectangle with this value
513        if x1 is not None:
514            self.x1 = x1
515        if x2 is not None:
516            self.x2 = x2
517        if y1 is not None:
518            self.y1 = y1
519        if y2 is not None:
520            self.y2 = y2
521        # # Draw 2 vertical lines and a marker
522        self.right_marker.set(xdata=[self.x1], ydata=[self.center_y])
523        self.right_line.set(xdata=[self.x1, self.x1], ydata=[self.y1, self.y2])
524        self.left_line.set(xdata=[self.x2, self.x2], ydata=[self.y1, self.y2])
525
526    def save(self, ev):
527        """
528        Remember the roughness for this layer and the next so that we
529        can restore on Esc.
530        """
531        self.save_x2 = self.x2
532        self.save_y2 = self.y2
533        self.save_x1 = self.x1
534        self.save_y1 = self.y1
535        self.save_half_height = self.half_height
536        self.save_half_width = self.half_width
537        self.base.freeze_axes()
538
539    def moveend(self, ev):
540        """
541            After a dragging motion reset the flag self.has_move to False
542        """
543        self.has_move = False
544        self.base.moveend(ev)
545
546    def restore(self):
547        """
548        Restore the roughness for this layer.
549        """
550        self.y2 = self.save_y2
551        self.x2 = self.save_x2
552        self.y1 = self.save_y1
553        self.x1 = self.save_x1
554        self.half_height = self.save_half_height
555        self.half_width = self.save_half_width
556
557    def move(self, x, y, ev):
558        """
559        Process move to a new position, making sure that the move is allowed.
560        """
561        self.x1 = x
562        delta = self.x1 - self.center_x
563        self.x2 = self.center_x - delta
564        self.half_width = math.fabs(self.x1 - self.x2) / 2
565        self.has_move = True
566        self.base.base.update()
567
568    def set_cursor(self, x, y):
569        """
570            Update the figure given x and y
571        """
572        self.move(x, y, None)
573        self.update()
574
575class HorizontalDoubleLine(_BaseInteractor):
576    """
577         Select an annulus through a 2D plot
578    """
579    def __init__(self, base, axes, color='black', zorder=5, x=0.5, y=0.5,
580                 center_x=0.0, center_y=0.0):
581
582        _BaseInteractor.__init__(self, base, axes, color=color)
583        # # Initialization the class
584        self.markers = []
585        self.axes = axes
586        # # Center coordinates
587        self.center_x = center_x
588        self.center_y = center_y
589        self.y1 = y + self.center_y
590        self.save_y1 = self.y1
591        delta = self.y1 - self.center_y
592        self.y2 = self.center_y - delta
593        self.save_y2 = self.y2
594        self.x1 = x + self.center_x
595        self.save_x1 = self.x1
596        delta = self.x1 - self.center_x
597        self.x2 = self.center_x - delta
598        self.save_x2 = self.x2
599        self.color = color
600        self.half_height = math.fabs(y)
601        self.save_half_height = math.fabs(y)
602        self.half_width = math.fabs(x)
603        self.save_half_width = math.fabs(x)
604        self.top_marker = self.axes.plot([0], [self.y1], linestyle='',
605                                         marker='s', markersize=10,
606                                         color=self.color, alpha=0.6,
607                                         pickradius=5, label="pick",
608                                         zorder=zorder, visible=True)[0]
609
610        # Define 2 horizotnal lines
611        self.top_line = self.axes.plot([self.x1, -self.x1], [self.y1, self.y1],
612                                       linestyle='-', marker='',
613                                       color=self.color, visible=True)[0]
614        self.bottom_line = self.axes.plot([self.x1, -self.x1],
615                                          [self.y2, self.y2],
616                                          linestyle='-', marker='',
617                                          color=self.color, visible=True)[0]
618        # # Flag to determine if the lines have moved
619        self.has_move = False
620        # # connection the marker and draw the pictures
621        self.connect_markers([self.top_marker])
622        self.update()
623
624    def set_layer(self, n):
625        """
626            Allow adding plot to the same panel
627            @param n: the number of layer
628        """
629        self.layernum = n
630        self.update()
631
632    def clear(self):
633        """
634            Clear this figure and its markers
635        """
636        self.clear_markers()
637        try:
638            self.top_marker.remove()
639            self.bottom_line.remove()
640            self.top_line.remove()
641        except:
642            # Old version of matplotlib
643            for item in range(len(self.axes.lines)):
644                del self.axes.lines[0]
645
646    def update(self, x1=None, x2=None, y1=None, y2=None,
647               width=None, height=None, center=None):
648        """
649        Draw the new roughness on the graph.
650        :param x1: new maximum value of x coordinates
651        :param x2: new minimum value of x coordinates
652        :param y1: new maximum value of y coordinates
653        :param y2: new minimum value of y coordinates
654        :param width: is the width of the new rectangle
655        :param height: is the height of the new rectangle
656        :param center: provided x, y  coordinates of the center point
657        """
658        # # save the new height, witdh of the rectangle if given as a param
659        if width is not None:
660            self.half_width = width
661        if height is not None:
662            self.half_height = height
663        # # If new  center coordinates are given draw the rectangle
664        # #given these value
665        if center is not None:
666            self.center_x = center.x
667            self.center_y = center.y
668            self.x1 = self.half_width + self.center_x
669            self.x2 = -self.half_width + self.center_x
670
671            self.y1 = self.half_height + self.center_y
672            self.y2 = -self.half_height + self.center_y
673
674            self.top_marker.set(xdata=[self.center_x], ydata=[self.y1])
675            self.top_line.set(xdata=[self.x1, self.x2],
676                              ydata=[self.y1, self.y1])
677            self.bottom_line.set(xdata=[self.x1, self.x2],
678                                 ydata=[self.y2, self.y2])
679            return
680        # # if x1, y1, y2, y3 are given draw the rectangle with this value
681        if x1 is not None:
682            self.x1 = x1
683        if x2 is not None:
684            self.x2 = x2
685        if y1 is not None:
686            self.y1 = y1
687        if y2 is not None:
688            self.y2 = y2
689        # # Draw 2 vertical lines and a marker
690        self.top_marker.set(xdata=[self.center_x], ydata=[self.y1])
691        self.top_line.set(xdata=[self.x1, self.x2], ydata=[self.y1, self.y1])
692        self.bottom_line.set(xdata=[self.x1, self.x2], ydata=[self.y2, self.y2])
693
694    def save(self, ev):
695        """
696        Remember the roughness for this layer and the next so that we
697        can restore on Esc.
698        """
699        self.save_x2 = self.x2
700        self.save_y2 = self.y2
701        self.save_x1 = self.x1
702        self.save_y1 = self.y1
703        self.save_half_height = self.half_height
704        self.save_half_width = self.half_width
705        self.base.freeze_axes()
706
707    def moveend(self, ev):
708        """
709        After a dragging motion reset the flag self.has_move to False
710        """
711        self.has_move = False
712        self.base.moveend(ev)
713
714    def restore(self):
715        """
716        Restore the roughness for this layer.
717        """
718        self.y2 = self.save_y2
719        self.x2 = self.save_x2
720        self.y1 = self.save_y1
721        self.x1 = self.save_x1
722        self.half_height = self.save_half_height
723        self.half_width = self.save_half_width
724
725    def move(self, x, y, ev):
726        """
727        Process move to a new position, making sure that the move is allowed.
728        """
729        self.y1 = y
730        delta = self.y1 - self.center_y
731        self.y2 = self.center_y - delta
732        self.half_height = math.fabs(self.y1) - self.center_y
733        self.has_move = True
734        self.base.base.update()
735
736    def set_cursor(self, x, y):
737        """
738            Update the figure given x and y
739        """
740        self.move(x, y, None)
741        self.update()
Note: See TracBrowser for help on using the repository browser.