- Timestamp:
- Dec 16, 2016 12:43:18 PM (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:
- d3ca363
- Parents:
- 0ba0774
- Location:
- src/sas/qtgui
- Files:
-
- 3 added
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
src/sas/qtgui/DataExplorer.py
r0ba0774 r9290b1a 401 401 new_plot = Plotter(self) 402 402 403 def addDataPlot(plot, plot_set):404 plot.data = plot_set405 plot.plot()406 407 403 def addDataPlot2D(plot_set): 408 404 plot2D = Plotter2D(self) 409 addDataPlot(plot2D,plot_set)405 plot2D.plot(plot_set) 410 406 self.plotAdd(plot2D) 411 407 412 408 for plot_set in plots: 413 409 if isinstance(plot_set, Data1D): 414 addDataPlot(new_plot,plot_set)410 new_plot.plot(plot_set) 415 411 elif isinstance(plot_set, Data2D): 416 412 addDataPlot2D(plot_set) … … 418 414 msg = "Incorrect data type passed to Plotting" 419 415 raise AttributeError, msg 420 421 416 422 417 if plots and \ -
src/sas/qtgui/GUITests.py
r27313b7 r9290b1a 2 2 3 3 from UnitTesting import AboutBoxTest 4 from UnitTesting import AddTextTest 4 5 from UnitTesting import DataExplorerTest 5 6 from UnitTesting import WelcomePanelTest … … 22 23 suites = ( 23 24 unittest.makeSuite(AboutBoxTest.AboutBoxTest, 'test'), 25 unittest.makeSuite(AddTextTest.AddTextTest, 'test'), 24 26 unittest.makeSuite(DataExplorerTest.DataExplorerTest, 'test'), 25 27 unittest.makeSuite(WelcomePanelTest.WelcomePanelTest, 'test'), -
src/sas/qtgui/PlotUtilities.py
rfecfe28 r9290b1a 175 175 176 176 return image 177 178 def rescale(lo, hi, step, pt=None, bal=None, scale='linear'): 179 """ 180 Rescale (lo,hi) by step, returning the new (lo,hi) 181 The scaling is centered on pt, with positive values of step 182 driving lo/hi away from pt and negative values pulling them in. 183 If bal is given instead of point, it is already in [0,1] coordinates. 184 185 This is a helper function for step-based zooming. 186 """ 187 # Convert values into the correct scale for a linear transformation 188 # TODO: use proper scale transformers 189 loprev = lo 190 hiprev = hi 191 if scale == 'log': 192 assert lo > 0 193 if lo > 0: 194 lo = numpy.log10(lo) 195 if hi > 0: 196 hi = numpy.log10(hi) 197 if pt is not None: 198 pt = numpy.log10(pt) 199 200 # Compute delta from axis range * %, or 1-% if persent is negative 201 if step > 0: 202 delta = float(hi - lo) * step / 100 203 else: 204 delta = float(hi - lo) * step / (100 - step) 205 206 # Add scale factor proportionally to the lo and hi values, 207 # preserving the 208 # point under the mouse 209 if bal is None: 210 bal = float(pt - lo) / (hi - lo) 211 lo = lo - (bal * delta) 212 hi = hi + (1 - bal) * delta 213 214 # Convert transformed values back to the original scale 215 if scale == 'log': 216 if (lo <= -250) or (hi >= 250): 217 lo = loprev 218 hi = hiprev 219 else: 220 lo, hi = numpy.power(10., lo), numpy.power(10., hi) 221 return (lo, hi) 222 -
src/sas/qtgui/Plotter.py
r27313b7 r9290b1a 2 2 3 3 import matplotlib.pyplot as plt 4 4 from matplotlib.font_manager import FontProperties 5 6 from sas.sasgui.guiframe.dataFitting import Data1D 5 7 from sas.sasgui.plottools import transform 6 8 from sas.sasgui.plottools.convert_units import convert_unit 7 9 from sas.qtgui.PlotterBase import PlotterBase 10 from sas.qtgui.AddText import AddText 8 11 9 12 class PlotterWidget(PlotterBase): … … 27 30 self.title(title=value.title) 28 31 29 def plot(self, marker=None, linestyle=None, hide_error=False):32 def plot(self, data=None, marker=None, linestyle=None, hide_error=False): 30 33 """ 31 34 Plot self._data 32 35 """ 36 # Data1D 37 if isinstance(data, Data1D): 38 self.data = data 39 assert(self._data) 40 33 41 # Shortcut for an axis 34 42 ax = self.ax … … 45 53 marker=marker, 46 54 linestyle=linestyle, 47 label=self._title) 55 label=self._title, 56 picker=True) 48 57 else: 49 58 ax.errorbar(self._data.view.x, self._data.view.y, … … 54 63 lolims=False, uplims=False, 55 64 xlolims=False, xuplims=False, 56 label=self._title) 65 label=self._title, 66 picker=True) 57 67 58 68 # Now add the legend with some customizations. 59 legend = ax.legend(loc='upper right', shadow=True) 69 self.legend = ax.legend(loc='upper right', shadow=True) 70 #self.legend.get_frame().set_alpha(0.4) 71 self.legend.set_picker(True) 60 72 61 73 # Current labels for axes … … 142 154 Show a dialog allowing adding custom text to the chart 143 155 """ 144 print("onAddText") 145 pass 156 self.addText = AddText(self) 157 if self.addText.exec_() == QtGui.QDialog.Accepted: 158 # Retrieve the new text, its font and color 159 extra_text = self.addText.text() 160 extra_font = self.addText.font() 161 extra_color = self.addText.color() 162 163 # Place the text on the screen at (0,0) 164 pos_x = self.x_click 165 pos_y = self.y_click 166 167 # Map QFont onto MPL font 168 mpl_font = FontProperties() 169 mpl_font.set_size(int(extra_font.pointSize())) 170 mpl_font.set_family(str(extra_font.family())) 171 mpl_font.set_weight(int(extra_font.weight())) 172 # MPL style names 173 styles = ['normal', 'italic', 'oblique'] 174 # QFont::Style maps directly onto the above 175 try: 176 mpl_font.set_style(styles[extra_font.style()]) 177 except: 178 pass 179 180 if len(extra_text) > 0: 181 new_text = self.ax.text(str(pos_x), 182 str(pos_y), 183 extra_text, 184 color=extra_color, 185 fontproperties=mpl_font) 186 # Update the list of annotations 187 self.textList.append(new_text) 188 self.canvas.draw_idle() 146 189 147 190 def onRemoveText(self): 148 191 """ 149 Remove the most recent added text 150 """ 151 print("onRemoveText") 152 pass 192 Remove the most recently added text 193 """ 194 num_text = len(self.textList) 195 if num_text < 1: 196 return 197 txt = self.textList[num_text - 1] 198 text_remove = txt.get_text() 199 txt.remove() 200 self.textList.remove(txt) 201 202 self.canvas.draw_idle() 153 203 154 204 def onSetGraphRange(self): … … 172 222 # Clear the plot first 173 223 plt.cla() 224 self.ax.cla() 174 225 175 226 # Changing the scale might be incompatible with -
src/sas/qtgui/Plotter2D.py
rc4e5400 r9290b1a 6 6 7 7 DEFAULT_CMAP = pylab.cm.jet 8 from mpl_toolkits.mplot3d import Axes3D 8 9 9 10 import sas.qtgui.PlotUtilities as PlotUtilities 10 11 from sas.qtgui.PlotterBase import PlotterBase 11 from mpl_toolkits.mplot3d import Axes3D12 from sas.sasgui.guiframe.dataFitting import Data2D 12 13 13 14 # Minimum value of Z for which we will present data. … … 43 44 self.title(title=data.title) 44 45 45 def plot(self, marker=None, linestyle=None):46 def plot(self, data=None, marker=None, linestyle=None): 46 47 """ 47 48 Plot 2D self._data 48 49 """ 50 # Assing data 51 if isinstance(data, Data2D): 52 self.data = data 53 54 assert(self._data) 55 49 56 # Toggle the scale 50 57 zmin_2D_temp = self.zmin -
src/sas/qtgui/PlotterBase.py
r27313b7 r9290b1a 1 1 import pylab 2 import numpy 2 3 3 4 from PyQt4 import QtGui … … 13 14 14 15 DEFAULT_CMAP = pylab.cm.jet 16 from sas.sasgui.plottools.binder import BindArtist 17 15 18 from sas.qtgui.ScaleProperties import ScaleProperties 16 19 from sas.qtgui.WindowTitle import WindowTitle 17 20 import sas.qtgui.PlotHelper as PlotHelper 21 import sas.qtgui.PlotUtilities as PlotUtilities 18 22 19 23 class PlotterBase(QtGui.QWidget): … … 53 57 self.y_label = "log10(y)" 54 58 59 # Mouse click related 60 self.x_click = None 61 self.y_click = None 62 self.event_pos = None 63 self.leftdown = False 64 self.gotLegend = 0 65 66 # Annotations 67 self.selectedText = None 68 self.textList = [] 69 55 70 # Pre-define the Scale properties dialog 56 71 self.properties = ScaleProperties(self, … … 66 81 self.ax = self.figure.add_subplot(self.current_plot) 67 82 83 # Remove this, DAMMIT 84 self.axes = [self.ax] 85 68 86 # Set the background color to white 69 87 self.canvas.figure.set_facecolor('#FFFFFF') 88 89 # Canvas event handlers 90 self.canvas.mpl_connect('button_release_event', self.onMplMouseUp) 91 self.canvas.mpl_connect('button_press_event', self.onMplMouseDown) 92 self.canvas.mpl_connect('motion_notify_event', self.onMplMouseMotion) 93 self.canvas.mpl_connect('pick_event', self.onMplPick) 94 self.canvas.mpl_connect('scroll_event', self.onMplWheel) 70 95 71 96 if not quickplot: … … 166 191 """ 167 192 Define common context menu and associated actions for the MPL widget 168 TODO: move to plotter1d/plotter2d169 193 """ 170 194 raise NotImplementedError("Context menu method must be implemented in derived class.") … … 180 204 Display the context menu 181 205 """ 182 self.contextMenu.exec_(self.canvas.mapToGlobal(event.pos())) 206 event_pos = event.pos() 207 self.contextMenu.exec_(self.canvas.mapToGlobal(event_pos)) 208 209 def onMplMouseDown(self, event): 210 """ 211 Left button down and ready to drag 212 """ 213 # Check that the LEFT button was pressed 214 if event.button == 1: 215 self.leftdown = True 216 ax = event.inaxes 217 for text in self.textList: 218 if text.contains(event)[0]: # If user has clicked on text 219 self.selectedText = text 220 return 221 222 if ax != None: 223 self.xInit, self.yInit = event.xdata, event.ydata 224 try: 225 self.x_click = float(event.xdata) # / size_x 226 self.y_click = float(event.ydata) # / size_y 227 except: 228 self.position = None 229 230 def onMplMouseUp(self, event): 231 """ 232 Set the data coordinates of the click 233 """ 234 self.x_click = event.xdata 235 self.y_click = event.ydata 236 237 # Check that the LEFT button was released 238 if event.button == 1: 239 self.leftdown = False 240 #self.leftup = True 241 self.selectedText = None 242 243 #release the legend 244 if self.gotLegend == 1: 245 self.gotLegend = 0 246 247 def onMplMouseMotion(self, event): 248 """ 249 Check if the left button is press and the mouse in moving. 250 Compute delta for x and y coordinates and then perform the drag 251 """ 252 if self.gotLegend == 1 and self.leftdown: 253 self.onLegendMotion(event) 254 return 255 256 if self.leftdown and self.selectedText is not None: 257 # User has clicked on text and is dragging 258 ax = event.inaxes 259 if ax != None: 260 # Only move text if mouse is within axes 261 self.selectedText.set_position((event.xdata, event.ydata)) 262 self.canvas.draw_idle() 263 else: 264 # User has dragged outside of axes 265 self.selectedText = None 266 return 267 268 def onMplPick(self, event): 269 """ 270 On pick legend 271 """ 272 legend = self.legend 273 if event.artist == legend: 274 # Get the box of the legend. 275 bbox = self.legend.get_window_extent() 276 # Get mouse coordinates at time of pick. 277 self.mouse_x = event.mouseevent.x 278 self.mouse_y = event.mouseevent.y 279 # Get legend coordinates at time of pick. 280 self.legend_x = bbox.xmin 281 self.legend_y = bbox.ymin 282 # Indicate we picked up the legend. 283 self.gotLegend = 1 284 285 #self.legend.legendPatch.set_alpha(0.5) 286 287 def onLegendMotion(self, event): 288 """ 289 On legend in motion 290 """ 291 ax = event.inaxes 292 if ax == None: 293 return 294 # Event occurred inside a plotting area 295 lo_x, hi_x = ax.get_xlim() 296 lo_y, hi_y = ax.get_ylim() 297 # How much the mouse moved. 298 x = mouse_diff_x = self.mouse_x - event.x 299 y = mouse_diff_y = self.mouse_y - event.y 300 # Put back inside 301 if x < lo_x: 302 x = lo_x 303 if x > hi_x: 304 x = hi_x 305 if y < lo_y: 306 y = lo_y 307 if y > hi_y: 308 y = hi_y 309 # Move the legend from its previous location by that same amount 310 loc_in_canvas = self.legend_x - mouse_diff_x, \ 311 self.legend_y - mouse_diff_y 312 # Transform into legend coordinate system 313 trans_axes = self.legend.parent.transAxes.inverted() 314 loc_in_norm_axes = trans_axes.transform_point(loc_in_canvas) 315 self.legend_pos_loc = tuple(loc_in_norm_axes) 316 self.legend._loc = self.legend_pos_loc 317 # self.canvas.draw() 318 self.canvas.draw_idle() 319 320 def onMplWheel(self, event): 321 """ 322 Process mouse wheel as zoom events 323 """ 324 ax = event.inaxes 325 step = event.step 326 327 if ax != None: 328 # Event occurred inside a plotting area 329 lo, hi = ax.get_xlim() 330 lo, hi = PlotUtilities.rescale(lo, hi, step, 331 pt=event.xdata, scale=ax.get_xscale()) 332 if not self.xscale == 'log' or lo > 0: 333 self._scale_xlo = lo 334 self._scale_xhi = hi 335 ax.set_xlim((lo, hi)) 336 337 lo, hi = ax.get_ylim() 338 lo, hi = PlotUtilities.rescale(lo, hi, step, pt=event.ydata, 339 scale=ax.get_yscale()) 340 if not self.yscale == 'log' or lo > 0: 341 self._scale_ylo = lo 342 self._scale_yhi = hi 343 ax.set_ylim((lo, hi)) 344 else: 345 # Check if zoom happens in the axes 346 xdata, ydata = None, None 347 x, y = event.x, event.y 348 349 for ax in self.axes: 350 insidex, _ = ax.xaxis.contains(event) 351 if insidex: 352 xdata, _ = ax.transAxes.inverted().transform_point((x, y)) 353 insidey, _ = ax.yaxis.contains(event) 354 if insidey: 355 _, ydata = ax.transAxes.inverted().transform_point((x, y)) 356 if xdata is not None: 357 lo, hi = ax.get_xlim() 358 lo, hi = PlotUtilities.rescale(lo, hi, step, 359 bal=xdata, scale=ax.get_xscale()) 360 if not self.xscale == 'log' or lo > 0: 361 self._scale_xlo = lo 362 self._scale_xhi = hi 363 ax.set_xlim((lo, hi)) 364 if ydata is not None: 365 lo, hi = ax.get_ylim() 366 lo, hi = PlotUtilities.rescale(lo, hi, step, bal=ydata, 367 scale=ax.get_yscale()) 368 if not self.yscale == 'log' or lo > 0: 369 self._scale_ylo = lo 370 self._scale_yhi = hi 371 ax.set_ylim((lo, hi)) 372 self.canvas.draw_idle() 183 373 184 374 def clean(self): -
src/sas/qtgui/UI/convert_all.sh
r3968752 r9290b1a 1 1 # UI -> PY 2 2 for filename in *.ui; do 3 pyuic 4$filename > "`basename "$filename" .ui`.py"3 pyuic.bat $filename > "`basename "$filename" .ui`.py" 4 4 done 5 5 -
src/sas/qtgui/UnitTesting/PlotterBaseTest.py
r27313b7 r9290b1a 157 157 158 158 def testOnWindowsTitle(self): 159 ''' test changing the plot title'''159 """ Test changing the plot title""" 160 160 # Mock the modal dialog's response 161 161 QtGui.QDialog.exec_ = MagicMock(return_value=QtGui.QDialog.Accepted) … … 171 171 self.assertEqual(self.plotter.windowTitle(), "I am a new title") 172 172 173 def testOnMplMouseDown(self): 174 """ Test what happens on mouse click down in chart """ 175 pass 176 177 def testOnMplMouseUp(self): 178 """ Test what happens on mouse release in chart """ 179 pass 180 181 def testOnMplMouseMotion(self): 182 """ Test what happens on mouse move in chart """ 183 pass 184 185 def testOnMplPick(self): 186 """ Test what happens on mouse pick in chart """ 187 pass 188 189 def testOnMplWheel(self): 190 """ Test what happens on mouse pick in chart """ 191 pass 192 173 193 if __name__ == "__main__": 174 194 unittest.main() -
src/sas/qtgui/UnitTesting/PlotterTest.py
r27313b7 r9290b1a 154 154 self.assertEqual(self.plotter.ax.get_ylabel(), "$ \\ \\ ^{4}(()^{4})$") 155 155 156 def testAddText(self): 157 """ Checks the functionality of adding text to graph """ 158 pass 159 160 def testOnRemoveText(self): 161 """ Cheks if annotations can be removed from the graph """ 162 pass 163 164 156 165 if __name__ == "__main__": 157 166 unittest.main() -
src/sas/qtgui/run_tests.bat
r27313b7 r9290b1a 17 17 python -m UnitTesting.ScalePropertiesTest 18 18 python -m UnitTesting.WindowTitleTest 19 19 python -m UnitTesting.AddTextTest -
src/sas/qtgui/run_tests.sh
r27313b7 r9290b1a 16 16 python -m UnitTesting.DensityCalculatorTest 17 17 python -m UnitTesting.WindowTitleTest 18 python -m UnitTesting.AddTextTest
Note: See TracChangeset
for help on using the changeset viewer.