qcodespp 0.1.2__tar.gz → 0.1.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. {qcodespp-0.1.2 → qcodespp-0.1.4}/PKG-INFO +1 -1
  2. {qcodespp-0.1.2 → qcodespp-0.1.4}/pyproject.toml +1 -1
  3. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/__init__.py +1 -0
  4. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/data/data_set.py +2 -0
  5. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/loops.py +32 -6
  6. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/parameters.py +147 -13
  7. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/plotting/analysis_tools.py +8 -5
  8. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/plotting/offline/datatypes.py +7 -4
  9. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/plotting/offline/editor.py +24 -9
  10. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/plotting/offline/filters.py +138 -27
  11. qcodespp-0.1.4/qcodespp/utils/__init__.py +0 -0
  12. qcodespp-0.1.4/qcodespp/version.py +1 -0
  13. qcodespp-0.1.2/qcodespp/version.py +0 -1
  14. {qcodespp-0.1.2 → qcodespp-0.1.4}/LICENSE +0 -0
  15. {qcodespp-0.1.2 → qcodespp-0.1.4}/README.rst +0 -0
  16. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/actions.py +0 -0
  17. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/data/__init__.py +0 -0
  18. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/data/data_array.py +0 -0
  19. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/data/format.py +0 -0
  20. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/data/gnuplot_format.py +0 -0
  21. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/data/hdf5_format.py +0 -0
  22. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/data/hdf5_format_hickle.py +0 -0
  23. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/data/io.py +0 -0
  24. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/data/location.py +0 -0
  25. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/Keysight/Keysight_34450A.py +0 -0
  26. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/Keysight/__init__.py +0 -0
  27. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/Keysight/private/Keysight_344xxA.py +0 -0
  28. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/Keysight/private/__init__.py +0 -0
  29. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/Lakeshore/Model_340.py +0 -0
  30. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/Lakeshore/__init__.py +0 -0
  31. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/QDevil/159fit_params_high_latest.json +0 -0
  32. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/QDevil/159fit_params_low_latest.json +0 -0
  33. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/QDevil/71fit_params_high_latest.json +0 -0
  34. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/QDevil/71fit_params_low_latest.json +0 -0
  35. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/QDevil/QDAC2.py +0 -0
  36. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/QDevil/QDAC2_Array.py +0 -0
  37. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/QDevil/QSwitch_elab.py +0 -0
  38. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/QDevil/__init__.py +0 -0
  39. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/ZI/ZIHF2LI.py +0 -0
  40. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/ZI/ZIMFLI.py +0 -0
  41. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/ZI/ZIMFLI_sync.py +0 -0
  42. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/ZI/__init__.py +0 -0
  43. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/__init__.py +0 -0
  44. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/cryogenic/CryogenicSMS120C.py +0 -0
  45. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/cryogenic/__init__.py +0 -0
  46. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/instrument_mocks.py +0 -0
  47. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/multiplexer_instrument.py +0 -0
  48. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/national_instruments/PXI_4461.py +0 -0
  49. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/national_instruments/PXI_4462.py +0 -0
  50. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/national_instruments/PXI_6259.py +0 -0
  51. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/national_instruments/PXI_6733.py +0 -0
  52. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/national_instruments/PXI_6733_e.py +0 -0
  53. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/national_instruments/__init__.py +0 -0
  54. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/oxford/__init__.py +0 -0
  55. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/oxford/mercuryiPS_serial.py +0 -0
  56. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/oxford/serial.py +0 -0
  57. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/oxford/triton.py +0 -0
  58. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/tektronix/Keithley_2000_Scan.py +0 -0
  59. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/tektronix/Keithley_2182a.py +0 -0
  60. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/tektronix/Keithley_2450.py +0 -0
  61. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/tektronix/Keithley_2700.py +0 -0
  62. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/tektronix/__init__.py +0 -0
  63. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/wir/Kepco.py +0 -0
  64. {qcodespp-0.1.2/qcodespp/instrument_drivers/yokogawa → qcodespp-0.1.4/qcodespp/instrument_drivers/wir}/__init__.py +0 -0
  65. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/instrument_drivers/yokogawa/GS200.py +0 -0
  66. {qcodespp-0.1.2/qcodespp/plotting → qcodespp-0.1.4/qcodespp/instrument_drivers/yokogawa}/__init__.py +0 -0
  67. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/measure.py +0 -0
  68. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/plotting/RemotePlot.py +0 -0
  69. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/plotting/RemotePlotClient.py +0 -0
  70. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/plotting/RemoteQtPlotWidgets.py +0 -0
  71. {qcodespp-0.1.2/qcodespp/plotting/offline → qcodespp-0.1.4/qcodespp/plotting}/__init__.py +0 -0
  72. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/plotting/colors.py +0 -0
  73. {qcodespp-0.1.2/qcodespp/utils → qcodespp-0.1.4/qcodespp/plotting/offline}/__init__.py +0 -0
  74. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/plotting/offline/design.py +0 -0
  75. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/plotting/offline/design.ui +0 -0
  76. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/plotting/offline/fits.py +0 -0
  77. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/plotting/offline/helpers.py +0 -0
  78. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/plotting/offline/iconGadget.png +0 -0
  79. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/plotting/offline/main.py +0 -0
  80. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/plotting/offline/popupwindows.py +0 -0
  81. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/plotting/offline/qcodes_pp_extension.py +0 -0
  82. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/plotting/offline/sidebars.py +0 -0
  83. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/station.py +0 -0
  84. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/utils/helpers.py +0 -0
  85. {qcodespp-0.1.2 → qcodespp-0.1.4}/qcodespp/utils/visa_helpers.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qcodespp
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: Package providing additional functions for QCoDeS
5
5
  Maintainer-email: Damon Carrad <damonc@dtu.dk>
6
6
  Requires-Python: >=3.10
@@ -5,7 +5,7 @@ build-backend = 'flit_core.buildapi'
5
5
 
6
6
  [project]
7
7
  name = "qcodespp"
8
- version = '0.1.2'
8
+ version = '0.1.4'
9
9
  maintainers = [{name = "Damon Carrad", email = "damonc@dtu.dk"}]
10
10
  description = "Package providing additional functions for QCoDeS"
11
11
  classifiers = [
@@ -65,6 +65,7 @@ from qcodespp.actions import Task, Wait, BreakIf
65
65
 
66
66
  from qcodespp.plotting.RemotePlot import Plot, live_plot
67
67
  from qcodespp.plotting.offline.main import offline_plotting
68
+ from qcodespp.plotting.analysis_tools import colorplot, colored_traces
68
69
 
69
70
  from qcodespp.data.data_set import new_data, load_data, load_data_num, load_data_nums, set_data_format, set_data_folder
70
71
 
@@ -274,6 +274,8 @@ class DataSetPP(DelegateAttributes):
274
274
  default_formatter = GNUPlotFormat()
275
275
  location_provider = FormatLocation()
276
276
 
277
+ default_folder=None
278
+
277
279
  background_functions: Dict[str, Callable] = OrderedDict()
278
280
 
279
281
  def __init__(self, location=None, arrays=None, formatter=None, io=None,
@@ -123,7 +123,10 @@ def loop1d(sweep_parameter,
123
123
  if measure:
124
124
  Station.default.set_measurement(*measure)
125
125
  loop=Loop(sweep_parameter.sweep(start,stop,num=num), delay).each(*Station.default.measure())
126
- name=f'{device_info} {sweep_parameter.full_name}({start:.6g} {stop:.6g}){sweep_parameter.unit} with {instrument_info}'
126
+
127
+ start_text, stop_text, unit_text = _filename_text(start, stop, sweep_parameter)
128
+
129
+ name=f'{device_info} {sweep_parameter.full_name}({start_text} {stop_text}){unit_text} with {instrument_info}'
127
130
  data=loop.get_data_set(name=name)
128
131
  if plot:
129
132
  pp=live_plot(data,plot)
@@ -208,8 +211,11 @@ def loop2d(sweep_parameter,
208
211
  else:
209
212
  loop2d=Loop(step_parameter.sweep(step_start,step_stop,num=step_num), step_delay,snake=snake).each(loop)
210
213
 
211
- name=(f'{device_info} {step_parameter.full_name}({step_start:.6g} {step_stop:.6g}){sweep_parameter.unit} '
212
- f'{sweep_parameter.full_name}({start:.6g} {stop:.6g}){sweep_parameter.unit} with {instrument_info}')
214
+ start_text, stop_text, unit_text = _filename_text(start, stop, sweep_parameter)
215
+ step_start_text, step_stop_text, step_unit_text = _filename_text(step_start, step_stop, step_parameter)
216
+
217
+ name=(f'{device_info} {step_parameter.full_name}({step_start_text} {step_stop_text}){step_unit_text} '
218
+ f'{sweep_parameter.full_name}({start_text} {stop_text}){unit_text} with {instrument_info}')
213
219
  data=loop2d.get_data_set(name=name)
214
220
 
215
221
  if plot:
@@ -297,8 +303,11 @@ def loop2dUD(sweep_parameter,
297
303
  else:
298
304
  loop2d=Loop(step_parameter.sweep(step_start,step_stop,num=step_num), step_delay).each(loop,loop_down)
299
305
 
300
- name=(f'{device_info} {step_parameter.full_name}({step_start:.6g} {step_stop:.6g}){sweep_parameter.unit} '
301
- f'{sweep_parameter.full_name}({start:.6g} {stop:.6g}){sweep_parameter.unit} with {instrument_info}')
306
+ start_text, stop_text, unit_text = _filename_text(start, stop, sweep_parameter)
307
+ step_start_text, step_stop_text, step_unit_text = _filename_text(step_start, step_stop, step_parameter)
308
+
309
+ name=(f'{device_info} {step_parameter.full_name}({step_start_text} {step_stop_text}){step_unit_text} '
310
+ f'{sweep_parameter.full_name}({start_text} {stop_text}){unit_text} with {instrument_info}')
302
311
  data=loop2d.get_data_set(name=name)
303
312
 
304
313
  if plot:
@@ -311,6 +320,23 @@ def loop2dUD(sweep_parameter,
311
320
 
312
321
  return loop2d
313
322
 
323
+ def _filename_text(start,stop,parameter):
324
+ '''
325
+ Function to deal with MultiParameter sweeps, where the filename text can become complicted
326
+ '''
327
+ if isinstance(start, tuple):
328
+ start_text= ','.join([f'{s:.6g}' for s in start])
329
+ start_text=f'({start_text})'
330
+ stop_text= ','.join([f'{s:.6g}' for s in stop])
331
+ stop_text=f'({stop_text})'
332
+ unit_text= ','.join([unit for unit in parameter.units])
333
+ unit_text=f'({unit_text})'
334
+ else:
335
+ start_text= f'{start:.6g}'
336
+ stop_text= f'{stop:.6g}'
337
+ unit_text= parameter.unit
338
+ return start_text, stop_text, unit_text
339
+
314
340
  class Loop(Metadatable):
315
341
  """
316
342
  Create a measurement loop to sweep over a parameter and store measured data from other
@@ -986,7 +1012,7 @@ class ActiveLoop(Metadatable):
986
1012
  if isinstance(action, ActiveLoop):
987
1013
  estimate=estimate+self.sweep_values.snapshot()['values'][0]['num']*action.sweep_values.snapshot()['values'][0]['num']*(commtime+action.delay+extra_delay[1])
988
1014
 
989
- string=(f'Estimated time: {estimate} s, {estimate/60} mins, {estimate/3600} hours\n'
1015
+ string=(f'Estimated time: {estimate:.2f} s / {estimate/60:.2f} mins / {estimate/3600:.2f} hours\n'
990
1016
  f'Done at: {time.asctime(time.localtime(time.time()+estimate))}')
991
1017
  return string
992
1018
 
@@ -1,6 +1,8 @@
1
1
  """A collection of functions that get added to the QCoDeS Parameter class.
2
2
 
3
- In addition, two wrapper classes are provided to easily create ArrayParameters and MultiParameters."""
3
+ In addition, two wrapper classes are provided to easily create ArrayParameters and MultiParameters.
4
+ MultiParameters created with this method become settable, sweepable and movable.
5
+ """
4
6
 
5
7
  import time
6
8
 
@@ -10,9 +12,15 @@ from qcodes.parameters import (
10
12
  ArrayParameter,
11
13
  MultiParameter,
12
14
  Parameter,
13
- SweepFixedValues,
15
+ ParameterBase,
16
+ SweepFixedValues
14
17
  )
15
18
 
19
+ from typing import Any
20
+
21
+ from qcodes.parameters.sequence_helpers import is_sequence
22
+ from qcodes.parameters.sweep_values import make_sweep
23
+
16
24
  def move(self,end_value,steps=101,step_time=0.03):
17
25
  """
18
26
  Move the parameter to a new value in a number of steps without taking data.
@@ -216,6 +224,52 @@ class ArrayParameterWrapper(ArrayParameter):
216
224
 
217
225
  super().__init__(name=name, shape=shape,instrument=instrument,label=label,unit=unit)
218
226
 
227
+ class SweepMultiValues(SweepFixedValues):
228
+ '''
229
+ Class to enable sweeping MultiParameters with different values for each parameter.
230
+
231
+ Simply a subclass of SweepFixedValues with a restricted set of options to ensure that the
232
+ setpoints are constructed correctly.
233
+
234
+ Args:
235
+ parameter (MultiParameter): The MultiParameter to sweep.
236
+ keys (list): A list of lists, where each inner list contains the setpoints for each
237
+ parameter at that sweep index.
238
+ '''
239
+ def __init__(
240
+ self,
241
+ parameter: ParameterBase,
242
+ keys: Any | None = None):
243
+
244
+ super().__init__(parameter,keys)
245
+ # Initialising the parent class constructs the setpoints incorrectly,
246
+ # so reset self._values to an empty list.
247
+ self._values: list[Any] = []
248
+ self._snapshot: dict[str, Any] = {}
249
+ self._value_snapshot: list[dict[str, Any]] = []
250
+
251
+ if isinstance(keys, slice):
252
+ self._add_slice(keys)
253
+ self._add_linear_snapshot(self._values)
254
+
255
+ elif is_sequence(keys):
256
+ for key in keys:
257
+ if isinstance(key, slice):
258
+ self._add_slice(key)
259
+ else:
260
+ # assume a single value
261
+ self._values.append(key)
262
+ # we dont want the snapshot to go crazy on big data
263
+ if self._values:
264
+ self._add_sequence_snapshot(self._values)
265
+
266
+ else:
267
+ # assume a single value
268
+ self._values.append(keys)
269
+ self._value_snapshot.append({"item": keys})
270
+
271
+ self.validate(self._values)
272
+
219
273
  class MultiParameterWrapper(MultiParameter):
220
274
  """
221
275
  Class to wrap multiple pre-existing parameters into MultiParameter. Enables getting, setting, sweeping and moving.
@@ -271,12 +325,28 @@ class MultiParameterWrapper(MultiParameter):
271
325
 
272
326
  self.labels=tuple(labels)
273
327
  self.units=tuple(units)
328
+ self.unit='' # Mainly to be compatible with automatic naming in loop1d,loop2d, etc.
274
329
 
275
330
  def get_raw(self):
331
+ '''
332
+ Method to get the values of all parameters in the MultiParameter.
333
+
334
+ Returns:
335
+ tuple: A tuple containing the values of all parameters in the MultiParameter.
336
+ '''
276
337
  return tuple([param.get() for param in self.parameters])
277
338
 
278
339
  def set_raw(self, values):
279
- if type(values) is int or type(values) is float:
340
+ """
341
+ Method to set the values of all parameters in the MultiParameter.
342
+
343
+ Args:
344
+ values (list, tuple, int, float): The values to set for the parameters.
345
+ If a single value is provided, it will be set for all parameters.
346
+ If a list or tuple is provided, it must match the number of parameters.
347
+ """
348
+
349
+ if type(values) in [int, float]:
280
350
  for parameter in self.parameters:
281
351
  parameter.set(values)
282
352
  elif numpy.array(values).shape != numpy.array(self.parameters).shape:
@@ -286,26 +356,90 @@ class MultiParameterWrapper(MultiParameter):
286
356
  self.parameters[i].set(value)
287
357
 
288
358
  def move(self,end_values,steps=101,step_time=0.03):
289
- if type(end_values) is int or type(end_values) is float:
359
+ """
360
+ Move all parameters to new values in a number of steps without taking data.
361
+
362
+ Args:
363
+ end_values (list, tuple, int, float): The values to move to.
364
+ If a single value is provided, it will be moved for all parameters.
365
+ If a list or tuple is provided, it must match the number of parameters.
366
+ steps (int, optional): Number of steps to take. Defaults to 101.
367
+ step_time (float, optional): Time in seconds between each step. Defaults to 0.03.
368
+ """
369
+
370
+ if type(end_values) in [int, float]:
290
371
  for i,param in enumerate(self.parameters):
291
372
  param.move(end_values,steps,step_time)
292
373
  else:
293
374
  for i,param in enumerate(self.parameters):
294
375
  param.move(list(end_values)[i],steps,step_time)
295
376
 
296
- def sweep(self, start_vals,stop_vals,num):
377
+ def sweep(self, start_vals,stop_vals,num,print_warning=True):
378
+ """
379
+ Create a collection of parameter values to be iterated over for all parameters in the MultiParameter.
380
+
381
+ Args:
382
+ start_vals (list, tuple, int, float): The starting values of the sequence.
383
+ If a single value is provided, it will be used for all parameters.
384
+ If a list or tuple is provided, it must match the number of parameters.
385
+
386
+ stop_vals (list, tuple, int, float): The end values of the sequence.
387
+ If a single value is provided, it will be used for all parameters.
388
+ If a list or tuple is provided, it must match the number of parameters.
389
+
390
+ num (int): Number of values to generate.
391
+
392
+ print_warning (bool): Whether to print a warning if the start value is different from the
393
+ current value. Defaults to True.
394
+
395
+ Returns:
396
+ SweepFixedValues or SweepMultiValues: A collection of parameter values to be iterated over which can be passed to a Loop.
397
+
398
+ Raises:
399
+ ValueError: If the number of start_vals or stop_vals does not match the number of parameters,
400
+ or if they are not a single value.
401
+ """
402
+
297
403
  #If the user is sweeping all params with the same values, the case is the same as Parameter.sweep
298
- if numpy.array(start_vals).shape == ():
404
+ if type(start_vals) in [int, float]:
405
+ # Check that the start and stop values are the same shape
299
406
  if numpy.array(start_vals).shape != numpy.array(stop_vals).shape:
300
407
  raise ValueError('Number of start values must match number of stop values')
408
+
409
+ # Warn the user if the start value is different from any of the current values
410
+ sweeprange= numpy.abs(stop_vals - start_vals)
411
+ for i,parameter in enumerate(self.parameters):
412
+ try:
413
+ if print_warning and numpy.abs(parameter.get()-start_vals)>sweeprange*1e-3:
414
+ print(f'Are you sure? Start value for {parameter.name} sweep is '
415
+ f'{start_vals} {parameter.unit} but '
416
+ f'{parameter.name}()={parameter.get()} {parameter.unit}')
417
+ except TypeError: #Sometimes a parameter (especially a dummy parameter) will return None if it has not been set yet.
418
+ pass
419
+
420
+ # return SweepFixedValues as for a Parameter
301
421
  return SweepFixedValues(self, start=start_vals, stop=stop_vals,num=num)
302
422
 
303
- #Otherwise, check that the shapes are correct, and make a setpointarray of the appropriate size for SweepFixedValues
423
+ # Otherwise, check that the shapes are correct, and make a setpointarray of the appropriate size
424
+ # for SweepMultiValues, after checking the start values are close to the current values.
304
425
  elif numpy.array(start_vals).shape != numpy.array(self.parameters).shape:
305
- raise ValueError('Number of start_vals must match number of parameters')
426
+ raise ValueError('Number of start_vals must match number of parameters, or be a signle value')
306
427
  elif numpy.array(stop_vals).shape != numpy.array(self.parameters).shape:
307
- raise ValueError('Number of stop_vals must match number of parameters')
308
- setpointarray=[]
309
- for j in range(num):
310
- setpointarray.append([start_vals[i] + (stop_vals[i] - start_vals[i])/(num-1) * j for i in range(numpy.array(self.parameters).shape[0])])
311
- return SweepFixedValues(self,setpointarray)
428
+ raise ValueError('Number of stop_vals must match number of parameters, or be a signle value')
429
+
430
+ else:
431
+ for i,parameter in enumerate(self.parameters):
432
+ sweeprange= numpy.abs(stop_vals[i] - start_vals[i])
433
+ try:
434
+ if print_warning and numpy.abs(parameter.get()-start_vals[i])>sweeprange*1e-3:
435
+ print(f'Are you sure? Start value for {parameter.name} sweep is '
436
+ f'{start_vals[i]} {parameter.unit} but '
437
+ f'{parameter.name}()={parameter.get()} {parameter.unit}')
438
+ except TypeError: #Sometimes a parameter (especially a dummy parameter) will return None if it has not been set yet.
439
+ pass
440
+
441
+ setpointarray=[]
442
+ for j in range(num):
443
+ setpointarray.append([start_vals[i] + (stop_vals[i] - start_vals[i])/(num-1) * j for i in range(numpy.array(self.parameters).shape[0])])
444
+ return SweepMultiValues(self,setpointarray)
445
+
@@ -7,7 +7,8 @@ from matplotlib.ticker import MultipleLocator
7
7
  import numpy as np
8
8
 
9
9
 
10
- def colorplot(x,y,z,figsize=0,cmap=0,labels=0,xlim=0,ylim=0,zlim=0,xmajor=0,xminor=0,ymajor=0,yminor=0,font_size=0,label_size=0):
10
+ def colorplot(x,y,z,figsize=0,cmap=0,labels=0,xlim=0,ylim=0,zlim=0,xmajor=0,
11
+ xminor=0,ymajor=0,yminor=0,font_size=0,label_size=0,check_shapes=True):
11
12
  """
12
13
  Make a nice colourplot from a three-dimensional data array using matplotlib.
13
14
 
@@ -43,6 +44,7 @@ def colorplot(x,y,z,figsize=0,cmap=0,labels=0,xlim=0,ylim=0,zlim=0,xmajor=0,xmin
43
44
 
44
45
  label_size (int, optional): Font size for the tick labels. Default is 12.
45
46
 
47
+ check_shapes (bool, optional): If True, checks the shapes of x, y, and z arrays and transposes if necessary. Default is True.
46
48
 
47
49
  Returns:
48
50
  tuple: A tuple containing the figure, axis, and colorbar axis objects.
@@ -65,10 +67,11 @@ def colorplot(x,y,z,figsize=0,cmap=0,labels=0,xlim=0,ylim=0,zlim=0,xmajor=0,xmin
65
67
  fig, (ax1, cax)=plt.subplots(nrows=1,ncols=2,figsize=figsize,dpi=300,gridspec_kw={'width_ratios':[1,0.02]}) #This allows us better control over the colourbar. Note you can then 'easily' generalise this to more subplots (see below)
66
68
  fig.tight_layout(h_pad=None, w_pad=-2)
67
69
 
68
- if np.shape(z)[1] != np.shape(x)[0] and np.shape(z)[0] == np.shape(x)[0]:
69
- z= z.T
70
- if np.shape(np.shape(y))==(2,) and np.shape(y)[1] != np.shape(x)[0] and np.shape(y)[0] == np.shape(x)[0]:
71
- y= y.T
70
+ if check_shapes:
71
+ if np.shape(z)[1] != np.shape(x)[0] and np.shape(z)[0] == np.shape(x)[0]:
72
+ z= z.T
73
+ if np.shape(np.shape(y))==(2,) and np.shape(y)[1] != np.shape(x)[0] and np.shape(y)[0] == np.shape(x)[0]:
74
+ y= y.T
72
75
 
73
76
  if zlim!=0:
74
77
  sdbs=ax1.pcolormesh(x,y,z,cmap=cmap,rasterized=True,linewidth=0,vmin=zlim[0],vmax=zlim[1])
@@ -401,7 +401,8 @@ class BaseClassData:
401
401
 
402
402
  def add_cbar_hist(self):
403
403
  self.hax=self.cbar.ax.inset_axes([-1.05, 0, 1, 1],picker=True)
404
- counts, self.cbar_hist_bins = np.histogram(self.processed_data[-1],bins=int(self.settings['cmap levels']))
404
+ counts, self.cbar_hist_bins = np.histogram(self.processed_data[-1],bins=int(self.settings['cmap levels']),
405
+ range=(np.nanmin(self.processed_data[-1]), np.nanmax(self.processed_data[-1])))
405
406
  midpoints = self.cbar_hist_bins[:-1] + np.diff(self.cbar_hist_bins)/2
406
407
  self.hax.fill_between(-counts, midpoints,0,color='mediumslateblue')
407
408
  self.haxfill=self.hax.fill_betweenx(np.linspace(self.view_settings['Minimum'], self.view_settings['Maximum'], 100),
@@ -448,7 +449,7 @@ class BaseClassData:
448
449
  norm=norm, cmap=cmap,
449
450
  rasterized=self.settings['rasterized'])
450
451
  if self.settings['colorbar'] == 'True':
451
- self.cbar = self.figure.colorbar(self.image, orientation='vertical')
452
+ self.cbar = self.figure.colorbar(self.image)
452
453
  if self.view_settings['CBarHist'] == True:
453
454
  self.add_cbar_hist()
454
455
 
@@ -884,7 +885,7 @@ class MixedInternalData(BaseClassData):
884
885
  norm=norm, cmap=cmap,
885
886
  rasterized=self.dataset2d.settings['rasterized'])
886
887
  if self.dataset2d.settings['colorbar'] == 'True':
887
- self.cbar = self.figure.colorbar(self.image, orientation='vertical')
888
+ self.cbar = self.figure.colorbar(self.image)
888
889
  if self.view_settings['CBarHist'] == True:
889
890
  self.add_cbar_hist()
890
891
 
@@ -933,7 +934,9 @@ class MixedInternalData(BaseClassData):
933
934
 
934
935
  def add_cbar_hist(self):
935
936
  self.hax=self.cbar.ax.inset_axes([-1.05, 0, 1, 1],picker=True)
936
- counts, self.cbar_hist_bins = np.histogram(self.dataset2d.processed_data[-1],bins=int(self.settings['cmap levels']))
937
+ counts, self.cbar_hist_bins = np.histogram(self.dataset2d.processed_data[-1],bins=int(self.settings['cmap levels']),
938
+ range=(np.nanmin(self.dataset2d.processed_data[-1]),
939
+ np.nanmax(self.dataset2d.processed_data[-1])))
937
940
  midpoints = self.cbar_hist_bins[:-1] + np.diff(self.cbar_hist_bins)/2
938
941
  self.hax.fill_between(-counts, midpoints,0,color='mediumslateblue')
939
942
  self.haxfill=self.hax.fill_betweenx(np.linspace(self.view_settings['Minimum'], self.view_settings['Maximum'], 100),
@@ -215,7 +215,7 @@ class Editor(QtWidgets.QMainWindow, design.Ui_MainWindow):
215
215
  self.update_link_to_folder(folder=folder)
216
216
  except Exception as e:
217
217
  print(f'Failed to link to folder {folder}:', e)
218
- elif link_to_default and os.path.isdir(DataSetPP.default_folder):
218
+ elif link_to_default and DataSetPP.default_folder and os.path.isdir(DataSetPP.default_folder):
219
219
  try:
220
220
  print(f'Linking to qcodespp data folder at {DataSetPP.default_folder}... This may take some time.')
221
221
  self.update_link_to_folder(folder=DataSetPP.default_folder)
@@ -1024,8 +1024,9 @@ class Editor(QtWidgets.QMainWindow, design.Ui_MainWindow):
1024
1024
 
1025
1025
  def reinstate_markers(self, item, orientation):
1026
1026
  orientations={'horizontal':'horimarkers','vertical':'vertmarkers'}
1027
- arrayname=orientations[orientation]
1028
- setattr(item.data,arrayname,[])
1027
+ if orientation != 'diagonal':
1028
+ arrayname=orientations[orientation]
1029
+ setattr(item.data,arrayname,[])
1029
1030
  if orientation == 'horizontal':
1030
1031
  for line in item.data.linecuts['horizontal']['lines']:
1031
1032
  z=item.data.linecuts[orientation]['lines'][line]['cut_axis_value']
@@ -1041,6 +1042,14 @@ class Editor(QtWidgets.QMainWindow, design.Ui_MainWindow):
1041
1042
  color=item.data.linecuts[orientation]['lines'][line]['linecolor']))
1042
1043
  item.data.vertmarkers.append(item.data.axes.axvline(x=z, linestyle='dashed', linewidth=1, ymin=0.9,
1043
1044
  color=item.data.linecuts[orientation]['lines'][line]['linecolor']))
1045
+
1046
+ elif orientation == 'diagonal':
1047
+ for line in item.data.linecuts[orientation]['lines']:
1048
+ points0= item.data.linecuts[orientation]['lines'][line]['points'][0]
1049
+ points1= item.data.linecuts[orientation]['lines'][line]['points'][1]
1050
+ item.data.linecuts[orientation]['lines'][line]['draggable_points']=[DraggablePoint(item.data, points0[0], points0[1],
1051
+ line,orientation),
1052
+ DraggablePoint(item.data, points1[0], points1[1],line,orientation,draw_line=True)]
1044
1053
 
1045
1054
  def clear_sidebar1D(self):
1046
1055
  # clear the sidebar1D
@@ -1074,7 +1083,7 @@ class Editor(QtWidgets.QMainWindow, design.Ui_MainWindow):
1074
1083
  item.data.axes = item.data.figure.add_subplot(rows, cols, index+1)
1075
1084
  item.data.add_plot(editor_window=self)
1076
1085
  if hasattr(item.data, 'linecuts'):
1077
- for orientation in ['horizontal','vertical']:#,'diagonal']:#,'circular']:
1086
+ for orientation in ['horizontal', 'vertical', 'diagonal']:
1078
1087
  if len(item.data.linecuts[orientation]['lines']) > 0:
1079
1088
  self.reinstate_markers(item,orientation)
1080
1089
  if item.data.linecuts[orientation]['linecut_window'] is not None and item==self.file_list.currentItem():
@@ -1474,7 +1483,7 @@ class Editor(QtWidgets.QMainWindow, design.Ui_MainWindow):
1474
1483
  else:
1475
1484
  item.data.filters = filters
1476
1485
 
1477
- else: # A filter is being appended
1486
+ else: # A filter is being appended to the table
1478
1487
  if isinstance(item.data,MixedInternalData) and self.mixeddata_filter_box.currentIndex() == 0:
1479
1488
  item.data.dataset2d.filters.append(filt)
1480
1489
  elif hasattr(item.data, 'sidebar1D'):
@@ -1485,6 +1494,9 @@ class Editor(QtWidgets.QMainWindow, design.Ui_MainWindow):
1485
1494
  filt.method_list.remove('Z')
1486
1495
  if hasattr(filt, 'method') and filt.method == 'Z':
1487
1496
  filt.method=filt.method_list[0]
1497
+ elif filt.name == 'Sort':
1498
+ filt.method_list = ['']
1499
+ filt.method= ''
1488
1500
  if isinstance(item.data,MixedInternalData):
1489
1501
  item.data.dataset1d.plotted_lines[current_line]['filters'].append(filt)
1490
1502
  else:
@@ -2177,6 +2189,10 @@ class Editor(QtWidgets.QMainWindow, design.Ui_MainWindow):
2177
2189
  method_box.setCurrentIndex(filt.method_list.index(filt.method))
2178
2190
  setting_1 = QtWidgets.QTableWidgetItem(filt.settings[0])
2179
2191
  setting_2 = QtWidgets.QTableWidgetItem(filt.settings[1])
2192
+ if hasattr(filt, 'tooltips'):
2193
+ setting_1.setToolTip(filt.tooltips[0])
2194
+ if len(filt.tooltips) > 1:
2195
+ setting_2.setToolTip(filt.tooltips[1])
2180
2196
  method_box.currentIndexChanged.connect(lambda: self.filters_table_edited(setting_1))
2181
2197
  self.filters_table.setItem(row, 0, filter_item)
2182
2198
  self.filters_table.setCellWidget(row, 1, method_box)
@@ -2219,13 +2235,12 @@ class Editor(QtWidgets.QMainWindow, design.Ui_MainWindow):
2219
2235
  if ((row > 0 and to == -1) or
2220
2236
  (row < self.filters_table.rowCount()-1 and to == 1)):
2221
2237
  filters[row], filters[row+to] = filters[row+to], filters[row]
2222
- self.show_current_filters()
2223
- self.filters_table.setCurrentCell(row+to, 0)
2224
2238
  if (self.filters_table.item(row,0).checkState() and
2225
2239
  self.filters_table.item(row+to,0).checkState()):
2226
- current_item.data.apply_all_filters()
2227
2240
  self.update_plots(update_color_limits=True)
2228
- self.show_current_view_settings()
2241
+ else:
2242
+ self.show_current_filters()
2243
+ self.filters_table.setCurrentCell(row+to, 0)
2229
2244
 
2230
2245
  def save_image(self):
2231
2246
  current_item = self.file_list.currentItem()
@@ -7,7 +7,9 @@ Created on Thu Nov 9 20:05:23 2017
7
7
 
8
8
  import numpy as np
9
9
  from scipy import ndimage, signal
10
- from scipy.interpolate import interp1d, interp2d
10
+ from scipy.interpolate import LinearNDInterpolator, CloughTocher2DInterpolator, make_interp_spline
11
+
12
+ from qcodespp.plotting.analysis_tools import sort_lists
11
13
 
12
14
 
13
15
  # Filter definitions
@@ -15,16 +17,16 @@ from scipy.interpolate import interp1d, interp2d
15
17
  def derivative(data, method, times_x, times_y):
16
18
  times_x, times_y = int(times_x), int(times_y)
17
19
  if len(data) == 3:
18
- for _ in range(times_x):
19
- data[-1] = np.gradient(data[-1], data[0][:,0], axis=0)
20
20
  for _ in range(times_y):
21
- data[-1] = np.gradient(data[-1], data[1][0,:], axis=1)
21
+ data[-1]= np.array([np.gradient(data[-1][i,:], data[1][i,:]) for i in range(data[-1].shape[0])])
22
+ for _ in range(times_x):
23
+ data[-1]= np.array([np.gradient(data[-1][:,i], data[0][:,i]) for i in range(data[-1].shape[1])]).T
22
24
  elif len(data) == 2:
23
25
  for _ in range(times_y):
24
- data[-1] = np.gradient(data[-1], data[0])
26
+ data[-1] = np.gradient(data[-1], data[0])
25
27
  return data
26
28
 
27
- def integrate(data, method, times_x, times_y):
29
+ def cumulative_sum(data, method, times_x, times_y):
28
30
  times_x, times_y = int(times_x), int(times_y)
29
31
  if len(data) == 3:
30
32
  if method=='Z':
@@ -46,7 +48,53 @@ def integrate(data, method, times_x, times_y):
46
48
  for _ in range(times_x):
47
49
  data[0] = np.cumsum(data[0])
48
50
 
49
- return data
51
+ return data
52
+
53
+ def integrate_rectangle(x, y):
54
+ """
55
+ Numerically integrate y with respect to x. Should be the same as cumulative sum for regularly spaced x.
56
+ """
57
+ integrated_y = np.zeros_like(y)
58
+ for i in range(1, len(y)):
59
+ integrated_y[i] = integrated_y[i-1] + y[i] * (x[i] - x[i-1])
60
+ return integrated_y
61
+
62
+ def integrate_trapezoid(x,y):
63
+ """
64
+ Numerically integrate y with respect to x using the trapezoidal rule.
65
+ """
66
+ integrated_y = np.zeros_like(y)
67
+ for i in range(1,len(y)):
68
+ integrated_y[i] = integrated_y[i-1] + (y[i] + y[i-1]) * (x[i] - x[i-1]) / 2.0
69
+ return integrated_y
70
+
71
+ def integrate_simpson(x, y):
72
+ """
73
+ Numerically integrate y with respect to x using Simpson's rule.
74
+ """
75
+ integrated_y = np.zeros_like(y)
76
+ for i in range(1,len(y) - 1):
77
+ integrated_y[i] = integrated_y[i-1] + (y[i-1] + 4 * y[i] + y[i+1]) * (x[i+1] - x[i-1])/6
78
+ # Use trapezoidal rule for the last segment
79
+ integrated_y[-1] = integrated_y[-2] + (y[-1] + y[-2]) * (x[-1] - x[-2]) / 2.0
80
+
81
+ return integrated_y
82
+
83
+
84
+ def integrate(data, method, times_x, times_y):
85
+ times_x, times_y = int(times_x), int(times_y)
86
+ functions={'Trapezoid': integrate_trapezoid, 'Simpson': integrate_simpson, 'Rectangle': integrate_rectangle}
87
+ if len(data) == 3:
88
+ for _ in range(times_x):
89
+ data[-1] = np.array([functions[method](data[-1][:,i], data[0][:,i]) for i in range(data[-1].shape[1])]).T
90
+ for _ in range(times_y):
91
+ data[-1] = np.array([functions[method](data[-1][i,:], data[1][i,:]) for i in range(data[-1].shape[0])])
92
+
93
+ elif len(data) == 2:
94
+ for _ in range(times_y):
95
+ data[-1] = functions[method](data[0], data[1])
96
+
97
+ return data
50
98
 
51
99
  def smooth(data, method, width_x, width_y):
52
100
  filters = {'Gauss': ndimage.gaussian_filter,
@@ -163,7 +211,10 @@ def cut_y(data, method, bottom, width):
163
211
  return data
164
212
 
165
213
  def swap_xy(data, method, setting1, setting2):
166
- data[0], data[1] = data[1], data[0]
214
+ if len(data) == 3:
215
+ data[0], data[1], data[-1] = data[1].T, data[0].T, data[-1].T
216
+ elif len(data) == 2:
217
+ data[0], data[1] = data[1], data[0]
167
218
  return data
168
219
 
169
220
  def flip(data, method, setting1, setting2):
@@ -388,23 +439,51 @@ def root(data, method, setting1, setting2):
388
439
  data[axis[method]][j] = np.abs(data[axis[method]][j])**(1/float(setting1))
389
440
  return data
390
441
 
442
+ def interp2d(x, y, z, kind='linear'):
443
+ """
444
+ Re-do the job that scipy used to do
445
+ """
446
+ if kind == 'linear':
447
+ interpolator = LinearNDInterpolator(list(zip(x,y)), z)
448
+ elif kind == 'cubic':
449
+ interpolator = CloughTocher2DInterpolator(list(zip(x,y)), z)
450
+ return interpolator
451
+
391
452
  def interpolate(data, method, n_x, n_y):
453
+ n_x, n_y = int(n_x), int(n_y)
392
454
  if len(data) == 3:
393
- x, y = data[0][:,0], data[1][0,:]
394
- f_z = interp2d(y, x, data[2], kind=method)
395
- n_x, n_y = int(n_x), int(n_y)
396
- min_x, max_x = np.amin(data[0]), np.amax(data[0])
397
- min_y, max_y = np.amin(data[1]), np.amax(data[1])
398
- yp, xp = np.linspace(min_y, max_y, n_y), np.linspace(min_x, max_x, n_x)
399
- data[1], data[0] = np.meshgrid(yp, xp)
400
- data[2] = f_z(yp, xp)
455
+ x=data[0].flatten()
456
+ y=data[1].flatten()
457
+ z=data[2].flatten()
458
+ f_z = interp2d(x,y,z, kind=method)
459
+ X, Y = np.linspace(min(x), max(x), n_x), np.linspace(min(y), max(y), n_y)
460
+ X, Y = np.meshgrid(X, Y)
461
+ data[2] = np.ma.masked_invalid(f_z(X,Y).T)
462
+ data[0] = X.T
463
+ data[1] = Y.T
401
464
  elif len(data) == 2:
402
- f = interp1d(data[0], data[1], kind=method)
403
- n_x = int(n_x)
404
- min_x, max_x = np.amin(data[0]), np.amax(data[0])
405
- data[0] = np.linspace(min_x, max_x, n_x)
465
+ kind={'linear': 1, 'cubic': 3}
466
+ x,y=sort_lists(data[0], data[1])
467
+ f = make_interp_spline(x, y, kind[method])
468
+ data[0] = np.linspace(np.min(x), np.max(x), n_x)
406
469
  data[1] = f(data[0])
407
470
  return data
471
+
472
+ def sort(data, method, setting1, setting2):
473
+ if len(data) == 3:
474
+ if method == 'X':
475
+ xsort,zsort=np.zeros_like(data[-1]),np.zeros_like(data[-1])
476
+ for i in range(data[-1].shape[1]):
477
+ xsort[:,i],zsort[:,i]=sort_lists(data[0][:,i],data[-1][:,i])
478
+ data=[xsort, data[1], zsort]
479
+ elif method == 'Y':
480
+ ysort,zsort=np.zeros_like(data[-1]),np.zeros_like(data[-1])
481
+ for i in range(data[-1].shape[0]):
482
+ ysort[i,:],zsort[i,:]=sort_lists(data[1][i],data[-1][i])
483
+ data=[data[0], ysort, zsort]
484
+ elif len(data) == 2:
485
+ data[0], data[1] = sort_lists(data[0], data[1])
486
+ return data
408
487
 
409
488
  def add_slope(data, method, a_x, a_y):
410
489
  if len(data) == 3:
@@ -431,36 +510,49 @@ def invert(data, method, setting1, setting2):
431
510
 
432
511
 
433
512
  class Filter:
434
- DEFAULT_SETTINGS = {'Derivative': {'Method': ['Mid'],
513
+ DEFAULT_SETTINGS = {'Derivative': {'Method': [''],
435
514
  'Settings': ['0', '1'],
515
+ 'tooltips': ['Order in X', 'Order in Y'],
436
516
  'Function': derivative,
437
517
  'Checkstate': 2},
438
- 'Integrate': {'Method': ['Z','Y','X'],
518
+ 'Integrate': {'Method': ['Trapezoid','Simpson','Rectangle'],
439
519
  'Settings': ['0', '1'],
520
+ 'tooltips': ['Order in X', 'Order in Y'],
440
521
  'Function': integrate,
441
522
  'Checkstate': 2},
523
+ 'Cumulative sum': {'Method': ['Z','Y','X'],
524
+ 'Settings': ['0', '1'],
525
+ 'tooltips': ['Order in zero-th index', 'Order in first index'],
526
+ 'Function': cumulative_sum,
527
+ 'Checkstate': 2},
442
528
  'Smoothen': {'Method': ['Gauss', 'Median'],
443
529
  'Settings': ['0', '2'],
530
+ 'tooltips': ['Smoothing window in X', 'Smoothing window in Y'],
444
531
  'Function': smooth,
445
532
  'Checkstate': 2},
446
533
  'Savitzy-Golay smoothing': {'Method': ['Y','X','dY','dX','ddY','ddX'],
447
534
  'Settings': ['7', '2'],
535
+ 'tooltips': ['Smoothing window', 'Polynomial order'],
448
536
  'Function': sav_gol,
449
- 'Checkstate': 2},
537
+ 'Checkstate': 2},
450
538
  'Add/Subtract': {'Method': ['X','Y','Z'],
451
539
  'Settings': ['0', ''],
540
+ 'tooltips': ['Value'],
452
541
  'Function': offset,
453
542
  'Checkstate': 2},
454
543
  'Multiply': {'Method': ['X','Y','Z'],
455
544
  'Settings': ['1', ''],
545
+ 'tooltips': ['Value'],
456
546
  'Function': multiply,
457
547
  'Checkstate': 2},
458
548
  'Divide': {'Method': ['X','Y','Z'],
459
549
  'Settings': ['1', ''],
550
+ 'tooltips': ['Value'],
460
551
  'Function': divide,
461
552
  'Checkstate': 0},
462
553
  'Add Slope': {'Method': [''],
463
554
  'Settings': ['0', '-1'],
555
+ 'tooltips': ['Slope value in X', 'Slope value in Y'],
464
556
  'Function': add_slope,
465
557
  'Checkstate': 2},
466
558
  'Invert': {'Method': ['X','Y','Z'],
@@ -469,6 +561,7 @@ class Filter:
469
561
  'Checkstate': 0},
470
562
  'Normalize': {'Method': ['Max', 'Min', 'Min to Max','Point'],
471
563
  'Settings': ['', ''],
564
+ 'tooltips': ['X coordinate', 'Y coordinate'],
472
565
  'Function': normalize,
473
566
  'Checkstate': 2},
474
567
  'Subtract average': {'Method': ['Z', 'Y', 'X'],
@@ -476,7 +569,8 @@ class Filter:
476
569
  'Function': subtract_average,
477
570
  'Checkstate': 2},
478
571
  'Offset line by line': {'Method': ['Z', 'Y'],
479
- 'Settings': ['', ''],
572
+ 'Settings': ['0', ''],
573
+ 'tooltips': ['Index'],
480
574
  'Function': offset_line_by_line,
481
575
  'Checkstate': 2},
482
576
  'Subtract average line by line': {'Method': ['Z', 'Y'],
@@ -485,18 +579,22 @@ class Filter:
485
579
  'Checkstate': 2},
486
580
  'Subtract trace': {'Method': ['Ver', 'Hor'],
487
581
  'Settings': ['0', ''],
582
+ 'tooltips': ['Index'],
488
583
  'Function': subtract_trace,
489
584
  'Checkstate': 0},
490
585
  'Logarithm': {'Method': ['Mask','Shift','Abs'],
491
586
  'Settings': ['10', ''],
587
+ 'tooltips': ['Base; 10, 2 or e'],
492
588
  'Function': logarithm,
493
589
  'Checkstate': 2},
494
590
  'Power': {'Method': ['X','Y','Z'],
495
591
  'Settings': ['2', ''],
592
+ 'tooltips': ['Exponent'],
496
593
  'Function': power,
497
594
  'Checkstate': 2},
498
595
  'Root': {'Method': ['X','Y','Z'],
499
596
  'Settings': ['2', ''],
597
+ 'tooltips': ['Exponent'],
500
598
  'Function': root,
501
599
  'Checkstate': 2},
502
600
  'Absolute': {'Method': [''],
@@ -507,32 +605,43 @@ class Filter:
507
605
  'Settings': ['', ''],
508
606
  'Function': flip,
509
607
  'Checkstate': 2},
510
- 'Interp': {'Method': ['linear','cubic','quintic'],
608
+ 'Interpolate': {'Method': ['linear','cubic'],
511
609
  'Settings': ['800', '600'],
610
+ 'tooltips': ['Number of points in X', 'Number of points in Y'],
512
611
  'Function': interpolate,
513
612
  'Checkstate': 0},
613
+ 'Sort': {'Method': ['X','Y'],
614
+ 'Settings': ['', ''],
615
+ 'Function': sort,
616
+ 'Checkstate': 2},
514
617
  'Roll X': {'Method': ['Index'],
515
618
  'Settings': ['0', '0'],
619
+ 'tooltips': ['Position', 'Amount'],
516
620
  'Function': roll_x,
517
621
  'Checkstate': 0},
518
622
  'Roll Y': {'Method': ['Index'],
519
623
  'Settings': ['0', '0'],
624
+ 'tooltips': ['Position', 'Amount'],
520
625
  'Function': roll_y,
521
626
  'Checkstate': 0},
522
627
  'Crop X': {'Method': ['Abs', 'Rel', 'Lim'],
523
628
  'Settings': ['-1', '1'],
629
+ 'tooltips': ['Min', 'Max'],
524
630
  'Function': crop_x,
525
631
  'Checkstate': 0},
526
632
  'Crop Y': {'Method': ['Abs', 'Rel', 'Lim'],
527
- 'Settings': ['-2', '2'],
633
+ 'Settings': ['-1', '1'],
634
+ 'tooltips': ['Min', 'Max'],
528
635
  'Function': crop_y,
529
636
  'Checkstate': 0},
530
637
  'Cut X': {'Method': ['Index'],
531
638
  'Settings': ['0', '0'],
639
+ 'tooltips': ['Left index', 'Width'],
532
640
  'Function': cut_x,
533
641
  'Checkstate': 0},
534
642
  'Cut Y': {'Method': ['Index'],
535
643
  'Settings': ['0', '0'],
644
+ 'tooltips': ['Bottom index', 'Width'],
536
645
  'Function': cut_y,
537
646
  'Checkstate': 0},
538
647
  'Swap X/Y': {'Method': [''],
@@ -541,7 +650,7 @@ class Filter:
541
650
  'Checkstate': 2},
542
651
  }
543
652
 
544
- def __init__(self, name, method=None, settings=None, checkstate=None):
653
+ def __init__(self, name, method=None, settings=None, checkstate=None, dimension=2):
545
654
  self.name = name
546
655
  default_settings = self.DEFAULT_SETTINGS.copy()
547
656
  self.method_list = default_settings[name]['Method']
@@ -558,4 +667,6 @@ class Filter:
558
667
  else:
559
668
  self.checkstate = default_settings[name]['Checkstate']
560
669
  self.function = default_settings[name]['Function']
670
+ if 'tooltips' in default_settings[name]:
671
+ self.tooltips = default_settings[name]['tooltips']
561
672
 
File without changes
@@ -0,0 +1 @@
1
+ __version__ = '0.1.4'
@@ -1 +0,0 @@
1
- __version__ = '0.1.2'
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes