mwxlib 1.6.10__py3-none-any.whl → 1.7.0__py3-none-any.whl

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.

Potentially problematic release.


This version of mwxlib might be problematic. Click here for more details.

mwx/graphman.py CHANGED
@@ -72,7 +72,7 @@ class Thread:
72
72
  if self.worker:
73
73
  return self.worker.is_alive()
74
74
  return False
75
-
75
+
76
76
  def __init__(self, owner=None):
77
77
  self.owner = owner
78
78
  self.worker = None
@@ -90,11 +90,11 @@ class Thread:
90
90
  'thread_end' : [ None ],
91
91
  },
92
92
  })
93
-
93
+
94
94
  def __del__(self):
95
95
  if self.active:
96
96
  self.Stop()
97
-
97
+
98
98
  @contextmanager
99
99
  def entry(self):
100
100
  """Exclusive reentrant lock manager.
@@ -110,26 +110,26 @@ class Thread:
110
110
  ## The thread must be activated to enter.
111
111
  ## assert self.active, f"{self!r} must be activated to enter {name!r}."
112
112
  yield self
113
-
113
+
114
114
  def enters(self, f):
115
115
  """Decorator to add a one-time handler for the enter event.
116
116
  The specified function will be called from the main thread.
117
117
  """
118
118
  return self.handler.binds('thread_begin', _F(f))
119
-
119
+
120
120
  def exits(self, f):
121
121
  """Decorator to add a one-time handler for the exit event.
122
122
  The specified function will be called from the main thread.
123
123
  """
124
124
  return self.handler.binds('thread_end', _F(f))
125
-
125
+
126
126
  def wraps(self, f, *args, **kwargs):
127
127
  """Decorator for a function that starts a new thread."""
128
128
  @wraps(f)
129
129
  def _f(*v, **kw):
130
130
  return self.Start(f, *v, *args, **kw, **kwargs)
131
131
  return _f
132
-
132
+
133
133
  def check(self, timeout=None):
134
134
  """Check the thread event flags."""
135
135
  if not self.running:
@@ -139,7 +139,7 @@ class Thread:
139
139
  if not self.active:
140
140
  raise KeyboardInterrupt("terminated by user")
141
141
  return True
142
-
142
+
143
143
  def pause(self, msg=None, caption=wx.MessageBoxCaptionStr):
144
144
  """Pause the thread.
145
145
  Confirm whether to terminate the thread.
@@ -168,7 +168,7 @@ class Thread:
168
168
  return False
169
169
  finally:
170
170
  self.event.set() # resume
171
-
171
+
172
172
  def Start(self, f, *args, **kwargs):
173
173
  """Start the thread to run the specified function.
174
174
  """
@@ -205,7 +205,7 @@ class Thread:
205
205
  args=args, kwargs=kwargs, daemon=True)
206
206
  self.worker.start()
207
207
  self.event.set()
208
-
208
+
209
209
  def Stop(self):
210
210
  """Stop the thread.
211
211
 
@@ -248,31 +248,31 @@ class LayerInterface(CtrlInterface):
248
248
  dockable = True
249
249
  reloadable = True
250
250
  unloadable = True
251
-
251
+
252
252
  graph = property(lambda self: self.parent.graph)
253
253
  output = property(lambda self: self.parent.output)
254
254
  histogram = property(lambda self: self.parent.histogram)
255
255
  selected_view = property(lambda self: self.parent.selected_view)
256
-
256
+
257
257
  message = property(lambda self: self.parent.message)
258
-
258
+
259
259
  ## thread_type = Thread
260
260
  thread = None
261
-
261
+
262
262
  ## layout helper function (internal use only)
263
263
  pack = mwx.pack
264
-
264
+
265
265
  ## funcall = interactive_call (internal use only)
266
266
  funcall = staticmethod(_F)
267
-
267
+
268
268
  ## for debug (internal use only)
269
269
  pane = property(lambda self: self.parent.get_pane(self))
270
-
270
+
271
271
  @property
272
272
  def Arts(self):
273
273
  """List of arts <matplotlib.artist.Artist>."""
274
274
  return self.__artists
275
-
275
+
276
276
  @Arts.setter
277
277
  def Arts(self, arts):
278
278
  for art in self.__artists[:]:
@@ -280,13 +280,13 @@ class LayerInterface(CtrlInterface):
280
280
  art.remove()
281
281
  self.__artists.remove(art)
282
282
  self.__artists = arts
283
-
283
+
284
284
  @Arts.deleter
285
285
  def Arts(self):
286
286
  for art in self.__artists:
287
287
  art.remove()
288
288
  self.__artists = []
289
-
289
+
290
290
  def attach_artists(self, axes, *artists):
291
291
  """Attach artists (e.g., patches) to the given axes."""
292
292
  for art in artists:
@@ -296,7 +296,7 @@ class LayerInterface(CtrlInterface):
296
296
  axes.add_artist(art)
297
297
  if art not in self.__artists:
298
298
  self.__artists.append(art)
299
-
299
+
300
300
  def detach_artists(self, *artists):
301
301
  """Detach artists (e.g., patches) from their axes."""
302
302
  for art in artists:
@@ -304,7 +304,7 @@ class LayerInterface(CtrlInterface):
304
304
  art.remove()
305
305
  art._transformSet = False
306
306
  self.__artists.remove(art)
307
-
307
+
308
308
  def __init__(self, parent, session=None):
309
309
  if hasattr(self, 'handler'):
310
310
  warn(f"Duplicate iniheritance of CtrlInterface by {self}.")
@@ -398,21 +398,21 @@ class LayerInterface(CtrlInterface):
398
398
  self.load_session(session)
399
399
  except Exception:
400
400
  traceback.print_exc() # Failed to load the plug session.
401
-
401
+
402
402
  def Init(self):
403
403
  """Initialize layout before load_session (to be overridden)."""
404
404
  pass
405
-
405
+
406
406
  def load_session(self, session):
407
407
  """Restore settings from a session file (to be overridden)."""
408
408
  if 'params' in session:
409
409
  self.parameters = session['params']
410
-
410
+
411
411
  def save_session(self, session):
412
412
  """Save settings in a session file (to be overridden)."""
413
413
  if self.parameters:
414
414
  session['params'] = self.parameters
415
-
415
+
416
416
  def OnDestroy(self, evt):
417
417
  if evt.EventObject is self:
418
418
  if self.thread and self.thread.active:
@@ -420,7 +420,7 @@ class LayerInterface(CtrlInterface):
420
420
  self.thread.Stop()
421
421
  del self.Arts
422
422
  evt.Skip()
423
-
423
+
424
424
  def OnShow(self, evt):
425
425
  if not self:
426
426
  return
@@ -430,11 +430,11 @@ class LayerInterface(CtrlInterface):
430
430
  else:
431
431
  self.handler('page_hidden', self)
432
432
  evt.Skip()
433
-
433
+
434
434
  Shown = property(
435
435
  lambda self: self.IsShown(),
436
436
  lambda self, v: self.Show(v))
437
-
437
+
438
438
  def IsShown(self):
439
439
  """Return True if the window is physically visible on the screen.
440
440
 
@@ -443,7 +443,7 @@ class LayerInterface(CtrlInterface):
443
443
  """
444
444
  ## return self.pane.IsShown()
445
445
  return self.IsShownOnScreen()
446
-
446
+
447
447
  def Show(self, show=True, interactive=False):
448
448
  """Shows or hides the window.
449
449
 
@@ -451,14 +451,14 @@ class LayerInterface(CtrlInterface):
451
451
  Note: This might be called from a thread.
452
452
  """
453
453
  wx.CallAfter(self.parent.show_pane, self, show, interactive) # Use main thread.
454
-
454
+
455
455
  Drawn = property(
456
456
  lambda self: self.IsDrawn(),
457
457
  lambda self, v: self.Draw(v))
458
-
458
+
459
459
  def IsDrawn(self):
460
460
  return any(art.get_visible() for art in self.Arts)
461
-
461
+
462
462
  def Draw(self, show=None):
463
463
  """Draw artists.
464
464
  If show is None:default, draw only when the pane is visible.
@@ -493,14 +493,14 @@ def _register__dummy_plug__(cls, module):
493
493
  ## warn(f"Duplicate iniheritance of LayerInterface by {cls}.")
494
494
  module.Plugin = cls
495
495
  return cls
496
-
496
+
497
497
  class _Plugin(cls, LayerInterface):
498
498
  def __init__(self, parent, session=None, **kwargs):
499
499
  cls.__init__(self, parent, **kwargs)
500
500
  LayerInterface.__init__(self, parent, session)
501
501
  Show = LayerInterface.Show
502
502
  IsShown = LayerInterface.IsShown
503
-
503
+
504
504
  _Plugin.__module__ = module.__name__
505
505
  _Plugin.__qualname__ = cls.__qualname__ + "~"
506
506
  _Plugin.__name__ = cls.__name__ + "~"
@@ -534,24 +534,24 @@ class Graph(GraphPlot):
534
534
  })
535
535
  ## ドロップターゲットを許可する
536
536
  self.SetDropTarget(MyFileDropLoader(self, self.loader))
537
-
537
+
538
538
  def refresh(self):
539
539
  if self.frame:
540
540
  self.frame.update_buffer()
541
541
  self.draw()
542
-
542
+
543
543
  def toggle_infobar(self):
544
544
  """Toggle infobar (frame.annotation)."""
545
545
  if self.infobar.IsShown():
546
546
  self.infobar.Dismiss()
547
547
  elif self.frame:
548
548
  self.infobar.ShowMessage(self.frame.annotation)
549
-
549
+
550
550
  def update_infobar(self, frame):
551
551
  """Show infobar (frame.annotation)."""
552
552
  if self.infobar.IsShown():
553
553
  self.infobar.ShowMessage(frame.annotation)
554
-
554
+
555
555
  def hide_layers(self):
556
556
  for plug in self.parent.get_all_plugs():
557
557
  for art in plug.Arts:
@@ -574,7 +574,7 @@ class MyFileDropLoader(wx.FileDropTarget):
574
574
 
575
575
  self.view = target
576
576
  self.loader = loader
577
-
577
+
578
578
  def OnDropFiles(self, x, y, filenames):
579
579
  pos = self.view.ScreenPosition + (x, y)
580
580
  paths = []
@@ -607,24 +607,24 @@ class Frame(mwx.Frame):
607
607
  graph = property(lambda self: self.__graph)
608
608
  output = property(lambda self: self.__output)
609
609
  histogram = property(lambda self: self.__histgrm)
610
-
610
+
611
611
  selected_view = property(lambda self: self.__view)
612
-
612
+
613
613
  def select_view(self, view):
614
614
  self.__view = view
615
615
  self.set_title(view.frame)
616
-
616
+
617
617
  @property
618
618
  def graphic_windows(self):
619
619
  """Graphic windows list.
620
620
  [0] graph [1] output [2:] others(user-defined)
621
621
  """
622
622
  return self.__graphic_windows
623
-
623
+
624
624
  @property
625
625
  def graphic_windows_on_screen(self):
626
626
  return [w for w in self.__graphic_windows if w.IsShownOnScreen()]
627
-
627
+
628
628
  def __init__(self, *args, **kwargs):
629
629
  mwx.Frame.__init__(self, *args, **kwargs)
630
630
 
@@ -823,9 +823,9 @@ class Frame(mwx.Frame):
823
823
 
824
824
  ## Accepts DnD
825
825
  self.SetDropTarget(MyFileDropLoader(self.graph, self))
826
-
826
+
827
827
  SYNC_SWITCH = True
828
-
828
+
829
829
  def sync(self, a, b):
830
830
  """Synchronize b to a."""
831
831
  if (self.SYNC_SWITCH
@@ -836,17 +836,17 @@ class Frame(mwx.Frame):
836
836
  b.ylim = a.ylim
837
837
  b.OnDraw(None)
838
838
  b.canvas.draw_idle()
839
-
839
+
840
840
  def set_title(self, frame):
841
841
  ssn = os.path.basename(self.session_file or '--')
842
842
  ssn, _ = os.path.splitext(ssn)
843
843
  name = (frame.pathname or frame.name) if frame else ''
844
844
  self.SetTitle("{}@{} - [{}] {}".format(self.Name, platform.node(), ssn, name))
845
-
845
+
846
846
  def OnActivate(self, evt): #<wx._core.ActivateEvent>
847
847
  if self and evt.Active:
848
848
  self.set_title(self.selected_view.frame)
849
-
849
+
850
850
  def OnClose(self, evt): #<wx._core.CloseEvent>
851
851
  ssn = os.path.basename(self.session_file or '--')
852
852
  with wx.MessageDialog(None,
@@ -881,15 +881,15 @@ class Frame(mwx.Frame):
881
881
  evt.Veto()
882
882
  return
883
883
  evt.Skip()
884
-
884
+
885
885
  def Destroy(self):
886
886
  self._mgr.UnInit()
887
887
  return mwx.Frame.Destroy(self)
888
-
888
+
889
889
  ## --------------------------------
890
890
  ## pane window interface
891
891
  ## --------------------------------
892
-
892
+
893
893
  def get_pane(self, name):
894
894
  """Get named pane or notebook pane.
895
895
 
@@ -901,7 +901,7 @@ class Frame(mwx.Frame):
901
901
  name = plug.category or plug
902
902
  if name:
903
903
  return self._mgr.GetPane(name)
904
-
904
+
905
905
  def show_pane(self, name, show=True, interactive=False):
906
906
  """Show named pane or notebook pane.
907
907
 
@@ -969,7 +969,7 @@ class Frame(mwx.Frame):
969
969
  pane.Show(show)
970
970
  self._mgr.Update()
971
971
  return (show != shown)
972
-
972
+
973
973
  def update_pane(self, name, **props):
974
974
  """Update the layout of the pane (internal use only).
975
975
 
@@ -996,7 +996,7 @@ class Frame(mwx.Frame):
996
996
  pane.Dock()
997
997
  else:
998
998
  pane.Float()
999
-
999
+
1000
1000
  def OnPaneClose(self, evt): #<wx.aui.AuiManagerEvent>
1001
1001
  pane = evt.GetPane()
1002
1002
  win = pane.window
@@ -1006,19 +1006,19 @@ class Frame(mwx.Frame):
1006
1006
  else:
1007
1007
  win.handler('page_closed', win)
1008
1008
  evt.Skip(False) # Don't skip to avoid being called twice.
1009
-
1009
+
1010
1010
  ## --------------------------------
1011
1011
  ## Plugin <Layer> interface
1012
1012
  ## --------------------------------
1013
1013
  plugins = property(lambda self: self.__plugins)
1014
-
1014
+
1015
1015
  def register(self, cls=None, **kwargs):
1016
1016
  """Decorator of plugin class register."""
1017
1017
  if cls is None:
1018
1018
  return lambda f: self.register(f, **kwargs)
1019
1019
  self.load_plug(cls, force=1, show=1, **kwargs)
1020
1020
  return cls
1021
-
1021
+
1022
1022
  def require(self, name):
1023
1023
  """Get named plug window.
1024
1024
  If not found, try to load it once.
@@ -1032,7 +1032,7 @@ class Frame(mwx.Frame):
1032
1032
  if self.load_plug(name) is not False:
1033
1033
  return self.get_plug(name)
1034
1034
  return plug
1035
-
1035
+
1036
1036
  def get_plug(self, name):
1037
1037
  """Get named plug window."""
1038
1038
  if isinstance(name, str):
@@ -1043,11 +1043,11 @@ class Frame(mwx.Frame):
1043
1043
  elif isinstance(name, LayerInterface):
1044
1044
  ## return name
1045
1045
  return next((x for x in self.get_all_plugs() if x is name), None)
1046
-
1046
+
1047
1047
  def get_all_plugs(self):
1048
1048
  for name, module in self.plugins.items():
1049
1049
  yield module.__plug__
1050
-
1050
+
1051
1051
  def load_plug(self, root, session=None, force=False, show=False,
1052
1052
  dock=0, floating_pos=None, floating_size=None,
1053
1053
  **kwargs):
@@ -1253,7 +1253,7 @@ class Frame(mwx.Frame):
1253
1253
 
1254
1254
  self.handler('plug_loaded', plug)
1255
1255
  return None
1256
-
1256
+
1257
1257
  def unload_plug(self, name):
1258
1258
  """Unload plugin and detach the pane from UI manager."""
1259
1259
  plug = self.get_plug(name)
@@ -1287,7 +1287,7 @@ class Frame(mwx.Frame):
1287
1287
  self._mgr.DetachPane(nb) # detach notebook pane
1288
1288
  self._mgr.Update()
1289
1289
  nb.Destroy()
1290
-
1290
+
1291
1291
  def reload_plug(self, name):
1292
1292
  """Reload plugin."""
1293
1293
  plug = self.get_plug(name)
@@ -1308,7 +1308,7 @@ class Frame(mwx.Frame):
1308
1308
  for shell in self.shellframe.get_all_shells():
1309
1309
  if shell.target is plug:
1310
1310
  shell.handler('shell_activated', shell)
1311
-
1311
+
1312
1312
  def inspect_plug(self, name):
1313
1313
  """Dive into the process to inspect plugs in the shell."""
1314
1314
  plug = self.get_plug(name)
@@ -1331,7 +1331,7 @@ class Frame(mwx.Frame):
1331
1331
  self.shellframe.Show()
1332
1332
  if wx.GetKeyState(wx.WXK_SHIFT): # open the source code.
1333
1333
  self.shellframe.load(plug)
1334
-
1334
+
1335
1335
  def OnLoadPlugins(self, evt):
1336
1336
  with wx.FileDialog(self, "Load a plugin file",
1337
1337
  wildcard="Python file (*.py)|*.py",
@@ -1340,7 +1340,7 @@ class Frame(mwx.Frame):
1340
1340
  if dlg.ShowModal() == wx.ID_OK:
1341
1341
  for path in dlg.Paths:
1342
1342
  self.load_plug(path)
1343
-
1343
+
1344
1344
  def Quit(self, evt=None):
1345
1345
  """Stop all Layer threads."""
1346
1346
  for plug in self.get_all_plugs():
@@ -1348,12 +1348,12 @@ class Frame(mwx.Frame):
1348
1348
  if thread and thread.active:
1349
1349
  ## thread.active = 0
1350
1350
  thread.Stop()
1351
-
1351
+
1352
1352
  ## --------------------------------
1353
1353
  ## load/save index file
1354
1354
  ## --------------------------------
1355
1355
  ATTRIBUTESFILE = "results.index"
1356
-
1356
+
1357
1357
  def load_index(self, filename=None, view=None):
1358
1358
  """Load frames :ref to the Index file.
1359
1359
 
@@ -1389,7 +1389,7 @@ class Frame(mwx.Frame):
1389
1389
  "{} files are missing.".format(n, len(res)-n, len(mis)))
1390
1390
  print(self.message.read())
1391
1391
  return frames
1392
-
1392
+
1393
1393
  def save_index(self, filename=None, frames=None):
1394
1394
  """Save frames :ref to the Index file.
1395
1395
  """
@@ -1439,11 +1439,11 @@ class Frame(mwx.Frame):
1439
1439
  "{} files are missing.".format(n, len(res)-n, len(mis)))
1440
1440
  print(self.message.read())
1441
1441
  return frames
1442
-
1442
+
1443
1443
  ## --------------------------------
1444
1444
  ## load/save frames and attributes
1445
1445
  ## --------------------------------
1446
-
1446
+
1447
1447
  @classmethod
1448
1448
  def read_attributes(self, filename):
1449
1449
  """Read attributes file."""
@@ -1473,7 +1473,7 @@ class Frame(mwx.Frame):
1473
1473
  print("- Failed to read attributes.", e)
1474
1474
  wx.MessageBox(str(e), style=wx.ICON_ERROR)
1475
1475
  return res, mis
1476
-
1476
+
1477
1477
  @classmethod
1478
1478
  def write_attributes(self, filename, frames):
1479
1479
  """Write attributes file."""
@@ -1493,7 +1493,7 @@ class Frame(mwx.Frame):
1493
1493
  print("- Failed to write attributes.", e)
1494
1494
  wx.MessageBox(str(e), style=wx.ICON_ERROR)
1495
1495
  return new, mis
1496
-
1496
+
1497
1497
  def load_frame(self, paths=None, view=None):
1498
1498
  """Load frames from files to the view window.
1499
1499
 
@@ -1512,7 +1512,7 @@ class Frame(mwx.Frame):
1512
1512
  results = savedirs[savedir]
1513
1513
  frame.update_attr(results.get(frame.name))
1514
1514
  return frames
1515
-
1515
+
1516
1516
  def save_frame(self, path=None, frame=None):
1517
1517
  """Save frame to a file.
1518
1518
 
@@ -1524,7 +1524,7 @@ class Frame(mwx.Frame):
1524
1524
  fn = os.path.join(savedir, self.ATTRIBUTESFILE)
1525
1525
  res, mis = self.write_attributes(fn, [frame])
1526
1526
  return frame
1527
-
1527
+
1528
1528
  ## --------------------------------
1529
1529
  ## load/save images
1530
1530
  ## --------------------------------
@@ -1532,7 +1532,7 @@ class Frame(mwx.Frame):
1532
1532
  "TIF file (*.tif)|*.tif",
1533
1533
  "ALL files (*.*)|*.*",
1534
1534
  ]
1535
-
1535
+
1536
1536
  @staticmethod
1537
1537
  def read_buffer(path):
1538
1538
  """Read buffer from a file (to be overridden)."""
@@ -1543,7 +1543,7 @@ class Frame(mwx.Frame):
1543
1543
  ## return np.asarray(buf), info # ref
1544
1544
  ## return np.array(buf), info # copy
1545
1545
  return buf, info
1546
-
1546
+
1547
1547
  @staticmethod
1548
1548
  def write_buffer(path, buf):
1549
1549
  """Write buffer to a file (to be overridden)."""
@@ -1556,7 +1556,7 @@ class Frame(mwx.Frame):
1556
1556
  if os.path.exists(path):
1557
1557
  os.remove(path)
1558
1558
  raise
1559
-
1559
+
1560
1560
  @ignore(ResourceWarning)
1561
1561
  def load_buffer(self, paths=None, view=None):
1562
1562
  """Load buffers from paths to the view window.
@@ -1616,7 +1616,7 @@ class Frame(mwx.Frame):
1616
1616
  if frame:
1617
1617
  view.select(frame)
1618
1618
  return frames
1619
-
1619
+
1620
1620
  def save_buffer(self, path=None, frame=None):
1621
1621
  """Save buffer of the frame to a file.
1622
1622
  """
@@ -1655,7 +1655,7 @@ class Frame(mwx.Frame):
1655
1655
  self.message("\b failed.")
1656
1656
  wx.MessageBox(str(e), style=wx.ICON_ERROR)
1657
1657
  return None
1658
-
1658
+
1659
1659
  def save_buffers_as_tiffs(self, path=None, frames=None):
1660
1660
  """Save buffers to a file as a multi-page tiff."""
1661
1661
  if not frames:
@@ -1688,12 +1688,12 @@ class Frame(mwx.Frame):
1688
1688
  self.message("\b failed.")
1689
1689
  wx.MessageBox(str(e), style=wx.ICON_ERROR)
1690
1690
  return False
1691
-
1691
+
1692
1692
  ## --------------------------------
1693
1693
  ## load/save session
1694
1694
  ## --------------------------------
1695
1695
  session_file = None
1696
-
1696
+
1697
1697
  def load_session(self, filename=None, flush=True):
1698
1698
  """Load session from file."""
1699
1699
  if not filename:
@@ -1739,7 +1739,7 @@ class Frame(mwx.Frame):
1739
1739
  win.handler('page_shown', win)
1740
1740
 
1741
1741
  self.message("\b done.")
1742
-
1742
+
1743
1743
  def save_session_as(self):
1744
1744
  """Save session as a new file."""
1745
1745
  with wx.FileDialog(self, "Save session as",
@@ -1751,7 +1751,7 @@ class Frame(mwx.Frame):
1751
1751
  if dlg.ShowModal() == wx.ID_OK:
1752
1752
  self.session_file = dlg.Path
1753
1753
  self.save_session()
1754
-
1754
+
1755
1755
  def save_session(self):
1756
1756
  """Save session to file."""
1757
1757
  if not self.session_file: