Changeset 824e488 in sasview for src/sas/guiframe
- Timestamp:
- Mar 5, 2015 2:18:47 PM (10 years ago)
- Branches:
- master, ESS_GUI, ESS_GUI_Docs, ESS_GUI_batch_fitting, ESS_GUI_bumps_abstraction, ESS_GUI_iss1116, ESS_GUI_iss879, ESS_GUI_iss959, ESS_GUI_opencl, ESS_GUI_ordering, ESS_GUI_sync_sascalc, costrafo411, magnetic_scatt, release-4.1.1, release-4.1.2, release-4.2.2, release_4.0.1, ticket-1009, ticket-1094-headless, ticket-1242-2d-resolution, ticket-1243, ticket-1249, ticket885, unittest-saveload
- Children:
- b5de88e
- Parents:
- b9dbd6b
- Location:
- src/sas/guiframe/local_perspectives/plotting
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
src/sas/guiframe/local_perspectives/plotting/AnnulusSlicer.py
r400155b r824e488 1 # TODO: the line slicer should listen to all 2DREFRESH events, get the data and slice it1 # TODO: the line slicer should listen to all 2DREFRESH events, get the data and slice it 2 2 # before pushing a new 1D data update. 3 3 4 4 # 5 # TODO: NEED MAJOR REFACTOR5 # TODO: NEED MAJOR REFACTOR 6 6 # 7 7 8 8 import math 9 9 import wx 10 # from copy import deepcopy10 # from copy import deepcopy 11 11 # Debug printout 12 12 from sas.guiframe.events import NewPlotEvent … … 20 20 """ 21 21 Select an annulus through a 2D plot. 22 This interactor is used to average 2D data with the region 22 This interactor is used to average 2D data with the region 23 23 defined by 2 radius. 24 24 this class is defined by 2 Ringinterators. 25 25 """ 26 26 def __init__(self, base, axes, color='black', zorder=3): 27 27 28 28 _BaseInteractor.__init__(self, base, axes, color=color) 29 29 self.markers = [] … … 31 31 self.base = base 32 32 self.qmax = min(math.fabs(self.base.data2D.xmax), 33 math.fabs(self.base.data2D.xmin)) # must be positive33 math.fabs(self.base.data2D.xmin)) # must be positive 34 34 self.connect = self.base.connect 35 36 # # Number of points on the plot35 36 # # Number of points on the plot 37 37 self.nbins = 36 38 # Cursor position of Rings (Left(-1) or Right(1))38 # Cursor position of Rings (Left(-1) or Right(1)) 39 39 self.xmaxd = self.base.data2D.xmax 40 40 self.xmind = self.base.data2D.xmin … … 46 46 # Inner circle 47 47 self.inner_circle = RingInteractor(self, self.base.subplot, 48 49 r=self.qmax/2.0, sign=self.sign)48 zorder=zorder, 49 r=self.qmax / 2.0, sign=self.sign) 50 50 self.inner_circle.qmax = self.qmax 51 51 self.outer_circle = RingInteractor(self, self.base.subplot, 52 zorder=zorder +1, r=self.qmax/1.8,52 zorder=zorder + 1, r=self.qmax / 1.8, 53 53 sign=self.sign) 54 54 self.outer_circle.qmax = self.qmax * 1.2 55 55 self.update() 56 56 self._post_data() 57 57 58 58 # Bind to slice parameter events 59 59 self.base.Bind(EVT_SLICER_PARS, self._onEVT_SLICER_PARS) 60 60 61 61 def _onEVT_SLICER_PARS(self, event): 62 62 """ 63 63 receive an event containing parameters values to reset the slicer 64 65 :param event: event of type SlicerParameterEvent with params as 64 65 :param event: event of type SlicerParameterEvent with params as 66 66 attribute 67 67 68 68 """ 69 69 wx.PostEvent(self.base, … … 77 77 """ 78 78 Allow adding plot to the same panel 79 79 80 80 :param n: the number of layer 81 81 82 82 """ 83 83 self.layernum = n 84 84 self.update() 85 85 86 86 def clear(self): 87 87 """ … … 93 93 self.base.connect.clearall() 94 94 self.base.Unbind(EVT_SLICER_PARS) 95 95 96 96 def update(self): 97 97 """ … … 99 99 resetting the widgets. 100 100 """ 101 # Update locations 101 # Update locations 102 102 self.inner_circle.update() 103 103 self.outer_circle.update() 104 104 105 105 def save(self, ev): 106 106 """ … … 115 115 """ 116 116 Uses annulus parameters to plot averaged data into 1D data. 117 118 :param nbins: the number of points to plot 119 120 """ 121 # Data to average117 118 :param nbins: the number of points to plot 119 120 """ 121 # Data to average 122 122 data = self.base.data2D 123 123 # If we have no data, just return 124 124 if data == None: 125 125 return 126 126 127 127 from sas.dataloader.manipulations import Ring 128 128 rmin = min(math.fabs(self.inner_circle.get_radius()), 129 math.fabs(self.outer_circle.get_radius()))129 math.fabs(self.outer_circle.get_radius())) 130 130 rmax = max(math.fabs(self.inner_circle.get_radius()), 131 131 math.fabs(self.outer_circle.get_radius())) 132 # if the user does not specify the numbers of points to plot132 # if the user does not specify the numbers of points to plot 133 133 # the default number will be nbins= 36 134 134 if nbins == None: … … 136 136 else: 137 137 self.nbins = nbins 138 # # create the data1D Q average of data2D138 # # create the data1D Q average of data2D 139 139 sect = Ring(r_min=rmin, r_max=rmax, nbins=self.nbins) 140 140 sector = sect(self.base.data2D) 141 141 142 142 if hasattr(sector, "dxl"): 143 143 dxl = sector.dxl … … 148 148 else: 149 149 dxw = None 150 new_plot = Data1D(x=(sector.x - math.pi) * 180 /math.pi,150 new_plot = Data1D(x=(sector.x - math.pi) * 180 / math.pi, 151 151 y=sector.y, dy=sector.dy) 152 152 new_plot.dxl = dxl 153 153 new_plot.dxw = dxw 154 new_plot.name = "AnnulusPhi" + "("+ self.base.data2D.name+")"155 154 new_plot.name = "AnnulusPhi" + "(" + self.base.data2D.name + ")" 155 156 156 new_plot.source = self.base.data2D.source 157 # new_plot.info=self.base.data2D.info157 # new_plot.info=self.base.data2D.info 158 158 new_plot.interactive = True 159 159 new_plot.detector = self.base.data2D.detector … … 168 168 new_plot.group_id = "AnnulusPhi" + self.base.data2D.name 169 169 new_plot.id = "AnnulusPhi" + self.base.data2D.name 170 new_plot.is_data = True170 new_plot.is_data = True 171 171 new_plot.xtransform = "x" 172 172 new_plot.ytransform = "y" 173 173 self.base.parent.update_theory(data_id=data.id, theory=new_plot) 174 wx.PostEvent(self.base.parent, NewPlotEvent(plot=new_plot, 175 title="AnnulusPhi")) 176 174 wx.PostEvent(self.base.parent, NewPlotEvent(plot=new_plot, title="AnnulusPhi")) 175 177 176 def moveend(self, ev): 178 177 """ … … 188 187 event.params = self.get_params() 189 188 wx.PostEvent(self.base, event) 190 # create a 1D data plot 191 #self._post_data() 192 189 193 190 def restore(self): 194 191 """ … … 203 200 """ 204 201 pass 205 202 206 203 def set_cursor(self, x, y): 207 204 pass 208 205 209 206 def get_params(self): 210 207 """ 211 208 Store a copy of values of parameters of the slicer into a dictionary. 212 209 213 210 :return params: the dictionary created 214 211 215 212 """ 216 213 params = {} … … 219 216 params["nbins"] = self.nbins 220 217 return params 221 218 222 219 def set_params(self, params): 223 220 """ 224 Receive a dictionary and reset the slicer with values contained 221 Receive a dictionary and reset the slicer with values contained 225 222 in the values of the dictionary. 226 227 :param params: a dictionary containing name of slicer parameters and 223 224 :param params: a dictionary containing name of slicer parameters and 228 225 values the user assigned to the slicer. 229 226 230 227 """ 231 228 inner = math.fabs(params["inner_radius"]) 232 229 outer = math.fabs(params["outer_radius"]) 233 230 self.nbins = int(params["nbins"]) 234 # # Update the picture231 # # Update the picture 235 232 self.inner_circle.set_cursor(inner, self.inner_circle._inner_mouse_y) 236 233 self.outer_circle.set_cursor(outer, self.outer_circle._inner_mouse_y) 237 # # Post the data given the nbins entered by the user234 # # Post the data given the nbins entered by the user 238 235 self._post_data(self.nbins) 239 236 240 237 def freeze_axes(self): 241 238 """ 242 239 """ 243 240 self.base.freeze_axes() 244 241 245 242 def thaw_axes(self): 246 243 """ … … 253 250 self.base.draw() 254 251 255 252 256 253 class RingInteractor(_BaseInteractor): 257 254 """ 258 Draw a ring Given a radius 255 Draw a ring Given a radius 259 256 """ 260 257 def __init__(self, base, axes, color='black', zorder=5, r=1.0, sign=1): … … 262 259 :param: the color of the line that defined the ring 263 260 :param r: the radius of the ring 264 :param sign: the direction of motion the the marker 265 261 :param sign: the direction of motion the the marker 262 266 263 """ 267 264 _BaseInteractor.__init__(self, base, axes, color=color) … … 270 267 # Current radius of the ring 271 268 self._inner_mouse_x = r 272 # Value of the center of the ring269 # Value of the center of the ring 273 270 self._inner_mouse_y = 0 274 271 # previous value of that radius 275 self._inner_save_x 276 # Save value of the center of the ring277 self._inner_save_y 278 # Class instantiating RingIterator class272 self._inner_save_x = r 273 # Save value of the center of the ring 274 self._inner_save_y = 0 275 # Class instantiating RingIterator class 279 276 self.base = base 280 # the direction of the motion of the marker277 # the direction of the motion of the marker 281 278 self.sign = sign 282 # # Create a marker279 # # Create a marker 283 280 try: 284 281 # Inner circle marker 285 282 x_value = [self.sign * math.fabs(self._inner_mouse_x)] 286 self.inner_marker = self.axes.plot(x_value, 287 [0], 288 linestyle='', 289 marker='s', markersize=10, 290 color=self.color, alpha=0.6, 291 pickradius=5, label="pick", 292 zorder=zorder, 293 visible=True)[0] 283 self.inner_marker = self.axes.plot(x_value, [0], linestyle='', 284 marker='s', markersize=10, 285 color=self.color, alpha=0.6, 286 pickradius=5, label="pick", 287 zorder=zorder, 288 visible=True)[0] 294 289 except: 295 290 x_value = [self.sign * math.fabs(self._inner_mouse_x)] 296 self.inner_marker = self.axes.plot(x_value, 297 [0], 298 linestyle='', 299 marker='s', markersize=10, 300 color=self.color, alpha=0.6, 301 label="pick", 302 visible=True)[0] 303 message = "\nTHIS PROTOTYPE NEEDS THE LATEST" 291 self.inner_marker = self.axes.plot(x_value, [0], linestyle='', 292 marker='s', markersize=10, 293 color=self.color, alpha=0.6, 294 label="pick", 295 visible=True)[0] 296 message = "\nTHIS PROTOTYPE NEEDS THE LATEST" 304 297 message += " VERSION OF MATPLOTLIB\n" 305 298 message += "Get the SVN version that is at " 306 299 message += " least as recent as June 1, 2007" 307 300 308 301 owner = self.base.base.parent 309 wx.PostEvent(owner, 310 StatusEvent(status="AnnulusSlicer: %s" % message)) 311 312 # Draw a circle 313 [self.inner_circle] = self.axes.plot([], [], 314 linestyle='-', marker='', 315 color=self.color) 302 wx.PostEvent(owner, StatusEvent(status="AnnulusSlicer: %s" % message)) 303 304 # Draw a circle 305 [self.inner_circle] = self.axes.plot([], [], linestyle='-', marker='', color=self.color) 316 306 # the number of points that make the ring line 317 307 self.npts = 40 318 308 319 309 self.connect_markers([self.inner_marker]) 320 310 self.update() … … 323 313 """ 324 314 Allow adding plot to the same panel 325 315 326 316 :param n: the number of layer 327 317 328 318 """ 329 319 self.layernum = n 330 320 self.update() 331 321 332 322 def clear(self): 333 323 """ … … 342 332 for item in range(len(self.axes.lines)): 343 333 del self.axes.lines[0] 344 334 345 335 def get_radius(self): 346 336 """ … … 348 338 """ 349 339 return self._inner_mouse_x 350 340 351 341 def update(self): 352 342 """ … … 358 348 for i in range(self.npts): 359 349 phi = 2.0 * math.pi / (self.npts - 1) * i 360 361 xval = 1.0 * self._inner_mouse_x * math.cos(phi) 362 yval = 1.0 * self._inner_mouse_x * math.sin(phi) 363 350 351 xval = 1.0 * self._inner_mouse_x * math.cos(phi) 352 yval = 1.0 * self._inner_mouse_x * math.sin(phi) 353 364 354 x.append(xval) 365 355 y.append(yval) 366 367 self.inner_marker.set(xdata=[self.sign *math.fabs(self._inner_mouse_x)],356 357 self.inner_marker.set(xdata=[self.sign * math.fabs(self._inner_mouse_x)], 368 358 ydata=[0]) 369 self.inner_circle.set_data(x, y) 359 self.inner_circle.set_data(x, y) 370 360 371 361 def save(self, ev): … … 383 373 """ 384 374 self.base.moveend(ev) 385 375 386 376 def restore(self): 387 377 """ … … 398 388 self._inner_mouse_y = y 399 389 self.base.base.update() 400 390 401 391 def set_cursor(self, x, y): 402 392 """ 403 draw the ring given x, y value 393 draw the ring given x, y value 404 394 """ 405 395 self.move(x, y, None) 406 396 self.update() 407 408 397 398 409 399 def get_params(self): 410 400 """ 411 401 Store a copy of values of parameters of the slicer into a dictionary. 412 402 413 403 :return params: the dictionary created 414 404 415 405 """ 416 406 params = {} 417 407 params["radius"] = math.fabs(self._inner_mouse_x) 418 408 return params 419 409 420 410 def set_params(self, params): 421 411 """ 422 Receive a dictionary and reset the slicer with values contained 412 Receive a dictionary and reset the slicer with values contained 423 413 in the values of the dictionary. 424 425 :param params: a dictionary containing name of slicer parameters and 414 415 :param params: a dictionary containing name of slicer parameters and 426 416 values the user assigned to the slicer. 427 428 """ 429 x = params["radius"] 417 418 """ 419 x = params["radius"] 430 420 self.set_cursor(x, self._inner_mouse_y) 431 421 432 422 class CircularMask(_BaseInteractor): 433 423 """ 434 Draw a ring Given a radius 424 Draw a ring Given a radius 435 425 """ 436 426 def __init__(self, base, axes, color='grey', zorder=3, side=None): 437 427 """ 438 439 428 :param: the color of the line that defined the ring 440 429 :param r: the radius of the ring 441 :param sign: the direction of motion the the marker 442 430 :param sign: the direction of motion the the marker 443 431 """ 444 432 _BaseInteractor.__init__(self, base, axes, color=color) … … 448 436 self.is_inside = side 449 437 self.qmax = min(math.fabs(self.base.data.xmax), 450 math.fabs(self.base.data.xmin)) # must be positive438 math.fabs(self.base.data.xmin)) # must be positive 451 439 self.connect = self.base.connect 452 453 # Cursor position of Rings (Left(-1) or Right(1))440 441 # Cursor position of Rings (Left(-1) or Right(1)) 454 442 self.xmaxd = self.base.data.xmax 455 443 self.xmind = self.base.data.xmin … … 461 449 # Inner circle 462 450 self.outer_circle = RingInteractor(self, self.base.subplot, 'blue', 463 zorder=zorder+1, r=self.qmax/1.8,464 451 zorder=zorder + 1, r=self.qmax / 1.8, 452 sign=self.sign) 465 453 self.outer_circle.qmax = self.qmax * 1.2 466 454 self.update() 467 455 self._post_data() 468 456 469 457 # Bind to slice parameter events 470 # self.base.Bind(EVT_SLICER_PARS, self._onEVT_SLICER_PARS)471 458 # self.base.Bind(EVT_SLICER_PARS, self._onEVT_SLICER_PARS) 459 472 460 def _onEVT_SLICER_PARS(self, event): 473 461 """ 474 462 receive an event containing parameters values to reset the slicer 475 476 :param event: event of type SlicerParameterEvent with params as 463 464 :param event: event of type SlicerParameterEvent with params as 477 465 attribute 478 466 """ … … 487 475 """ 488 476 Allow adding plot to the same panel 489 477 490 478 :param n: the number of layer 491 479 492 480 """ 493 481 self.layernum = n 494 482 self.update() 495 483 496 484 def clear(self): 497 485 """ … … 501 489 self.outer_circle.clear() 502 490 self.base.connect.clearall() 503 # self.base.Unbind(EVT_SLICER_PARS)504 491 # self.base.Unbind(EVT_SLICER_PARS) 492 505 493 def update(self): 506 494 """ … … 508 496 resetting the widgets. 509 497 """ 510 # Update locations 498 # Update locations 511 499 self.outer_circle.update() 512 # if self.is_inside != None:500 # if self.is_inside != None: 513 501 out = self._post_data() 514 502 return out … … 525 513 """ 526 514 Uses annulus parameters to plot averaged data into 1D data. 527 528 :param nbins: the number of points to plot 529 530 """ 531 # Data to average515 516 :param nbins: the number of points to plot 517 518 """ 519 # Data to average 532 520 data = self.base.data 533 521 534 522 # If we have no data, just return 535 523 if data == None: 536 524 return 537 mask = data.mask 525 mask = data.mask 538 526 from sas.dataloader.manipulations import Ringcut 539 527 540 528 rmin = 0 541 529 rmax = math.fabs(self.outer_circle.get_radius()) 542 530 543 # # create the data1D Q average of data2D544 mask = Ringcut(r_min=rmin, r_max= 531 # # create the data1D Q average of data2D 532 mask = Ringcut(r_min=rmin, r_max=rmax) 545 533 546 534 if self.is_inside: … … 548 536 else: 549 537 out = (mask(data)) 550 # self.base.data.mask=out551 return out 552 553 538 # self.base.data.mask=out 539 return out 540 541 554 542 def moveend(self, ev): 555 543 """ … … 562 550 # create a 1D data plot 563 551 self._post_data() 564 552 565 553 def restore(self): 566 554 """ … … 574 562 """ 575 563 pass 576 564 577 565 def set_cursor(self, x, y): 578 566 pass 579 567 580 568 def get_params(self): 581 569 """ 582 570 Store a copy of values of parameters of the slicer into a dictionary. 583 571 584 572 :return params: the dictionary created 585 573 586 574 """ 587 575 params = {} 588 576 params["outer_radius"] = math.fabs(self.outer_circle._inner_mouse_x) 589 577 return params 590 578 591 579 def set_params(self, params): 592 580 """ 593 Receive a dictionary and reset the slicer with values contained 581 Receive a dictionary and reset the slicer with values contained 594 582 in the values of the dictionary. 595 596 :param params: a dictionary containing name of slicer parameters and 583 584 :param params: a dictionary containing name of slicer parameters and 597 585 values the user assigned to the slicer. 598 586 """ 599 outer = math.fabs(params["outer_radius"] 600 # # Update the picture587 outer = math.fabs(params["outer_radius"]) 588 # # Update the picture 601 589 self.outer_circle.set_cursor(outer, self.outer_circle._inner_mouse_y) 602 # # Post the data given the nbins entered by the user590 # # Post the data given the nbins entered by the user 603 591 self._post_data() 604 592 605 593 def freeze_axes(self): 606 594 self.base.freeze_axes() 607 595 608 596 def thaw_axes(self): 609 597 self.base.thaw_axes() … … 611 599 def draw(self): 612 600 self.base.update() 613 601 -
src/sas/guiframe/local_perspectives/plotting/Arc.py
r79492222 r824e488 6 6 from BaseInteractor import _BaseInteractor 7 7 from sas.guiframe.events import SlicerParameterEvent 8 8 9 9 class ArcInteractor(_BaseInteractor): 10 10 """ 11 11 Select an annulus through a 2D plot 12 12 """ 13 def __init__(self, base, axes, color='black', zorder=5, r=1.0, 14 theta1=math.pi/8, theta2=math.pi/4): 15 13 def __init__(self, base, axes, color='black', zorder=5, r=1.0, 14 theta1=math.pi / 8, theta2=math.pi / 4): 16 15 _BaseInteractor.__init__(self, base, axes, color=color) 17 16 self.markers = [] … … 19 18 self._mouse_x = r 20 19 self._mouse_y = 0 21 22 self._save_x = r 23 self._save_y = 0 24 20 self._save_x = r 21 self._save_y = 0 25 22 self.scale = 10.0 26 27 23 self.theta1 = theta1 28 24 self.theta2 = theta2 29 25 self.radius = r 30 [self.arc] = self.axes.plot([], [], 31 linestyle='-', marker='', 32 color=self.color) 26 [self.arc] = self.axes.plot([], [], linestyle='-', marker='', color=self.color) 33 27 self.npts = 20 34 self.has_move = False 28 self.has_move = False 35 29 self.connect_markers([self.arc]) 36 30 self.update() … … 43 37 self.layernum = n 44 38 self.update() 45 39 46 40 def clear(self): 47 41 """ … … 57 51 for item in range(len(self.axes.lines)): 58 52 del self.axes.lines[0] 59 53 60 54 def get_radius(self): 61 55 """ … … 65 59 math.pow(self._mouse_y, 2)) 66 60 return radius 67 61 68 62 def update(self, theta1=None, theta2=None, nbins=None, r=None): 69 63 """ … … 85 79 while self.theta2 >= (self.theta1 + 2 * math.pi): 86 80 self.theta2 -= (2 * math.pi) 87 npts = int((self.theta2 - self.theta1) /(math.pi/120))88 81 npts = int((self.theta2 - self.theta1) / (math.pi / 120)) 82 89 83 if r == None: 90 self.radius = 84 self.radius = math.sqrt(math.pow(self._mouse_x, 2) + \ 91 85 math.pow(self._mouse_y, 2)) 92 86 else: 93 87 self.radius = r 94 88 for i in range(self.npts): 95 phi = (self.theta2 - self.theta1) /(self.npts - 1) * i + self.theta196 xval = 1.0 * self.radius * math.cos(phi) 97 yval = 1.0 * self.radius * math.sin(phi) 98 89 phi = (self.theta2 - self.theta1) / (self.npts - 1) * i + self.theta1 90 xval = 1.0 * self.radius * math.cos(phi) 91 yval = 1.0 * self.radius * math.sin(phi) 92 99 93 x.append(xval) 100 94 y.append(yval) 101 # self.marker.set(xdata=[self._mouse_x],ydata=[0])102 self.arc.set_data(x, y) 103 95 # self.marker.set(xdata=[self._mouse_x],ydata=[0]) 96 self.arc.set_data(x, y) 97 104 98 def save(self, ev): 105 99 """ … … 109 103 self._save_x = self._mouse_x 110 104 self._save_y = self._mouse_y 111 # self._save_x = ev.xdata112 # self._save_y = ev.ydata105 # self._save_x = ev.xdata 106 # self._save_y = ev.ydata 113 107 self.base.freeze_axes() 114 108 … … 119 113 """ 120 114 self.has_move = False 121 115 122 116 event = SlicerParameterEvent() 123 117 event.type = self.__class__.__name__ 124 118 event.params = self.get_params() 125 119 self.base.moveend(ev) 126 120 127 121 def restore(self): 128 122 """ … … 131 125 self._mouse_x = self._save_x 132 126 self._mouse_y = self._save_y 133 127 134 128 def move(self, x, y, ev): 135 129 """ 136 130 Process move to a new position, making sure that the move is allowed. 137 131 """ 138 # print "ring move x, y", x,y132 # print "ring move x, y", x,y 139 133 self._mouse_x = x 140 134 self._mouse_y = y 141 135 self.has_move = True 142 136 self.base.base.update() 143 137 144 138 def set_cursor(self, radius, phi_min, phi_max, nbins): 145 139 """ … … 157 151 params["theta2"] = self.theta2 158 152 return params 159 153 160 154 def set_params(self, params): 161 155 """ 162 156 """ 163 x = params["radius"] 157 x = params["radius"] 164 158 phi_max = self.theta2 165 159 nbins = self.npts 166 160 self.set_cursor(x, self._mouse_y, phi_max, nbins) 167 168 161 -
src/sas/guiframe/local_perspectives/plotting/AzimutSlicer.py
r79492222 r824e488 1 #TODO: the line slicer should listen to all 2DREFRESH events, get the data and slice it 2 # before pushing a new 1D data update. 3 1 # TODO: the line slicer should listen to all 2DREFRESH events, get the data and slice it 2 # before pushing a new 1D data update. 4 3 # 5 # TODO: NEED MAJOR REFACTOR4 # TODO: NEED MAJOR REFACTOR 6 5 # 7 8 9 # Debug printout10 6 import math 11 7 import wx 12 from copy import deepcopy13 8 from BaseInteractor import _BaseInteractor 14 9 from sas.guiframe.events import NewPlotEvent 15 from sas.guiframe.events import StatusEvent16 from sas.guiframe.events import SlicerParameterEvent17 10 from sas.guiframe.events import EVT_SLICER_PARS 18 19 11 20 12 class SectorInteractor(_BaseInteractor): … … 30 22 self.qmax = self.base.data2D.xmax 31 23 self.connect = self.base.connect 32 33 # # Number of points on the plot24 25 # # Number of points on the plot 34 26 self.nbins = 20 35 theta1 = math.pi/8 36 theta2 = math.pi/2 37 theta1 = 2 * math.pi/3 38 theta2 = -2 * math.pi/3 39 r1 = self.qmax/2.0 40 r2 = self.qmax/1.8 41 27 theta1 = 2 * math.pi / 3 28 theta2 = -2 * math.pi / 3 29 42 30 # Inner circle 43 31 from Arc import ArcInteractor 44 32 self.inner_circle = ArcInteractor(self, self.base.subplot, 45 46 r=self.qmax/2.0,47 48 33 zorder=zorder, 34 r=self.qmax / 2.0, 35 theta1=theta1, 36 theta2=theta2) 49 37 self.inner_circle.qmax = self.qmax 50 38 self.outer_circle = ArcInteractor(self, self.base.subplot, 51 zorder=zorder +1,52 r=self.qmax /1.8,39 zorder=zorder + 1, 40 r=self.qmax / 1.8, 53 41 theta1=theta1, 54 42 theta2=theta2) 55 43 self.outer_circle.qmax = self.qmax * 1.2 56 # self.outer_circle.set_cursor(self.base.qmax/1.8, 0)44 # self.outer_circle.set_cursor(self.base.qmax/1.8, 0) 57 45 from Edge import RadiusInteractor 58 self.right_edge = RadiusInteractor(self, self.base.subplot,59 zorder=zorder+1,60 61 62 63 self.left_edge = RadiusInteractor(self, self.base.subplot,64 zorder=zorder+1,65 66 67 46 self.right_edge = RadiusInteractor(self, self.base.subplot, 47 zorder=zorder + 1, 48 arc1=self.inner_circle, 49 arc2=self.outer_circle, 50 theta=theta1) 51 self.left_edge = RadiusInteractor(self, self.base.subplot, 52 zorder=zorder + 1, 53 arc1=self.inner_circle, 54 arc2=self.outer_circle, 55 theta=theta2) 68 56 self.update() 69 57 self._post_data() … … 74 62 """ 75 63 """ 76 # printEVT("AnnulusSlicer._onEVT_SLICER_PARS")64 # printEVT("AnnulusSlicer._onEVT_SLICER_PARS") 77 65 event.Skip() 78 66 if event.type == self.__class__.__name__: … … 85 73 self.layernum = n 86 74 self.update() 87 75 88 76 def clear(self): 89 77 """ … … 94 82 self.right_edge.clear() 95 83 self.left_edge.clear() 96 # self.base.connect.disconnect()84 # self.base.connect.disconnect() 97 85 self.base.parent.Unbind(EVT_SLICER_PARS) 98 86 99 87 def update(self): 100 88 """ … … 102 90 resetting the widgets. 103 91 """ 104 # Update locations 105 if self.inner_circle.has_move: 106 # print "inner circle has moved"92 # Update locations 93 if self.inner_circle.has_move: 94 # print "inner circle has moved" 107 95 self.inner_circle.update() 108 96 r1 = self.inner_circle.get_radius() … … 110 98 self.right_edge.update(r1, r2) 111 99 self.left_edge.update(r1, r2) 112 if self.outer_circle.has_move: 113 # print "outer circle has moved"100 if self.outer_circle.has_move: 101 # print "outer circle has moved" 114 102 self.outer_circle.update() 115 103 r1 = self.inner_circle.get_radius() … … 118 106 self.right_edge.update(r1, r2) 119 107 if self.right_edge.has_move: 120 # print "right edge has moved"108 # print "right edge has moved" 121 109 self.right_edge.update() 122 110 self.inner_circle.update(theta1=self.right_edge.get_angle(), … … 125 113 theta2=None) 126 114 if self.left_edge.has_move: 127 # print "left Edge has moved"115 # print "left Edge has moved" 128 116 self.left_edge.update() 129 117 self.inner_circle.update(theta1=None, … … 131 119 self.outer_circle.update(theta1=None, 132 120 theta2=self.left_edge.get_angle()) 133 121 134 122 def save(self, ev): 135 123 """ … … 142 130 self.right_edge.save(ev) 143 131 self.left_edge.save(ev) 144 132 145 133 def _post_data(self): 146 134 pass 147 148 def post_data(self, new_sector):135 136 def post_data(self, new_sector): 149 137 """ post data averaging in Q""" 150 138 if self.inner_circle.get_radius() < self.outer_circle.get_radius(): … … 159 147 else: 160 148 phimin = self.left_edge.get_angle() 161 phimax = self.right_edge.get_angle() 162 # print "phimin, phimax, rmin ,rmax",math.degrees(phimin),149 phimax = self.right_edge.get_angle() 150 # print "phimin, phimax, rmin ,rmax",math.degrees(phimin), 163 151 # math.degrees(phimax), rmin ,rmax 164 # from sas.dataloader.manipulations import SectorQ165 152 # from sas.dataloader.manipulations import SectorQ 153 166 154 sect = new_sector(r_min=rmin, r_max=rmax, 167 155 phi_min=phimin, phi_max=phimax) 168 156 sector = sect(self.base.data2D) 169 157 170 158 from sas.guiframe.dataFitting import Data1D 171 159 if hasattr(sector, "dxl"): … … 180 168 dxl=dxl, dxw=dxw) 181 169 new_plot.name = str(new_sector.__name__) + \ 182 "(" + self.base.data2D.name+")"170 "(" + self.base.data2D.name + ")" 183 171 new_plot.source = self.base.data2D.source 184 172 new_plot.interactive = True 185 # print "loader output.detector",output.source173 # print "loader output.detector",output.source 186 174 new_plot.detector = self.base.data2D.detector 187 175 # If the data file does not tell us what the axes are, just assume... … … 192 180 theory=new_plot) 193 181 wx.PostEvent(self.base.parent, 194 NewPlotEvent(plot=new_plot, title=str(new_sector.__name__)))195 182 NewPlotEvent(plot=new_plot, title=str(new_sector.__name__))) 183 196 184 def moveend(self, ev): 197 #self.base.thaw_axes() 198 199 # Post paramters 200 #event = SlicerParameterEvent() 201 #event.type = self.__class__.__name__ 202 #event.params = self.get_params() 203 #print "main moveend ", event.params 204 #wx.PostEvent(self.base.parent, event) 205 #self._post_data() 206 pass 207 185 #TODO: why is this empty? 186 pass 187 208 188 def restore(self): 209 189 """ … … 220 200 """ 221 201 pass 222 202 223 203 def set_cursor(self, x, y): 224 204 """ 225 205 """ 226 206 pass 227 207 228 208 def get_params(self): 229 209 """ … … 236 216 params["nbins"] = self.nbins 237 217 return params 238 218 239 219 def set_params(self, params): 240 220 """ 241 221 """ 242 # print "setparams on main slicer ",params243 inner = params["r_min"] 244 outer = params["r_max"] 245 phi_min = params["phi_min"]246 phi_max =params["phi_max"]222 # print "setparams on main slicer ",params 223 inner = params["r_min"] 224 outer = params["r_max"] 225 phi_min = params["phi_min"] 226 phi_max = params["phi_max"] 247 227 self.nbins = int(params["nbins"]) 248 249 self.inner_circle.set_cursor(inner, phi_min, phi_max, self.nbins)250 self.outer_circle.set_cursor(outer, 228 229 self.inner_circle.set_cursor(inner, phi_min, phi_max, self.nbins) 230 self.outer_circle.set_cursor(outer, phi_min, phi_max, self.nbins) 251 231 self.right_edge.set_cursor(inner, outer, phi_min) 252 232 self.left_edge.set_cursor(inner, outer, phi_max) 253 233 self._post_data() 254 234 255 235 def freeze_axes(self): 256 236 """ 257 237 """ 258 238 self.base.freeze_axes() 259 239 260 240 def thaw_axes(self): 261 241 """ … … 275 255 """ 276 256 SectorInteractor.__init__(self, base, axes, color=color) 277 self.base =base278 self._post_data() 279 257 self.base = base 258 self._post_data() 259 280 260 def _post_data(self): 281 261 """ 282 262 """ 283 263 from sas.dataloader.manipulations import SectorQ 284 self.post_data(SectorQ) 285 264 self.post_data(SectorQ) 265 286 266 287 267 class SectorInteractorPhi(SectorInteractor): … … 292 272 """ 293 273 SectorInteractor.__init__(self, base, axes, color=color) 294 self.base =base295 self._post_data() 296 274 self.base = base 275 self._post_data() 276 297 277 def _post_data(self): 298 278 """ 299 279 """ 300 280 from sas.dataloader.manipulations import SectorPhi 301 self.post_data(SectorPhi ) 302 303 281 self.post_data(SectorPhi) 282 -
src/sas/guiframe/local_perspectives/plotting/BaseInteractor.py
r79492222 r824e488 8 8 profile_colors = [rho_color, mu_color, P_color, theta_color] 9 9 10 class _BaseInteractor :10 class _BaseInteractor(object): 11 11 """ 12 12 Share some functions between the interface interactor and various layer 13 13 interactors. 14 14 15 15 Individual interactors need the following functions: 16 16 17 17 save(ev) - save the current state for later restore 18 18 restore() - restore the old state … … 20 20 moveend(ev) - end the drag event 21 21 update() - draw the interactors 22 22 23 23 The following are provided by the base class: 24 24 25 25 connect_markers(markers) - register callbacks for all markers 26 26 clear_markers() - remove all items in self.markers … … 31 31 onDrag(ev) - mouse move: calls move() or restore() 32 32 onKey(ev) - keyboard move: calls move() or restore() 33 33 34 34 Interactor attributes: 35 35 36 36 base - model we are operating on 37 37 axes - axes holding the interactor 38 38 color - color of the interactor in non-active state 39 39 markers - list of handles for the interactor 40 40 41 41 """ 42 42 def __init__(self, base, axes, color='black'): … … 49 49 self.clicky = None 50 50 self.markers = [] 51 51 52 52 def clear_markers(self): 53 53 """ … … 63 63 """ 64 64 pass 65 65 66 66 def restore(self, ev): 67 67 """ 68 68 """ 69 69 pass 70 70 71 71 def move(self, x, y, ev): 72 72 """ 73 73 """ 74 74 pass 75 75 76 76 def moveend(self, ev): 77 77 """ … … 83 83 Connect markers to callbacks 84 84 """ 85 85 86 86 for h in markers: 87 87 connect = self.base.connect … … 109 109 self.base.draw() 110 110 return True 111 111 112 112 def onClick(self, ev): 113 113 """ … … 138 138 self.base.update() 139 139 return True 140 140 141 141 def onKey(self, ev): 142 142 """ 143 143 Respond to keyboard events. Arrow keys move the widget. Escape 144 144 restores it to the position before the last click. 145 145 146 146 Calls move() to update the state. Calls restore() on escape. 147 147 """ … … 173 173 px, py = ax.transData.inverse_xy_tup((x, y)) 174 174 if nudge: 175 nx, ny = ax.transData.xy_tup((px +0.2, py+0.2))175 nx, ny = ax.transData.xy_tup((px + 0.2, py + 0.2)) 176 176 else: 177 nx, ny = ax.transData.xy_tup((px +1.0, py+1.0))178 dx, dy = nx -x, ny-y177 nx, ny = ax.transData.xy_tup((px + 1.0, py + 1.0)) 178 dx, dy = nx - x, ny - y 179 179 return dx, dy 180 180 -
src/sas/guiframe/local_perspectives/plotting/appearanceDialog.py
r79492222 r824e488 19 19 Initialization of the Panel 20 20 """ 21 super(appearanceDialog, self).__init__(parent, title=title,22 size=(570,450),23 style=wx.DEFAULT_FRAME_STYLE|wx.FRAME_FLOAT_ON_PARENT)21 super(appearanceDialog, 22 self).__init__(parent, title=title, size=(570, 450), 23 style=wx.DEFAULT_FRAME_STYLE | wx.FRAME_FLOAT_ON_PARENT) 24 24 25 25 self.okay_clicked = False … … 45 45 ivbox1 = wx.BoxSizer(wx.VERTICAL) 46 46 ivbox2 = wx.BoxSizer(wx.VERTICAL) 47 47 48 48 ihbox1 = wx.BoxSizer(wx.HORIZONTAL) 49 49 ihbox2 = wx.BoxSizer(wx.HORIZONTAL) … … 61 61 # selection widgets 62 62 self.symbollistbox = wx.ListBox(panel, -1, size=(200, 200)) 63 self.colorlistbox = wx.ComboBox(panel, style=wx.CB_READONLY, 63 self.colorlistbox = wx.ComboBox(panel, style=wx.CB_READONLY, 64 64 size=(185, -1)) 65 self.sizecombobox = wx.ComboBox(panel, style=wx.CB_READONLY, 65 self.sizecombobox = wx.ComboBox(panel, style=wx.CB_READONLY, 66 66 size=(90, -1)) 67 67 self.sizecombobox.Bind(wx.EVT_COMBOBOX, self.combo_click) 68 68 self.sizecustombutton = wx.Button(panel, label='Custom...') 69 69 self.sizecustombutton.Bind(wx.EVT_BUTTON, self.custom_size) 70 self.labeltextbox = wx.TextCtrl(panel, -1, "", 70 self.labeltextbox = wx.TextCtrl(panel, -1, "", size=(440, -1)) 71 71 72 72 # buttons … … 77 77 78 78 # now Add all the widgets to relevant spacer - tricky 79 ivbox1.Add(symboltext, flag=wx.ALL |wx.ALIGN_LEFT, border=10)80 ivbox1.Add(self.symbollistbox, flag=wx.ALL |wx.ALIGN_LEFT, border=10)81 82 ihbox1.Add(sizetext, flag=wx.ALL |wx.ALIGN_LEFT, border=10)83 ihbox1.Add(self.sizecombobox, 84 flag= wx.ALL|wx.RIGHT|wx.ALIGN_LEFT, border=10)85 ihbox1.Add(self.sizecustombutton, 86 flag=wx.ALIGN_LEFT |wx.ALL, border=10)87 88 ihbox2.Add(colortext, flag=wx.ALL |wx.ALIGN_LEFT, border=10)89 ihbox2.Add(self.colorlistbox, flag=wx.ALL |wx.ALIGN_LEFT, border=10)79 ivbox1.Add(symboltext, flag=wx.ALL | wx.ALIGN_LEFT, border=10) 80 ivbox1.Add(self.symbollistbox, flag=wx.ALL | wx.ALIGN_LEFT, border=10) 81 82 ihbox1.Add(sizetext, flag=wx.ALL | wx.ALIGN_LEFT, border=10) 83 ihbox1.Add(self.sizecombobox, 84 flag=wx.ALL | wx.RIGHT | wx.ALIGN_LEFT, border=10) 85 ihbox1.Add(self.sizecustombutton, 86 flag=wx.ALIGN_LEFT | wx.ALL, border=10) 87 88 ihbox2.Add(colortext, flag=wx.ALL | wx.ALIGN_LEFT, border=10) 89 ihbox2.Add(self.colorlistbox, flag=wx.ALL | wx.ALIGN_LEFT, border=10) 90 90 91 91 ivbox2.Add(ihbox1, flag=wx.ALIGN_LEFT, border=10) … … 95 95 hbox1.Add(ivbox2, flag=wx.ALIGN_LEFT, border=10) 96 96 97 hbox2.Add(okbutton, flag=wx.ALL | wx.ALIGN_RIGHT, border=10)98 hbox2.Add(cancelbutton, flag=wx.ALL |wx.ALIGN_RIGHT, border=10)99 100 hbox3.Add(labeltext, flag=wx.EXPAND |wx.ALL|wx.ALIGN_LEFT, border=10)101 hbox3.Add(self.labeltextbox, flag=wx.EXPAND |wx.ALL|wx.ALIGN_LEFT, border=10)102 103 symbolstaticboxsizer.Add(hbox1, flag=wx.ALL |wx.EXPAND, border=10)104 vbox.Add(symbolstaticboxsizer, flag=wx.ALL |wx.EXPAND, border=10)105 vbox.Add(hbox3, flag=wx.EXPAND |wx.RIGHT, border=10)106 vbox.Add(wx.StaticLine(panel), 0, wx.ALL |wx.EXPAND, 5)107 vbox.Add(hbox2, flag=wx.RIGHT |wx.ALIGN_RIGHT, border=10)97 hbox2.Add(okbutton, flag=wx.ALL | wx.ALIGN_RIGHT, border=10) 98 hbox2.Add(cancelbutton, flag=wx.ALL | wx.ALIGN_RIGHT, border=10) 99 100 hbox3.Add(labeltext, flag=wx.EXPAND | wx.ALL | wx.ALIGN_LEFT, border=10) 101 hbox3.Add(self.labeltextbox, flag=wx.EXPAND | wx.ALL | wx.ALIGN_LEFT, border=10) 102 103 symbolstaticboxsizer.Add(hbox1, flag=wx.ALL | wx.EXPAND, border=10) 104 vbox.Add(symbolstaticboxsizer, flag=wx.ALL | wx.EXPAND, border=10) 105 vbox.Add(hbox3, flag=wx.EXPAND | wx.RIGHT, border=10) 106 vbox.Add(wx.StaticLine(panel), 0, wx.ALL | wx.EXPAND, 5) 107 vbox.Add(hbox2, flag=wx.RIGHT | wx.ALIGN_RIGHT, border=10) 108 108 109 109 panel.SetSizer(vbox) … … 119 119 On custom size 120 120 """ 121 dlg = wx.TextEntryDialog(self, 122 'Enter custom size', 123 'Custom size', 124 str(self.final_size)) 125 if(dlg.ShowModal() == wx.ID_OK): 126 if(float(dlg.GetValue()) < 0): 121 dlg = wx.TextEntryDialog(self, 'Enter custom size', 'Custom size', str(self.final_size)) 122 if dlg.ShowModal() == wx.ID_OK: 123 if float(dlg.GetValue()) < 0: 127 124 msg = "Unfortunately imaginary icons are not yet supported." 128 125 msg += "Please enter a positive value" 129 dial = wx.MessageDialog(None, msg, 'Error', 130 wx.OK|wx.ICON_ERROR) 126 dial = wx.MessageDialog(None, msg, 'Error', wx.OK | wx.ICON_ERROR) 131 127 dial.ShowModal() 132 128 dlg.Destroy() … … 145 141 # set up gui values 146 142 self.labeltextbox.SetValue(label) 147 if (size % 1 == 0 and size > 1 and size < 11):143 if size % 1 == 0 and size > 1 and size < 11: 148 144 self.sizecombobox.SetSelection(int(size) - 1) 149 145 else: 150 146 self.sizecombobox.SetSelection(4) 151 147 self.symbollistbox.SetSelection(self.sorted_sym_dic[symbol]) 152 colorname = appearanceDialog.find_key(self.parent.get_color_label(), 153 color) 148 colorname = appearanceDialog.find_key(self.parent.get_color_label(), color) 154 149 self.colorlistbox.SetStringSelection(colorname) 155 150 … … 158 153 Populate Symbols 159 154 """ 160 self.sorted_symbo_labels = sorted(self.symbo_labels.iteritems(), 155 self.sorted_symbo_labels = sorted(self.symbo_labels.iteritems(), 161 156 key=operator.itemgetter(1)) 162 157 self.sorted_sym_dic = {} … … 171 166 Populate Colors 172 167 """ 173 sortedcolor_labels = sorted(self.color_labels.iteritems(), 174 key=operator.itemgetter(1))168 sortedcolor_labels = sorted(self.color_labels.iteritems(), 169 key=operator.itemgetter(1)) 175 170 for color in sortedcolor_labels: 176 171 self.colorlistbox.Append(str(color[0])) 177 172 178 173 def populate_size(self): 179 174 """ … … 203 198 """ 204 199 return [k for k, v in dic.iteritems() if v == val][0] 205 206 def get_current_values(self): 200 201 def get_current_values(self): 207 202 """ 208 203 Get Current Values … … 212 207 name = str(self.labeltextbox.GetValue()) 213 208 seltuple = self.symbollistbox.GetSelections() 214 symbol = appearanceDialog.find_key(self.sorted_sym_dic, 209 symbol = appearanceDialog.find_key(self.sorted_sym_dic, 215 210 int(seltuple[0])) 216 color = str(self.colorlistbox.GetValue()) 211 color = str(self.colorlistbox.GetValue()) 217 212 return(size, color, symbol, name) 218 213 -
src/sas/guiframe/local_perspectives/plotting/binder.py
r79492222 r824e488 2 2 Extension to MPL to support the binding of artists to key/mouse events. 3 3 """ 4 5 class Selection: 4 import logging 5 import sys 6 7 class Selection(object): 6 8 """ 7 9 Store and compare selections. … … 9 11 # TODO: We need some way to check in prop matches, preferably 10 12 # TODO: without imposing structure on prop. 11 13 12 14 artist = None 13 15 prop = {} 14 16 def __init__(self, artist=None, prop={}): 15 17 self.artist, self.prop = artist, self.prop 16 18 17 19 def __eq__(self, other): 18 20 return self.artist is other.artist 19 21 20 22 def __ne__(self, other): 21 23 return self.artist is not other.artist 22 24 23 25 def __nonzero__(self): 24 26 return self.artist is not None 25 27 26 class BindArtist: 27 28 # Track keyboard modifiers for events. 29 # TODO: Move keyboard modifier support into the backend. We cannot 30 # TODO: properly support it from outside the windowing system since there 31 # TODO: is no way to recognized whether shift is held down when the mouse 32 # TODO: first clicks on the the application window. 28 class BindArtist(object): 29 """ 30 Track keyboard modifiers for events. 31 TODO: Move keyboard modifier support into the backend. We cannot 32 TODO: properly support it from outside the windowing system since there 33 TODO: is no way to recognized whether shift is held down when the mouse 34 TODO: first clicks on the the application window. 35 """ 33 36 control, shift, alt, meta = False, False, False, False 34 37 … … 36 39 dclick_threshhold = 0.25 37 40 _last_button, _last_time = None, 0 38 41 39 42 # Mouse/keyboard events we can bind to 40 43 events = ['enter', 'leave', 'motion', 'click', 'dclick', 'drag', 'release', 41 'scroll', 'key', 'keyup']44 'scroll', 'key', 'keyup'] 42 45 # TODO: Need our own event structure 43 46 def __init__(self, figure): … … 54 57 ] 55 58 except: 56 # print "bypassing scroll_event: wrong matplotlib version"59 # print "bypassing scroll_event: wrong matplotlib version" 57 60 self._connections = [ 58 61 canvas.mpl_connect('motion_notify_event', self._onMotion), … … 66 69 canvas.mpl_disconnect(canvas.button_pick_id) 67 70 canvas.mpl_disconnect(canvas.scroll_pick_id) 68 except: 69 pass71 except: 72 logging.error(sys.exc_value) 70 73 self.canvas = canvas 71 74 self.figure = figure 72 75 self.clearall() 73 76 74 77 def clear(self, *artists): 75 78 """ 76 79 self.clear(h1,h2,...) 77 80 Remove connections for artists h1, h2, ... 78 81 79 82 Use clearall() to reset all connections. 80 83 81 84 """ 82 85 for h in artists: … … 92 95 if self._haskey.artist in artists: 93 96 self._haskey = Selection() 94 97 95 98 def clearall(self): 96 99 """ 97 100 Clear connections to all artists. 98 101 99 102 Use clear(h1,h2,...) to reset specific artists. 100 103 """ … … 113 116 In case we need to disconnect from the canvas... 114 117 """ 115 try: 118 try: 116 119 for cid in self._connections: 117 120 self.canvas.mpl_disconnect(cid) 118 except: 121 except: 119 122 pass 120 123 self._connections = [] … … 125 128 def __call__(self, trigger, artist, action): 126 129 """Register a callback for an artist to a particular trigger event. 127 130 128 131 usage: 129 132 self.connect(eventname,artist,action) 130 133 131 134 where: 132 135 eventname is a string … … 148 151 key: key pressed when mouse is on the artist 149 152 keyrelease: key released for the artist 150 153 151 154 The event received by action has a number of attributes: 152 155 name is the event name which was triggered … … 158 161 shift,control,alt,meta are flags which are true if the 159 162 corresponding key is pressed at the time of the event. 160 details is a dictionary of artist specific details, such as the 163 details is a dictionary of artist specific details, such as the 161 164 id(s) of the point that were clicked. 162 165 163 166 When receiving an event, first check the modifier state to be 164 167 sure it applies. E.g., the callback for 'press' might be: … … 175 178 :TODO: Attach multiple callbacks to the same event? 176 179 :TODO: Clean up interaction with toolbar modes 177 :TODO: push/pushclear/pop context so that binding changes 180 :TODO: push/pushclear/pop context so that binding changes 178 181 for the duration 179 182 :TODO: e.g., to support ? context sensitive help 180 183 181 184 """ 182 185 # Check that the trigger is valid … … 186 189 # Register the trigger callback 187 190 self._actions[trigger][artist] = action 188 # print "==> added",artist,[artist],"to",trigger,":",189 # self._actions[trigger].keys()191 # print "==> added",artist,[artist],"to",trigger,":", 192 # self._actions[trigger].keys() 190 193 # Maintain a list of all artists 191 if artist not in self._artists: 194 if artist not in self._artists: 192 195 self._artists.append(artist) 193 196 … … 231 234 # print "search"," ".join([str(h) for h in self._artists]) 232 235 found = Selection() 233 # print "searching in",self._artists236 # print "searching in",self._artists 234 237 for artist in self._artists: 235 238 # TODO: should contains() return false if invisible? 236 if not artist.get_visible(): 239 if not artist.get_visible(): 237 240 continue 238 241 # TODO: optimization - exclude artists not inaxes 239 242 try: 240 inside, prop = artist.contains(event)243 inside, prop = artist.contains(event) 241 244 except: 242 245 # Probably an old version of matplotlib … … 245 248 found.artist, found.prop = artist, prop 246 249 break 247 # print "found",found.artist248 250 # print "found",found.artist 251 249 252 # TODO: how to check if prop is equal? 250 253 if found != self._current: … … 253 256 self._current = found 254 257 return found 255 258 256 259 def _onMotion(self, event): 257 260 """ … … 259 262 other artists are invisible. 260 263 """ 261 # # Can't kill double-click on motion since Windows produces262 # # spurious motion events.263 # self._last_button = None264 264 # # Can't kill double-click on motion since Windows produces 265 # # spurious motion events. 266 # self._last_button = None 267 265 268 # Dibs on the motion event for the clicked artist 266 269 if self._hasclick: 267 270 # Make sure the x,y data use the coordinate system of the 268 271 # artist rather than the default axes coordinates. 269 272 270 273 transform = self._hasclick.artist.get_transform() 271 # x,y = event.xdata,event.ydata274 # x,y = event.xdata,event.ydata 272 275 x, y = event.x, event.y 273 276 try: … … 280 283 else: 281 284 found = self._find_current(event) 282 # print "found",found.artist285 # print "found",found.artist 283 286 self.trigger(found, 'motion', event) 284 287 … … 288 291 """ 289 292 import time 290 293 291 294 # Check for double-click 292 295 event_time = time.time() 293 # print event_time,self._last_time,self.dclick_threshhold294 # print (event_time > self._last_time + self.dclick_threshhold)295 # print event.button,self._last_button296 # print event_time,self._last_time,self.dclick_threshhold 297 # print (event_time > self._last_time + self.dclick_threshhold) 298 # print event.button,self._last_button 296 299 if (event.button != self._last_button) or \ 297 300 (event_time > self._last_time + self.dclick_threshhold): … … 301 304 self._last_button = event.button 302 305 self._last_time = event_time 303 306 304 307 # If an artist is already dragging, feed any additional button 305 308 # presses to that artist. … … 311 314 else: 312 315 found = self._find_current(event) 313 # print "button %d pressed"%event.button316 # print "button %d pressed"%event.button 314 317 # Note: it seems like if "click" returns False then hasclick should 315 318 # not be set. The problem is that there are two reasons it can … … 346 349 self.trigger(self._hasclick, 'release', event) 347 350 self._hasclick = Selection() 348 351 349 352 def _onKey(self, event): 350 353 """ … … 355 358 # TODO: Can we tab between items? 356 359 # TODO: How do unhandled events get propogated to axes, figure and 357 # TODO: finally to application? Do we need to implement a full tags 360 # TODO: finally to application? Do we need to implement a full tags 358 361 # TODO: architecture a la Tk? 359 362 # TODO: Do modifiers cause a grab? Does the artist see the modifiers? … … 368 371 self.trigger(found, 'key', event) 369 372 self._haskey = found 370 373 371 374 def _onKeyRelease(self, event): 372 375 """
Note: See TracChangeset
for help on using the changeset viewer.