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.
- {wxmplot-0.9.57/wxmplot.egg-info → wxmplot-0.9.59}/PKG-INFO +11 -2
- wxmplot-0.9.59/examples/dump_config.py +49 -0
- wxmplot-0.9.59/examples/scope_mode_function.py +24 -0
- wxmplot-0.9.59/examples/scope_mode_generator.py +25 -0
- wxmplot-0.9.59/examples/scope_mode_mpl_compare.py +29 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/basepanel.py +15 -6
- {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/config.py +136 -48
- {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/imageconf.py +9 -11
- {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/imageframe.py +48 -46
- {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/imagepanel.py +31 -30
- {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/interactive.py +110 -5
- {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/plotconfigframe.py +36 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/plotpanel.py +2 -1
- wxmplot-0.9.59/wxmplot/version.py +16 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59/wxmplot.egg-info}/PKG-INFO +11 -2
- {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot.egg-info/SOURCES.txt +4 -0
- wxmplot-0.9.57/wxmplot/version.py +0 -4
- {wxmplot-0.9.57 → wxmplot-0.9.59}/ChangeLog +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/LICENSE +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/MANIFEST.in +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/README.md +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/basic_screenshot.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/compare_dislin_mpl.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/compare_plplot.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/contour.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/demo.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/errorbar.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/fill_to_zero.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/fill_uncertainties.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/floatcontrol.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/histogram.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/image.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/image_scroll.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/imagematrix.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/interactive_multiplewindows.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/leftright.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/multiplot.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/pilatus_display.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/plot_fromdatafile.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/plot_many_traces.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/plotapp.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/rgb_image.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/scatterplot.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/simple.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/stackedplot.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/stripchart.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/theme_compare.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/tiff_display.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/tifffile.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/time.dat +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/time_update.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/timedata.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/examples/xafs.dat +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/pyproject.toml +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/requirements.txt +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/setup.cfg +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/setup.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/tests/basic_test.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/__init__.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/allow_idle_macosx.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/baseframe.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/colors.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/imagematrixframe.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/inputhook.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/multiframe.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/plotapp.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/plotframe.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/residualplotframe.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/stackedplotframe.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot/utils.py +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot.egg-info/dependency_links.txt +0 -0
- {wxmplot-0.9.57 → wxmplot-0.9.59}/wxmplot.egg-info/requires.txt +0 -0
- {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.
|
|
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
|
-
|
|
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
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
294
|
-
self.
|
|
295
|
-
self.
|
|
296
|
-
|
|
297
|
-
self.
|
|
298
|
-
|
|
299
|
-
|
|
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
|
|
324
|
-
"""save dict of current configuration options
|
|
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
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
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.
|
|
385
|
+
self.get_config()
|
|
340
386
|
self.configdict.update(conf)
|
|
341
|
-
self.
|
|
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
|
|
435
|
-
for
|
|
436
|
-
t.
|
|
437
|
-
|
|
438
|
-
t
|
|
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[
|
|
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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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=
|
|
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,
|
|
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', '
|
|
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):
|