- Timestamp:
- Feb 2, 2017 8:29:07 AM (8 years ago)
- Branches:
- 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
- Children:
- 965fbd8
- Parents:
- 5d89f43
- git-author:
- Piotr Rozyczko <rozyczko@…> (01/23/17 09:21:03)
- git-committer:
- Piotr Rozyczko <rozyczko@…> (02/02/17 08:29:07)
- Location:
- src/sas
- Files:
-
- 7 added
- 14 edited
Legend:
- Unmodified
- Added
- Removed
-
src/sas/qtgui/ColorMap.py
r5d89f43 r3bdbfcc 111 111 self.canvas.draw() 112 112 113 def onApply(self):114 """115 Respond to the Apply button click.116 Send a signal to the plotter with vmin/vmax/cmap for chart update117 """118 self.apply_signal.emit(self.norm(), self.cmap())119 120 113 def initDetectorData(self): 121 114 """ … … 214 207 norm=self._norm, 215 208 orientation='horizontal') 216 self.cb.set_label(' Color map range')209 self.cb.set_label('Detector Colors') 217 210 218 211 def onColorMapReversed(self, isChecked): -
src/sas/qtgui/DataExplorer.py
r87cc73a r3bdbfcc 399 399 new_plot = Plotter(self) 400 400 401 def addDataPlot2D(plot_set ):401 def addDataPlot2D(plot_set, item): 402 402 plot2D = Plotter2D(self) 403 plot2D.item = item 403 404 plot2D.plot(plot_set) 404 405 self.plotAdd(plot2D) 405 406 406 for plot_set in plots:407 for item, plot_set in plots: 407 408 if isinstance(plot_set, Data1D): 408 409 new_plot.plot(plot_set) 409 410 elif isinstance(plot_set, Data2D): 410 addDataPlot2D(plot_set )411 addDataPlot2D(plot_set, item) 411 412 else: 412 413 msg = "Incorrect data type passed to Plotting" … … 450 451 451 452 # Add new data to the old plot, if data type is the same. 452 for plot_set in new_plots:453 for _, plot_set in new_plots: 453 454 if type(plot_set) is type(old_plot._data): 454 455 old_plot.data = plot_set -
src/sas/qtgui/GUITests.py
r092a3d9 r3bdbfcc 24 24 from UnitTesting import PlotUtilitiesTest 25 25 from UnitTesting import ColorMapTest 26 from UnitTesting import BoxSumTest 27 from UnitTesting import SlicerModelTest 26 28 27 29 def suite(): … … 50 52 unittest.makeSuite(PlotUtilitiesTest.PlotUtilitiesTest, 'test'), 51 53 unittest.makeSuite(ColorMapTest.ColorMapTest, 'test'), 54 unittest.makeSuite(BoxSumTest.BoxSumTest, 'test'), 55 unittest.makeSuite(SlicerModelTest.SlicerModelTest, 'test'), 52 56 ) 53 57 return unittest.TestSuite(suites) -
src/sas/qtgui/GuiUtils.py
ra66ff280 r3bdbfcc 242 242 assert isinstance(item, QtGui.QStandardItem) 243 243 assert isinstance(update_data, QtCore.QVariant) 244 py_update_data = update_data.toPyObject() 245 246 # Check if data with the same ID is already present 247 for index in range(item.rowCount()): 248 plot_item = item.child(index) 249 if plot_item.isCheckable(): 250 plot_data = plot_item.child(0).data().toPyObject() 251 if plot_data.id == py_update_data.id: 252 item.removeRow(index) 253 break 244 254 245 255 checkbox_item = QtGui.QStandardItem(True) … … 249 259 250 260 # Add "Info" item 251 py_update_data = update_data.toPyObject()252 261 if isinstance(py_update_data, (Data1D or Data2D)): 253 262 # If Data1/2D added - extract Info from it … … 298 307 if item.isCheckable() and item.checkState() == QtCore.Qt.Checked: 299 308 # TODO: assure item type is correct (either data1/2D or Plotter) 300 plot_data.append( item.child(0).data().toPyObject())309 plot_data.append((item, item.child(0).data().toPyObject())) 301 310 # Going 1 level deeper only 302 311 for index_2 in range(item.rowCount()): … … 304 313 if item_2 and item_2.isCheckable() and item_2.checkState() == QtCore.Qt.Checked: 305 314 # TODO: assure item type is correct (either data1/2D or Plotter) 306 plot_data.append( item_2.child(0).data().toPyObject())315 plot_data.append((item_2, item_2.child(0).data().toPyObject())) 307 316 308 317 return plot_data -
src/sas/qtgui/Plotter.py
r092a3d9 r3bdbfcc 516 516 self.plot(data=self.fit_result, marker='-', hide_error=True) 517 517 518 def onMplMouseDown(self, event): 519 """ 520 Left button down and ready to drag 521 """ 522 # Check that the LEFT button was pressed 523 if event.button == 1: 524 self.leftdown = True 525 ax = event.inaxes 526 for text in self.textList: 527 if text.contains(event)[0]: # If user has clicked on text 528 self.selectedText = text 529 return 530 531 if ax != None: 532 self.xInit, self.yInit = event.xdata, event.ydata 533 try: 534 self.x_click = float(event.xdata) # / size_x 535 self.y_click = float(event.ydata) # / size_y 536 except: 537 self.position = None 538 539 def onMplMouseUp(self, event): 540 """ 541 Set the data coordinates of the click 542 """ 543 self.x_click = event.xdata 544 self.y_click = event.ydata 545 546 # Check that the LEFT button was released 547 if event.button == 1: 548 self.leftdown = False 549 #self.leftup = True 550 self.selectedText = None 551 552 #release the legend 553 if self.gotLegend == 1: 554 self.gotLegend = 0 555 556 def onMplMouseMotion(self, event): 557 """ 558 Check if the left button is press and the mouse in moving. 559 Compute delta for x and y coordinates and then perform the drag 560 """ 561 if self.gotLegend == 1 and self.leftdown: 562 self.onLegendMotion(event) 563 return 564 565 if self.leftdown and self.selectedText is not None: 566 # User has clicked on text and is dragging 567 ax = event.inaxes 568 if ax != None: 569 # Only move text if mouse is within axes 570 self.selectedText.set_position((event.xdata, event.ydata)) 571 self.canvas.draw_idle() 572 else: 573 # User has dragged outside of axes 574 self.selectedText = None 575 return 576 577 def onMplPick(self, event): 578 """ 579 On pick legend 580 """ 581 legend = self.legend 582 if event.artist == legend: 583 # Get the box of the legend. 584 bbox = self.legend.get_window_extent() 585 # Get mouse coordinates at time of pick. 586 self.mouse_x = event.mouseevent.x 587 self.mouse_y = event.mouseevent.y 588 # Get legend coordinates at time of pick. 589 self.legend_x = bbox.xmin 590 self.legend_y = bbox.ymin 591 # Indicate we picked up the legend. 592 self.gotLegend = 1 593 594 #self.legend.legendPatch.set_alpha(0.5) 595 596 def onLegendMotion(self, event): 597 """ 598 On legend in motion 599 """ 600 ax = event.inaxes 601 if ax == None: 602 return 603 # Event occurred inside a plotting area 604 lo_x, hi_x = ax.get_xlim() 605 lo_y, hi_y = ax.get_ylim() 606 # How much the mouse moved. 607 x = mouse_diff_x = self.mouse_x - event.x 608 y = mouse_diff_y = self.mouse_y - event.y 609 # Put back inside 610 if x < lo_x: 611 x = lo_x 612 if x > hi_x: 613 x = hi_x 614 if y < lo_y: 615 y = lo_y 616 if y > hi_y: 617 y = hi_y 618 # Move the legend from its previous location by that same amount 619 loc_in_canvas = self.legend_x - mouse_diff_x, \ 620 self.legend_y - mouse_diff_y 621 # Transform into legend coordinate system 622 trans_axes = self.legend.parent.transAxes.inverted() 623 loc_in_norm_axes = trans_axes.transform_point(loc_in_canvas) 624 self.legend_pos_loc = tuple(loc_in_norm_axes) 625 self.legend._loc = self.legend_pos_loc 626 # self.canvas.draw() 627 self.canvas.draw_idle() 628 629 def onMplWheel(self, event): 630 """ 631 Process mouse wheel as zoom events 632 """ 633 ax = event.inaxes 634 step = event.step 635 636 if ax != None: 637 # Event occurred inside a plotting area 638 lo, hi = ax.get_xlim() 639 lo, hi = PlotUtilities.rescale(lo, hi, step, 640 pt=event.xdata, scale=ax.get_xscale()) 641 if not self.xscale == 'log' or lo > 0: 642 self._scale_xlo = lo 643 self._scale_xhi = hi 644 ax.set_xlim((lo, hi)) 645 646 lo, hi = ax.get_ylim() 647 lo, hi = PlotUtilities.rescale(lo, hi, step, pt=event.ydata, 648 scale=ax.get_yscale()) 649 if not self.yscale == 'log' or lo > 0: 650 self._scale_ylo = lo 651 self._scale_yhi = hi 652 ax.set_ylim((lo, hi)) 653 else: 654 # Check if zoom happens in the axes 655 xdata, ydata = None, None 656 x, y = event.x, event.y 657 658 for ax in self.axes: 659 insidex, _ = ax.xaxis.contains(event) 660 if insidex: 661 xdata, _ = ax.transAxes.inverted().transform_point((x, y)) 662 insidey, _ = ax.yaxis.contains(event) 663 if insidey: 664 _, ydata = ax.transAxes.inverted().transform_point((x, y)) 665 if xdata is not None: 666 lo, hi = ax.get_xlim() 667 lo, hi = PlotUtilities.rescale(lo, hi, step, 668 bal=xdata, scale=ax.get_xscale()) 669 if not self.xscale == 'log' or lo > 0: 670 self._scale_xlo = lo 671 self._scale_xhi = hi 672 ax.set_xlim((lo, hi)) 673 if ydata is not None: 674 lo, hi = ax.get_ylim() 675 lo, hi = PlotUtilities.rescale(lo, hi, step, bal=ydata, 676 scale=ax.get_yscale()) 677 if not self.yscale == 'log' or lo > 0: 678 self._scale_ylo = lo 679 self._scale_yhi = hi 680 ax.set_ylim((lo, hi)) 681 self.canvas.draw_idle() 682 518 683 519 684 class Plotter(QtGui.QDialog, PlotterWidget): -
src/sas/qtgui/Plotter2D.py
r5d89f43 r3bdbfcc 11 11 12 12 import sas.qtgui.PlotUtilities as PlotUtilities 13 import sas.qtgui.GuiUtils as GuiUtils 13 14 from sas.qtgui.PlotterBase import PlotterBase 14 15 from sas.qtgui.ColorMap import ColorMap 16 from sas.sasgui.guiframe.dataFitting import Data1D 15 17 from sas.sasgui.guiframe.dataFitting import Data2D 18 from sas.sascalc.dataloader.manipulations import CircularAverage 19 from sas.sasgui.guiframe.local_perspectives.plotting.binder import BindArtist 20 from sas.qtgui.BoxSum import BoxSum 21 from sas.qtgui.GuiUtils import formatNumber 22 from sas.qtgui.SlicerParameters import SlicerParameters 23 from sas.sasgui.guiframe.local_perspectives.plotting.boxSlicer import BoxInteractorX 24 from sas.sasgui.guiframe.local_perspectives.plotting.AnnulusSlicer import AnnulusInteractor 25 from sas.sasgui.guiframe.local_perspectives.plotting.SectorSlicer import SectorInteractor 26 from sas.sasgui.guiframe.local_perspectives.plotting.boxSum import BoxSumCalculator 27 from sas.sasgui.guiframe.local_perspectives.plotting.boxSlicer import BoxInteractorY 16 28 17 29 # Minimum value of Z for which we will present data. 18 MIN_Z =-3230 MIN_Z = -32 19 31 20 32 class Plotter2DWidget(PlotterBase): … … 29 41 # Default scale 30 42 self.scale = 'log_{10}' 43 # to set the order of lines drawn first. 44 self.slicer_z = 5 45 # Reference to the current slicer 46 self.slicer = None 47 # Create Artist and bind it 48 self.connect = BindArtist(self.figure) 31 49 self.vmin = None 32 50 self.vmax = None … … 53 71 self.title(title=data.title) 54 72 55 def plot(self, data=None, marker=None, linestyle=None): 73 @property 74 def item(self): 75 ''' getter for this plot's QStandardItem ''' 76 return self._item 77 78 @item.setter 79 def item(self, item=None): 80 ''' setter for this plot's QStandardItem ''' 81 self._item = item 82 83 def plot(self, data=None): 56 84 """ 57 85 Plot 2D self._data … … 61 89 self.data = data 62 90 63 assert (self._data)91 assert self._data 64 92 65 93 # Toggle the scale … … 128 156 self.actionBoxAveragingY = self.contextMenu.addAction("&Box Averaging in Qy") 129 157 self.actionBoxAveragingY.triggered.connect(self.onBoxAveragingY) 130 self.contextMenu.addSeparator() 131 self.actionEditGraphLabel = self.contextMenu.addAction("&Edit Graph Label") 132 self.actionEditGraphLabel.triggered.connect(self.onEditgraphLabel) 158 # Additional items for slicer interaction 159 if self.slicer: 160 self.actionClearSlicer = self.contextMenu.addAction("&Clear Slicer") 161 self.actionClearSlicer.triggered.connect(self.onClearSlicer) 162 self.actionEditSlicer = self.contextMenu.addAction("&Edit Slicer Parameters") 163 self.actionEditSlicer.triggered.connect(self.onEditSlicer) 133 164 self.contextMenu.addSeparator() 134 165 self.actionColorMap = self.contextMenu.addAction("&2D Color Map") … … 166 197 self.plot() 167 198 199 def onClearSlicer(self): 200 """ 201 Remove all sclicers from the chart 202 """ 203 if self.slicer: 204 self.slicer.clear() 205 self.canvas.draw() 206 self.slicer = None 207 208 def onEditSlicer(self): 209 """ 210 Present a small dialog for manipulating the current slicer 211 """ 212 assert self.slicer 213 214 self.param_model = self.slicer.model() 215 # Pass the model to the Slicer Parameters widget 216 self.slicer_widget = SlicerParameters(self, model=self.param_model) 217 self.slicer_widget.show() 218 168 219 def onCircularAverage(self): 169 220 """ 170 """ 171 pass 221 Perform circular averaging on Data2D 222 """ 223 # Find the best number of bins 224 npt = numpy.sqrt(len(self.data.data[numpy.isfinite(self.data.data)])) 225 npt = numpy.floor(npt) 226 # compute the maximum radius of data2D 227 self.qmax = max(numpy.fabs(self.data.xmax), 228 numpy.fabs(self.data.xmin)) 229 self.ymax = max(numpy.fabs(self.data.ymax), 230 numpy.fabs(self.data.ymin)) 231 self.radius = numpy.sqrt(numpy.power(self.qmax, 2) + numpy.power(self.ymax, 2)) 232 #Compute beam width 233 bin_width = (self.qmax + self.qmax) / npt 234 # Create data1D circular average of data2D 235 circle = CircularAverage(r_min=0, r_max=self.radius, bin_width=bin_width) 236 circ = circle(self.data) 237 dxl = circ.dxl if hasattr(circ, "dxl") else None 238 dxw = circ.dxw if hasattr(circ, "dxw") else None 239 240 new_plot = Data1D(x=circ.x, y=circ.y, dy=circ.dy, dx=circ.dx) 241 new_plot.dxl = dxl 242 new_plot.dxw = dxw 243 new_plot.name = new_plot.title = "Circ avg " + self.data.name 244 new_plot.source = self.data.source 245 new_plot.interactive = True 246 new_plot.detector = self.data.detector 247 248 # Define axes if not done yet. 249 new_plot.xaxis("\\rm{Q}", "A^{-1}") 250 if hasattr(self.data, "scale") and \ 251 self.data.scale == 'linear': 252 new_plot.ytransform = 'y' 253 new_plot.yaxis("\\rm{Residuals} ", "normalized") 254 else: 255 new_plot.yaxis("\\rm{Intensity} ", "cm^{-1}") 256 257 new_plot.group_id = "2daverage" + self.data.name 258 new_plot.id = "Circ avg " + self.data.name 259 new_plot.is_data = True 260 variant_plot = QtCore.QVariant(new_plot) 261 GuiUtils.updateModelItemWithPlot(self._item, variant_plot, new_plot.id) 262 # TODO: force immediate display (?) 263 264 def setSlicer(self, slicer): 265 """ 266 Clear the previous slicer and create a new one. 267 slicer: slicer class to create 268 """ 269 # Clear current slicer 270 if self.slicer is not None: 271 self.slicer.clear() 272 # Create a new slicer 273 self.slicer_z += 1 274 self.slicer = slicer(self, self.ax, item=self._item, zorder=self.slicer_z) 275 self.ax.set_ylim(self.data.ymin, self.data.ymax) 276 self.ax.set_xlim(self.data.xmin, self.data.xmax) 277 # Draw slicer 278 self.figure.canvas.draw() 279 self.slicer.update() 172 280 173 281 def onSectorView(self): 174 282 """ 175 """ 176 pass 283 Perform sector averaging on Q and draw sector slicer 284 """ 285 self.setSlicer(slicer=SectorInteractor) 177 286 178 287 def onAnnulusView(self): 179 288 """ 180 """ 181 pass 289 Perform sector averaging on Phi and draw annulus slicer 290 """ 291 self.setSlicer(slicer=AnnulusInteractor) 182 292 183 293 def onBoxSum(self): 184 294 """ 185 """ 186 pass 295 Perform 2D Data averaging Qx and Qy. 296 Display box slicer details. 297 """ 298 self.onClearSlicer() 299 self.slicer_z += 1 300 self.slicer = BoxSumCalculator(self, self.ax, zorder=self.slicer_z) 301 302 self.ax.set_ylim(self.data.ymin, self.data.ymax) 303 self.ax.set_xlim(self.data.xmin, self.data.xmax) 304 self.figure.canvas.draw() 305 self.slicer.update() 306 307 # Get the BoxSumCalculator model. 308 self.box_sum_model = self.slicer.model() 309 # Pass the BoxSumCalculator model to the BoxSum widget 310 self.boxwidget = BoxSum(self, model=self.box_sum_model) 311 # Add the plot to the workspace 312 self.manager.parent.workspace().addWindow(self.boxwidget) 313 self.boxwidget.show() 187 314 188 315 def onBoxAveragingX(self): 189 316 """ 190 """ 191 pass 317 Perform 2D data averaging on Qx 318 Create a new slicer. 319 """ 320 self.setSlicer(slicer=BoxInteractorX) 192 321 193 322 def onBoxAveragingY(self): 194 323 """ 195 """ 196 pass 197 198 def onEditgraphLabel(self): 199 """ 200 """ 201 pass 324 Perform 2D data averaging on Qy 325 Create a new slicer . 326 """ 327 self.setSlicer(slicer=BoxInteractorY) 202 328 203 329 def onColorMap(self): … … 225 351 226 352 def showPlot(self, data, qx_data, qy_data, xmin, xmax, ymin, ymax, 227 zmin, zmax, color=0, symbol=0, markersize=0, 228 label='data2D', cmap=DEFAULT_CMAP): 353 zmin, zmax, label='data2D', cmap=DEFAULT_CMAP): 229 354 """ 230 355 Render and show the current data … … 310 435 self.figure.subplots_adjust(left=0.1, right=.8, bottom=.1) 311 436 312 X = self._data.x_bins[0:-1] 313 Y = self._data.y_bins[0:-1] 314 X, Y = numpy.meshgrid(X, Y) 437 data_x, data_y = numpy.meshgrid(self._data.x_bins[0:-1], 438 self._data.y_bins[0:-1]) 315 439 316 440 ax = Axes3D(self.figure) … … 319 443 # TODO: Define "large" for a dataset 320 444 SET_TOO_LARGE = 500 321 if len( X) > SET_TOO_LARGE:445 if len(data_x) > SET_TOO_LARGE: 322 446 ax.disable_mouse_rotation() 323 447 324 448 self.figure.canvas.resizing = False 325 im = ax.plot_surface(X, Y, output, rstride=1, cstride=1, cmap=cmap, 449 im = ax.plot_surface(data_x, data_y, output, rstride=1, 450 cstride=1, cmap=cmap, 326 451 linewidth=0, antialiased=False) 327 452 self.ax.set_axis_off() … … 332 457 self.figure.canvas.draw() 333 458 459 def update(self): 460 self.figure.canvas.draw() 461 462 def draw(self): 463 self.figure.canvas.draw() 464 465 334 466 class Plotter2D(QtGui.QDialog, Plotter2DWidget): 467 """ 468 Plotter widget implementation 469 """ 335 470 def __init__(self, parent=None, quickplot=False, dimension=2): 336 337 471 QtGui.QDialog.__init__(self) 338 472 Plotter2DWidget.__init__(self, manager=parent, quickplot=quickplot, dimension=dimension) -
src/sas/qtgui/PlotterBase.py
r092a3d9 r3bdbfcc 220 220 self.contextMenu.exec_(self.canvas.mapToGlobal(event_pos)) 221 221 222 def onMplMouseUp(self, event): 223 """ 224 Mouse button up callback 225 """ 226 pass 227 222 228 def onMplMouseDown(self, event): 223 229 """ 224 Left button down and ready to drag 225 """ 226 # Check that the LEFT button was pressed 227 if event.button == 1: 228 self.leftdown = True 229 ax = event.inaxes 230 for text in self.textList: 231 if text.contains(event)[0]: # If user has clicked on text 232 self.selectedText = text 233 return 234 235 if ax != None: 236 self.xInit, self.yInit = event.xdata, event.ydata 237 try: 238 self.x_click = float(event.xdata) # / size_x 239 self.y_click = float(event.ydata) # / size_y 240 except: 241 self.position = None 242 243 def onMplMouseUp(self, event): 244 """ 245 Set the data coordinates of the click 246 """ 247 self.x_click = event.xdata 248 self.y_click = event.ydata 249 250 # Check that the LEFT button was released 251 if event.button == 1: 252 self.leftdown = False 253 #self.leftup = True 254 self.selectedText = None 255 256 #release the legend 257 if self.gotLegend == 1: 258 self.gotLegend = 0 230 Mouse button down callback 231 """ 232 pass 259 233 260 234 def onMplMouseMotion(self, event): 261 235 """ 262 Check if the left button is press and the mouse in moving. 263 Compute delta for x and y coordinates and then perform the drag 264 """ 265 if self.gotLegend == 1 and self.leftdown: 266 self.onLegendMotion(event) 267 return 268 269 if self.leftdown and self.selectedText is not None: 270 # User has clicked on text and is dragging 271 ax = event.inaxes 272 if ax != None: 273 # Only move text if mouse is within axes 274 self.selectedText.set_position((event.xdata, event.ydata)) 275 self.canvas.draw_idle() 276 else: 277 # User has dragged outside of axes 278 self.selectedText = None 279 return 236 Mouse motion callback 237 """ 238 pass 280 239 281 240 def onMplPick(self, event): 282 241 """ 283 On pick legend 284 """ 285 legend = self.legend 286 if event.artist == legend: 287 # Get the box of the legend. 288 bbox = self.legend.get_window_extent() 289 # Get mouse coordinates at time of pick. 290 self.mouse_x = event.mouseevent.x 291 self.mouse_y = event.mouseevent.y 292 # Get legend coordinates at time of pick. 293 self.legend_x = bbox.xmin 294 self.legend_y = bbox.ymin 295 # Indicate we picked up the legend. 296 self.gotLegend = 1 297 298 #self.legend.legendPatch.set_alpha(0.5) 299 300 def onLegendMotion(self, event): 301 """ 302 On legend in motion 303 """ 304 ax = event.inaxes 305 if ax == None: 306 return 307 # Event occurred inside a plotting area 308 lo_x, hi_x = ax.get_xlim() 309 lo_y, hi_y = ax.get_ylim() 310 # How much the mouse moved. 311 x = mouse_diff_x = self.mouse_x - event.x 312 y = mouse_diff_y = self.mouse_y - event.y 313 # Put back inside 314 if x < lo_x: 315 x = lo_x 316 if x > hi_x: 317 x = hi_x 318 if y < lo_y: 319 y = lo_y 320 if y > hi_y: 321 y = hi_y 322 # Move the legend from its previous location by that same amount 323 loc_in_canvas = self.legend_x - mouse_diff_x, \ 324 self.legend_y - mouse_diff_y 325 # Transform into legend coordinate system 326 trans_axes = self.legend.parent.transAxes.inverted() 327 loc_in_norm_axes = trans_axes.transform_point(loc_in_canvas) 328 self.legend_pos_loc = tuple(loc_in_norm_axes) 329 self.legend._loc = self.legend_pos_loc 330 # self.canvas.draw() 331 self.canvas.draw_idle() 242 Mouse pick callback 243 """ 244 pass 332 245 333 246 def onMplWheel(self, event): 334 247 """ 335 Process mouse wheel as zoom events 336 """ 337 ax = event.inaxes 338 step = event.step 339 340 if ax != None: 341 # Event occurred inside a plotting area 342 lo, hi = ax.get_xlim() 343 lo, hi = PlotUtilities.rescale(lo, hi, step, 344 pt=event.xdata, scale=ax.get_xscale()) 345 if not self.xscale == 'log' or lo > 0: 346 self._scale_xlo = lo 347 self._scale_xhi = hi 348 ax.set_xlim((lo, hi)) 349 350 lo, hi = ax.get_ylim() 351 lo, hi = PlotUtilities.rescale(lo, hi, step, pt=event.ydata, 352 scale=ax.get_yscale()) 353 if not self.yscale == 'log' or lo > 0: 354 self._scale_ylo = lo 355 self._scale_yhi = hi 356 ax.set_ylim((lo, hi)) 357 else: 358 # Check if zoom happens in the axes 359 xdata, ydata = None, None 360 x, y = event.x, event.y 361 362 for ax in self.axes: 363 insidex, _ = ax.xaxis.contains(event) 364 if insidex: 365 xdata, _ = ax.transAxes.inverted().transform_point((x, y)) 366 insidey, _ = ax.yaxis.contains(event) 367 if insidey: 368 _, ydata = ax.transAxes.inverted().transform_point((x, y)) 369 if xdata is not None: 370 lo, hi = ax.get_xlim() 371 lo, hi = PlotUtilities.rescale(lo, hi, step, 372 bal=xdata, scale=ax.get_xscale()) 373 if not self.xscale == 'log' or lo > 0: 374 self._scale_xlo = lo 375 self._scale_xhi = hi 376 ax.set_xlim((lo, hi)) 377 if ydata is not None: 378 lo, hi = ax.get_ylim() 379 lo, hi = PlotUtilities.rescale(lo, hi, step, bal=ydata, 380 scale=ax.get_yscale()) 381 if not self.yscale == 'log' or lo > 0: 382 self._scale_ylo = lo 383 self._scale_yhi = hi 384 ax.set_ylim((lo, hi)) 385 self.canvas.draw_idle() 248 Mouse wheel scroll callback 249 """ 250 pass 386 251 387 252 def clean(self): -
src/sas/qtgui/UnitTesting/Plotter2DTest.py
r03c372d r3bdbfcc 1 1 import sys 2 2 import unittest 3 import numpy 3 4 4 5 from PyQt4 import QtGui … … 24 25 def setUp(self): 25 26 '''create''' 26 self.plotter = Plotter2D.Plotter2D(None, quickplot=True) 27 class dummy_manager(object): 28 def communicator(self): 29 return Communicate() 30 def perspective(self): 31 return MyPerspective() 32 def workspace(self): 33 return None 34 35 self.plotter = Plotter2D.Plotter2D(parent=dummy_manager(), quickplot=True) 27 36 28 37 self.data = Data2D(image=[0.1]*4, … … 103 112 104 113 self.assertTrue(FigureCanvas.draw_idle.called) 114 115 def testOnBoxSum(self): 116 """ Test the box sum display and functionality """ 117 118 # hacky way to make things work in manipulations._sum 119 self.data.detector = [1] 120 self.data.err_data = numpy.array([0.0, 0.0, 0.1, 0.0]) 121 self.plotter.data = self.data 122 self.plotter.show() 123 124 # Mock the main window 125 self.plotter.manager.parent = MagicMock() 126 127 # Call the main tested method 128 self.plotter.onBoxSum() 129 130 # Test various properties 131 self.assertIsInstance(self.plotter.slicer.model(), QtGui.QStandardItemModel) 132 self.assertTrue(self.plotter.boxwidget.isVisible()) 133 self.assertIsInstance(self.plotter.boxwidget.model, QtGui.QStandardItemModel) 105 134 106 135 def testContextMenuQuickPlot(self): -
src/sas/qtgui/run_tests.bat
r092a3d9 r3bdbfcc 23 23 python -m UnitTesting.PlotUtilitiesTest 24 24 python -m UnitTesting.ColorMapTest 25 python -m UnitTesting.BoxSumTest 26 python -m UnitTesting.SlicerModelTest -
src/sas/qtgui/run_tests.sh
r092a3d9 r3bdbfcc 22 22 python -m UnitTesting.PlotUtilitiesTest 23 23 python -m UnitTesting.ColorMapTest 24 python -m UnitTesting.BoxSumTest 25 python -m UnitTesting.SlicerModelTest -
src/sas/sasgui/guiframe/local_perspectives/plotting/AnnulusSlicer.py
rd85c194 r3bdbfcc 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 4 # 5 # TODO: NEED MAJOR REFACTOR 6 # 7 8 import math 9 import wx 10 # from copy import deepcopy 11 # Debug printout 12 from sas.sasgui.guiframe.events import NewPlotEvent 13 from sas.sasgui.guiframe.events import StatusEvent 14 from sas.sasgui.guiframe.events import SlicerParameterEvent 15 from sas.sasgui.guiframe.events import EVT_SLICER_PARS 1 import numpy 2 from PyQt4 import QtGui 3 from PyQt4 import QtCore 4 16 5 from BaseInteractor import _BaseInteractor 17 6 from sas.sasgui.guiframe.dataFitting import Data1D 18 19 class AnnulusInteractor(_BaseInteractor): 7 import sas.qtgui.GuiUtils as GuiUtils 8 from sas.qtgui.GuiUtils import formatNumber 9 from sas.qtgui.SlicerModel import SlicerModel 10 11 class AnnulusInteractor(_BaseInteractor, SlicerModel): 20 12 """ 21 13 Select an annulus through a 2D plot. … … 24 16 this class is defined by 2 Ringinterators. 25 17 """ 26 def __init__(self, base, axes, color='black', zorder=3):18 def __init__(self, base, axes, item=None, color='black', zorder=3): 27 19 28 20 _BaseInteractor.__init__(self, base, axes, color=color) 21 SlicerModel.__init__(self) 22 29 23 self.markers = [] 30 24 self.axes = axes 31 25 self.base = base 32 self.qmax = min(math.fabs(self.base.data2D.xmax), 33 math.fabs(self.base.data2D.xmin)) # must be positive 26 self._item = item 27 self.qmax = min(numpy.fabs(self.base.data.xmax), 28 numpy.fabs(self.base.data.xmin)) # must be positive 34 29 self.connect = self.base.connect 35 30 36 # #Number of points on the plot31 # Number of points on the plot 37 32 self.nbins = 36 38 33 # Cursor position of Rings (Left(-1) or Right(1)) 39 self.xmaxd = self.base.data 2D.xmax40 self.xmind = self.base.data 2D.xmin34 self.xmaxd = self.base.data.xmax 35 self.xmind = self.base.data.xmin 41 36 42 37 if (self.xmaxd + self.xmind) > 0: … … 45 40 self.sign = -1 46 41 # Inner circle 47 self.inner_circle = RingInteractor(self, self. base.subplot,42 self.inner_circle = RingInteractor(self, self.axes, 48 43 zorder=zorder, 49 44 r=self.qmax / 2.0, sign=self.sign) 50 45 self.inner_circle.qmax = self.qmax 51 self.outer_circle = RingInteractor(self, self. base.subplot,46 self.outer_circle = RingInteractor(self, self.axes, 52 47 zorder=zorder + 1, r=self.qmax / 1.8, 53 48 sign=self.sign) … … 56 51 self._post_data() 57 52 58 # Bind to slice parameter events 59 self.base.Bind(EVT_SLICER_PARS, self._onEVT_SLICER_PARS) 60 61 def _onEVT_SLICER_PARS(self, event): 62 """ 63 receive an event containing parameters values to reset the slicer 64 65 :param event: event of type SlicerParameterEvent with params as 66 attribute 67 68 """ 69 wx.PostEvent(self.base, 70 StatusEvent(status="AnnulusSlicer._onEVT_SLICER_PARS")) 71 event.Skip() 72 if event.type == self.__class__.__name__: 73 self.set_params(event.params) 74 self.base.update() 53 self.setModelFromParams() 75 54 76 55 def set_layer(self, n): … … 92 71 self.inner_circle.clear() 93 72 self.base.connect.clearall() 94 self.base.Unbind(EVT_SLICER_PARS)95 73 96 74 def update(self): … … 108 86 can restore on Esc. 109 87 """ 110 self.base.freeze_axes()111 88 self.inner_circle.save(ev) 112 89 self.outer_circle.save(ev) … … 120 97 """ 121 98 # Data to average 122 data = self.base.data2D 123 # If we have no data, just return 124 if data == None: 99 data = self.base.data 100 if data is None: 125 101 return 126 102 127 103 from sas.sascalc.dataloader.manipulations import Ring 128 rmin = min( math.fabs(self.inner_circle.get_radius()),129 math.fabs(self.outer_circle.get_radius()))130 rmax = max( math.fabs(self.inner_circle.get_radius()),131 math.fabs(self.outer_circle.get_radius()))132 # if the user does not specify the numbers of points to plot104 rmin = min(numpy.fabs(self.inner_circle.get_radius()), 105 numpy.fabs(self.outer_circle.get_radius())) 106 rmax = max(numpy.fabs(self.inner_circle.get_radius()), 107 numpy.fabs(self.outer_circle.get_radius())) 108 # If the user does not specify the numbers of points to plot 133 109 # the default number will be nbins= 36 134 if nbins ==None:110 if nbins is None: 135 111 self.nbins = 36 136 112 else: 137 113 self.nbins = nbins 138 # # create the data1D Q average of data2D114 # Create the data1D Q average of data2D 139 115 sect = Ring(r_min=rmin, r_max=rmax, nbins=self.nbins) 140 sector = sect(self.base.data 2D)116 sector = sect(self.base.data) 141 117 142 118 if hasattr(sector, "dxl"): … … 148 124 else: 149 125 dxw = None 150 new_plot = Data1D(x=(sector.x - math.pi) * 180 / math.pi,126 new_plot = Data1D(x=(sector.x - numpy.pi) * 180 / numpy.pi, 151 127 y=sector.y, dy=sector.dy) 152 128 new_plot.dxl = dxl 153 129 new_plot.dxw = dxw 154 new_plot.name = "AnnulusPhi" + "(" + self.base.data 2D.name + ")"155 156 new_plot.source = self.base.data2D.source 157 # new_plot.info=self.base.data2D.info130 new_plot.name = "AnnulusPhi" + "(" + self.base.data.name + ")" 131 new_plot.title = "AnnulusPhi" + "(" + self.base.data.name + ")" 132 133 new_plot.source = self.base.data.source 158 134 new_plot.interactive = True 159 new_plot.detector = self.base.data 2D.detector135 new_plot.detector = self.base.data.detector 160 136 # If the data file does not tell us what the axes are, just assume... 161 137 new_plot.xaxis("\\rm{\phi}", 'degrees') 162 138 new_plot.yaxis("\\rm{Intensity} ", "cm^{-1}") 163 139 if hasattr(data, "scale") and data.scale == 'linear' and \ 164 self.base.data 2D.name.count("Residuals") > 0:140 self.base.data.name.count("Residuals") > 0: 165 141 new_plot.ytransform = 'y' 166 142 new_plot.yaxis("\\rm{Residuals} ", "/") 167 143 168 new_plot.group_id = "AnnulusPhi" + self.base.data 2D.name169 new_plot.id = "AnnulusPhi" + self.base.data 2D.name144 new_plot.group_id = "AnnulusPhi" + self.base.data.name 145 new_plot.id = "AnnulusPhi" + self.base.data.name 170 146 new_plot.is_data = True 171 147 new_plot.xtransform = "x" 172 148 new_plot.ytransform = "y" 173 self.base.parent.update_theory(data_id=data.id, theory=new_plot) 174 wx.PostEvent(self.base.parent, NewPlotEvent(plot=new_plot, title="AnnulusPhi")) 149 variant_plot = QtCore.QVariant(new_plot) 150 GuiUtils.updateModelItemWithPlot(self._item, variant_plot, new_plot.id) 151 152 if self.update_model: 153 self.setModelFromParams() 154 self.draw() 155 175 156 176 157 def moveend(self, ev): 177 158 """ 178 159 Called when any dragging motion ends. 179 Post an event (type =SlicerParameterEvent) 180 to plotter 2D with a copy slicer parameters 181 Call _post_data method 182 """ 183 self.base.thaw_axes() 184 # Post parameters to plotter 2D 185 event = SlicerParameterEvent() 186 event.type = self.__class__.__name__ 187 event.params = self.get_params() 188 wx.PostEvent(self.base, event) 160 Redraw the plot with new parameters. 161 """ 162 self._post_data(self.nbins) 189 163 190 164 def restore(self): … … 204 178 pass 205 179 206 def get _params(self):180 def getParams(self): 207 181 """ 208 182 Store a copy of values of parameters of the slicer into a dictionary. 209 210 183 :return params: the dictionary created 211 212 184 """ 213 185 params = {} 214 params["inner_radius"] = math.fabs(self.inner_circle._inner_mouse_x)215 params["outer_radius"] = math.fabs(self.outer_circle._inner_mouse_x)186 params["inner_radius"] = numpy.fabs(self.inner_circle._inner_mouse_x) 187 params["outer_radius"] = numpy.fabs(self.outer_circle._inner_mouse_x) 216 188 params["nbins"] = self.nbins 217 189 return params 218 190 219 def set _params(self, params):191 def setParams(self, params): 220 192 """ 221 193 Receive a dictionary and reset the slicer with values contained … … 224 196 :param params: a dictionary containing name of slicer parameters and 225 197 values the user assigned to the slicer. 226 227 """ 228 inner = math.fabs(params["inner_radius"]) 229 outer = math.fabs(params["outer_radius"]) 198 """ 199 inner = numpy.fabs(params["inner_radius"]) 200 outer = numpy.fabs(params["outer_radius"]) 230 201 self.nbins = int(params["nbins"]) 231 # #Update the picture202 # Update the picture 232 203 self.inner_circle.set_cursor(inner, self.inner_circle._inner_mouse_y) 233 204 self.outer_circle.set_cursor(outer, self.outer_circle._inner_mouse_y) 234 # #Post the data given the nbins entered by the user205 # Post the data given the nbins entered by the user 235 206 self._post_data(self.nbins) 236 237 def freeze_axes(self):238 """239 """240 self.base.freeze_axes()241 242 def thaw_axes(self):243 """244 """245 self.base.thaw_axes()246 207 247 208 def draw(self): … … 278 239 self.sign = sign 279 240 # # Create a marker 280 try: 281 # Inner circle marker 282 x_value = [self.sign * math.fabs(self._inner_mouse_x)] 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] 289 except: 290 x_value = [self.sign * math.fabs(self._inner_mouse_x)] 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" 297 message += " VERSION OF MATPLOTLIB\n" 298 message += "Get the SVN version that is at " 299 message += " least as recent as June 1, 2007" 300 301 owner = self.base.base.parent 302 wx.PostEvent(owner, StatusEvent(status="AnnulusSlicer: %s" % message)) 303 241 # Inner circle marker 242 x_value = [self.sign * numpy.fabs(self._inner_mouse_x)] 243 self.inner_marker = self.axes.plot(x_value, [0], linestyle='', 244 marker='s', markersize=10, 245 color=self.color, alpha=0.6, 246 pickradius=5, label="pick", 247 zorder=zorder, 248 visible=True)[0] 304 249 # Draw a circle 305 250 [self.inner_circle] = self.axes.plot([], [], linestyle='-', marker='', color=self.color) 306 # the number of points that make the ring line251 # The number of points that make the ring line 307 252 self.npts = 40 308 253 … … 325 270 """ 326 271 self.clear_markers() 327 try: 328 self.inner_marker.remove() 329 self.inner_circle.remove() 330 except: 331 # Old version of matplotlib 332 for item in range(len(self.axes.lines)): 333 del self.axes.lines[0] 272 self.inner_marker.remove() 273 self.inner_circle.remove() 334 274 335 275 def get_radius(self): … … 347 287 y = [] 348 288 for i in range(self.npts): 349 phi = 2.0 * math.pi / (self.npts - 1) * i350 351 xval = 1.0 * self._inner_mouse_x * math.cos(phi)352 yval = 1.0 * self._inner_mouse_x * math.sin(phi)289 phi = 2.0 * numpy.pi / (self.npts - 1) * i 290 291 xval = 1.0 * self._inner_mouse_x * numpy.cos(phi) 292 yval = 1.0 * self._inner_mouse_x * numpy.sin(phi) 353 293 354 294 x.append(xval) 355 295 y.append(yval) 356 296 357 self.inner_marker.set(xdata=[self.sign * math.fabs(self._inner_mouse_x)],297 self.inner_marker.set(xdata=[self.sign * numpy.fabs(self._inner_mouse_x)], 358 298 ydata=[0]) 359 299 self.inner_circle.set_data(x, y) … … 366 306 self._inner_save_x = self._inner_mouse_x 367 307 self._inner_save_y = self._inner_mouse_y 368 self.base.freeze_axes()369 308 370 309 def moveend(self, ev): … … 396 335 self.update() 397 336 398 399 def get_params(self): 337 def getParams(self): 400 338 """ 401 339 Store a copy of values of parameters of the slicer into a dictionary. 402 403 340 :return params: the dictionary created 404 405 341 """ 406 342 params = {} 407 params["radius"] = math.fabs(self._inner_mouse_x)343 params["radius"] = numpy.fabs(self._inner_mouse_x) 408 344 return params 409 345 410 def set _params(self, params):346 def setParams(self, params): 411 347 """ 412 348 Receive a dictionary and reset the slicer with values contained … … 435 371 self.base = base 436 372 self.is_inside = side 437 self.qmax = min( math.fabs(self.base.data.xmax),438 math.fabs(self.base.data.xmin)) # must be positive373 self.qmax = min(numpy.fabs(self.base.data.xmax), 374 numpy.fabs(self.base.data.xmin)) # must be positive 439 375 self.connect = self.base.connect 440 376 … … 448 384 self.sign = -1 449 385 # Inner circle 450 self.outer_circle = RingInteractor(self, self. base.subplot, 'blue',386 self.outer_circle = RingInteractor(self, self.axes, 'blue', 451 387 zorder=zorder + 1, r=self.qmax / 1.8, 452 388 sign=self.sign) … … 455 391 self._post_data() 456 392 457 # Bind to slice parameter events458 # self.base.Bind(EVT_SLICER_PARS, self._onEVT_SLICER_PARS)459 460 def _onEVT_SLICER_PARS(self, event):461 """462 receive an event containing parameters values to reset the slicer463 464 :param event: event of type SlicerParameterEvent with params as465 attribute466 """467 wx.PostEvent(self.base,468 StatusEvent(status="AnnulusSlicer._onEVT_SLICER_PARS"))469 event.Skip()470 if event.type == self.__class__.__name__:471 self.set_params(event.params)472 self.base.update()473 474 393 def set_layer(self, n): 475 394 """ 476 395 Allow adding plot to the same panel 477 478 396 :param n: the number of layer 479 480 397 """ 481 398 self.layernum = n … … 489 406 self.outer_circle.clear() 490 407 self.base.connect.clearall() 491 # self.base.Unbind(EVT_SLICER_PARS)492 408 493 409 def update(self): … … 498 414 # Update locations 499 415 self.outer_circle.update() 500 # if self.is_inside != None:416 self._post_data() 501 417 out = self._post_data() 502 418 return out … … 507 423 can restore on Esc. 508 424 """ 509 self.base.freeze_axes()510 425 self.outer_circle.save(ev) 511 426 … … 521 436 522 437 # If we have no data, just return 523 if data ==None:438 if data is None: 524 439 return 525 440 mask = data.mask … … 527 442 528 443 rmin = 0 529 rmax = math.fabs(self.outer_circle.get_radius())530 531 # # create the data1D Q average of data2D444 rmax = numpy.fabs(self.outer_circle.get_radius()) 445 446 # Create the data1D Q average of data2D 532 447 mask = Ringcut(r_min=rmin, r_max=rmax) 533 448 … … 536 451 else: 537 452 out = (mask(data)) 538 # self.base.data.mask=out539 453 return out 540 454 … … 566 480 pass 567 481 568 def get _params(self):482 def getParams(self): 569 483 """ 570 484 Store a copy of values of parameters of the slicer into a dictionary. … … 574 488 """ 575 489 params = {} 576 params["outer_radius"] = math.fabs(self.outer_circle._inner_mouse_x)490 params["outer_radius"] = numpy.fabs(self.outer_circle._inner_mouse_x) 577 491 return params 578 492 579 def set _params(self, params):493 def setParams(self, params): 580 494 """ 581 495 Receive a dictionary and reset the slicer with values contained … … 585 499 values the user assigned to the slicer. 586 500 """ 587 outer = math.fabs(params["outer_radius"])588 # #Update the picture501 outer = numpy.fabs(params["outer_radius"]) 502 # Update the picture 589 503 self.outer_circle.set_cursor(outer, self.outer_circle._inner_mouse_y) 590 # #Post the data given the nbins entered by the user504 # Post the data given the nbins entered by the user 591 505 self._post_data() 592 593 def freeze_axes(self):594 self.base.freeze_axes()595 596 def thaw_axes(self):597 self.base.thaw_axes()598 506 599 507 def draw(self): -
src/sas/sasgui/guiframe/local_perspectives/plotting/SectorSlicer.py
rd85c194 r3bdbfcc 3 3 """ 4 4 import math 5 import wx 5 from PyQt4 import QtGui 6 from PyQt4 import QtCore 7 6 8 from BaseInteractor import _BaseInteractor 7 from sas.sasgui.guiframe.events import NewPlotEvent8 from sas.sasgui.guiframe.events import StatusEvent9 from sas.sasgui.guiframe.events import SlicerParameterEvent10 from sas.sasgui.guiframe.events import EVT_SLICER_PARS11 9 from sas.sasgui.guiframe.dataFitting import Data1D 12 13 14 class SectorInteractor(_BaseInteractor): 10 import sas.qtgui.GuiUtils as GuiUtils 11 from sas.qtgui.SlicerModel import SlicerModel 12 13 14 class SectorInteractor(_BaseInteractor, SlicerModel): 15 15 """ 16 16 Draw a sector slicer.Allow to performQ averaging on data 2D 17 17 """ 18 def __init__(self, base, axes, color='black', zorder=3):18 def __init__(self, base, axes, item=None, color='black', zorder=3): 19 19 20 20 _BaseInteractor.__init__(self, base, axes, color=color) 21 ## Class initialization 21 SlicerModel.__init__(self) 22 # Class initialization 22 23 self.markers = [] 23 24 self.axes = axes 24 ## connect the plot to event 25 self._item = item 26 # Connect the plot to event 25 27 self.connect = self.base.connect 26 28 27 # # compute qmax limit to reset the graph28 x = math.pow(max(self.base.data 2D.xmax,29 math.fabs(self.base.data 2D.xmin)), 2)30 y = math.pow(max(self.base.data 2D.ymax,31 math.fabs(self.base.data 2D.ymin)), 2)29 # Compute qmax limit to reset the graph 30 x = math.pow(max(self.base.data.xmax, 31 math.fabs(self.base.data.xmin)), 2) 32 y = math.pow(max(self.base.data.ymax, 33 math.fabs(self.base.data.ymin)), 2) 32 34 self.qmax = math.sqrt(x + y) 33 # #Number of points on the plot35 # Number of points on the plot 34 36 self.nbins = 20 35 # #Angle of the middle line37 # Angle of the middle line 36 38 self.theta2 = math.pi / 3 37 # #Absolute value of the Angle between the middle line and any side line39 # Absolute value of the Angle between the middle line and any side line 38 40 self.phi = math.pi / 12 39 # #Middle line40 self.main_line = LineInteractor(self, self. base.subplot, color='blue',41 # Middle line 42 self.main_line = LineInteractor(self, self.axes, color='blue', 41 43 zorder=zorder, r=self.qmax, 42 44 theta=self.theta2) 43 45 self.main_line.qmax = self.qmax 44 # #Right Side line45 self.right_line = SideInteractor(self, self. base.subplot, color='black',46 # Right Side line 47 self.right_line = SideInteractor(self, self.axes, color='black', 46 48 zorder=zorder, r=self.qmax, 47 49 phi=-1 * self.phi, theta2=self.theta2) 48 50 self.right_line.qmax = self.qmax 49 # #Left Side line50 self.left_line = SideInteractor(self, self. base.subplot, color='black',51 # Left Side line 52 self.left_line = SideInteractor(self, self.axes, color='black', 51 53 zorder=zorder, r=self.qmax, 52 54 phi=self.phi, theta2=self.theta2) 53 55 self.left_line.qmax = self.qmax 54 # #draw the sector56 # draw the sector 55 57 self.update() 56 58 self._post_data() 57 ## Bind to slice parameter events 58 self.base.Bind(EVT_SLICER_PARS, self._onEVT_SLICER_PARS) 59 60 def _onEVT_SLICER_PARS(self, event): 61 """ 62 receive an event containing parameters values to reset the slicer 63 64 :param event: event of type SlicerParameterEvent with params as 65 attribute 66 67 """ 68 wx.PostEvent(self.base.parent, 69 StatusEvent(status="SectorSlicer._onEVT_SLICER_PARS")) 70 event.Skip() 71 if event.type == self.__class__.__name__: 72 self.set_params(event.params) 73 self.base.update() 59 self.setModelFromParams() 74 60 75 61 def set_layer(self, n): 76 62 """ 77 63 Allow adding plot to the same panel 78 79 64 :param n: the number of layer 80 81 65 """ 82 66 self.layernum = n … … 92 76 self.right_line.clear() 93 77 self.base.connect.clearall() 94 self.base.Unbind(EVT_SLICER_PARS)95 78 96 79 def update(self): … … 100 83 """ 101 84 # Update locations 102 # #Check if the middle line was dragged and103 # update the picture accordingly85 # Check if the middle line was dragged and 86 # update the picture accordingly 104 87 if self.main_line.has_move: 105 88 self.main_line.update() … … 108 91 self.left_line.update(delta=self.left_line.phi / 2, 109 92 mline=self.main_line.theta) 110 # #Check if the left side has moved and update the slicer accordingly93 # Check if the left side has moved and update the slicer accordingly 111 94 if self.left_line.has_move: 112 95 self.main_line.update() … … 116 99 mline=self.main_line, side=True, 117 100 left=False, right=True) 118 ## Check if the right side line has moved and 119 #update the slicer accordingly 101 # Check if the right side line has moved and update the slicer accordingly 120 102 if self.right_line.has_move: 121 103 self.main_line.update() … … 130 112 can restore on Esc. 131 113 """ 132 self.base.freeze_axes()133 114 self.main_line.save(ev) 134 115 self.right_line.save(ev) … … 141 122 :param nbins: the number of point to plot for the average 1D data 142 123 """ 143 # # get the data2D to average144 data = self.base.data 2D124 # Get the data2D to average 125 data = self.base.data 145 126 # If we have no data, just return 146 127 if data == None: 147 128 return 148 # #Averaging129 # Averaging 149 130 from sas.sascalc.dataloader.manipulations import SectorQ 150 131 radius = self.qmax … … 157 138 phi_max=phimax + math.pi, nbins=nbins) 158 139 159 sector = sect(self.base.data 2D)160 # #Create 1D data resulting from average140 sector = sect(self.base.data) 141 # Create 1D data resulting from average 161 142 162 143 if hasattr(sector, "dxl"): … … 171 152 new_plot.dxl = dxl 172 153 new_plot.dxw = dxw 173 new_plot.name = "SectorQ" + "(" + self.base.data 2D.name + ")"174 new_plot. source = self.base.data2D.source175 #new_plot.info=self.base.data2D.info154 new_plot.name = "SectorQ" + "(" + self.base.data.name + ")" 155 new_plot.title = "SectorQ" + "(" + self.base.data.name + ")" 156 new_plot.source = self.base.data.source 176 157 new_plot.interactive = True 177 new_plot.detector = self.base.data 2D.detector178 # # If the data file does not tell us what the axes are, just assume...158 new_plot.detector = self.base.data.detector 159 # If the data file does not tell us what the axes are, just assume them. 179 160 new_plot.xaxis("\\rm{Q}", "A^{-1}") 180 161 new_plot.yaxis("\\rm{Intensity}", "cm^{-1}") 181 162 if hasattr(data, "scale") and data.scale == 'linear' and \ 182 self.base.data 2D.name.count("Residuals") > 0:163 self.base.data.name.count("Residuals") > 0: 183 164 new_plot.ytransform = 'y' 184 165 new_plot.yaxis("\\rm{Residuals} ", "/") 185 166 186 new_plot.group_id = "2daverage" + self.base.data 2D.name187 new_plot.id = "SectorQ" + self.base.data 2D.name167 new_plot.group_id = "2daverage" + self.base.data.name 168 new_plot.id = "SectorQ" + self.base.data.name 188 169 new_plot.is_data = True 189 self.base.parent.update_theory(data_id=data.id, theory=new_plot) 190 wx.PostEvent(self.base.parent, 191 NewPlotEvent(plot=new_plot, title="SectorQ" + self.base.data2D.name)) 170 variant_plot = QtCore.QVariant(new_plot) 171 GuiUtils.updateModelItemWithPlot(self._item, variant_plot, new_plot.id) 172 173 if self.update_model: 174 self.setModelFromParams() 175 self.draw() 192 176 193 177 def moveend(self, ev): … … 195 179 Called a dragging motion ends.Get slicer event 196 180 """ 197 self.base.thaw_axes() 198 ## Post parameters 199 event = SlicerParameterEvent() 200 event.type = self.__class__.__name__ 201 event.params = self.get_params() 202 ## Send slicer paramers to plotter2D 203 wx.PostEvent(self.base, event) 181 # Post parameters 182 self._post_data(self.nbins) 204 183 205 184 def restore(self): … … 222 201 pass 223 202 224 def get _params(self):203 def getParams(self): 225 204 """ 226 205 Store a copy of values of parameters of the slicer into a dictionary. 227 228 206 :return params: the dictionary created 229 230 207 """ 231 208 params = {} 232 # #Always make sure that the left and the right line are at phi233 # #angle of the middle line209 # Always make sure that the left and the right line are at phi 210 # angle of the middle line 234 211 if math.fabs(self.left_line.phi) != math.fabs(self.right_line.phi): 235 212 msg = "Phi left and phi right are different" … … 241 218 return params 242 219 243 def set _params(self, params):220 def setParams(self, params): 244 221 """ 245 222 Receive a dictionary and reset the slicer with values contained … … 253 230 self.nbins = int(params["nbins"]) 254 231 self.main_line.theta = main 255 # #Reset the slicer parameters232 # Reset the slicer parameters 256 233 self.main_line.update() 257 234 self.right_line.update(phi=phi, delta=None, mline=self.main_line, … … 259 236 self.left_line.update(phi=phi, delta=None, 260 237 mline=self.main_line, side=True) 261 # # post the new corresponding data238 # Post the new corresponding data 262 239 self._post_data(nbins=self.nbins) 263 264 def freeze_axes(self):265 """266 """267 self.base.freeze_axes()268 269 def thaw_axes(self):270 """271 """272 self.base.thaw_axes()273 240 274 241 def draw(self): … … 291 258 """ 292 259 _BaseInteractor.__init__(self, base, axes, color=color) 293 # #Initialize the class260 # Initialize the class 294 261 self.markers = [] 295 262 self.axes = axes 296 # #compute the value of the angle between the current line and297 # #the x-axis263 # compute the value of the angle between the current line and 264 # the x-axis 298 265 self.save_theta = theta2 + phi 299 266 self.theta = theta2 + phi 300 # #the value of the middle line angle with respect to the x-axis267 # the value of the middle line angle with respect to the x-axis 301 268 self.theta2 = theta2 302 # #Radius to find polar coordinates this line's endpoints269 # Radius to find polar coordinates this line's endpoints 303 270 self.radius = r 304 # #phi is the phase between the current line and the middle line271 # phi is the phase between the current line and the middle line 305 272 self.phi = phi 306 # #End points polar coordinates273 # End points polar coordinates 307 274 x1 = self.radius * math.cos(self.theta) 308 275 y1 = self.radius * math.sin(self.theta) 309 276 x2 = -1 * self.radius * math.cos(self.theta) 310 277 y2 = -1 * self.radius * math.sin(self.theta) 311 # # defining a new marker278 # Defining a new marker 312 279 self.inner_marker = self.axes.plot([x1 / 2.5], [y1 / 2.5], linestyle='', 313 280 marker='s', markersize=10, … … 316 283 zorder=zorder, visible=True)[0] 317 284 318 # #Defining the current line285 # Defining the current line 319 286 self.line = self.axes.plot([x1, x2], [y1, y2], 320 287 linestyle='-', marker='', 321 288 color=self.color, visible=True)[0] 322 # #Flag to differentiate the left line from the right line motion289 # Flag to differentiate the left line from the right line motion 323 290 self.left_moving = False 324 # #Flag to define a motion291 # Flag to define a motion 325 292 self.has_move = False 326 # #connecting markers and draw the picture293 # connecting markers and draw the picture 327 294 self.connect_markers([self.inner_marker, self.line]) 328 295 … … 330 297 """ 331 298 Allow adding plot to the same panel 332 333 299 :param n: the number of layer 334 335 300 """ 336 301 self.layernum = n … … 359 324 360 325 """ 361 #print "update left or right ", self.has_move362 326 self.left_moving = left 363 327 theta3 = 0 … … 396 360 """ 397 361 self.save_theta = self.theta 398 self.base.freeze_axes()399 362 400 363 def moveend(self, ev): … … 416 379 self.theta = math.atan2(y, x) 417 380 self.has_move = True 418 #ToDo: Simplify below419 381 if not self.left_moving: 420 382 if self.theta2 - self.theta <= 0 and self.theta2 > 0: … … 464 426 self.update() 465 427 466 def get _params(self):428 def getParams(self): 467 429 """ 468 430 """ … … 472 434 return params 473 435 474 def set _params(self, params):436 def setParams(self, params): 475 437 """ 476 438 """ … … 554 516 """ 555 517 self.save_theta = self.theta 556 self.base.freeze_axes()557 518 558 519 def moveend(self, ev): … … 582 543 self.update() 583 544 584 def get _params(self):545 def getParams(self): 585 546 """ 586 547 """ … … 590 551 return params 591 552 592 def set _params(self, params):553 def setParams(self, params): 593 554 """ 594 555 """ -
src/sas/sasgui/guiframe/local_perspectives/plotting/boxSlicer.py
rd85c194 r3bdbfcc 1 import wx2 import math3 1 import numpy 4 from sas.sasgui.guiframe.events import NewPlotEvent 5 from sas.sasgui.guiframe.events import StatusEvent 6 from sas.sasgui.guiframe.events import SlicerParameterEvent 7 from sas.sasgui.guiframe.events import EVT_SLICER_PARS 2 from PyQt4 import QtGui 3 from PyQt4 import QtCore 4 8 5 from BaseInteractor import _BaseInteractor 9 6 from sas.sasgui.guiframe.dataFitting import Data1D 10 11 12 class BoxInteractor(_BaseInteractor): 7 import sas.qtgui.GuiUtils as GuiUtils 8 from sas.qtgui.SlicerModel import SlicerModel 9 10 11 class BoxInteractor(_BaseInteractor, SlicerModel): 13 12 """ 14 13 BoxInteractor define a rectangle that return data1D average of Data2D 15 14 in a rectangle area defined by -x, x ,y, -y 16 15 """ 17 def __init__(self, base, axes, color='black', zorder=3):16 def __init__(self, base, axes, item=None, color='black', zorder=3): 18 17 _BaseInteractor.__init__(self, base, axes, color=color) 19 # # Class initialization 18 SlicerModel.__init__(self) 19 # Class initialization 20 20 self.markers = [] 21 21 self.axes = axes 22 # #connecting artist 22 self._item = item 23 #connecting artist 23 24 self.connect = self.base.connect 24 # #which direction is the preferred interaction direction25 # which direction is the preferred interaction direction 25 26 self.direction = None 26 # #determine x y values27 self.x = 0.5 * min( math.fabs(self.base.data2D.xmax),28 math.fabs(self.base.data2D.xmin))29 self.y = 0.5 * min( math.fabs(self.base.data2D.xmax),30 math.fabs(self.base.data2D.xmin))31 # #when reach qmax reset the graph32 self.qmax = max(self.base.data 2D.xmax, self.base.data2D.xmin,33 self.base.data 2D.ymax, self.base.data2D.ymin)34 # #Number of points on the plot27 # determine x y values 28 self.x = 0.5 * min(numpy.fabs(self.base.data.xmax), 29 numpy.fabs(self.base.data.xmin)) 30 self.y = 0.5 * min(numpy.fabs(self.base.data.xmax), 31 numpy.fabs(self.base.data.xmin)) 32 # when reach qmax reset the graph 33 self.qmax = max(self.base.data.xmax, self.base.data.xmin, 34 self.base.data.ymax, self.base.data.ymin) 35 # Number of points on the plot 35 36 self.nbins = 30 36 # #If True, I(|Q|) will be return, otherwise,37 # If True, I(|Q|) will be return, otherwise, 37 38 # negative q-values are allowed 38 39 self.fold = True 39 # #reference of the current Slab averaging40 # reference of the current Slab averaging 40 41 self.averager = None 41 # #Create vertical and horizaontal lines for the rectangle42 # Create vertical and horizaontal lines for the rectangle 42 43 self.vertical_lines = VerticalLines(self, 43 self. base.subplot,44 self.axes, 44 45 color='blue', 45 46 zorder=zorder, … … 49 50 50 51 self.horizontal_lines = HorizontalLines(self, 51 self. base.subplot,52 self.axes, 52 53 color='green', 53 54 zorder=zorder, … … 55 56 y=self.y) 56 57 self.horizontal_lines.qmax = self.qmax 57 # #draw the rectangle and plost the data 1D resulting58 # #of averaging data2D58 # draw the rectangle and plost the data 1D resulting 59 # of averaging data2D 59 60 self.update() 60 61 self._post_data() 61 # # Bind to slice parameter events 62 self.base.Bind(EVT_SLICER_PARS, self._onEVT_SLICER_PARS) 63 64 def _onEVT_SLICER_PARS(self, event): 65 """ 66 receive an event containing parameters values to reset the slicer 67 68 :param event: event of type SlicerParameterEvent with params as 69 attribute 70 """ 71 wx.PostEvent(self.base.parent, 72 StatusEvent(status="BoxSlicer._onEVT_SLICER_PARS")) 73 event.Skip() 74 if event.type == self.__class__.__name__: 75 self.set_params(event.params) 76 self.base.update() 62 self.setModelFromParams() 77 63 78 64 def update_and_post(self): … … 102 88 self.vertical_lines.clear() 103 89 self.base.connect.clearall() 104 self.base.Unbind(EVT_SLICER_PARS)105 90 106 91 def update(self): … … 123 108 can restore on Esc. 124 109 """ 125 self.base.freeze_axes()126 110 self.vertical_lines.save(ev) 127 111 self.horizontal_lines.save(ev) … … 139 123 140 124 """ 141 if self.direction ==None:125 if self.direction is None: 142 126 self.direction = direction 143 127 144 x_min = -1 * math.fabs(self.vertical_lines.x)145 x_max = math.fabs(self.vertical_lines.x)146 y_min = -1 * math.fabs(self.horizontal_lines.y)147 y_max = math.fabs(self.horizontal_lines.y)148 149 if nbins !=None:128 x_min = -1 * numpy.fabs(self.vertical_lines.x) 129 x_max = numpy.fabs(self.vertical_lines.x) 130 y_min = -1 * numpy.fabs(self.horizontal_lines.y) 131 y_max = numpy.fabs(self.horizontal_lines.y) 132 133 if nbins is not None: 150 134 self.nbins = nbins 151 if self.averager ==None:152 if new_slab ==None:135 if self.averager is None: 136 if new_slab is None: 153 137 msg = "post data:cannot average , averager is empty" 154 138 raise ValueError, msg … … 158 142 x_low = 0 159 143 else: 160 x_low = math.fabs(x_min)144 x_low = numpy.fabs(x_min) 161 145 bin_width = (x_max + x_low) / self.nbins 162 146 elif self.direction == "Y": … … 164 148 y_low = 0 165 149 else: 166 y_low = math.fabs(y_min)150 y_low = numpy.fabs(y_min) 167 151 bin_width = (y_max + y_low) / self.nbins 168 152 else: … … 173 157 bin_width=bin_width) 174 158 box.fold = self.fold 175 boxavg = box(self.base.data 2D)159 boxavg = box(self.base.data) 176 160 # 3 Create Data1D to plot 177 161 if hasattr(boxavg, "dxl"): … … 187 171 new_plot.dxw = dxw 188 172 new_plot.name = str(self.averager.__name__) + \ 189 "(" + self.base.data2D.name + ")" 190 new_plot.source = self.base.data2D.source 173 "(" + self.base.data.name + ")" 174 new_plot.title = str(self.averager.__name__) + \ 175 "(" + self.base.data.name + ")" 176 new_plot.source = self.base.data.source 191 177 new_plot.interactive = True 192 new_plot.detector = self.base.data 2D.detector178 new_plot.detector = self.base.data.detector 193 179 # # If the data file does not tell us what the axes are, just assume... 194 180 new_plot.xaxis("\\rm{Q}", "A^{-1}") 195 181 new_plot.yaxis("\\rm{Intensity} ", "cm^{-1}") 196 182 197 data = self.base.data 2D183 data = self.base.data 198 184 if hasattr(data, "scale") and data.scale == 'linear' and \ 199 self.base.data 2D.name.count("Residuals") > 0:185 self.base.data.name.count("Residuals") > 0: 200 186 new_plot.ytransform = 'y' 201 187 new_plot.yaxis("\\rm{Residuals} ", "/") 202 188 203 new_plot.group_id = "2daverage" + self.base.data 2D.name204 new_plot.id = (self.averager.__name__) + self.base.data 2D.name189 new_plot.group_id = "2daverage" + self.base.data.name 190 new_plot.id = (self.averager.__name__) + self.base.data.name 205 191 new_plot.is_data = True 206 self.base.parent.update_theory(data_id=self.base.data2D.id, \ 207 theory=new_plot) 208 wx.PostEvent(self.base.parent, 209 NewPlotEvent(plot=new_plot, title=str(self.averager.__name__))) 192 variant_plot = QtCore.QVariant(new_plot) 193 GuiUtils.updateModelItemWithPlot(self._item, variant_plot, new_plot.id) 194 195 if self.update_model: 196 self.setModelFromParams() 197 self.draw() 210 198 211 199 def moveend(self, ev): … … 215 203 corresponding to the new average 216 204 """ 217 self.base.thaw_axes()218 # Post paramters219 event = SlicerParameterEvent()220 event.type = self.__class__.__name__221 event.params = self.get_params()222 wx.PostEvent(self.base.parent, event)223 # create the new data1D224 205 self._post_data() 225 206 … … 240 221 pass 241 222 242 def get _params(self):223 def getParams(self): 243 224 """ 244 225 Store a copy of values of parameters of the slicer into a dictionary. … … 248 229 """ 249 230 params = {} 250 params["x_max"] = math.fabs(self.vertical_lines.x)251 params["y_max"] = math.fabs(self.horizontal_lines.y)231 params["x_max"] = numpy.fabs(self.vertical_lines.x) 232 params["y_max"] = numpy.fabs(self.horizontal_lines.y) 252 233 params["nbins"] = self.nbins 253 234 return params 254 235 255 def set _params(self, params):236 def setParams(self, params): 256 237 """ 257 238 Receive a dictionary and reset the slicer with values contained … … 261 242 values the user assigned to the slicer. 262 243 """ 263 self.x = float( math.fabs(params["x_max"]))264 self.y = float( math.fabs(params["y_max"]))244 self.x = float(numpy.fabs(params["x_max"])) 245 self.y = float(numpy.fabs(params["y_max"])) 265 246 self.nbins = params["nbins"] 266 247 … … 269 250 self.post_data(nbins=None) 270 251 271 def freeze_axes(self):272 """273 """274 self.base.freeze_axes()275 276 def thaw_axes(self):277 """278 """279 self.base.thaw_axes()280 281 252 def draw(self): 282 253 """ … … 294 265 """ 295 266 _BaseInteractor.__init__(self, base, axes, color=color) 296 # #Class initialization267 # Class initialization 297 268 self.markers = [] 298 269 self.axes = axes 299 # #Saving the end points of two lines270 # Saving the end points of two lines 300 271 self.x = x 301 272 self.save_x = x … … 303 274 self.y = y 304 275 self.save_y = y 305 # #Creating a marker276 # Creating a marker 306 277 # Inner circle marker 307 278 self.inner_marker = self.axes.plot([0], [self.y], linestyle='', … … 311 282 zorder=zorder, 312 283 visible=True)[0] 313 # #Define 2 horizontal lines284 # Define 2 horizontal lines 314 285 self.top_line = self.axes.plot([self.x, -self.x], [self.y, self.y], 315 286 linestyle='-', marker='', … … 318 289 linestyle='-', marker='', 319 290 color=self.color, visible=True)[0] 320 # #Flag to check the motion of the lines291 # Flag to check the motion of the lines 321 292 self.has_move = False 322 # #Connecting markers to mouse events and draw293 # Connecting markers to mouse events and draw 323 294 self.connect_markers([self.top_line, self.inner_marker]) 324 295 self.update() … … 339 310 """ 340 311 self.clear_markers() 341 try: 342 self.inner_marker.remove() 343 self.top_line.remove() 344 self.bottom_line.remove() 345 except: 346 # Old version of matplotlib 347 for item in range(len(self.axes.lines)): 348 del self.axes.lines[0] 312 self.inner_marker.remove() 313 self.top_line.remove() 314 self.bottom_line.remove() 349 315 350 316 def update(self, x=None, y=None): … … 356 322 357 323 """ 358 # #Reset x, y- coordinates if send as parameters359 if x !=None:360 self.x = numpy.sign(self.x) * math.fabs(x)361 if y !=None:362 self.y = numpy.sign(self.y) * math.fabs(y)363 # #Draw lines and markers324 # Reset x, y- coordinates if send as parameters 325 if x is not None: 326 self.x = numpy.sign(self.x) * numpy.fabs(x) 327 if y is not None: 328 self.y = numpy.sign(self.y) * numpy.fabs(y) 329 # Draw lines and markers 364 330 self.inner_marker.set(xdata=[0], ydata=[self.y]) 365 331 self.top_line.set(xdata=[self.x, -self.x], ydata=[self.y, self.y]) … … 373 339 self.save_x = self.x 374 340 self.save_y = self.y 375 self.base.freeze_axes()376 341 377 342 def moveend(self, ev): … … 409 374 self.markers = [] 410 375 self.axes = axes 411 self.x = math.fabs(x)376 self.x = numpy.fabs(x) 412 377 self.save_x = self.x 413 self.y = math.fabs(y)378 self.y = numpy.fabs(y) 414 379 self.save_y = y 415 380 # Inner circle marker … … 446 411 """ 447 412 self.clear_markers() 448 try: 449 self.inner_marker.remove() 450 self.left_line.remove() 451 self.right_line.remove() 452 except: 453 # Old version of matplotlib 454 for item in range(len(self.axes.lines)): 455 del self.axes.lines[0] 413 self.inner_marker.remove() 414 self.left_line.remove() 415 self.right_line.remove() 456 416 457 417 def update(self, x=None, y=None): … … 463 423 464 424 """ 465 # # reset x, y -coordinates if given as parameters466 if x !=None:467 self.x = numpy.sign(self.x) * math.fabs(x)468 if y !=None:469 self.y = numpy.sign(self.y) * math.fabs(y)470 # # draw lines and markers425 # Reset x, y -coordinates if given as parameters 426 if x is not None: 427 self.x = numpy.sign(self.x) * numpy.fabs(x) 428 if y is not None: 429 self.y = numpy.sign(self.y) * numpy.fabs(y) 430 # Draw lines and markers 471 431 self.inner_marker.set(xdata=[self.x], ydata=[0]) 472 432 self.left_line.set(xdata=[-self.x, -self.x], ydata=[self.y, -self.y]) … … 480 440 self.save_x = self.x 481 441 self.save_y = self.y 482 self.base.freeze_axes()483 442 484 443 def moveend(self, ev): … … 510 469 Average in Qx direction 511 470 """ 512 def __init__(self, base, axes, color='black', zorder=3):513 BoxInteractor.__init__(self, base, axes, color=color)471 def __init__(self, base, axes, item=None, color='black', zorder=3): 472 BoxInteractor.__init__(self, base, axes, item=item, color=color) 514 473 self.base = base 515 474 self._post_data() … … 527 486 Average in Qy direction 528 487 """ 529 def __init__(self, base, axes, color='black', zorder=3):530 BoxInteractor.__init__(self, base, axes, color=color)488 def __init__(self, base, axes, item=None, color='black', zorder=3): 489 BoxInteractor.__init__(self, base, axes, item=item, color=color) 531 490 self.base = base 532 491 self._post_data() -
src/sas/sasgui/guiframe/local_perspectives/plotting/boxSum.py
rd85c194 r3bdbfcc 1 1 """ 2 Boxsum Class: determine 2 rectangular area to compute 3 the sum of pixel of a Data. 4 """ 5 import numpy 6 from PyQt4 import QtGui 7 from PyQt4 import QtCore 8 from sas.qtgui.GuiUtils import formatNumber 9 10 from BaseInteractor import _BaseInteractor 11 from sas.sascalc.dataloader.manipulations import Boxavg 12 from sas.sascalc.dataloader.manipulations import Boxsum 13 14 from sas.qtgui.SlicerModel import SlicerModel 15 16 17 class BoxSumCalculator(_BaseInteractor): 18 """ 2 19 Boxsum Class: determine 2 rectangular area to compute 3 20 the sum of pixel of a Data. 4 """ 5 import math 6 import wx 7 from BaseInteractor import _BaseInteractor 8 from sas.sasgui.guiframe.events import SlicerParamUpdateEvent 9 from sas.sasgui.guiframe.events import EVT_SLICER_PARS 10 from sas.sasgui.guiframe.events import StatusEvent 11 12 13 class BoxSum(_BaseInteractor): 21 Uses PointerInteractor , VerticalDoubleLine,HorizontalDoubleLine. 22 @param zorder: Artists with lower zorder values are drawn first. 23 @param x_min: the minimum value of the x coordinate 24 @param x_max: the maximum value of the x coordinate 25 @param y_min: the minimum value of the y coordinate 26 @param y_max: the maximum value of the y coordinate 27 14 28 """ 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 def __init__(self, base, axes, color='black', zorder=3): 29 30 _BaseInteractor.__init__(self, base, axes, color=color) 30 # # class initialization 31 # #list of Boxsmun markers31 32 # list of Boxsmun markers 32 33 self.markers = [] 33 34 self.axes = axes 34 # # connect the artist for the motion 35 self._model = None 36 self.update_model = False 37 38 # connect the artist for the motion 35 39 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 40 41 # when qmax is reached the selected line is reset the its previous value 42 self.qmax = min(self.base.data.xmax, self.base.data.xmin) 43 44 # Define the boxsum limits 45 self.xmin = -1 * 0.5 * min(numpy.fabs(self.base.data.xmax), 46 numpy.fabs(self.base.data.xmin)) 47 self.ymin = -1 * 0.5 * min(numpy.fabs(self.base.data.xmax), 48 numpy.fabs(self.base.data.xmin)) 49 self.xmax = 0.5 * min(numpy.fabs(self.base.data.xmax), 50 numpy.fabs(self.base.data.xmin)) 51 self.ymax = 0.5 * min(numpy.fabs(self.base.data.xmax), 52 numpy.fabs(self.base.data.xmin)) 53 # center of the boxSum 48 54 self.center_x = 0.0002 49 55 self.center_y = 0.0003 50 # #Number of points on the plot56 # Number of points on the plot 51 57 self.nbins = 20 52 # #Define initial result the summation58 # Define initial result the summation 53 59 self.count = 0 54 60 self.error = 0 … … 56 62 self.totalerror = 0 57 63 self.points = 0 58 # #Flag to determine if the current figure has moved59 # #set to False == no motion , set to True== motion64 # Flag to determine if the current figure has moved 65 # set to False == no motion , set to True== motion 60 66 self.has_move = False 61 # #Create Boxsum edges67 # Create Boxsum edges 62 68 self.horizontal_lines = HorizontalDoubleLine(self, 63 self. base.subplot,69 self.axes, 64 70 color='blue', 65 71 zorder=zorder, … … 71 77 72 78 self.vertical_lines = VerticalDoubleLine(self, 73 self. base.subplot,79 self.axes, 74 80 color='black', 75 81 zorder=zorder, … … 81 87 82 88 self.center = PointInteractor(self, 83 self. base.subplot, color='grey',89 self.axes, color='grey', 84 90 zorder=zorder, 85 91 center_x=self.center_x, 86 92 center_y=self.center_y) 87 # #Save the name of the slicer panel associate with this slicer93 # Save the name of the slicer panel associate with this slicer 88 94 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 95 # Update and post slicer parameters 96 self.update_model = False 97 self.update() 98 self.postData() 99 100 # set up the model 101 self._model = QtGui.QStandardItemModel(1, 9) 102 self.setModelFromParams() 103 self.update_model = True 104 self._model.itemChanged.connect(self.setParamsFromModel) 105 106 def setModelFromParams(self): 107 """ 108 Set up the Qt model for data handling between controls 109 """ 110 parameters = self.getParams() 111 # Crete/overwrite model items 112 self._model.setData(self._model.index(0, 0), 113 QtCore.QVariant(formatNumber(parameters['Height']))) 114 self._model.setData(self._model.index(0, 1), 115 QtCore.QVariant(formatNumber(parameters['Width']))) 116 self._model.setData(self._model.index(0, 2), 117 QtCore.QVariant(formatNumber(parameters['center_x']))) 118 self._model.setData(self._model.index(0, 3), 119 QtCore.QVariant(formatNumber(parameters['center_y']))) 120 121 self.setReadOnlyParametersFromModel() 122 123 def model(self): 124 ''' model accessor ''' 125 return self._model 126 127 def setReadOnlyParametersFromModel(self): 128 """ 129 Cast model content onto "read-only" subset of parameters 130 """ 131 parameters = self.getParams() 132 self._model.setData(self._model.index(0, 4), 133 QtCore.QVariant(formatNumber(parameters['avg']))) 134 self._model.setData(self._model.index(0, 5), 135 QtCore.QVariant(formatNumber(parameters['avg_error']))) 136 self._model.setData(self._model.index(0, 6), 137 QtCore.QVariant(formatNumber(parameters['sum']))) 138 self._model.setData(self._model.index(0, 7), 139 QtCore.QVariant(formatNumber(parameters['sum_error']))) 140 self._model.setData(self._model.index(0, 8), 141 QtCore.QVariant(formatNumber(parameters['num_points']))) 142 143 def setParamsFromModel(self): 144 """ 145 Cast model content onto params dict 146 """ 147 params = {} 148 params["Height"] = float(self.model().item(0, 0).text()) 149 params["Width"] = float(self.model().item(0, 1).text()) 150 params["center_x"] = float(self.model().item(0, 2).text()) 151 params["center_y"] = float(self.model().item(0, 3).text()) 152 self.update_model = False 153 self.setParams(params) 154 self.setReadOnlyParametersFromModel() 155 self.update_model = True 156 157 def setPanelName(self, name): 158 """ 159 Store the name of the panel associated to this slicer 160 @param name: the name of this panel 99 161 """ 100 162 self.panel_name = name 101 163 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): 164 def setLayer(self, n): 118 165 """ 119 166 Allow adding plot to the same panel … … 132 179 self.center.clear() 133 180 self.base.connect.clearall() 134 self.base.Unbind(EVT_SLICER_PARS)135 181 136 182 def update(self): … … 139 185 resetting the widgets. 140 186 """ 141 # #check if the center point has moved and update the figure accordingly187 # check if the center point has moved and update the figure accordingly 142 188 if self.center.has_move: 143 189 self.center.update() 144 190 self.horizontal_lines.update(center=self.center) 145 191 self.vertical_lines.update(center=self.center) 146 # #check if the horizontal lines have moved and192 # check if the horizontal lines have moved and 147 193 # update the figure accordingly 148 194 if self.horizontal_lines.has_move: … … 151 197 y2=self.horizontal_lines.y2, 152 198 height=self.horizontal_lines.half_height) 153 # #check if the vertical lines have moved and199 # check if the vertical lines have moved and 154 200 # update the figure accordingly 155 201 if self.vertical_lines.has_move: … … 164 210 can restore on Esc. 165 211 """ 166 self.base.freeze_axes()167 212 self.horizontal_lines.save(ev) 168 213 self.vertical_lines.save(ev) 169 214 self.center.save(ev) 170 215 171 def _post_data(self):216 def postData(self): 172 217 """ 173 218 Get the limits of the boxsum and compute the sum of the pixel 174 219 contained in that region and the error on that sum 175 220 """ 176 # #the region of the summation221 # the region of the summation 177 222 x_min = self.horizontal_lines.x2 178 223 x_max = self.horizontal_lines.x1 179 224 y_min = self.vertical_lines.y2 180 225 y_max = self.vertical_lines.y1 181 # #computation of the sum and its error 182 from sas.sascalc.dataloader.manipulations import Boxavg 226 #computation of the sum and its error 183 227 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.data 2D)228 self.count, self.error = box(self.base.data) 185 229 # Dig out number of points summed, SMK & PDB, 04/03/2013 186 from sas.sascalc.dataloader.manipulations import Boxsum187 230 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) 231 self.total, self.totalerror, self.points = boxtotal(self.base.data) 232 if self.update_model: 233 self.setModelFromParams() 234 self.draw() 189 235 190 236 def moveend(self, ev): 191 237 """ 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) 238 After a dragging motion this function is called to compute 239 the error and the sum of pixel of a given data 2D 240 """ 241 # compute error an d sum of data's pixel 242 self.postData() 206 243 207 244 def restore(self): … … 213 250 self.center.restore() 214 251 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): 252 def getParams(self): 227 253 """ 228 254 Store a copy of values of parameters of the slicer into a dictionary. … … 230 256 """ 231 257 params = {} 232 params["Width"] = math.fabs(self.vertical_lines.half_width) * 2233 params["Height"] = math.fabs(self.horizontal_lines.half_height) * 2258 params["Width"] = numpy.fabs(self.vertical_lines.half_width) * 2 259 params["Height"] = numpy.fabs(self.horizontal_lines.half_height) * 2 234 260 params["center_x"] = self.center.x 235 261 params["center_y"] = self.center.y … … 241 267 return params 242 268 243 def get _result(self):244 """ 245 return the result of box summation269 def getResult(self): 270 """ 271 Return the result of box summation 246 272 """ 247 273 result = {} … … 253 279 return result 254 280 255 def set _params(self, params):281 def setParams(self, params): 256 282 """ 257 283 Receive a dictionary and reset the slicer with values contained 258 284 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 285 :param params: a dictionary containing name of slicer parameters 286 and values the user assigned to the slicer. 287 """ 288 x_max = numpy.fabs(params["Width"]) / 2 289 y_max = numpy.fabs(params["Height"]) / 2 263 290 264 291 self.center_x = params["center_x"] … … 271 298 width=x_max, height=y_max) 272 299 # 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() 300 self.postData() 284 301 285 302 def draw(self): 286 """ 287 """ 303 """ Redraw canvas""" 288 304 self.base.draw() 289 305 … … 297 313 def __init__(self, base, axes, color='black', zorder=5, center_x=0.0, 298 314 center_y=0.0): 299 """300 """301 315 _BaseInteractor.__init__(self, base, axes, color=color) 302 # #Initialization the class316 # Initialization the class 303 317 self.markers = [] 304 318 self.axes = axes … … 306 320 self.x = center_x 307 321 self.y = center_y 308 # #saved value of the center coordinates322 # saved value of the center coordinates 309 323 self.save_x = center_x 310 324 self.save_y = center_y 311 # #Create a marker325 # Create a marker 312 326 self.center_marker = self.axes.plot([self.x], [self.y], linestyle='', 313 327 marker='s', markersize=10, … … 316 330 zorder=zorder, 317 331 visible=True)[0] 318 # #Draw a point332 # Draw a point 319 333 self.center = self.axes.plot([self.x], [self.y], 320 334 linestyle='-', marker='', 321 335 color=self.color, 322 336 visible=True)[0] 323 # #Flag to determine the motion this point337 # Flag to determine the motion this point 324 338 self.has_move = False 325 # #connecting the marker to allow them to move339 # connecting the marker to allow them to move 326 340 self.connect_markers([self.center_marker]) 327 # #Update the figure328 self.update() 329 330 def set _layer(self, n):331 """ 332 333 341 # Update the figure 342 self.update() 343 344 def setLayer(self, n): 345 """ 346 Allow adding plot to the same panel 347 @param n: the number of layer 334 348 """ 335 349 self.layernum = n … … 338 352 def clear(self): 339 353 """ 340 354 Clear this figure and its markers 341 355 """ 342 356 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] 357 self.center.remove() 358 self.center_marker.remove() 350 359 351 360 def update(self, center_x=None, center_y=None): 352 361 """ 353 362 Draw the new roughness on the graph. 354 363 """ 355 364 if center_x != None: … … 367 376 self.save_x = self.x 368 377 self.save_y = self.y 369 self.base.freeze_axes()370 378 371 379 def moveend(self, ev): … … 391 399 self.base.base.update() 392 400 393 def set _cursor(self, x, y):401 def setCursor(self, x, y): 394 402 """ 395 403 """ … … 399 407 class VerticalDoubleLine(_BaseInteractor): 400 408 """ 401 402 409 Draw 2 vertical lines moving in opposite direction and centered on 410 a point (PointInteractor) 403 411 """ 404 412 def __init__(self, base, axes, color='black', zorder=5, x=0.5, y=0.5, 405 413 center_x=0.0, center_y=0.0): 406 """407 """408 414 _BaseInteractor.__init__(self, base, axes, color=color) 409 # #Initialization the class415 # Initialization the class 410 416 self.markers = [] 411 417 self.axes = axes 412 # #Center coordinates418 # Center coordinates 413 419 self.center_x = center_x 414 420 self.center_y = center_y 415 # #defined end points vertical lignes and their saved values421 # defined end points vertical lignes and their saved values 416 422 self.y1 = y + self.center_y 417 423 self.save_y1 = self.y1 … … 429 435 # # save the color of the line 430 436 self.color = color 431 # #the height of the rectangle432 self.half_height = math.fabs(y)433 self.save_half_height = math.fabs(y)434 # #the with of the rectangle435 self.half_width = math.fabs(self.x1 - self.x2) / 2436 self.save_half_width = math.fabs(self.x1 - self.x2) / 2437 # #Create marker437 # the height of the rectangle 438 self.half_height = numpy.fabs(y) 439 self.save_half_height = numpy.fabs(y) 440 # the with of the rectangle 441 self.half_width = numpy.fabs(self.x1 - self.x2) / 2 442 self.save_half_width = numpy.fabs(self.x1 - self.x2) / 2 443 # Create marker 438 444 self.right_marker = self.axes.plot([self.x1], [0], linestyle='', 439 445 marker='s', markersize=10, … … 442 448 zorder=zorder, visible=True)[0] 443 449 444 # # define the left and right lines of the rectangle450 # Define the left and right lines of the rectangle 445 451 self.right_line = self.axes.plot([self.x1, self.x1], [self.y1, self.y2], 446 452 linestyle='-', marker='', … … 449 455 linestyle='-', marker='', 450 456 color=self.color, visible=True)[0] 451 # #Flag to determine if the lines have moved457 # Flag to determine if the lines have moved 452 458 self.has_move = False 453 # # connection the marker and draw the pictures459 # Connection the marker and draw the pictures 454 460 self.connect_markers([self.right_marker]) 455 461 self.update() 456 462 457 def set _layer(self, n):463 def setLayer(self, n): 458 464 """ 459 465 Allow adding plot to the same panel … … 468 474 """ 469 475 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] 476 self.right_marker.remove() 477 self.right_line.remove() 478 self.left_line.remove() 478 479 479 480 def update(self, x1=None, x2=None, y1=None, y2=None, width=None, … … 489 490 :param center: provided x, y coordinates of the center point 490 491 """ 491 # # save the new height, witdh of the rectangle if given as a param492 if width !=None:492 # Save the new height, witdh of the rectangle if given as a param 493 if width is not None: 493 494 self.half_width = width 494 if height !=None:495 if height is not None: 495 496 self.half_height = height 496 # #If new center coordinates are given draw the rectangle497 # #given these value498 if center !=None:497 # If new center coordinates are given draw the rectangle 498 # given these value 499 if center is not None: 499 500 self.center_x = center.x 500 501 self.center_y = center.y … … 510 511 ydata=[self.y1, self.y2]) 511 512 return 512 # #if x1, y1, y2, y3 are given draw the rectangle with this value513 if x1 !=None:513 # if x1, y1, y2, y3 are given draw the rectangle with this value 514 if x1 is not None: 514 515 self.x1 = x1 515 if x2 !=None:516 if x2 is not None: 516 517 self.x2 = x2 517 if y1 !=None:518 if y1 is not None: 518 519 self.y1 = y1 519 if y2 !=None:520 if y2 is not None: 520 521 self.y2 = y2 521 # #Draw 2 vertical lines and a marker522 # Draw 2 vertical lines and a marker 522 523 self.right_marker.set(xdata=[self.x1], ydata=[self.center_y]) 523 524 self.right_line.set(xdata=[self.x1, self.x1], ydata=[self.y1, self.y2]) … … 535 536 self.save_half_height = self.half_height 536 537 self.save_half_width = self.half_width 537 self.base.freeze_axes()538 538 539 539 def moveend(self, ev): 540 540 """ 541 541 After a dragging motion reset the flag self.has_move to False 542 542 """ 543 543 self.has_move = False … … 562 562 delta = self.x1 - self.center_x 563 563 self.x2 = self.center_x - delta 564 self.half_width = math.fabs(self.x1 - self.x2) / 2564 self.half_width = numpy.fabs(self.x1 - self.x2) / 2 565 565 self.has_move = True 566 566 self.base.base.update() 567 567 568 def set _cursor(self, x, y):569 """ 570 568 def setCursor(self, x, y): 569 """ 570 Update the figure given x and y 571 571 """ 572 572 self.move(x, y, None) … … 575 575 class HorizontalDoubleLine(_BaseInteractor): 576 576 """ 577 577 Select an annulus through a 2D plot 578 578 """ 579 579 def __init__(self, base, axes, color='black', zorder=5, x=0.5, y=0.5, … … 581 581 582 582 _BaseInteractor.__init__(self, base, axes, color=color) 583 # #Initialization the class583 # Initialization the class 584 584 self.markers = [] 585 585 self.axes = axes 586 # #Center coordinates586 # Center coordinates 587 587 self.center_x = center_x 588 588 self.center_y = center_y … … 598 598 self.save_x2 = self.x2 599 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)600 self.half_height = numpy.fabs(y) 601 self.save_half_height = numpy.fabs(y) 602 self.half_width = numpy.fabs(x) 603 self.save_half_width = numpy.fabs(x) 604 604 self.top_marker = self.axes.plot([0], [self.y1], linestyle='', 605 605 marker='s', markersize=10, … … 616 616 linestyle='-', marker='', 617 617 color=self.color, visible=True)[0] 618 # #Flag to determine if the lines have moved618 # Flag to determine if the lines have moved 619 619 self.has_move = False 620 # #connection the marker and draw the pictures620 # connection the marker and draw the pictures 621 621 self.connect_markers([self.top_marker]) 622 622 self.update() 623 623 624 def set _layer(self, n):625 """ 626 627 624 def setLayer(self, n): 625 """ 626 Allow adding plot to the same panel 627 @param n: the number of layer 628 628 """ 629 629 self.layernum = n … … 632 632 def clear(self): 633 633 """ 634 634 Clear this figure and its markers 635 635 """ 636 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] 637 self.top_marker.remove() 638 self.bottom_line.remove() 639 self.top_line.remove() 645 640 646 641 def update(self, x1=None, x2=None, y1=None, y2=None, … … 656 651 :param center: provided x, y coordinates of the center point 657 652 """ 658 # # save the new height, witdh of the rectangle if given as a param659 if width !=None:653 # Save the new height, witdh of the rectangle if given as a param 654 if width is not None: 660 655 self.half_width = width 661 if height !=None:656 if height is not None: 662 657 self.half_height = height 663 # #If new center coordinates are given draw the rectangle664 # #given these value665 if center !=None:658 # If new center coordinates are given draw the rectangle 659 # given these value 660 if center is not None: 666 661 self.center_x = center.x 667 662 self.center_y = center.y … … 678 673 ydata=[self.y2, self.y2]) 679 674 return 680 # #if x1, y1, y2, y3 are given draw the rectangle with this value681 if x1 !=None:675 # if x1, y1, y2, y3 are given draw the rectangle with this value 676 if x1 is not None: 682 677 self.x1 = x1 683 if x2 !=None:678 if x2 is not None: 684 679 self.x2 = x2 685 if y1 !=None:680 if y1 is not None: 686 681 self.y1 = y1 687 if y2 !=None:682 if y2 is not None: 688 683 self.y2 = y2 689 # #Draw 2 vertical lines and a marker684 # Draw 2 vertical lines and a marker 690 685 self.top_marker.set(xdata=[self.center_x], ydata=[self.y1]) 691 686 self.top_line.set(xdata=[self.x1, self.x2], ydata=[self.y1, self.y1]) … … 703 698 self.save_half_height = self.half_height 704 699 self.save_half_width = self.half_width 705 self.base.freeze_axes()706 700 707 701 def moveend(self, ev): … … 730 724 delta = self.y1 - self.center_y 731 725 self.y2 = self.center_y - delta 732 self.half_height = math.fabs(self.y1) - self.center_y726 self.half_height = numpy.fabs(self.y1) - self.center_y 733 727 self.has_move = True 734 728 self.base.base.update() 735 729 736 def set _cursor(self, x, y):737 """ 738 730 def setCursor(self, x, y): 731 """ 732 Update the figure given x and y 739 733 """ 740 734 self.move(x, y, None)
Note: See TracChangeset
for help on using the changeset viewer.