OpenMPCD
Plotter.py
1 from .App import App
2 
3 from .. import Exceptions
4 from .. import PlotTools
5 from .. import Utilities
6 
7 import copy
8 import os
9 
10 class Plotter:
11  """
12  Graphical User Interface for plotting data.
13 
14  @var _plotDashedIfNegative Whether the negative parts of plots should instead be plotted
15  positively, but with dashed lines.
16  @var _yScaleIsLog Whether the y axis is logarithmic.
17  @var _plotSelector Instance of _PlotSelectionList used to select plots for display.
18  @var _hiddenCharacteristics List of plot characteristics that are hidden in the plot selector.
19  @var _characteristicsOrder Order of the plot characteristics.
20  """
21 
22  def __init__(self):
23  self.app = App(self)
24  self.plots = {}
25  self.nextPlotID = 0
26  self._plotDashedIfNegative = False
27  self._yScaleIsLog = False
28  self._hiddenCharacteristics = []
29  self._characteristicsOrder = []
30 
31  def run(self):
32  self.app.MainLoop()
33 
34  def provideData(self, x, y, show=True, label=None, characteristics=None):
35  """
36  Provides a new plot by specifying the x and y coordinates.
37 
38  @param[in] x A list of x coordinates.
39  @param[in] y A list of y coordinates corresponding to the x coordinates.
40  @param[in] show Whether to draw the plot initially, as a bool.
41  @param[in] label The label for the plot.
42  @param[in] characteristics Plot characteristics, as used in the plot selection window.
43  @throw TypeError Throws if show is not of type bool.
44  """
45 
46  if type(show) is not bool:
47  raise TypeError("Inavlid type for parameter 'show'")
48 
49  lines = None
50  if show:
51  lines = self.plot(x, y, label=label)
52  self.app.canvasFrame.update()
53 
54  if characteristics is None:
55  characteristics = {}
56 
57  self.plots[self.nextPlotID] = {'lines': lines, 'x': x, 'y': y, 'show': show, 'label': label, 'characteristics': characteristics}
58  self.nextPlotID = self.nextPlotID + 1
59 
60  self._updatePlotSelector()
61 
62  def provideDataFile(self, path, characteristics={}):
63  """
64  Adds the given file, or rather its contents, to the list of available plots.
65 
66  The added plot is not drawn on the canvas.
67 
68  Each line in the file that is of the form
69  #name = value
70  is considered to describe the plot's characteristic "name", the value of which
71  is "value". "value" is treated as a float, if possible, and as a string otherwise.
72 
73  Any other line must consist of a float, followed by a space, and another float.
74  The first float corresponds to the x coordinate of a plot point, the second
75  float is the corresponding y coordinate.
76 
77  @param[in] path The path to the file.
78  @param[in] characteristics A dictionary of characteristics for the plot.
79  Conflicting file comments are ignored.
80  @throw FileFormatException Throws if the given file did not adhere to the expected format.
81  """
82 
83  x = []
84  y = []
85 
86  with Utilities.openPossiblyCompressedFile(path) as file:
87  for line in file:
88  if line[0] == '#':
89  parts = line.split('=')
90  if len(parts) > 0 and parts[0][1:].strip() == 'rundirs':
91  parts = line.split('=', 1)
92 
93  if len(parts) != 2:
94  raise Exceptions.FileFormatException("Unknown comment format in " + path)
95 
96  property_, value = parts
97  property_ = property_[1:].strip()
98 
99  if property_ in characteristics:
100  continue
101 
102  try:
103  value = float(value)
104  except:
105  pass
106  characteristics[property_] = value
107 
108  continue
109 
110  parts = line.split()
111  if len(parts) != 2:
112  raise Exceptions.FileFormatException("Unknown value format in " + path)
113 
114  x.append(float(parts[0]))
115  y.append(float(parts[1]))
116 
117  self.provideData(x, y, show=False, characteristics=characteristics)
118 
119  def provideDataDirectory(self, path, characteristics={}, recursive=False):
120  """
121  Adds all files in the given directory to the available data files.
122 
123  Each file corresponds to a plot.
124  The added plots are not drawn on the canvas.
125 
126  @param[in] path The path to the directory to be added.
127  @param[in] characteristics A dictionary of characteristics for all plots.
128  Conflicting file comments are ignored.
129  @param[in] recursive Whether to traverse the directory recursively.
130  @throw FileFormatException Any of the given files did not adhere to the expected format,
131  as described in provideDataFile.
132  """
133 
134  for file in os.listdir(path):
135  filepath = path + '/' + file
136  if os.path.isfile(filepath):
137  self.provideDataFile(filepath, copy.copy(characteristics))
138  else:
139  if recursive:
140  self.provideDataDirectory(filepath, characteristics, recursive)
141 
142  def setXScale(self, scale):
143  self.app.canvasFrame.axes.set_xscale(scale)
144  self.app.canvasFrame.setLogXCheckbox(scale == 'log')
145 
146  def setYScale(self, scale):
147  self.app.canvasFrame.axes.set_yscale(scale)
148  self.app.canvasFrame.setLogYCheckbox(scale == 'log')
149  if scale == 'log':
150  self._yScaleIsLog = True
151  else:
152  self._yScaleIsLog = False
153 
154  def setPlotDashedIfNegative(self, state):
155  self._plotDashedIfNegative = state
156  self.app.canvasFrame.setDashedIfNegativeCheckbox(state)
157  self.replot()
158 
159  def hideCharacteristics(self, toHide):
160  """
161  Hides the given characteristics from the plot selection window.
162 
163  @param[in] toHide A list of plot characteristics to hide.
164  """
165 
167  self._updatePlotSelector()
168 
169  def setCharacteristicsOrder(self, order):
170  """
171  Sets the order in which plot characteristics are displayed in the plot selection window.
172 
173  @param[in] order An ordered list of characteristics to display. Characteristics not in
174  this list will be displayed in undetermined order after all
175  characteristics present in this list.
176  """
177 
178  self._characteristicsOrder = [x for x in order]
179 
180  def setSortingCharacteristic(self, characteristic, ascending):
181  """
182  Sets by which characteristic to sort the plots in the plot selection window.
183 
184  @param[in] characteristic The characteristic name to sort by.
185  @param[in] ascending Set to true to sort by ascending values, false for descending.
186  @throw InvalidArgumentException Throws if there is no such characteristic.
187  """
188 
189  columnID = None
190 
191  for column in range(0, self._plotSelector.GetColumnCount()):
192  name = self._plotSelector.getColumnName(column)
193  if name == characteristic:
194  columnID = column
195  break
196 
197  if columnID is None:
198  raise Exceptions.InvalidArgumentException('No such characteristic.')
199 
200  self._plotSelector.SortListItems(columnID, ascending)
201 
202  def toggleVisibility(self, plotID):
203  if not self.plots[plotID]['show']:
204  lines = self.plot(self.plots[plotID]['x'], self.plots[plotID]['y'], label=self.plots[plotID]['label'])
205  self.plots[plotID]['lines'] = lines
206  self.plots[plotID]['show'] = True
207  else:
208  for line in self.plots[plotID]['lines']:
209  self.app.canvasFrame.axes.lines.remove(line)
210  self.plots[plotID]['lines'] = None
211  self.plots[plotID]['show'] = False
212 
213  self.app.canvasFrame.update()
214  self._updatePlotSelector()
215 
216  def replot(self):
217  for line in self.app.canvasFrame.axes.get_lines():
218  self.app.canvasFrame.axes.lines.remove(line)
219 
220  self.app.canvasFrame.axes.set_color_cycle(None)
221  for plotID, plot in self.plots.items():
222  lines = None
223  if plot['show']:
224  lines = self.plot(plot['x'], plot['y'], label=plot['label'])
225 
226  plot['lines'] = lines
227 
228  def plot(self, x, y, **kwargs):
229  if self._plotDashedIfNegative:
230  lines = PlotTools.plotDashedIfNegative(x, y, logY=self._yScaleIsLog, ax=self.app.canvasFrame.axes, **kwargs)
231  else:
232  lines = self.app.canvasFrame.axes.plot(x, y, **kwargs)
233 
234  return lines
235 
236  def _updatePlotSelector(self):
237  """
238  Updates the plot selector.
239  """
240 
241  characteristics = self._getListOfPlotCharacteristics(['Plotted'])
242 
243  sortState = None
244  if self._plotSelector.GetColumnCount() != 0:
245  sortState = self._plotSelector.GetSortState()
246  if self._plotSelector.getColumnName(sortState[0]) in self._hiddenCharacteristics:
247  sortState = None
248 
249  columnWidths = {}
250  for column in range(0, self._plotSelector.GetColumnCount()):
251  name = self._plotSelector.getColumnName(column)
252  columnWidths[name] = self._plotSelector.GetColumnWidth(column)
253 
254  self._plotSelector.DeleteAllColumns()
255 
256  column = 0
257  for characteristic in characteristics:
258  if characteristic in self._hiddenCharacteristics:
259  continue
260 
261  self._plotSelector.InsertColumn(column, characteristic)
262  if characteristic in columnWidths:
263  self._plotSelector.SetColumnWidth(column, columnWidths[characteristic])
264  column = column + 1
265 
266  self._plotSelector.SetColumnCount(len(characteristics))
267 
268  plotDict = {}
269  for plotID, plot in self.plots.items():
270  plotCharacteristics = []
271 
272  for characteristic in characteristics:
273  if characteristic in self._hiddenCharacteristics:
274  continue
275 
276  if characteristic == 'Plotted':
277  plotCharacteristics.append(plot['show'])
278  continue
279 
280  if characteristic in plot['characteristics']:
281  plotCharacteristics.append(plot['characteristics'][characteristic])
282  else:
283  plotCharacteristics.append(None)
284 
285  plotDict[plotID] = plotCharacteristics
286 
287  self._plotSelector.itemDataMap = plotDict
288  self._plotSelector.itemIndexMap = plotDict.keys()
289  self._plotSelector.SetItemCount(len(plotDict))
290 
291  if sortState is not None:
292  self._plotSelector.SortListItems(sortState[0], sortState[1])
293 
294 
295  def _getListOfPlotCharacteristics(self, initial=[]):
296  """
297  Returns a list of characteristics that are used in any of the known plots.
298 
299  @param[in] initial A list of characteristics that are to be included in the returned result,
300  even if not used by any plot.
301  """
302 
303  characteristics = []
304 
305  for c in self._characteristicsOrder:
306  if c in characteristics:
307  continue
308 
309  if c in initial:
310  characteristics.append(c)
311  continue
312 
313  for _plotID, plot in self.plots.items():
314  if c in plot['characteristics'].keys():
315  characteristics.append(c)
316  break
317 
318 
319  for c in initial:
320  if c not in characteristics:
321  characteristics.append(c)
322 
323  for _plotID, plot in self.plots.items():
324  for c in plot['characteristics'].keys():
325  if c not in characteristics:
326  characteristics.append(c)
327 
328  return characteristics
329 
330  def _registerPlotSelector(self, plotSelector):
331  """
332  Registers an instance of _PlotSelectionList
333 
334  @param[in] plotSelector The instance to register.
335  """
336 
337  self._plotSelector = plotSelector
MPCDAnalysis.Exceptions.FileFormatException
Definition: Exceptions.py:5
MPCDAnalysis.InteractivePlotter.App.App
Definition: App.py:9
MPCDAnalysis.InteractivePlotter.Plotter.Plotter.nextPlotID
nextPlotID
Definition: Plotter.py:26
MPCDAnalysis.InteractivePlotter.Plotter.Plotter.provideDataFile
def provideDataFile(self, path, characteristics={})
Definition: Plotter.py:84
MPCDAnalysis.InteractivePlotter.Plotter.Plotter.setCharacteristicsOrder
def setCharacteristicsOrder(self, order)
Definition: Plotter.py:182
MPCDAnalysis.InteractivePlotter.Plotter.Plotter._yScaleIsLog
_yScaleIsLog
Definition: Plotter.py:28
MPCDAnalysis.InteractivePlotter.Plotter.Plotter._plotDashedIfNegative
_plotDashedIfNegative
Definition: Plotter.py:27
MPCDAnalysis.InteractivePlotter.Plotter.Plotter.plot
def plot(self, x, y, **kwargs)
Definition: Plotter.py:235
MPCDAnalysis.InteractivePlotter.Plotter.Plotter.app
app
Definition: Plotter.py:24
MPCDAnalysis.InteractivePlotter.Plotter.Plotter._getListOfPlotCharacteristics
def _getListOfPlotCharacteristics(self, initial=[])
Definition: Plotter.py:310
MPCDAnalysis.InteractivePlotter.Plotter.Plotter.setSortingCharacteristic
def setSortingCharacteristic(self, characteristic, ascending)
Definition: Plotter.py:194
MPCDAnalysis.Exceptions.InvalidArgumentException
Definition: Exceptions.py:13
MPCDAnalysis.InteractivePlotter.Plotter.Plotter._plotSelector
_plotSelector
Definition: Plotter.py:347
MPCDAnalysis.InteractivePlotter.Plotter.Plotter.provideData
def provideData(self, x, y, show=True, label=None, characteristics=None)
Definition: Plotter.py:46
MPCDAnalysis.InteractivePlotter.Plotter.Plotter._hiddenCharacteristics
_hiddenCharacteristics
Definition: Plotter.py:29
MPCDAnalysis.InteractivePlotter.Plotter.Plotter.provideDataDirectory
def provideDataDirectory(self, path, characteristics={}, recursive=False)
Definition: Plotter.py:136
MPCDAnalysis.InteractivePlotter.Plotter.Plotter._updatePlotSelector
def _updatePlotSelector(self)
Definition: Plotter.py:247
MPCDAnalysis.InteractivePlotter.Plotter.Plotter._characteristicsOrder
_characteristicsOrder
Definition: Plotter.py:30
MPCDAnalysis.InteractivePlotter.Plotter.Plotter.hideCharacteristics
def hideCharacteristics(self, toHide)
Definition: Plotter.py:169
MPCDAnalysis.InteractivePlotter.Plotter.Plotter.plots
plots
Definition: Plotter.py:25
MPCDAnalysis.InteractivePlotter.Plotter.Plotter.replot
def replot(self)
Definition: Plotter.py:223