wxmplot 0.9.57__tar.gz → 0.9.59__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 (73) hide show
  1. {wxmplot-0.9.57/wxmplot.egg-info → wxmplot-0.9.59}/PKG-INFO +11 -2
  2. wxmplot-0.9.59/examples/dump_config.py +49 -0
  3. wxmplot-0.9.59/examples/scope_mode_function.py +24 -0
  4. wxmplot-0.9.59/examples/scope_mode_generator.py +25 -0
  5. wxmplot-0.9.59/examples/scope_mode_mpl_compare.py +29 -0
  6. {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/basepanel.py +15 -6
  7. {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/config.py +136 -48
  8. {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/imageconf.py +9 -11
  9. {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/imageframe.py +48 -46
  10. {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/imagepanel.py +31 -30
  11. {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/interactive.py +110 -5
  12. {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/plotconfigframe.py +36 -0
  13. {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/plotpanel.py +2 -1
  14. wxmplot-0.9.59/wxmplot/version.py +16 -0
  15. {wxmplot-0.9.57 → wxmplot-0.9.59/wxmplot.egg-info}/PKG-INFO +11 -2
  16. {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot.egg-info/SOURCES.txt +4 -0
  17. wxmplot-0.9.57/wxmplot/version.py +0 -4
  18. {wxmplot-0.9.57 → wxmplot-0.9.59}/ChangeLog +0 -0
  19. {wxmplot-0.9.57 → wxmplot-0.9.59}/LICENSE +0 -0
  20. {wxmplot-0.9.57 → wxmplot-0.9.59}/MANIFEST.in +0 -0
  21. {wxmplot-0.9.57 → wxmplot-0.9.59}/README.md +0 -0
  22. {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/basic_screenshot.py +0 -0
  23. {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/compare_dislin_mpl.py +0 -0
  24. {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/compare_plplot.py +0 -0
  25. {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/contour.py +0 -0
  26. {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/demo.py +0 -0
  27. {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/errorbar.py +0 -0
  28. {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/fill_to_zero.py +0 -0
  29. {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/fill_uncertainties.py +0 -0
  30. {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/floatcontrol.py +0 -0
  31. {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/histogram.py +0 -0
  32. {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/image.py +0 -0
  33. {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/image_scroll.py +0 -0
  34. {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/imagematrix.py +0 -0
  35. {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/interactive_multiplewindows.py +0 -0
  36. {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/leftright.py +0 -0
  37. {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/multiplot.py +0 -0
  38. {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/pilatus_display.py +0 -0
  39. {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/plot_fromdatafile.py +0 -0
  40. {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/plot_many_traces.py +0 -0
  41. {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/plotapp.py +0 -0
  42. {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/rgb_image.py +0 -0
  43. {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/scatterplot.py +0 -0
  44. {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/simple.py +0 -0
  45. {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/stackedplot.py +0 -0
  46. {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/stripchart.py +0 -0
  47. {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/theme_compare.py +0 -0
  48. {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/tiff_display.py +0 -0
  49. {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/tifffile.py +0 -0
  50. {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/time.dat +0 -0
  51. {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/time_update.py +0 -0
  52. {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/timedata.py +0 -0
  53. {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/xafs.dat +0 -0
  54. {wxmplot-0.9.57 → wxmplot-0.9.59}/pyproject.toml +0 -0
  55. {wxmplot-0.9.57 → wxmplot-0.9.59}/requirements.txt +0 -0
  56. {wxmplot-0.9.57 → wxmplot-0.9.59}/setup.cfg +0 -0
  57. {wxmplot-0.9.57 → wxmplot-0.9.59}/setup.py +0 -0
  58. {wxmplot-0.9.57 → wxmplot-0.9.59}/tests/basic_test.py +0 -0
  59. {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/__init__.py +0 -0
  60. {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/allow_idle_macosx.py +0 -0
  61. {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/baseframe.py +0 -0
  62. {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/colors.py +0 -0
  63. {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/imagematrixframe.py +0 -0
  64. {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/inputhook.py +0 -0
  65. {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/multiframe.py +0 -0
  66. {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/plotapp.py +0 -0
  67. {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/plotframe.py +0 -0
  68. {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/residualplotframe.py +0 -0
  69. {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/stackedplotframe.py +0 -0
  70. {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/utils.py +0 -0
  71. {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot.egg-info/dependency_links.txt +0 -0
  72. {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot.egg-info/requires.txt +0 -0
  73. {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: wxmplot
3
- Version: 0.9.57
3
+ Version: 0.9.59
4
4
  Summary: wxPython plotting widgets using matplotlib
5
5
  Home-page: https://github.com/newville/wxmplot
6
6
  Author: Matthew Newville
@@ -27,9 +27,18 @@ Classifier: Programming Language :: Python :: 3.9
27
27
  Classifier: Programming Language :: Python :: 3.10
28
28
  Classifier: Programming Language :: Python :: 3.11
29
29
  Requires-Python: >=3.8
30
+ License-File: LICENSE
31
+ Requires-Dist: wxPython>=4.1.0
32
+ Requires-Dist: wxutils>=0.3.0
33
+ Requires-Dist: matplotlib>=3.5.0
34
+ Requires-Dist: numpy>=1.18
35
+ Requires-Dist: Pillow>=7.0
36
+ Requires-Dist: pyyaml>=5.0
30
37
  Provides-Extra: doc
38
+ Requires-Dist: sphinx; extra == "doc"
39
+ Requires-Dist: jupyter_sphinx; extra == "doc"
31
40
  Provides-Extra: test
32
- License-File: LICENSE
41
+ Requires-Dist: pytest; extra == "test"
33
42
 
34
43
 
35
44
  WXMPlot provides advanced wxPython widgets for plotting and image display
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/python
2
+ import numpy as np
3
+ import wxmplot.interactive as wi
4
+ import json
5
+
6
+ x = np.linspace(0.0, 20.0, 201)
7
+ disp = wi.plot(x, np.sin(x)/(x+1), ylabel='response', xlabel='T (sec)')
8
+ cnf = disp.panel.conf
9
+
10
+ print("Line 1 ", cnf.get_mpline(0))
11
+
12
+
13
+ out = cnf.get_config()
14
+
15
+ #
16
+ #
17
+ # for attr in ('added_texts', 'auto_margins', 'axes_style',
18
+ # 'data_deriv', 'data_expr', 'draggable_legend', 'facecolor',
19
+ # 'framecolor', 'gridcolor', 'hidewith_legend', 'legend_loc',
20
+ # 'legend_onaxis', 'linecolors', 'margins', 'mpl_legend', 'ntrace',
21
+ # 'plot_type', 'scatter_mask', 'scatter_normalcolor',
22
+ # 'scatter_normaledge', 'scatter_selectcolor', 'scatter_selectedge',
23
+ # 'scatter_size', 'show_grid', 'show_legend', 'show_legend_frame',
24
+ # 'textcolor', 'title', 'viewpad', 'with_data_process',
25
+ # 'xlabel', 'xscale', 'y2label', 'ylabel', 'yscale', 'zoom_lims',
26
+ # 'zoom_style'):
27
+ #
28
+ # out[attr] = getattr(cnf, attr)
29
+ #
30
+ # ntrace = int(out['ntrace'])
31
+ #
32
+ # for attr in ('fills', 'traces'):
33
+ # val = getattr(cnf, attr)
34
+ # if attr == 'traces':
35
+ # val = cnf.get_traces()
36
+ # out[attr] = val[:ntrace+1]
37
+ #
38
+ #
39
+
40
+ conf = {'axes_style': 'open',
41
+ 'xlabel': 'New X',
42
+ 'traces': [{'color': '#440044', 'style': 'solid',
43
+ 'linewidth': 3.5, 'zorder': 5, 'fill': False,
44
+ 'label': 'x111', 'drawstyle': 'default', 'alpha': 1,
45
+ 'markersize': 5, 'marker': '+', 'markercolor': 'black'}]}
46
+
47
+
48
+ cnf.load_config(conf)
49
+ disp.panel.canvas.draw()
@@ -0,0 +1,24 @@
1
+ import numpy as np
2
+ from wxmplot.interactive import plot, set_data_generator
3
+
4
+ npts = 501
5
+ x = np.linspace(0, 50, npts)
6
+ y = 3.5*np.cos(1.1*(x-1)/(25+x)) + 2.4*np.cos(3.7*(x-11))
7
+ z = 4.1*np.cos(1.6*(x-4)/(40+x)) + 1.9*np.cos(3.2*(x-21))
8
+
9
+ nx = 2
10
+ def get_more_data():
11
+ global nx
12
+ nx += 1
13
+ if nx >= npts:
14
+ return None
15
+ return [(x[:nx], y[:nx]),
16
+ (x[:nx], z[:nx])]
17
+
18
+ # set up initial plot
19
+ plot(x[:nx], y[:nx])
20
+
21
+ # use data generator to run function to retrieve more data
22
+ set_data_generator(get_more_data, polltime=25)
23
+
24
+ print("consuming data from function...")
@@ -0,0 +1,25 @@
1
+ import numpy as np
2
+ from wxmplot.interactive import plot, set_data_generator
3
+
4
+ # generator of datasets
5
+ npts = 501
6
+ x = np.linspace(0, 50, npts)
7
+ datasets = ((np.cos(1.3*x) + np.sin(0.8*(x+nx/7)),
8
+ np.cos(1.1*x) - np.sin(0.6*(x+nx/43)))
9
+ for nx in range(npts))
10
+
11
+ def more_data():
12
+ """yield next pair of datasets from data generator"""
13
+ while True:
14
+ try:
15
+ ds = next(datasets)
16
+ yield [(x, ds[0]), (x, ds[1])]
17
+ except StopIteration:
18
+ break
19
+
20
+ # set up an initial plot
21
+ plot(x, np.zeros(len(x)))
22
+
23
+ # now set data generator and wait
24
+ set_data_generator(more_data, polltime=30)
25
+ print("consuming data from generator...")
@@ -0,0 +1,29 @@
1
+ # This could be comparable to
2
+ # https://matplotlib.org/stable/gallery/animation/strip_chart.html
3
+
4
+ import numpy as np
5
+ from wxmplot.interactive import plot, set_data_generator
6
+
7
+ class Scope:
8
+ def __init__(self, nmax=50, dt=0.1):
9
+ self.dt = dt
10
+ self.nmax = nmax
11
+ self.t = [0]
12
+ self.y = [0]
13
+
14
+ def update(self):
15
+ if len(self.t) > self.nmax:
16
+ self.t = [0]
17
+ self.y = [0]
18
+
19
+ p = np.random.rand()
20
+ v = np.random.rand() if p < 0.15 else 0
21
+ self.y.append(v)
22
+ self.t.append(len(self.t))
23
+ return [(np.array(self.t)*self.dt, np.array(self.y))]
24
+
25
+ NMAX, dt = 200, 0.05
26
+ scope = Scope(nmax=NMAX, dt=dt)
27
+
28
+ plot([0], [0], xmax=dt*NMAX)
29
+ set_data_generator(scope.update, polltime=int(1000*dt))
@@ -18,6 +18,7 @@ from matplotlib.backends.backend_wx import RendererWx
18
18
 
19
19
  from .utils import Printer, MenuItem
20
20
 
21
+
21
22
  class BasePanel(wx.Panel):
22
23
  """
23
24
  wx.Panel component shared by PlotPanel and ImagePanel.
@@ -568,11 +569,20 @@ class BasePanel(wx.Panel):
568
569
  self.x_lastmove = event.xdata
569
570
  if event.ydata is not None:
570
571
  self.y_lastmove = event.ydata
571
- x0 = min(x, ini_x)
572
- ymax = max(y, ini_y)
573
- width = abs(x-ini_x)
574
- height = abs(y-ini_y)
575
- y0 = self.canvas.figure.bbox.height - ymax
572
+
573
+ dpi_sf = 1.0
574
+ if wx.Platform != '__WXMSW__':
575
+ try:
576
+ dpi_sf = self.canvas.GetDPIScaleFactor()
577
+ except:
578
+ dpi_sf = 1.0
579
+
580
+ bheight = self.canvas.figure.bbox.height/dpi_sf
581
+ x0 = min(x, ini_x)/dpi_sf
582
+ ymax = max(y, ini_y)/dpi_sf
583
+ width = abs(x-ini_x)/dpi_sf
584
+ height = abs(y-ini_y)/dpi_sf
585
+ y0 = bheight - ymax
576
586
  limits = self.canvas.figure.axes[0].bbox.corners()
577
587
  if self.conf.zoom_style.startswith('x'):
578
588
  height = int(round(limits[3][1] - limits[0][1]))
@@ -635,7 +645,6 @@ class BasePanel(wx.Panel):
635
645
  tlims[ax][2:] = [ymin, ymax]
636
646
  elif self.conf.zoom_style.startswith('y'):
637
647
  tlims[ax][:2] = [xmin, xmax]
638
-
639
648
  self.conf.zoom_lims.append(tlims)
640
649
  # now apply limits:
641
650
  self.set_viewlimits()
@@ -37,17 +37,7 @@ StyleMap = {}
37
37
  DrawStyleMap = {}
38
38
  MarkerMap = {}
39
39
 
40
- default_config = dict(viewpad=2.5, title='', xscale='linear',
41
- yscale='linear', xlabel='', ylabel='', y2label='',
42
- plot_type='lineplot', scatter_size=30,
43
- scatter_normalcolor='blue',
44
- scatter_normaledge='blue', scatter_selectcolor='red',
45
- scatter_selectedge='red', auto_margins=True,
46
- legend_loc= 'best', legend_onaxis='on plot',
47
- draggable_legend=False, hidewith_legend=True,
48
- show_legend=False, show_legend_frame=False,
49
- axes_style='box', labelfont=9, legendfont=7,
50
- titlefont=10, theme='light')
40
+
51
41
 
52
42
 
53
43
  for k in ('default', 'steps-pre','steps-mid', 'steps-post'):
@@ -164,6 +154,43 @@ for tname in ('light', 'white-background', 'dark', 'matplotlib', 'ggplot',
164
154
  theme.update(matplotlib.style.library[tname])
165
155
  Themes[tname.lower()] = theme
166
156
 
157
+ default_config = dict(auto_margins=True,
158
+ axes_style='box',
159
+ current_theme='light',
160
+ data_deriv=False,
161
+ data_expr=None,
162
+ draggable_legend=False,
163
+ hidewith_legend=True,
164
+ legend_loc= 'best',
165
+ legend_onaxis='on plot',
166
+ linecolors=linecolors,
167
+ margins=(0.15, 0.05, 0.05, 0.15),
168
+ mpl_legend=None,
169
+ plot_type='lineplot',
170
+ scatter_size=30,
171
+ scatter_mask=None,
172
+ scatter_normalcolor='blue',
173
+ scatter_normaledge='blue',
174
+ scatter_selectcolor='red',
175
+ scatter_selectedge='red',
176
+ show_grid=True,
177
+ show_legend=False,
178
+ show_legend_frame=False,
179
+ textcolor='#000000',
180
+ title='',
181
+ xscale='linear',
182
+ yscale='linear',
183
+ xlabel='',
184
+ ylabel='',
185
+ y2label='',
186
+ viewpad=2.5,
187
+ with_data_process=True,
188
+ zoom_style='both x and y',
189
+ labelfont=9,
190
+ legendfont=7,
191
+ titlefont=10)
192
+
193
+
167
194
  def ifnot_none(val, default):
168
195
  "return val if val is not None else default"
169
196
  return val if val is not None else default
@@ -175,7 +202,7 @@ class LineProps:
175
202
  to make the matplotlib calls to set the Line2D properties
176
203
  """
177
204
  REPRFMT = """LineProps(color='{color:s}', style='{style:s}', linewidth={linewidth:.1f},
178
- label='{label:s}', zorder={zorder:d}, drawstyle='{drawstyle:s}',
205
+ label='{label:s}', zorder={zorder:d}, drawstyle='{drawstyle:s}', alpha={alpha:3f},
179
206
  marker='{marker:s}', markersize={markersize:.1f}, markercolor={markercolor:s})"""
180
207
 
181
208
  def __init__(self, color='black', style='solid', drawstyle='default',
@@ -199,13 +226,13 @@ class LineProps:
199
226
 
200
227
  def __repr__(self):
201
228
  if self.zorder is None:
202
- self.zorder = 33
229
+ self.zorder = 30
203
230
  return self.REPRFMT.format(**self.__dict__)
204
231
 
205
232
  def set(self, color=None, style=None, drawstyle=None, linewidth=None,
206
233
  marker=None, markersize=None, markercolor=None, zorder=None,
207
234
  label=None, fill=False, alpha=None):
208
- self.color = ifnotNOne(color, self.color)
235
+ self.color = ifnot_none(color, self.color)
209
236
  self.style = style
210
237
  self.drawstyle = drawstyle
211
238
  self.fill = fill
@@ -217,6 +244,14 @@ class LineProps:
217
244
  self.zorder = zorder
218
245
  self.alpha = alpha
219
246
 
247
+ def asdict(self):
248
+ return dict(color=self.color, style=self.style,
249
+ linewidth=self.linewidth, zorder=self.zorder,
250
+ fill=self.fill, label=self.label, drawstyle=self.drawstyle,
251
+ alpha=self.alpha, markersize=self.markersize,
252
+ marker=self.marker, markercolor=self.markercolor)
253
+
254
+
220
255
 
221
256
  class PlotConfig:
222
257
  """Plot Configuration for Line Plots, holding most configuration data """
@@ -262,7 +297,7 @@ class PlotConfig:
262
297
  self.axes_style_choices = ['box', 'open']
263
298
  self.legend_onaxis_choices = ['on plot', 'off plot']
264
299
 
265
- self.configdict = default_config
300
+ self.configdict = {k: v for k, v in default_config.items()}
266
301
  if custom_config is not None:
267
302
  self.configdict.update(custom_config)
268
303
  self.themes = Themes
@@ -270,18 +305,12 @@ class PlotConfig:
270
305
  self.set_defaults()
271
306
 
272
307
  def set_defaults(self):
273
- fontsize = {}
274
- for key, val in self.configdict.items():
275
- if 'font' in key:
276
- fontsize[key] = val
277
- else:
278
- setattr(self, key, val)
279
-
280
308
  self.zoom_lims = []
281
309
  self.added_texts = []
282
310
  self.scatter_xdata = None
283
311
  self.scatter_ydata = None
284
312
  self.scatter_mask = None
313
+
285
314
  self.margins = None
286
315
  self.mpl_legend = None
287
316
  self.axes_traces = {}
@@ -290,15 +319,19 @@ class PlotConfig:
290
319
  self.traces = []
291
320
  self.reset_lines()
292
321
 
293
- f0 = FontProperties()
294
- self.labelfont = f0.copy()
295
- self.titlefont = f0.copy()
296
- self.legendfont = f0.copy()
297
- self.legendfont.set_size(fontsize['legendfont'])
298
- self.labelfont.set_size(fontsize['labelfont'])
299
- self.titlefont.set_size(fontsize['titlefont'])
322
+ self.labelfont = FontProperties()
323
+ self.titlefont = FontProperties()
324
+ self.legendfont = FontProperties()
325
+
326
+ for key, val in self.configdict.items():
327
+ if 'font' in key:
328
+ thisfont = getattr(self, key, FontProperties())
329
+ thisfont.set_size(val)
330
+ else:
331
+ setattr(self, key, val)
300
332
  self.set_theme()
301
333
 
334
+
302
335
  def set_theme(self, theme=None):
303
336
  if theme in self.themes:
304
337
  self.current_theme = theme
@@ -320,25 +353,73 @@ class PlotConfig:
320
353
  self.reset_trace_properties()
321
354
  self.set_axes_style()
322
355
 
323
- def get_current_config(self):
324
- """save dict of current configuration options to self.configdict
356
+ def get_config(self):
357
+ """save json-ifiable dict of current configuration options
358
+ to self.configdict
325
359
  """
326
360
  cnf = {}
327
- for key in self.configdict:
328
- if hasattr(self, key):
329
- val = getattr(self, key)
330
- if key in ('legendfont', 'labelfont', 'titlefont'):
331
- val = val.get_size()
332
- elif key == 'linecolors':
333
- val = [trace.color for trace in self.traces[:10]]
334
- cnf[key] = val
361
+ for attr in ('added_texts', 'auto_margins', 'axes_style', 'current_theme',
362
+ 'data_deriv', 'data_expr', 'draggable_legend', 'facecolor',
363
+ 'framecolor', 'gridcolor', 'hidewith_legend', 'legend_loc',
364
+ 'legend_onaxis', 'linecolors', 'margins', 'mpl_legend', 'ntrace',
365
+ 'plot_type', 'scatter_mask', 'scatter_normalcolor',
366
+ 'scatter_normaledge', 'scatter_selectcolor', 'scatter_selectedge',
367
+ 'scatter_size', 'show_grid', 'show_legend', 'show_legend_frame',
368
+ 'textcolor', 'title', 'viewpad', 'with_data_process',
369
+ 'xlabel', 'xscale', 'y2label', 'ylabel', 'yscale', 'zoom_lims',
370
+ 'zoom_style', 'legendfont', 'labelfont', 'titlefont',
371
+ 'fills', 'traces'):
372
+ val = getattr(self, attr)
373
+ if attr in ('legendfont', 'labelfont', 'titlefont'):
374
+ val = val.get_size()
375
+ elif attr == 'fills':
376
+ val = val[:self.ntrace]
377
+ elif attr == 'traces':
378
+ val = self.get_traces()[:self.ntrace]
379
+
380
+ cnf[attr] = val
335
381
  self.configdict = cnf
336
382
  return cnf
337
383
 
338
384
  def load_config(self, conf):
339
- self.get_current_config()
385
+ self.get_config()
340
386
  self.configdict.update(conf)
341
- self.set_defaults()
387
+ cnf = self.configdict
388
+
389
+ self.ntrace = cnf.get('ntrace', 1)
390
+
391
+ # self.lines = [None]*self.ntrace
392
+ # self.dy = [None]*self.ntrace
393
+ # self.fills = [None]*self.ntrace
394
+
395
+ self.set_theme(theme=cnf['current_theme'])
396
+ for attr in ('added_texts', 'auto_margins', 'axes_style', 'current_theme',
397
+ 'data_deriv', 'data_expr', 'draggable_legend', 'facecolor',
398
+ 'framecolor', 'gridcolor', 'hidewith_legend', 'legend_loc',
399
+ 'legend_onaxis', 'linecolors', 'margins', 'mpl_legend',
400
+ 'plot_type', 'scatter_mask', 'scatter_normalcolor',
401
+ 'scatter_normaledge', 'scatter_selectcolor', 'scatter_selectedge',
402
+ 'scatter_size', 'show_grid', 'show_legend', 'show_legend_frame',
403
+ 'textcolor', 'title', 'viewpad', 'with_data_process',
404
+ 'xlabel', 'xscale', 'y2label', 'ylabel', 'yscale', 'zoom_lims',
405
+ 'zoom_style'):
406
+ if attr in cnf:
407
+ setattr(self, attr, cnf.get(attr))
408
+
409
+ # for fname in ('legendfont', 'labelfont', 'titlefont'):
410
+ # fsize = cnf.get(fname, None)
411
+ # if fsize is not None:
412
+ # thisfont = getattr(self, fname).set_size(fsize)
413
+ #
414
+ # for i, xfill in enumerate(cnf['fills']):
415
+ # self.fills[i] = xfill
416
+ #
417
+ # self.traces = []
418
+ # for trace in cnf['traces']:
419
+ # thistrace = LineProps()
420
+ # thistrace.set(**trace)
421
+ # self.traces.append(thistrace)
422
+
342
423
 
343
424
  def reset_lines(self):
344
425
  self.lines = [None]*len(self.traces)
@@ -393,7 +474,6 @@ class PlotConfig:
393
474
  except:
394
475
  return self.lines[n-1]
395
476
 
396
-
397
477
  def get_trace(self, trace):
398
478
  if trace is None:
399
479
  trace = self.ntrace
@@ -401,6 +481,13 @@ class PlotConfig:
401
481
  self.traces.append(LineProps())
402
482
  return trace
403
483
 
484
+ def get_traces(self):
485
+ out = []
486
+ for i in range(self.ntrace):
487
+ out.append(self.traces[i].asdict())
488
+ return out
489
+
490
+
404
491
  def relabel(self, xlabel=None, ylabel=None,
405
492
  y2label=None, title=None, delay_draw=False):
406
493
  " re draw labels (title, x, y labels)"
@@ -431,11 +518,12 @@ class PlotConfig:
431
518
  self.y2label not in ('', None, 'None')):
432
519
  axes[1].set_ylabel(self.y2label, **kws)
433
520
 
434
- for ax in axes[0].xaxis, axes[0].yaxis:
435
- for t in ax.get_ticklabels():
436
- t.set_color(self.textcolor)
437
- if hasattr(t, 'set_fontsize'):
438
- t.set_fontsize(n)
521
+ for axes in self.canvas.figure.get_axes():
522
+ for ax in axes.xaxis, axes.yaxis:
523
+ for t in ax.get_ticklabels():
524
+ t.set_color(self.textcolor)
525
+ if hasattr(t, 'set_fontsize'):
526
+ t.set_fontsize(n)
439
527
 
440
528
  self.set_added_text_size()
441
529
  if self.mpl_legend is not None:
@@ -840,7 +928,7 @@ class PlotConfig:
840
928
  labs.append(xl)
841
929
  labs = tuple(labs)
842
930
 
843
- lgn = axes[0].legend
931
+ lgn = axes[-1].legend
844
932
  if self.legend_onaxis.startswith('off'):
845
933
  lgn = self.canvas.figure.legend
846
934
  # 'best' and 'off axis' not implemented yet
@@ -46,11 +46,11 @@ for cm in ('gray', 'coolwarm', 'viridis', 'inferno', 'plasma', 'magma',
46
46
  if cm in cm_names or hasattr(cmap, cm) and cm not in ColorMap_List:
47
47
  ColorMap_List.append(cm)
48
48
 
49
-
50
- Contrast_List = ['None', '0.001', '0.002', '0.005', '0.01', '0.02', '0.05',
51
- '0.1', '0.2', '0.5', '1.0', '2.0', '5.0', '10.0']
52
-
53
- Contrast_NDArray = np.array((-1.0, 0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1., 2, 5.))
49
+ Contrast_Levels = ('0', '0.00010', '0.00015', '0.00020', '0.0003', '0.0005',
50
+ '0.0007', '0.0010', '0.0015', '0.0020', '0.003', '0.005',
51
+ '0.007', '0.010', '0.015', '0.020', '0.03', '0.05', '0.07',
52
+ '0.10', '0.15', '0.20', '0.3', '0.5', '0.7', '1.0', '1.5',
53
+ '2.0', '3.0', '5.0', '7.0', '10.0', '15.0', '20.0', '30.0')
54
54
 
55
55
  Interp_List = ('nearest', 'bicubic', 'quadric', 'gaussian', 'kaiser',
56
56
  'bessel', 'mitchell', 'catrom', 'spline16', 'spline36',
@@ -217,7 +217,7 @@ class ImageConfig:
217
217
  if len(dticks) < 2:
218
218
  dticks.append(dat.min())
219
219
  dticks.append(dat.max())
220
-
220
+ dticks = np.array(dticks)
221
221
  dstep = max(2.e-15, abs(np.diff(dticks).mean()))
222
222
  if dstep > 5e4 or (dstep < 5.e-4 and dticks.mean() < 5.e-2):
223
223
  fmt = '%.2e'
@@ -315,12 +315,12 @@ class ImageConfig:
315
315
  return out
316
316
 
317
317
  def set_config(self, interp=None, colormap=None, reverse_colormap=None,
318
- contrast_level=None, flip_ud=None, flip_lr=None,
318
+ contrast_level=0, flip_ud=None, flip_lr=None,
319
319
  rot=None, tricolor_bg=None, ncontour_levels=None,
320
320
  title=None, style=None):
321
321
  """set configuration options:
322
322
 
323
- interp, colormap, reverse_colormap, contrast_levels, flip_ud,
323
+ interp, colormap, reverse_colormap, contrast_level, flip_ud,
324
324
  flip_lr, rot, tricolor_bg, ncontour_levels, title, style
325
325
  """
326
326
  if interp is not None:
@@ -361,14 +361,12 @@ class ImageConfig:
361
361
  def get_config(self):
362
362
  """get dictionary of configuration options"""
363
363
  out = {'reverse_colormap': self.cmap_reverse}
364
- for attr in ('interp', 'colormap', 'contrast_levels', 'flip_ud',
364
+ for attr in ('interp', 'colormap', 'contrast_level', 'flip_ud',
365
365
  'flip_lr', 'rot', 'tricolor_bg', 'ncontour_levels',
366
366
  'title', 'style'):
367
367
  out[attr] = getattr(self, attr)
368
368
  return out
369
369
 
370
-
371
-
372
370
  class ImageConfigFrame(wx.Frame):
373
371
  """ GUI Configure Frame for Images"""
374
372
  def __init__(self, parent=None, config=None, trace_color_callback=None):