wxmplot 2026.2.1__tar.gz → 2026.2.3__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 (86) hide show
  1. {wxmplot-2026.2.1/wxmplot.egg-info → wxmplot-2026.2.3}/PKG-INFO +5 -2
  2. wxmplot-2026.2.3/examples/image_canvas_scroll.py +123 -0
  3. wxmplot-2026.2.3/examples/simple.py +8 -0
  4. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/pyproject.toml +4 -2
  5. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/wxmplot/__init__.py +1 -5
  6. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/wxmplot/colors.py +7 -3
  7. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/wxmplot/config.py +48 -24
  8. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/wxmplot/image_canvas.py +22 -8
  9. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/wxmplot/line_plot.py +3 -3
  10. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/wxmplot/plotconfigframe.py +7 -38
  11. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/wxmplot/version.py +3 -3
  12. {wxmplot-2026.2.1 → wxmplot-2026.2.3/wxmplot.egg-info}/PKG-INFO +5 -2
  13. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/wxmplot.egg-info/SOURCES.txt +1 -0
  14. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/wxmplot.egg-info/requires.txt +3 -0
  15. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/wxmplot.egg-info/scm_file_list.json +122 -121
  16. wxmplot-2026.2.3/wxmplot.egg-info/scm_version.json +8 -0
  17. wxmplot-2026.2.1/examples/simple.py +0 -6
  18. wxmplot-2026.2.1/wxmplot.egg-info/scm_version.json +0 -8
  19. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/ChangeLog +0 -0
  20. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/LICENSE +0 -0
  21. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/MANIFEST.in +0 -0
  22. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/README.md +0 -0
  23. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/BasicExamples.ipynb +0 -0
  24. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/DynamicExamples.ipynb +0 -0
  25. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/basic_screenshot.py +0 -0
  26. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/compare_dislin_mpl.py +0 -0
  27. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/compare_plplot.py +0 -0
  28. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/contour.py +0 -0
  29. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/demo.py +0 -0
  30. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/discrete_data.py +0 -0
  31. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/errorbar.py +0 -0
  32. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/extra_marker_and_line_reporting.py +0 -0
  33. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/fill_to_zero.py +0 -0
  34. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/fill_uncertainties.py +0 -0
  35. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/floatcontrol.py +0 -0
  36. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/histogram.py +0 -0
  37. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/image.py +0 -0
  38. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/image_canvas_ex.py +0 -0
  39. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/image_scroll.py +0 -0
  40. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/imagematrix.py +0 -0
  41. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/interactive_multiplewindows.py +0 -0
  42. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/leftright.py +0 -0
  43. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/multiple_yaxes.py +0 -0
  44. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/multiplot.py +0 -0
  45. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/pilatus_display.py +0 -0
  46. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/plot_fromdatafile.py +0 -0
  47. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/plot_many_traces.py +0 -0
  48. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/plotapp.py +0 -0
  49. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/rgb_image.py +0 -0
  50. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/scatterplot.py +0 -0
  51. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/scope_mode_function.py +0 -0
  52. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/scope_mode_generator.py +0 -0
  53. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/scope_mode_mpl_compare.py +0 -0
  54. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/stackedplot.py +0 -0
  55. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/stripchart.py +0 -0
  56. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/theme_compare.py +0 -0
  57. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/tiff_display.py +0 -0
  58. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/tifffile.py +0 -0
  59. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/time.dat +0 -0
  60. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/time_update.py +0 -0
  61. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/timedata.py +0 -0
  62. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/wxmplot_jupyter.ipynb +0 -0
  63. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/examples/xafs.dat +0 -0
  64. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/setup.cfg +0 -0
  65. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/setup.py +0 -0
  66. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/tests/basic_test.py +0 -0
  67. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/wxmplot/allow_idle_macosx.py +0 -0
  68. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/wxmplot/baseframe.py +0 -0
  69. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/wxmplot/basepanel.py +0 -0
  70. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/wxmplot/histogram.py +0 -0
  71. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/wxmplot/imageconf.py +0 -0
  72. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/wxmplot/imageframe.py +0 -0
  73. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/wxmplot/imagematrixframe.py +0 -0
  74. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/wxmplot/imagepanel.py +0 -0
  75. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/wxmplot/inputhook.py +0 -0
  76. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/wxmplot/interactive.py +0 -0
  77. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/wxmplot/multiframe.py +0 -0
  78. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/wxmplot/plotapp.py +0 -0
  79. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/wxmplot/plotframe.py +0 -0
  80. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/wxmplot/plotpanel.py +0 -0
  81. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/wxmplot/residualplotframe.py +0 -0
  82. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/wxmplot/stackedplotframe.py +0 -0
  83. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/wxmplot/utils.py +0 -0
  84. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/wxmplot/vispy_utils.py +0 -0
  85. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/wxmplot.egg-info/dependency_links.txt +0 -0
  86. {wxmplot-2026.2.1 → wxmplot-2026.2.3}/wxmplot.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wxmplot
3
- Version: 2026.2.1
3
+ Version: 2026.2.3
4
4
  Summary: wxPython plotting widgets using matplotlib
5
5
  Author-email: Matthew Newville <matt.newville@gmail.com>
6
6
  License-Expression: MIT
@@ -22,7 +22,7 @@ Classifier: Programming Language :: Python :: 3.11
22
22
  Classifier: Programming Language :: Python :: 3.12
23
23
  Classifier: Programming Language :: Python :: 3.13
24
24
  Classifier: Programming Language :: Python :: 3.14
25
- Requires-Python: >=3.10
25
+ Requires-Python: >=3.11
26
26
  Description-Content-Type: text/markdown
27
27
  License-File: LICENSE
28
28
  Requires-Dist: wxPython>=4.2.3
@@ -46,6 +46,9 @@ Requires-Dist: Sphinx; extra == "doc"
46
46
  Requires-Dist: jupyter_sphinx; extra == "doc"
47
47
  Requires-Dist: sphinx-copybutton; extra == "doc"
48
48
  Requires-Dist: sphinxcontrib-video; extra == "doc"
49
+ Requires-Dist: nbsphinx; extra == "doc"
50
+ Requires-Dist: sphinx-design; extra == "doc"
51
+ Requires-Dist: sphinx-breeze-theme; extra == "doc"
49
52
  Provides-Extra: test
50
53
  Requires-Dist: pytest; extra == "test"
51
54
  Requires-Dist: pytest-cov; extra == "test"
@@ -0,0 +1,123 @@
1
+ import time, os, sys
2
+ from random import shuffle
3
+
4
+ import numpy as np
5
+
6
+ import wx
7
+ from wxutils import pack
8
+ from wxmplot import ImageFrame
9
+ from wxmplot.image_canvas import ImageCanvas
10
+
11
+
12
+ class ImageCanvasFrame(wx.Frame):
13
+ def __init__(self, parent, title='WXMPLOT Image Canvas', size=(700,600)):
14
+ wx.Frame.__init__(self, None, title=title, size=size,
15
+ style=wx.DEFAULT_FRAME_STYLE)
16
+
17
+ self.im_canvas = ImageCanvas(self)
18
+ sizer = wx.BoxSizer(wx.VERTICAL)
19
+ sizer.Add(self.im_canvas, 1, wx.ALL|wx.GROW)
20
+ pack(self, sizer)
21
+
22
+ def set_colormap(self, colormap: str):
23
+ self.im_canvas.set_colormap(colormap)
24
+
25
+ def set_image(self, image: np.ndarray):
26
+ self.im_canvas.set_image(image)
27
+ self.im_canvas.set_auto_scale(True, level=0.5)
28
+
29
+ class TestFrame(wx.Frame):
30
+ def __init__(self, parent=None, *args,**kwds):
31
+ kwds["style"] = wx.DEFAULT_FRAME_STYLE|wx.RESIZE_BORDER|wx.TAB_TRAVERSAL
32
+
33
+ wx.Frame.__init__(self, parent, -1, '',
34
+ wx.DefaultPosition, wx.Size(-1,-1), **kwds)
35
+ self.SetTitle(" WXMPlot Image Scroll")
36
+
37
+ self.SetFont(wx.Font(12,wx.SWISS,wx.NORMAL,wx.BOLD,False))
38
+ menu = wx.Menu()
39
+
40
+ self.arrays = []
41
+ self.imageframe = None
42
+
43
+ framesizer = wx.BoxSizer(wx.VERTICAL)
44
+
45
+ panel = wx.Panel(self, -1, size=(-1, -1))
46
+ panelsizer = wx.BoxSizer(wx.VERTICAL)
47
+
48
+ panelsizer.Add( wx.StaticText(panel, -1, 'Show Images'),
49
+ 0, wx.LEFT|wx.EXPAND, 10)
50
+
51
+ btn = wx.Button(panel, -1, 'start scrolling', size=(-1,-1))
52
+ btn.Bind(wx.EVT_BUTTON,self.onScrollImages)
53
+
54
+ btn2 = wx.Button(panel, -1, 'stop scrolling', size=(-1,-1))
55
+ btn2.Bind(wx.EVT_BUTTON,self.onStop)
56
+
57
+ self.msg = wx.StaticText(panel, label='000 images in 00.0000 seconds ', size=(500, -1))
58
+
59
+ panelsizer.Add(btn, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.LEFT, 5)
60
+ panelsizer.Add(btn2, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.LEFT, 5)
61
+ panelsizer.Add(self.msg, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.LEFT, 5)
62
+
63
+ panel.SetSizer(panelsizer)
64
+ panelsizer.Fit(panel)
65
+
66
+ framesizer.Add(panel, 0, wx.EXPAND, 2)
67
+ self.SetSizer(framesizer)
68
+ framesizer.Fit(self)
69
+ self.create_data()
70
+ self.ShowImageCanvasFrame()
71
+ self.count = 0
72
+ self.Bind(wx.EVT_TIMER, self.onTimer)
73
+ self.timer = wx.Timer(self)
74
+ self.Refresh()
75
+
76
+ def create_data(self):
77
+ nx = ny = 1001
78
+ print("Creating 240 images..")
79
+ for xoff in np.linspace(-2.5, 2.5, 20):
80
+ y, x = np.mgrid[-10+xoff:10+xoff:nx*1j, -10:10:nx*1j]
81
+ for xscale in (4.5, 5.0, 6.0):
82
+ for yscale in (0.8, 1.0, 1.1, 1.2):
83
+ dat = np.sin(x*x/xscale + y*y/yscale)/(1 + (x+y)*(x+y))
84
+ dat += np.random.normal(scale=0.12, size=(nx, ny))
85
+ self.arrays.append(dat)
86
+ shuffle(self.arrays)
87
+ print("Built %d arrays, shape=%s" % (len(self.arrays), repr(dat.shape)))
88
+
89
+ def ShowImageCanvasFrame(self):
90
+ if self.imageframe is None:
91
+ self.imageframe = ImageCanvasFrame(self)
92
+ try:
93
+ self.imageframe.Show()
94
+ except RuntimeError:
95
+ self.imageframe = ImageCanvasframe(self)
96
+ self.imageframe.Show()
97
+
98
+ self.imageframe.set_image(self.arrays[0])
99
+ self.imageframe.set_colormap('bone')
100
+ self.imageframe.Raise()
101
+
102
+ def onTimer(self, event):
103
+ self.count += 1
104
+ message = " %d images in %.3f sec" % (self.count,
105
+ time.time()-self.t0)
106
+ self.msg.SetLabel(message)
107
+ wx.CallAfter(self.imageframe.set_image,
108
+ self.arrays[self.count % len(self.arrays)])
109
+
110
+ def onScrollImages(self,event=None):
111
+ self.ShowImageCanvasFrame()
112
+ self.count = 0
113
+ self.t0 = time.time()
114
+ self.timer.Start(10)
115
+
116
+ def onStop(self,event=None):
117
+ self.timer.Stop()
118
+
119
+ if __name__ == '__main__':
120
+ app = wx.App()
121
+ f = TestFrame(None,-1)
122
+ f.Show(True)
123
+ app.MainLoop()
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/python
2
+ import numpy as np
3
+ import wxmplot.interactive as wi
4
+
5
+ x = np.linspace(0.0, 20.0, 201)
6
+ wi.plot(x, np.sin(x)/(x+1),
7
+ title='Titles can include latex: $\\chi^2/\\epsilon $ \n and newlines',
8
+ ylabel='unicde can also be used [\u03c7] (\u212B)', xlabel='T (sec)')
@@ -15,7 +15,7 @@ omit = ["tests/*"]
15
15
  [project]
16
16
  name = "wxmplot"
17
17
  dynamic = ["version"]
18
- requires-python = ">= 3.10"
18
+ requires-python = ">= 3.11"
19
19
  description = "wxPython plotting widgets using matplotlib"
20
20
  readme = "README.md"
21
21
  authors = [
@@ -64,6 +64,8 @@ Tracker = "https://github.com/newville/wxmplot/issues"
64
64
 
65
65
  [project.optional-dependencies]
66
66
  dev = ["build", "twine"]
67
- doc = ["Sphinx", "jupyter_sphinx", "sphinx-copybutton", "sphinxcontrib-video"]
67
+ doc = ["Sphinx", "jupyter_sphinx", "sphinx-copybutton", "sphinxcontrib-video",
68
+ "nbsphinx", "sphinx-design", "sphinx-breeze-theme"]
69
+
68
70
  test = ["pytest", "pytest-cov", "coverage"]
69
71
  all = ["wxmplot[dev, doc, test]"]
@@ -8,10 +8,8 @@
8
8
  with from wx programs. More importantly, the widgets created by wxmplot
9
9
  give the end user a flexible set of tools for interacting with their
10
10
  data and customizing the plots and displays. wxmplot panels are more
11
- interactive than typical displayss from matplotlib's pyplot module.
11
+ interactive than typical displays from matplotlib's pyplot module.
12
12
 
13
- version: 0.9.56
14
- last update: 2023-Jul-02
15
13
  License: MIT
16
14
  Author: Matthew Newville <newville@cars.uchicago.edu>
17
15
  Center for Advanced Radiation Sources,
@@ -47,5 +45,3 @@ from .image_canvas import ImageCanvas, BinMethod
47
45
  from .line_plot import LinePlot
48
46
  from .histogram import Histogram, compute_histogram_data
49
47
 
50
- if sys.platform.lower() == 'darwin':
51
- wx.PyApp.IsDisplayAvailable = lambda _: True
@@ -56,10 +56,14 @@ def hexcolor(color):
56
56
 
57
57
  # now, get color to an rgba tuple
58
58
  cvals = (0, 0, 0)
59
- if isinstance(color, tuple):
60
- cvals = color
61
- elif isinstance(color, list):
59
+ if isinstance(color, list):
62
60
  cvals = tuple(color)
61
+
62
+ if isinstance(color, tuple):
63
+ cvals = (min(255, max(0, c)) for c in color)
64
+ if isinstance(color[0], float) and color[0] < 2.0:
65
+ cvals = [int(255*c) for c in color]
66
+
63
67
  elif isinstance(color, str):
64
68
  c = color.lower().replace(' ', '').replace('gray', 'grey')
65
69
  if c in X11_COLORS:
@@ -222,6 +222,36 @@ def ifnot_none(val, default):
222
222
  return val if val is not None else default
223
223
 
224
224
 
225
+ def clean_texmath(text):
226
+ """
227
+ clean a string with mixed TeX math and control strings
228
+
229
+ inside of TeX dollar signs, the text is preserved.
230
+
231
+ outsde of TeX dollar signs '\\n' will be replaced in '\n', and `\\t' with '\t'
232
+ """
233
+ def clean_escape(s):
234
+ s = s.replace('\\n', '\n').replace('\\t', '\t').replace('\\r', '\r')
235
+ if '\\N{' in s or '\\u' in s:
236
+ s = s.encode("utf-8").decode("unicode_escape")
237
+ return s
238
+
239
+ if '$' not in text:
240
+ return clean_escape(text)
241
+
242
+ ndollar = text.count('$')
243
+ if ndollar == 0 or ndollar % 2 == 1:
244
+ return clean_escape(text)
245
+
246
+ sections = []
247
+ for isect, sect in enumerate(text.split('$')):
248
+ if isect % 2 == 0:
249
+ sect = clean_escape(sect)
250
+ sections.append(sect)
251
+ return '$'.join(sections)
252
+
253
+
254
+
225
255
  class LineProps:
226
256
  """ abstraction for Line2D properties, closely related to a
227
257
  MatPlotlib Line2D. used to set internal line properties, and
@@ -246,7 +276,7 @@ class LineProps:
246
276
  if markercolor is None:
247
277
  markercolor = color
248
278
  self.markercolor= markercolor
249
- self.label = label
279
+ self.label = clean_texmath(label)
250
280
  self.zorder = zorder
251
281
  self.mpline = mpline
252
282
  self.yaxes = yaxes
@@ -267,7 +297,7 @@ class LineProps:
267
297
  self.marker = ifnot_none(marker, self.marker)
268
298
  self.markersize = ifnot_none(markersize, self.markersize)
269
299
  self.markercolor= ifnot_none(markercolor,self.markercolor)
270
- self.label = ifnot_none(label, self.label)
300
+ self.label = ifnot_none(clean_texmath(label), self.label)
271
301
  self.zorder = ifnot_none(zorder, self.zorder)
272
302
  self.alpha = ifnot_none(alpha, self.alpha)
273
303
  self.yaxes = ifnot_none(yaxes, self.yaxes)
@@ -425,12 +455,10 @@ class PlotConfig:
425
455
  elif attr in conf:
426
456
  setattr(self, attr, conf[attr])
427
457
 
428
- l, r, t, b = self.margins
429
- self.set_margins(l, r, t, b, delay_draw=True)
458
+ self.set_margins(*self.margins, delay_draw=True)
430
459
  if self.auto_margins:
431
460
  self.panel.autoset_margins()
432
461
 
433
- ntrace = self.ntrace
434
462
  self.reset_trace_properties()
435
463
 
436
464
  if 'traces' in conf:
@@ -547,17 +575,17 @@ class PlotConfig:
547
575
  rcParams['xtick.labelsize'] = rcParams['ytick.labelsize'] = n
548
576
 
549
577
  if xlabel is not None:
550
- self.xlabel = xlabel
578
+ self.xlabel = clean_texmath(xlabel)
551
579
  if ylabel is not None:
552
- self.ylabel = ylabel
580
+ self.ylabel = clean_texmath(ylabel)
553
581
  if y2label is not None:
554
- self.y2label = y2label
582
+ self.y2label = clean_texmath(y2label)
555
583
  if y3label is not None:
556
- self.y3label = y3label
584
+ self.y3label = clean_texmath(y3label)
557
585
  if y4label is not None:
558
- self.y4label = y4label
586
+ self.y4label = clean_texmath(y4label)
559
587
  if title is not None:
560
- self.title = title
588
+ self.title = clean_texmath(title)
561
589
  if self.canvas is None:
562
590
  return
563
591
  axes = self.canvas.figure.get_axes()
@@ -928,8 +956,7 @@ class PlotConfig:
928
956
  if yaxes_tracecolor is not None:
929
957
  self.yaxes_tracecolor = bool(yaxes_tracecolor)
930
958
 
931
- cur_theme = self.themes[self.current_theme]
932
- tcolor = mpl2hexcolor(self.textcolor) # cur_theme['ytick.color'])
959
+ tcolor = mpl2hexcolor(self.textcolor)
933
960
 
934
961
  axes = self.canvas.figure.get_axes()
935
962
  colors = [tcolor]*(len(axes)+2)
@@ -1096,7 +1123,7 @@ class PlotConfig:
1096
1123
  for trace, lines in enumerate(ax.get_lines()):
1097
1124
  try:
1098
1125
  dats = copy(self.data_save[ax][trace])
1099
- except:
1126
+ except Exception:
1100
1127
  return
1101
1128
  xd, yd = np.asarray(dats[0][:]), np.asarray(dats[1][:])
1102
1129
  if expr == 'Y*X':
@@ -1152,7 +1179,7 @@ class PlotConfig:
1152
1179
  x_minpos= min(x[np.where(x>0)])
1153
1180
  else:
1154
1181
  x_minpos= min(x_minpos, min(x[np.where(x>0)]))
1155
- except:
1182
+ except Exception:
1156
1183
  pass
1157
1184
  if limits == [None, None, None, None]:
1158
1185
  limits = [min(x), max(x), min(y), max(y)]
@@ -1177,14 +1204,14 @@ class PlotConfig:
1177
1204
  try:
1178
1205
  if xrange < 1.e-10:
1179
1206
  xrange = max(1.e-10, (limits[1] + limits[0] )/2.0)
1180
- except:
1207
+ except Exception:
1181
1208
  pass
1182
1209
 
1183
1210
  yrange = limits[3] - limits[2]
1184
1211
  try:
1185
1212
  if yrange < 1.e-10:
1186
1213
  yrange = max(1.e-10, (limits[3] + limits[2] )/2.0)
1187
- except:
1214
+ except Exception:
1188
1215
  pass
1189
1216
 
1190
1217
  limits[0] = limits[0] - xrange * self.viewpad /100.0
@@ -1208,11 +1235,11 @@ class PlotConfig:
1208
1235
  all_limits.append(limits)
1209
1236
  try:
1210
1237
  ax.set_xlim((limits[0], limits[1]), emit=True)
1211
- except:
1238
+ except Exception:
1212
1239
  pass
1213
1240
  try:
1214
1241
  ax.set_ylim((limits[2], limits[3]), emit=True)
1215
- except:
1242
+ except Exception:
1216
1243
  pass
1217
1244
  return all_limits
1218
1245
 
@@ -1235,11 +1262,11 @@ class PlotConfig:
1235
1262
  if i in (1, 2, 3):
1236
1263
  ys = getattr(self, f'y{i+1}scale', 'linear')
1237
1264
  axes.set_yscale(ys)
1238
- except:
1265
+ except Exception:
1239
1266
  axes.set_yscale('linear')
1240
1267
  try:
1241
1268
  axes.set_xscale(self.xscale)
1242
- except:
1269
+ except Exception:
1243
1270
  axes.set_xscale('linear')
1244
1271
  if not delay_draw:
1245
1272
  self.process_data()
@@ -1255,10 +1282,7 @@ class PlotConfig:
1255
1282
  """make keywords for axes.hist()"""
1256
1283
  kwargs = {}
1257
1284
 
1258
- # print("make hist kwargs")
1259
1285
  trace = self.get_trace(trace)
1260
- prop = self.traces[trace]
1261
- # print("L Trace ", prop)
1262
1286
 
1263
1287
  for key in ('bins', 'density', 'cumulative', 'histtype',
1264
1288
  'orientation', 'align', 'stacked', 'rwidth'):
@@ -103,6 +103,7 @@ class ImageCanvas(wx.Panel):
103
103
  self._first_image = True
104
104
  self._auto_scale = True
105
105
  self._filter_gaps = False
106
+ self._percentile_level: "float | None" = None
106
107
  self._min_value = 0.0
107
108
  self._max_value = 255.0
108
109
  self._data_min = 0.0
@@ -168,7 +169,7 @@ class ImageCanvas(wx.Panel):
168
169
  self._pixel_info_text = scene.visuals.Text(
169
170
  text="",
170
171
  color=vispy_colour("green"),
171
- font_size=6,
172
+ font_size=8,
172
173
  bold=True,
173
174
  anchor_x="left",
174
175
  anchor_y="top",
@@ -179,7 +180,7 @@ class ImageCanvas(wx.Panel):
179
180
  self._fps_text = scene.visuals.Text(
180
181
  text="",
181
182
  color=vispy_colour("green"),
182
- font_size=6,
183
+ font_size=8,
183
184
  bold=True,
184
185
  anchor_x="left",
185
186
  anchor_y="top",
@@ -226,11 +227,23 @@ class ImageCanvas(wx.Panel):
226
227
  self._image_visual.clim = (self._norm_fwd(min_val), self._norm_fwd(max_val))
227
228
  self._canvas.update()
228
229
 
229
- def set_auto_scale(self, enabled: bool, level: (None, float) = None) -> None:
230
+ def set_auto_scale(self, enabled: bool, level: "float | None" = None) -> None:
230
231
  """Enable or disable automatic contrast scaling."""
231
232
  self._auto_scale = enabled
232
233
  if enabled and self._raw_image is not None:
233
- self._min_value, self._max_value = self._compute_auto_clim(self._raw_image, level=level)
234
+ effective_level = level if level is not None else self._percentile_level
235
+ self._min_value, self._max_value = self._compute_auto_clim(self._raw_image, level=effective_level)
236
+ self._image_visual.clim = (self._norm_fwd(self._min_value), self._norm_fwd(self._max_value))
237
+ self._canvas.update()
238
+
239
+ def set_percentile_level(self, level: "float | None") -> None:
240
+ """Set a persistent contrast clip applied on every frame regardless of auto-scale (None=off)."""
241
+ self._percentile_level = level
242
+ if self._raw_image is not None:
243
+ if level is not None:
244
+ self._min_value, self._max_value = self._compute_auto_clim(self._raw_image, level=level)
245
+ elif self._auto_scale:
246
+ self._min_value, self._max_value = self._compute_auto_clim(self._raw_image)
234
247
  self._image_visual.clim = (self._norm_fwd(self._min_value), self._norm_fwd(self._max_value))
235
248
  self._canvas.update()
236
249
 
@@ -386,7 +399,9 @@ class ImageCanvas(wx.Panel):
386
399
  gpu_image = np.ascontiguousarray(gpu_image)
387
400
 
388
401
  self._data_min, self._data_max = self._compute_full_range(full_res)
389
- if self._auto_scale:
402
+ if self._percentile_level is not None:
403
+ self._min_value, self._max_value = self._compute_auto_clim(full_res, level=self._percentile_level)
404
+ elif self._auto_scale:
390
405
  self._min_value, self._max_value = self._compute_auto_clim(full_res)
391
406
 
392
407
  display_image = self._norm_apply(gpu_image)
@@ -413,7 +428,7 @@ class ImageCanvas(wx.Panel):
413
428
 
414
429
  def _compute_auto_clim(self, img: np.ndarray, level=None) -> tuple[float, float]:
415
430
  """Estimate display clim from a sampled subset of pixels.
416
- Uses percentiles when filter_gaps is on."""
431
+ level: symmetric contrast_level — clips this % from each side (e.g. 2 → [2, 98])."""
417
432
  flat = img.reshape(-1)
418
433
  step = max(1, flat.size // self._AUTO_CLIM_SAMPLE_BUDGET)
419
434
  sample = flat[::step]
@@ -432,9 +447,8 @@ class ImageCanvas(wx.Panel):
432
447
  else:
433
448
  vmin, vmax = float(sample.min()), float(sample.max())
434
449
 
435
- # alternative implementation
436
450
  if level is not None:
437
- vmin, vmax = np.percentile(img, [level, 100.0-level])
451
+ vmin, vmax = np.percentile(img, [level, 100.0 - level])
438
452
 
439
453
  # Ensure min != max to avoid histogram handle overlap
440
454
  if vmax <= vmin:
@@ -528,7 +528,7 @@ class LinePlot(wx.Panel):
528
528
  gc.StrokeLine(ml, mt + ph, ml + pw, mt + ph)
529
529
  gc.StrokeLine(ml, mt, ml, mt + ph)
530
530
 
531
- font_small = wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)
531
+ font_small = wx.Font(wx.Size(0, 10), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)
532
532
  ranges = self._data_ranges()
533
533
 
534
534
  if ranges is None:
@@ -536,7 +536,7 @@ class LinePlot(wx.Panel):
536
536
  gc.SetPen(wx.TRANSPARENT_PEN)
537
537
  gc.DrawRectangle(ml, mt, pw, ph)
538
538
  gc.SetFont(
539
- wx.Font(13, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD),
539
+ wx.Font(wx.Size(0, 13), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD),
540
540
  empty_text,
541
541
  )
542
542
  msg = "No data"
@@ -586,7 +586,7 @@ class LinePlot(wx.Panel):
586
586
  gc.PopState()
587
587
 
588
588
  if self._hover_data_x is not None and self._hover_data_y is not None:
589
- hover_font = wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)
589
+ hover_font = wx.Font(wx.Size(0, 8), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)
590
590
  gc.SetFont(hover_font, get_theme().green)
591
591
  text = self.format_hover_info(self._hover_data_x, self._hover_data_y)
592
592
  tw, th = gc.GetTextExtent(text)
@@ -3,14 +3,12 @@
3
3
  # wxmplott GUI to Configure Line Plots
4
4
 
5
5
  from functools import partial
6
- import yaml
7
6
  import numpy as np
8
7
  import wx
9
8
  import wx.lib.colourselect as csel
10
9
  import wx.lib.scrolledpanel as scrolled
11
10
 
12
- from wxutils import (flatnotebook, get_color, set_color,
13
- SimpleText, TextCtrl)
11
+ from wxutils import (flatnotebook, get_color)
14
12
 
15
13
  from .utils import LabeledTextCtrl, MenuItem, Choice, FloatSpin
16
14
  from .config import PlotConfig
@@ -29,39 +27,10 @@ def ffmt(val):
29
27
  if val is not None:
30
28
  try:
31
29
  return "%.5g" % val
32
- except:
30
+ except Exception:
33
31
  pass
34
32
  return repr(val)
35
33
 
36
- def clean_texmath(txt):
37
- """
38
- clean tex math string, preserving control sequences
39
- (incluing \n, so also '\nu') inside $ $, while allowing
40
- \n and \t to be meaningful in the text string
41
- """
42
- s = "%s " % txt
43
- out = []
44
- i = 0
45
- while i < len(s)-1:
46
- if s[i] == '\\' and s[i+1] in ('n', 't'):
47
- if s[i+1] == 'n':
48
- out.append('\n')
49
- elif s[i+1] == 't':
50
- out.append('\t')
51
- i += 1
52
- elif s[i] == '$':
53
- j = s[i+1:].find('$')
54
- if j < 0:
55
- j = len(s)
56
- out.append(s[i:j+2])
57
- i += j+2
58
- else:
59
- out.append(s[i])
60
- i += 1
61
- if i > 5000:
62
- break
63
- return ''.join(out).strip()
64
-
65
34
  ############################################################
66
35
  # monkey-patch of ColourSelect text setting
67
36
  # yes, a PR has been submitted to wx, no it is not merged or released.
@@ -245,13 +214,13 @@ class PlotConfigFrame(wx.Frame):
245
214
  raxes = axes[1]
246
215
  try:
247
216
  user_lims = self.conf.user_limits[laxes]
248
- except:
217
+ except Exception:
249
218
  user_lims = 4*[None]
250
219
  auto_b = wx.CheckBox(panel,-1, ' From Data ', (-1, -1), (-1, -1))
251
220
  auto_b.Bind(wx.EVT_CHECKBOX,self.onAutoBounds)
252
221
  try:
253
222
  auto_b.SetValue(self.conf.user_limits[laxes] == 4*[None])
254
- except:
223
+ except Exception:
255
224
  pass
256
225
 
257
226
  self.vpad_val = FloatSpin(panel, value=2.5, min_val=0, max_val=100,
@@ -962,7 +931,7 @@ class PlotConfigFrame(wx.Frame):
962
931
  return None
963
932
  try:
964
933
  return float(v)
965
- except:
934
+ except Exception:
966
935
  return None
967
936
 
968
937
  axes = self.canvas.figure.get_axes()
@@ -1096,7 +1065,7 @@ class PlotConfigFrame(wx.Frame):
1096
1065
  self.conf.relabel(**kws)
1097
1066
  wid.SetBackgroundColour(get_color('text_bg'))
1098
1067
  wid.SetForegroundColour(get_color('text'))
1099
- except: # as from latex error
1068
+ except Exception: # as from latex error
1100
1069
  print("invalid text for item ", item, s)
1101
1070
 
1102
1071
  wid.SetBackgroundColour(get_color('text_invalid_bg'))
@@ -1104,7 +1073,7 @@ class PlotConfigFrame(wx.Frame):
1104
1073
  elif item == 'trace':
1105
1074
  try:
1106
1075
  self.conf.set_trace_label(s, trace=trace)
1107
- except:
1076
+ except Exception:
1108
1077
  pass
1109
1078
 
1110
1079
  def onShowGrid(self,event):
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '2026.2.1'
22
- __version_tuple__ = version_tuple = (2026, 2, 1)
21
+ __version__ = version = '2026.2.3'
22
+ __version_tuple__ = version_tuple = (2026, 2, 3)
23
23
 
24
- __commit_id__ = commit_id = 'g1950bafd1'
24
+ __commit_id__ = commit_id = 'g514ae8af4'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wxmplot
3
- Version: 2026.2.1
3
+ Version: 2026.2.3
4
4
  Summary: wxPython plotting widgets using matplotlib
5
5
  Author-email: Matthew Newville <matt.newville@gmail.com>
6
6
  License-Expression: MIT
@@ -22,7 +22,7 @@ Classifier: Programming Language :: Python :: 3.11
22
22
  Classifier: Programming Language :: Python :: 3.12
23
23
  Classifier: Programming Language :: Python :: 3.13
24
24
  Classifier: Programming Language :: Python :: 3.14
25
- Requires-Python: >=3.10
25
+ Requires-Python: >=3.11
26
26
  Description-Content-Type: text/markdown
27
27
  License-File: LICENSE
28
28
  Requires-Dist: wxPython>=4.2.3
@@ -46,6 +46,9 @@ Requires-Dist: Sphinx; extra == "doc"
46
46
  Requires-Dist: jupyter_sphinx; extra == "doc"
47
47
  Requires-Dist: sphinx-copybutton; extra == "doc"
48
48
  Requires-Dist: sphinxcontrib-video; extra == "doc"
49
+ Requires-Dist: nbsphinx; extra == "doc"
50
+ Requires-Dist: sphinx-design; extra == "doc"
51
+ Requires-Dist: sphinx-breeze-theme; extra == "doc"
49
52
  Provides-Extra: test
50
53
  Requires-Dist: pytest; extra == "test"
51
54
  Requires-Dist: pytest-cov; extra == "test"
@@ -20,6 +20,7 @@ examples/floatcontrol.py
20
20
  examples/histogram.py
21
21
  examples/image.py
22
22
  examples/image_canvas_ex.py
23
+ examples/image_canvas_scroll.py
23
24
  examples/image_scroll.py
24
25
  examples/imagematrix.py
25
26
  examples/interactive_multiplewindows.py
@@ -26,6 +26,9 @@ Sphinx
26
26
  jupyter_sphinx
27
27
  sphinx-copybutton
28
28
  sphinxcontrib-video
29
+ nbsphinx
30
+ sphinx-design
31
+ sphinx-breeze-theme
29
32
 
30
33
  [test]
31
34
  pytest
@@ -1,149 +1,150 @@
1
1
  {
2
2
  "files": [
3
- "LICENSE",
4
- "ChangeLog",
5
- "pyproject.toml",
6
- "MANIFEST.in",
7
- "README.md",
8
- "setup.py",
9
- ".gitignore",
10
3
  ".gitattributes",
11
- "tests/basic_test.py",
12
- "wxmplot/config.py",
13
- "wxmplot/baseframe.py",
14
- "wxmplot/vispy_utils.py",
15
- "wxmplot/histogram.py",
16
- "wxmplot/multiframe.py",
17
- "wxmplot/basepanel.py",
18
- "wxmplot/imagematrixframe.py",
19
- "wxmplot/residualplotframe.py",
20
- "wxmplot/plotapp.py",
21
- "wxmplot/__init__.py",
22
- "wxmplot/stackedplotframe.py",
23
- "wxmplot/allow_idle_macosx.py",
24
- "wxmplot/utils.py",
25
- "wxmplot/imageframe.py",
26
- "wxmplot/plotpanel.py",
27
- "wxmplot/interactive.py",
28
- "wxmplot/inputhook.py",
29
- "wxmplot/image_canvas.py",
30
- "wxmplot/plotframe.py",
31
- "wxmplot/imageconf.py",
32
- "wxmplot/line_plot.py",
33
- "wxmplot/imagepanel.py",
34
- "wxmplot/plotconfigframe.py",
35
- "wxmplot/colors.py",
36
- "examples/stackedplot.py",
37
- "examples/scope_mode_generator.py",
38
- "examples/time_update.py",
39
- "examples/extra_marker_and_line_reporting.py",
40
- "examples/time.dat",
41
- "examples/scope_mode_mpl_compare.py",
42
- "examples/rgb_image.py",
43
- "examples/scatterplot.py",
44
- "examples/pilatus_display.py",
45
- "examples/image_canvas_ex.py",
46
- "examples/tifffile.py",
47
- "examples/histogram.py",
48
- "examples/leftright.py",
49
- "examples/wxmplot_jupyter.ipynb",
50
- "examples/BasicExamples.ipynb",
51
- "examples/DynamicExamples.ipynb",
52
- "examples/plotapp.py",
53
- "examples/scope_mode_function.py",
54
- "examples/discrete_data.py",
55
- "examples/basic_screenshot.py",
56
- "examples/image_scroll.py",
57
- "examples/compare_dislin_mpl.py",
58
- "examples/Pilatus.tiff",
59
- "examples/timedata.py",
60
- "examples/fill_uncertainties.py",
61
- "examples/ceo2.tiff",
62
- "examples/plot_many_traces.py",
63
- "examples/floatcontrol.py",
64
- "examples/multiple_yaxes.py",
65
- "examples/xafs.dat",
66
- "examples/interactive_multiplewindows.py",
67
- "examples/stripchart.py",
68
- "examples/tiff_display.py",
69
- "examples/fill_to_zero.py",
70
- "examples/theme_compare.py",
71
- "examples/demo.py",
72
- "examples/compare_plplot.py",
73
- "examples/simple.py",
74
- "examples/errorbar.py",
75
- "examples/contour.py",
76
- "examples/imagematrix.py",
77
- "examples/image.py",
78
- "examples/multiplot.py",
79
- "examples/plot_fromdatafile.py",
80
4
  ".github/dependabot.yml",
81
5
  ".github/workflows/test_wxmplot_install.yml",
82
- "doc/index.rst",
6
+ ".gitignore",
7
+ "ChangeLog",
8
+ "LICENSE",
9
+ "MANIFEST.in",
10
+ "README.md",
83
11
  "doc/Makefile",
12
+ "doc/_static/empty",
13
+ "doc/_static/scope_mode_function.mp4",
14
+ "doc/_static/scope_mode_generator.mp4",
15
+ "doc/_static/scope_mode_mpl_compare.mp4",
16
+ "doc/_templates/indexsidebar.html",
84
17
  "doc/comparisons.rst",
85
18
  "doc/conf.py",
86
19
  "doc/examples.rst",
87
20
  "doc/imagepanel.rst",
88
- "doc/overview.rst",
89
- "doc/interactive.rst",
90
- "doc/installation.rst",
91
- "doc/other.rst",
92
- "doc/plotpanel.rst",
93
- "doc/images/plot_compare_wxplot_wx.png",
94
- "doc/images/imagedisplay.png",
95
- "doc/images/wxmplot_dislin.png",
96
- "doc/images/contour_wxmplot.png",
97
- "doc/images/plot_alphafill_config.png",
98
- "doc/images/plot_compare_plotly.png",
21
+ "doc/images/ImageConfig.png",
99
22
  "doc/images/PlotConfig_LineProps.png",
100
23
  "doc/images/PlotConfig_LinePropsAlphaFill.png",
24
+ "doc/images/PlotConfig_Ranges.png",
25
+ "doc/images/PlotConfig_Scatter.png",
101
26
  "doc/images/PlotConfig_Text.png",
102
- "doc/images/multiplot.png",
103
- "doc/images/wxmplot_leftright.png",
104
- "doc/images/discrete_data.png",
105
- "doc/images/imshow_wxmplot.png",
27
+ "doc/images/basic_screenshot.png",
106
28
  "doc/images/contour.png",
107
- "doc/images/plot_compare_dislin.png",
108
- "doc/images/imshow_no_contrast.png",
109
- "doc/images/imshow_scalebar.png",
110
- "doc/images/two_axes.png",
111
- "doc/images/image_3color_white.png",
112
- "doc/images/PlotConfig_Scatter.png",
113
- "doc/images/plot_alphafill_to_dy.png",
114
- "doc/images/plot_alphafill_to_zero.png",
29
+ "doc/images/contour_wxmplot.png",
30
+ "doc/images/datafile_plot.png",
31
+ "doc/images/discrete_data.png",
115
32
  "doc/images/errorbar.png",
116
33
  "doc/images/histogram.png",
117
- "doc/images/plot_compare_qttutorial1_qt.png",
34
+ "doc/images/image_3color.png",
35
+ "doc/images/image_3color_white.png",
36
+ "doc/images/imagedisplay.png",
37
+ "doc/images/imagematrix.png",
38
+ "doc/images/imshow_high_contrast.png",
39
+ "doc/images/imshow_low_contrast.png",
118
40
  "doc/images/imshow_mpl.png",
41
+ "doc/images/imshow_no_contrast.png",
42
+ "doc/images/imshow_scalebar.png",
43
+ "doc/images/imshow_wxmplot.png",
44
+ "doc/images/interactive1.png",
45
+ "doc/images/interactive2.png",
119
46
  "doc/images/multiple_yaxes.png",
120
- "doc/images/wxmplot_composite.png",
47
+ "doc/images/multiplot.png",
48
+ "doc/images/plot_alphafill_config.png",
49
+ "doc/images/plot_alphafill_to_dy.png",
50
+ "doc/images/plot_alphafill_to_zero.png",
51
+ "doc/images/plot_compare_dislin.png",
52
+ "doc/images/plot_compare_plotly.png",
121
53
  "doc/images/plot_compare_plplot.png",
54
+ "doc/images/plot_compare_qt.png",
122
55
  "doc/images/plot_compare_qttutorial1.png",
56
+ "doc/images/plot_compare_qttutorial1_qt.png",
57
+ "doc/images/plot_compare_wxplot_wx.png",
58
+ "doc/images/plot_compare_wxplot_wxmplot.png",
123
59
  "doc/images/plot_mpl.png",
124
- "doc/images/scatterplot.png",
125
- "doc/images/PlotConfig_Ranges.png",
126
60
  "doc/images/plot_wxmplot.png",
127
- "doc/images/plot_compare_wxplot_wxmplot.png",
128
- "doc/images/imagematrix.png",
129
- "doc/images/plot_compare_qt.png",
130
- "doc/images/wxmplot_histogram.png",
61
+ "doc/images/scatterplot.png",
131
62
  "doc/images/stackedplot.png",
132
- "doc/images/ImageConfig.png",
133
63
  "doc/images/tiff_display.png",
134
- "doc/images/imshow_low_contrast.png",
135
64
  "doc/images/tifffile_image.png",
65
+ "doc/images/two_axes.png",
66
+ "doc/images/wxmplot_composite.png",
67
+ "doc/images/wxmplot_dislin.png",
68
+ "doc/images/wxmplot_histogram.png",
69
+ "doc/images/wxmplot_leftright.png",
136
70
  "doc/images/wxmplot_plplot.png",
137
- "doc/images/interactive1.png",
138
- "doc/images/image_3color.png",
139
- "doc/images/datafile_plot.png",
140
- "doc/images/basic_screenshot.png",
141
- "doc/images/interactive2.png",
142
- "doc/images/imshow_high_contrast.png",
143
- "doc/_templates/indexsidebar.html",
144
- "doc/_static/scope_mode_function.mp4",
145
- "doc/_static/empty",
146
- "doc/_static/scope_mode_generator.mp4",
147
- "doc/_static/scope_mode_mpl_compare.mp4"
71
+ "doc/index.rst",
72
+ "doc/installation.rst",
73
+ "doc/interactive.rst",
74
+ "doc/other.rst",
75
+ "doc/overview.rst",
76
+ "doc/plotpanel.rst",
77
+ "examples/BasicExamples.ipynb",
78
+ "examples/DynamicExamples.ipynb",
79
+ "examples/Pilatus.tiff",
80
+ "examples/basic_screenshot.py",
81
+ "examples/ceo2.tiff",
82
+ "examples/compare_dislin_mpl.py",
83
+ "examples/compare_plplot.py",
84
+ "examples/contour.py",
85
+ "examples/demo.py",
86
+ "examples/discrete_data.py",
87
+ "examples/errorbar.py",
88
+ "examples/extra_marker_and_line_reporting.py",
89
+ "examples/fill_to_zero.py",
90
+ "examples/fill_uncertainties.py",
91
+ "examples/floatcontrol.py",
92
+ "examples/histogram.py",
93
+ "examples/image.py",
94
+ "examples/image_canvas_ex.py",
95
+ "examples/image_canvas_scroll.py",
96
+ "examples/image_scroll.py",
97
+ "examples/imagematrix.py",
98
+ "examples/interactive_multiplewindows.py",
99
+ "examples/leftright.py",
100
+ "examples/multiple_yaxes.py",
101
+ "examples/multiplot.py",
102
+ "examples/pilatus_display.py",
103
+ "examples/plot_fromdatafile.py",
104
+ "examples/plot_many_traces.py",
105
+ "examples/plotapp.py",
106
+ "examples/rgb_image.py",
107
+ "examples/scatterplot.py",
108
+ "examples/scope_mode_function.py",
109
+ "examples/scope_mode_generator.py",
110
+ "examples/scope_mode_mpl_compare.py",
111
+ "examples/simple.py",
112
+ "examples/stackedplot.py",
113
+ "examples/stripchart.py",
114
+ "examples/theme_compare.py",
115
+ "examples/tiff_display.py",
116
+ "examples/tifffile.py",
117
+ "examples/time.dat",
118
+ "examples/time_update.py",
119
+ "examples/timedata.py",
120
+ "examples/wxmplot_jupyter.ipynb",
121
+ "examples/xafs.dat",
122
+ "pyproject.toml",
123
+ "setup.py",
124
+ "tests/basic_test.py",
125
+ "wxmplot/__init__.py",
126
+ "wxmplot/allow_idle_macosx.py",
127
+ "wxmplot/baseframe.py",
128
+ "wxmplot/basepanel.py",
129
+ "wxmplot/colors.py",
130
+ "wxmplot/config.py",
131
+ "wxmplot/histogram.py",
132
+ "wxmplot/image_canvas.py",
133
+ "wxmplot/imageconf.py",
134
+ "wxmplot/imageframe.py",
135
+ "wxmplot/imagematrixframe.py",
136
+ "wxmplot/imagepanel.py",
137
+ "wxmplot/inputhook.py",
138
+ "wxmplot/interactive.py",
139
+ "wxmplot/line_plot.py",
140
+ "wxmplot/multiframe.py",
141
+ "wxmplot/plotapp.py",
142
+ "wxmplot/plotconfigframe.py",
143
+ "wxmplot/plotframe.py",
144
+ "wxmplot/plotpanel.py",
145
+ "wxmplot/residualplotframe.py",
146
+ "wxmplot/stackedplotframe.py",
147
+ "wxmplot/utils.py",
148
+ "wxmplot/vispy_utils.py"
148
149
  ]
149
150
  }
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "2026.2.3",
3
+ "distance": 0,
4
+ "node": "g514ae8af45f85a5f69edaea0db68f16f66ead976",
5
+ "dirty": false,
6
+ "branch": "master",
7
+ "node_date": "2026-09-01"
8
+ }
@@ -1,6 +0,0 @@
1
- #!/usr/bin/python
2
- import numpy as np
3
- import wxmplot.interactive as wi
4
-
5
- x = np.linspace(0.0, 20.0, 201)
6
- wi.plot(x, np.sin(x)/(x+1), ylabel='response', xlabel='T (sec)')
@@ -1,8 +0,0 @@
1
- {
2
- "tag": "2026.2.1",
3
- "distance": 0,
4
- "node": "g1950bafd1c567ad5c5c6dbcf1d73184feb37b505",
5
- "dirty": false,
6
- "branch": "master",
7
- "node_date": "2026-07-30"
8
- }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes