wolfhece 2.1.108__py3-none-any.whl → 2.1.110__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.
- wolfhece/PyDraw.py +234 -5
 - wolfhece/PyVertex.py +17 -1
 - wolfhece/PyVertexvectors.py +732 -112
 - wolfhece/apps/curvedigitizer.py +197 -141
 - wolfhece/apps/version.py +1 -1
 - wolfhece/lazviewer/laz_viewer.py +22 -0
 - wolfhece/matplotlib_fig.py +433 -66
 - wolfhece/pybridges.py +227 -87
 - {wolfhece-2.1.108.dist-info → wolfhece-2.1.110.dist-info}/METADATA +1 -1
 - {wolfhece-2.1.108.dist-info → wolfhece-2.1.110.dist-info}/RECORD +13 -13
 - {wolfhece-2.1.108.dist-info → wolfhece-2.1.110.dist-info}/WHEEL +0 -0
 - {wolfhece-2.1.108.dist-info → wolfhece-2.1.110.dist-info}/entry_points.txt +0 -0
 - {wolfhece-2.1.108.dist-info → wolfhece-2.1.110.dist-info}/top_level.txt +0 -0
 
    
        wolfhece/matplotlib_fig.py
    CHANGED
    
    | 
         @@ -2,6 +2,7 @@ from matplotlib.backends.backend_wx import NavigationToolbar2Wx as NavigationToo 
     | 
|
| 
       2 
2 
     | 
    
         
             
            from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
         
     | 
| 
       3 
3 
     | 
    
         
             
            from typing import Literal
         
     | 
| 
       4 
4 
     | 
    
         
             
            from matplotlib.figure import Figure
         
     | 
| 
      
 5 
     | 
    
         
            +
            from matplotlib.axes import Axes
         
     | 
| 
       5 
6 
     | 
    
         
             
            import matplotlib.pyplot as plt
         
     | 
| 
       6 
7 
     | 
    
         
             
            from matplotlib.gridspec import GridSpec
         
     | 
| 
       7 
8 
     | 
    
         
             
            import numpy as np
         
     | 
| 
         @@ -11,6 +12,8 @@ from wolfhece.PyParams import Wolf_Param, new_json 
     | 
|
| 
       11 
12 
     | 
    
         
             
            from wolfhece.PyTranslate import _
         
     | 
| 
       12 
13 
     | 
    
         
             
            from wolfhece.PyVertex import getRGBfromI
         
     | 
| 
       13 
14 
     | 
    
         | 
| 
      
 15 
     | 
    
         
            +
            from PIL import Image, ImageOps
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
       14 
17 
     | 
    
         | 
| 
       15 
18 
     | 
    
         
             
            import wx
         
     | 
| 
       16 
19 
     | 
    
         
             
            from matplotlib.backend_bases import KeyEvent, MouseEvent
         
     | 
| 
         @@ -55,7 +58,7 @@ def sanitize_fmt(fmt): 
     | 
|
| 
       55 
58 
     | 
    
         | 
| 
       56 
59 
     | 
    
         
             
            class Matplotlib_ax_properties():
         
     | 
| 
       57 
60 
     | 
    
         | 
| 
       58 
     | 
    
         
            -
                def __init__(self, ax =None) -> None:
         
     | 
| 
      
 61 
     | 
    
         
            +
                def __init__(self, ax:Axes =None) -> None:
         
     | 
| 
       59 
62 
     | 
    
         | 
| 
       60 
63 
     | 
    
         
             
                    self._ax = ax
         
     | 
| 
       61 
64 
     | 
    
         
             
                    self._myprops = None
         
     | 
| 
         @@ -64,29 +67,55 @@ class Matplotlib_ax_properties(): 
     | 
|
| 
       64 
67 
     | 
    
         
             
                    self._tmp_line_prop:Matplolib_line_properties = None
         
     | 
| 
       65 
68 
     | 
    
         
             
                    self._selected_line = -1
         
     | 
| 
       66 
69 
     | 
    
         | 
| 
       67 
     | 
    
         
            -
                     
     | 
| 
       68 
     | 
    
         
            -
             
     | 
| 
       69 
     | 
    
         
            -
             
     | 
| 
       70 
     | 
    
         
            -
             
     | 
| 
       71 
     | 
    
         
            -
             
     | 
| 
       72 
     | 
    
         
            -
             
     | 
| 
       73 
     | 
    
         
            -
             
     | 
| 
       74 
     | 
    
         
            -
             
     | 
| 
       75 
     | 
    
         
            -
             
     | 
| 
       76 
     | 
    
         
            -
             
     | 
| 
       77 
     | 
    
         
            -
             
     | 
| 
       78 
     | 
    
         
            -
             
     | 
| 
       79 
     | 
    
         
            -
             
     | 
| 
       80 
     | 
    
         
            -
             
     | 
| 
       81 
     | 
    
         
            -
             
     | 
| 
       82 
     | 
    
         
            -
             
     | 
| 
       83 
     | 
    
         
            -
             
     | 
| 
       84 
     | 
    
         
            -
             
     | 
| 
       85 
     | 
    
         
            -
             
     | 
| 
       86 
     | 
    
         
            -
             
     | 
| 
       87 
     | 
    
         
            -
             
     | 
| 
       88 
     | 
    
         
            -
             
     | 
| 
       89 
     | 
    
         
            -
             
     | 
| 
      
 70 
     | 
    
         
            +
                    if ax is None:
         
     | 
| 
      
 71 
     | 
    
         
            +
                        self.title = 'Figure'
         
     | 
| 
      
 72 
     | 
    
         
            +
                        self.xtitle = 'X [m]'
         
     | 
| 
      
 73 
     | 
    
         
            +
                        self.ytitle = 'Y [m]'
         
     | 
| 
      
 74 
     | 
    
         
            +
                        self.legend = False
         
     | 
| 
      
 75 
     | 
    
         
            +
                        self.xmin = -99999
         
     | 
| 
      
 76 
     | 
    
         
            +
                        self.xmax = -99999
         
     | 
| 
      
 77 
     | 
    
         
            +
                        self.ymin = -99999
         
     | 
| 
      
 78 
     | 
    
         
            +
                        self.ymax = -99999
         
     | 
| 
      
 79 
     | 
    
         
            +
                        self.gridx_major = False
         
     | 
| 
      
 80 
     | 
    
         
            +
                        self.gridy_major = False
         
     | 
| 
      
 81 
     | 
    
         
            +
                        self.gridx_minor = False
         
     | 
| 
      
 82 
     | 
    
         
            +
                        self.gridy_minor = False
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                        self._equal_axis = 0
         
     | 
| 
      
 85 
     | 
    
         
            +
                        self.scaling_factor = 1.
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                        self.ticks_x = 1.
         
     | 
| 
      
 88 
     | 
    
         
            +
                        self.ticks_y = 1.
         
     | 
| 
      
 89 
     | 
    
         
            +
                        self.ticks_label_x = 1.
         
     | 
| 
      
 90 
     | 
    
         
            +
                        self.ticks_label_y = 1.
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                        self.format_x = '.2f'
         
     | 
| 
      
 93 
     | 
    
         
            +
                        self.format_y = '.2f'
         
     | 
| 
      
 94 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 95 
     | 
    
         
            +
                        self.title = ax.get_title()
         
     | 
| 
      
 96 
     | 
    
         
            +
                        self.xtitle = ax.get_xlabel()
         
     | 
| 
      
 97 
     | 
    
         
            +
                        self.ytitle = ax.get_ylabel()
         
     | 
| 
      
 98 
     | 
    
         
            +
                        self.legend = ax.get_legend() is not None
         
     | 
| 
      
 99 
     | 
    
         
            +
                        self.xmin = -99999
         
     | 
| 
      
 100 
     | 
    
         
            +
                        self.xmax = -99999
         
     | 
| 
      
 101 
     | 
    
         
            +
                        self.ymin = -99999
         
     | 
| 
      
 102 
     | 
    
         
            +
                        self.ymax = -99999
         
     | 
| 
      
 103 
     | 
    
         
            +
                        self.gridx_major = False
         
     | 
| 
      
 104 
     | 
    
         
            +
                        self.gridy_major = False
         
     | 
| 
      
 105 
     | 
    
         
            +
                        self.gridx_minor = False
         
     | 
| 
      
 106 
     | 
    
         
            +
                        self.gridy_minor = False
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
                        aspect = ax.get_aspect()
         
     | 
| 
      
 109 
     | 
    
         
            +
                        self._equal_axis = 0 if aspect == 'auto' else 1 if aspect == 1. else 2
         
     | 
| 
      
 110 
     | 
    
         
            +
                        self.scaling_factor = aspect
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
                        self.ticks_x = ax.get_xticks()
         
     | 
| 
      
 113 
     | 
    
         
            +
                        self.ticks_y = ax.get_yticks
         
     | 
| 
      
 114 
     | 
    
         
            +
                        self.ticks_label_x = ax.get_xticklabels()
         
     | 
| 
      
 115 
     | 
    
         
            +
                        self.ticks_label_y = ax.get_yticklabels()
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
                        self.format_x = '.2f'
         
     | 
| 
      
 118 
     | 
    
         
            +
                        self.format_y = '.2f'
         
     | 
| 
       90 
119 
     | 
    
         | 
| 
       91 
120 
     | 
    
         
             
                    self._set_props()
         
     | 
| 
       92 
121 
     | 
    
         | 
| 
         @@ -234,9 +263,10 @@ class Matplotlib_ax_properties(): 
     | 
|
| 
       234 
263 
     | 
    
         
             
                        return
         
     | 
| 
       235 
264 
     | 
    
         | 
| 
       236 
265 
     | 
    
         
             
                    lines = self._ax.get_lines()
         
     | 
| 
      
 266 
     | 
    
         
            +
                    img   = self._ax.get_images()
         
     | 
| 
       237 
267 
     | 
    
         | 
| 
       238 
     | 
    
         
            -
                    if len(lines) == 0:
         
     | 
| 
       239 
     | 
    
         
            -
                        logging.warning('No lines found')
         
     | 
| 
      
 268 
     | 
    
         
            +
                    if len(lines) == 0 and len(img) == 0:
         
     | 
| 
      
 269 
     | 
    
         
            +
                        logging.warning('No lines/image found')
         
     | 
| 
       240 
270 
     | 
    
         
             
                        return
         
     | 
| 
       241 
271 
     | 
    
         | 
| 
       242 
272 
     | 
    
         
             
                    xmin = np.inf
         
     | 
| 
         @@ -253,6 +283,13 @@ class Matplotlib_ax_properties(): 
     | 
|
| 
       253 
283 
     | 
    
         
             
                        ymin = min(ymin, np.min(y))
         
     | 
| 
       254 
284 
     | 
    
         
             
                        ymax = max(ymax, np.max(y))
         
     | 
| 
       255 
285 
     | 
    
         | 
| 
      
 286 
     | 
    
         
            +
                    for im in img:
         
     | 
| 
      
 287 
     | 
    
         
            +
                        x = im.get_extent()
         
     | 
| 
      
 288 
     | 
    
         
            +
                        xmin = min(xmin, x[0])
         
     | 
| 
      
 289 
     | 
    
         
            +
                        xmax = max(xmax, x[1])
         
     | 
| 
      
 290 
     | 
    
         
            +
                        ymin = min(ymin, x[2])
         
     | 
| 
      
 291 
     | 
    
         
            +
                        ymax = max(ymax, x[3])
         
     | 
| 
      
 292 
     | 
    
         
            +
             
     | 
| 
       256 
293 
     | 
    
         
             
                    return xmin, xmax, ymin, ymax
         
     | 
| 
       257 
294 
     | 
    
         | 
| 
       258 
295 
     | 
    
         
             
                def fill_property(self, verbosity= True):
         
     | 
| 
         @@ -346,8 +383,10 @@ class Matplotlib_ax_properties(): 
     | 
|
| 
       346 
383 
     | 
    
         
             
                    ax.xaxis.grid(self.gridx_major)
         
     | 
| 
       347 
384 
     | 
    
         
             
                    ax.yaxis.grid(self.gridy_major)
         
     | 
| 
       348 
385 
     | 
    
         | 
| 
       349 
     | 
    
         
            -
                     
     | 
| 
       350 
     | 
    
         
            -
             
     | 
| 
      
 386 
     | 
    
         
            +
                    if len(self.ticks_x) <= 100:
         
     | 
| 
      
 387 
     | 
    
         
            +
                        ax.set_xticks(self.ticks_x, self.ticks_label_x)
         
     | 
| 
      
 388 
     | 
    
         
            +
                    if len(self.ticks_y) <= 100:
         
     | 
| 
      
 389 
     | 
    
         
            +
                       ax.set_yticks(self.ticks_y, self.ticks_label_y)
         
     | 
| 
       351 
390 
     | 
    
         | 
| 
       352 
391 
     | 
    
         
             
                    if self.legend:
         
     | 
| 
       353 
392 
     | 
    
         
             
                        update = any(line.update_legend for line in self._lines)
         
     | 
| 
         @@ -612,11 +651,62 @@ class Matplolib_line_properties(): 
     | 
|
| 
       612 
651 
     | 
    
         | 
| 
       613 
652 
     | 
    
         
             
                    self.update_legend = False
         
     | 
| 
       614 
653 
     | 
    
         | 
| 
      
 654 
     | 
    
         
            +
                    self._scales = [1.0, 1.0]
         
     | 
| 
      
 655 
     | 
    
         
            +
                    self._origin_world = [0.0, 0.0]
         
     | 
| 
      
 656 
     | 
    
         
            +
                    self._origin_local = [0.0, 0.0]
         
     | 
| 
      
 657 
     | 
    
         
            +
             
     | 
| 
       615 
658 
     | 
    
         
             
                    self._set_props()
         
     | 
| 
       616 
659 
     | 
    
         | 
| 
       617 
660 
     | 
    
         
             
                    if self._line is not None:
         
     | 
| 
       618 
661 
     | 
    
         
             
                        self.get_properties()
         
     | 
| 
       619 
662 
     | 
    
         | 
| 
      
 663 
     | 
    
         
            +
                def get_xydata(self, two_columns:bool = False):
         
     | 
| 
      
 664 
     | 
    
         
            +
                    """ Get the xy data """
         
     | 
| 
      
 665 
     | 
    
         
            +
             
     | 
| 
      
 666 
     | 
    
         
            +
                    if self._line is None:
         
     | 
| 
      
 667 
     | 
    
         
            +
                        return None
         
     | 
| 
      
 668 
     | 
    
         
            +
             
     | 
| 
      
 669 
     | 
    
         
            +
                    if two_columns:
         
     | 
| 
      
 670 
     | 
    
         
            +
                        return (self._line.get_xdata() - self._origin_local[0]) * self._scales[0] + self._origin_world[0], \
         
     | 
| 
      
 671 
     | 
    
         
            +
                               (self._line.get_ydata() - self._origin_local[1]) * self._scales[1] + self._origin_world[1]
         
     | 
| 
      
 672 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 673 
     | 
    
         
            +
                        return np.array([(self._line.get_xdata() - self._origin_local[0]) * self._scales[0] + self._origin_world[0],
         
     | 
| 
      
 674 
     | 
    
         
            +
                                         (self._line.get_ydata() - self._origin_local[1]) * self._scales[1] + self._origin_world[1]]).T
         
     | 
| 
      
 675 
     | 
    
         
            +
             
     | 
| 
      
 676 
     | 
    
         
            +
                def set_xydata(self, xy_data:np.ndarray):
         
     | 
| 
      
 677 
     | 
    
         
            +
                    """ Set the xy data """
         
     | 
| 
      
 678 
     | 
    
         
            +
             
     | 
| 
      
 679 
     | 
    
         
            +
                    if self._line is None:
         
     | 
| 
      
 680 
     | 
    
         
            +
                        return
         
     | 
| 
      
 681 
     | 
    
         
            +
             
     | 
| 
      
 682 
     | 
    
         
            +
                    self._line.set_xdata((xy_data[:,0] - self._origin_world[0]) / self._scales[0] + self._origin_local[0])
         
     | 
| 
      
 683 
     | 
    
         
            +
                    self._line.set_ydata((xy_data[:,1] - self._origin_world[1]) / self._scales[1] + self._origin_local[1])
         
     | 
| 
      
 684 
     | 
    
         
            +
             
     | 
| 
      
 685 
     | 
    
         
            +
                @property
         
     | 
| 
      
 686 
     | 
    
         
            +
                def xdata(self):
         
     | 
| 
      
 687 
     | 
    
         
            +
                    return self.get_xydata(two_columns= True)[0]
         
     | 
| 
      
 688 
     | 
    
         
            +
             
     | 
| 
      
 689 
     | 
    
         
            +
                @property
         
     | 
| 
      
 690 
     | 
    
         
            +
                def ydata(self):
         
     | 
| 
      
 691 
     | 
    
         
            +
                    return self.get_xydata(two_columns= True)[1]
         
     | 
| 
      
 692 
     | 
    
         
            +
             
     | 
| 
      
 693 
     | 
    
         
            +
                @property
         
     | 
| 
      
 694 
     | 
    
         
            +
                def xydata(self):
         
     | 
| 
      
 695 
     | 
    
         
            +
                    return self.get_xydata()
         
     | 
| 
      
 696 
     | 
    
         
            +
             
     | 
| 
      
 697 
     | 
    
         
            +
                @xydata.setter
         
     | 
| 
      
 698 
     | 
    
         
            +
                def xydata(self, value):
         
     | 
| 
      
 699 
     | 
    
         
            +
             
     | 
| 
      
 700 
     | 
    
         
            +
                    if not isinstance(value, np.ndarray):
         
     | 
| 
      
 701 
     | 
    
         
            +
                        logging.warning('xydata must be a numpy array')
         
     | 
| 
      
 702 
     | 
    
         
            +
                        return
         
     | 
| 
      
 703 
     | 
    
         
            +
             
     | 
| 
      
 704 
     | 
    
         
            +
                    if value.shape[1] != 2:
         
     | 
| 
      
 705 
     | 
    
         
            +
                        logging.warning('xydata must have 2 columns')
         
     | 
| 
      
 706 
     | 
    
         
            +
                        return
         
     | 
| 
      
 707 
     | 
    
         
            +
             
     | 
| 
      
 708 
     | 
    
         
            +
                    self.set_xydata(value)
         
     | 
| 
      
 709 
     | 
    
         
            +
             
     | 
| 
       620 
710 
     | 
    
         
             
                @property
         
     | 
| 
       621 
711 
     | 
    
         
             
                def ax_props(self):
         
     | 
| 
       622 
712 
     | 
    
         
             
                    return self._ax_props
         
     | 
| 
         @@ -821,6 +911,14 @@ class Matplolib_line_properties(): 
     | 
|
| 
       821 
911 
     | 
    
         
             
                    self._myprops.addparam('Picker', 'Picker', self.picker, 'Logical', 'Picker')
         
     | 
| 
       822 
912 
     | 
    
         
             
                    self._myprops.addparam('Picker', 'Picker radius', self.picker_radius, 'Float', 'Picker radius')
         
     | 
| 
       823 
913 
     | 
    
         | 
| 
      
 914 
     | 
    
         
            +
                    self._myprops.addparam('Scales', 'X scale', self._scales[0], 'Float', 'X scale')
         
     | 
| 
      
 915 
     | 
    
         
            +
                    self._myprops.addparam('Scales', 'Y scale', self._scales[1], 'Float', 'Y scale')
         
     | 
| 
      
 916 
     | 
    
         
            +
             
     | 
| 
      
 917 
     | 
    
         
            +
                    self._myprops.addparam('Origin', 'X world', self._origin_world[0], 'Float', 'X origin into world')
         
     | 
| 
      
 918 
     | 
    
         
            +
                    self._myprops.addparam('Origin', 'Y world', self._origin_world[1], 'Float', 'Y origin into world')
         
     | 
| 
      
 919 
     | 
    
         
            +
                    self._myprops.addparam('Origin', 'X local', self._origin_local[0], 'Float', 'X origin into local references')
         
     | 
| 
      
 920 
     | 
    
         
            +
                    self._myprops.addparam('Origin', 'Y local', self._origin_local[1], 'Float', 'Y origin into local references')
         
     | 
| 
      
 921 
     | 
    
         
            +
             
     | 
| 
       824 
922 
     | 
    
         
             
                    self._myprops.Populate()
         
     | 
| 
       825 
923 
     | 
    
         
             
                    # self._myprops.Layout()
         
     | 
| 
       826 
924 
     | 
    
         
             
                    # self._myprops.SetSizeHints(500,500)
         
     | 
| 
         @@ -848,6 +946,14 @@ class Matplolib_line_properties(): 
     | 
|
| 
       848 
946 
     | 
    
         
             
                    self._myprops[('Picker', 'Picker')] = self.picker
         
     | 
| 
       849 
947 
     | 
    
         
             
                    self._myprops[('Picker', 'Picker radius')] = self.picker_radius
         
     | 
| 
       850 
948 
     | 
    
         | 
| 
      
 949 
     | 
    
         
            +
                    self._myprops[('Scales', 'X scale')] = self._scales[0]
         
     | 
| 
      
 950 
     | 
    
         
            +
                    self._myprops[('Scales', 'Y scale')] = self._scales[1]
         
     | 
| 
      
 951 
     | 
    
         
            +
             
     | 
| 
      
 952 
     | 
    
         
            +
                    self._myprops[('Origin', 'X world')] = self._origin_world[0]
         
     | 
| 
      
 953 
     | 
    
         
            +
                    self._myprops[('Origin', 'Y world')] = self._origin_world[1]
         
     | 
| 
      
 954 
     | 
    
         
            +
                    self._myprops[('Origin', 'X local')] = self._origin_local[0]
         
     | 
| 
      
 955 
     | 
    
         
            +
                    self._myprops[('Origin', 'Y local')] = self._origin_local[1]
         
     | 
| 
      
 956 
     | 
    
         
            +
             
     | 
| 
       851 
957 
     | 
    
         
             
                    self._myprops.Populate()
         
     | 
| 
       852 
958 
     | 
    
         | 
| 
       853 
959 
     | 
    
         
             
                def ui(self):
         
     | 
| 
         @@ -902,6 +1008,15 @@ class Matplolib_line_properties(): 
     | 
|
| 
       902 
1008 
     | 
    
         
             
                    self.picker = self._myprops[('Picker', 'Picker')]
         
     | 
| 
       903 
1009 
     | 
    
         
             
                    self.picker_radius = self._myprops[('Picker', 'Picker radius')]
         
     | 
| 
       904 
1010 
     | 
    
         | 
| 
      
 1011 
     | 
    
         
            +
                    self._scales[0] = self._myprops[('Scales', 'X scale')]
         
     | 
| 
      
 1012 
     | 
    
         
            +
                    self._scales[1] = self._myprops[('Scales', 'Y scale')]
         
     | 
| 
      
 1013 
     | 
    
         
            +
             
     | 
| 
      
 1014 
     | 
    
         
            +
                    self._origin_world[0] = self._myprops[('Origin', 'X world')]
         
     | 
| 
      
 1015 
     | 
    
         
            +
                    self._origin_world[1] = self._myprops[('Origin', 'Y world')]
         
     | 
| 
      
 1016 
     | 
    
         
            +
             
     | 
| 
      
 1017 
     | 
    
         
            +
                    self._origin_local[0] = self._myprops[('Origin', 'X local')]
         
     | 
| 
      
 1018 
     | 
    
         
            +
                    self._origin_local[1] = self._myprops[('Origin', 'Y local')]
         
     | 
| 
      
 1019 
     | 
    
         
            +
             
     | 
| 
       905 
1020 
     | 
    
         
             
                    self.set_properties()
         
     | 
| 
       906 
1021 
     | 
    
         | 
| 
       907 
1022 
     | 
    
         
             
                def set_properties(self, line:Line2D = None):
         
     | 
| 
         @@ -946,13 +1061,19 @@ class Matplolib_line_properties(): 
     | 
|
| 
       946 
1061 
     | 
    
         
             
                def show_properties(self):
         
     | 
| 
       947 
1062 
     | 
    
         
             
                    self.ui()
         
     | 
| 
       948 
1063 
     | 
    
         | 
| 
      
 1064 
     | 
    
         
            +
                @property
         
     | 
| 
      
 1065 
     | 
    
         
            +
                def has_world_transfer(self):
         
     | 
| 
      
 1066 
     | 
    
         
            +
                    return self._scales[0] != 1.0 or self._scales[1] != 1.0 or self._origin_world[0] != 0. or self._origin_world[1] != 0. or self._origin_local[0] != 0. or self._origin_local[1] != 0.
         
     | 
| 
      
 1067 
     | 
    
         
            +
             
     | 
| 
       949 
1068 
     | 
    
         
             
                def to_dict(self) -> str:
         
     | 
| 
       950 
1069 
     | 
    
         
             
                    """ properties to dict """
         
     | 
| 
       951 
1070 
     | 
    
         | 
| 
       952 
     | 
    
         
            -
                     
     | 
| 
       953 
     | 
    
         
            -
                     
     | 
| 
      
 1071 
     | 
    
         
            +
                    # We need to store the local data
         
     | 
| 
      
 1072 
     | 
    
         
            +
                    xy = self._line.get_xydata()
         
     | 
| 
      
 1073 
     | 
    
         
            +
                    xdata = xy[:,0].tolist()
         
     | 
| 
      
 1074 
     | 
    
         
            +
                    ydata = xy[:,1].tolist()
         
     | 
| 
       954 
1075 
     | 
    
         | 
| 
       955 
     | 
    
         
            -
                     
     | 
| 
      
 1076 
     | 
    
         
            +
                    locdict = {'color':self.color,
         
     | 
| 
       956 
1077 
     | 
    
         
             
                            'linewidth':self.linewidth,
         
     | 
| 
       957 
1078 
     | 
    
         
             
                            'linestyle':self.linestyle,
         
     | 
| 
       958 
1079 
     | 
    
         
             
                            'marker':self.marker,
         
     | 
| 
         @@ -967,12 +1088,31 @@ class Matplolib_line_properties(): 
     | 
|
| 
       967 
1088 
     | 
    
         
             
                            'picker':self.picker,
         
     | 
| 
       968 
1089 
     | 
    
         
             
                            'picker_radius':self.picker_radius,
         
     | 
| 
       969 
1090 
     | 
    
         
             
                            'xdata':xdata,
         
     | 
| 
       970 
     | 
    
         
            -
                            'ydata':ydata 
     | 
| 
      
 1091 
     | 
    
         
            +
                            'ydata':ydata,
         
     | 
| 
      
 1092 
     | 
    
         
            +
                            'xscale':self._scales[0],
         
     | 
| 
      
 1093 
     | 
    
         
            +
                            'yscale':self._scales[1],
         
     | 
| 
      
 1094 
     | 
    
         
            +
                            'xorigin_world':self._origin_world[0],
         
     | 
| 
      
 1095 
     | 
    
         
            +
                            'yorigin_world':self._origin_world[1],
         
     | 
| 
      
 1096 
     | 
    
         
            +
                            'xorigin_local':self._origin_local[0],
         
     | 
| 
      
 1097 
     | 
    
         
            +
                            'yorigin_local':self._origin_local[1]}
         
     | 
| 
      
 1098 
     | 
    
         
            +
             
     | 
| 
      
 1099 
     | 
    
         
            +
                    if self.has_world_transfer:
         
     | 
| 
      
 1100 
     | 
    
         
            +
                        world_xdata, world_ydata = self.get_xydata(two_columns = True)
         
     | 
| 
      
 1101 
     | 
    
         
            +
                        world_xdata = world_xdata.tolist()
         
     | 
| 
      
 1102 
     | 
    
         
            +
                        world_ydata = world_ydata.tolist()
         
     | 
| 
      
 1103 
     | 
    
         
            +
             
     | 
| 
      
 1104 
     | 
    
         
            +
                        locdict['world_xdata'] = world_xdata
         
     | 
| 
      
 1105 
     | 
    
         
            +
                        locdict['world_ydata'] = world_ydata
         
     | 
| 
      
 1106 
     | 
    
         
            +
             
     | 
| 
      
 1107 
     | 
    
         
            +
                    return locdict
         
     | 
| 
       971 
1108 
     | 
    
         | 
| 
       972 
1109 
     | 
    
         
             
                def from_dict(self, props:dict):
         
     | 
| 
       973 
1110 
     | 
    
         
             
                    """ properties from dict """
         
     | 
| 
       974 
1111 
     | 
    
         | 
| 
       975 
     | 
    
         
            -
                    keys = ['color', 'linewidth', 'linestyle', 'marker', 'markersize', 'alpha', 
     | 
| 
      
 1112 
     | 
    
         
            +
                    keys = ['color', 'linewidth', 'linestyle', 'marker', 'markersize', 'alpha',
         
     | 
| 
      
 1113 
     | 
    
         
            +
                            'label', 'markerfacecolor', 'markeredgecolor', 'markeredgewidth',
         
     | 
| 
      
 1114 
     | 
    
         
            +
                            'visible', 'zorder', 'picker', 'picker_radius',
         
     | 
| 
      
 1115 
     | 
    
         
            +
                            'xscale', 'yscale', 'xorigin_world', 'yorigin_world', 'xorigin_local', 'yorigin_local']
         
     | 
| 
       976 
1116 
     | 
    
         | 
| 
       977 
1117 
     | 
    
         
             
                    for key in keys:
         
     | 
| 
       978 
1118 
     | 
    
         
             
                        try:
         
     | 
| 
         @@ -981,11 +1121,63 @@ class Matplolib_line_properties(): 
     | 
|
| 
       981 
1121 
     | 
    
         
             
                            logging.warning('Key not found in properties dict')
         
     | 
| 
       982 
1122 
     | 
    
         
             
                            pass
         
     | 
| 
       983 
1123 
     | 
    
         | 
| 
      
 1124 
     | 
    
         
            +
                    # ATTENTION : The next 2 lines are done in the to_dict method of the axes
         
     | 
| 
      
 1125 
     | 
    
         
            +
                    # xydata = np.array([props['xdata'], props['ydata']]).T
         
     | 
| 
      
 1126 
     | 
    
         
            +
                    # self.set_xydata(xydata)
         
     | 
| 
      
 1127 
     | 
    
         
            +
             
     | 
| 
       984 
1128 
     | 
    
         
             
                    self.populate()
         
     | 
| 
       985 
1129 
     | 
    
         
             
                    self.set_properties()
         
     | 
| 
       986 
1130 
     | 
    
         | 
| 
       987 
1131 
     | 
    
         
             
                    return self
         
     | 
| 
       988 
1132 
     | 
    
         | 
| 
      
 1133 
     | 
    
         
            +
                @property
         
     | 
| 
      
 1134 
     | 
    
         
            +
                def xscale(self):
         
     | 
| 
      
 1135 
     | 
    
         
            +
                    return self._scales[0]
         
     | 
| 
      
 1136 
     | 
    
         
            +
             
     | 
| 
      
 1137 
     | 
    
         
            +
                @xscale.setter
         
     | 
| 
      
 1138 
     | 
    
         
            +
                def xscale(self, value):
         
     | 
| 
      
 1139 
     | 
    
         
            +
                    self._scales[0] = value
         
     | 
| 
      
 1140 
     | 
    
         
            +
             
     | 
| 
      
 1141 
     | 
    
         
            +
                @property
         
     | 
| 
      
 1142 
     | 
    
         
            +
                def yscale(self):
         
     | 
| 
      
 1143 
     | 
    
         
            +
                    return self._scales[1]
         
     | 
| 
      
 1144 
     | 
    
         
            +
             
     | 
| 
      
 1145 
     | 
    
         
            +
                @yscale.setter
         
     | 
| 
      
 1146 
     | 
    
         
            +
                def yscale(self, value):
         
     | 
| 
      
 1147 
     | 
    
         
            +
                    self._scales[1] = value
         
     | 
| 
      
 1148 
     | 
    
         
            +
             
     | 
| 
      
 1149 
     | 
    
         
            +
                @property
         
     | 
| 
      
 1150 
     | 
    
         
            +
                def xorigin_world(self):
         
     | 
| 
      
 1151 
     | 
    
         
            +
                    return self._origin_world[0]
         
     | 
| 
      
 1152 
     | 
    
         
            +
             
     | 
| 
      
 1153 
     | 
    
         
            +
                @xorigin_world.setter
         
     | 
| 
      
 1154 
     | 
    
         
            +
                def xorigin_world(self, value):
         
     | 
| 
      
 1155 
     | 
    
         
            +
                    self._origin_world[0] = value
         
     | 
| 
      
 1156 
     | 
    
         
            +
             
     | 
| 
      
 1157 
     | 
    
         
            +
                @property
         
     | 
| 
      
 1158 
     | 
    
         
            +
                def yorigin_world(self):
         
     | 
| 
      
 1159 
     | 
    
         
            +
                    return self._origin_world[1]
         
     | 
| 
      
 1160 
     | 
    
         
            +
             
     | 
| 
      
 1161 
     | 
    
         
            +
                @yorigin_world.setter
         
     | 
| 
      
 1162 
     | 
    
         
            +
                def yorigin_world(self, value):
         
     | 
| 
      
 1163 
     | 
    
         
            +
                    self._origin_world[1] = value
         
     | 
| 
      
 1164 
     | 
    
         
            +
             
     | 
| 
      
 1165 
     | 
    
         
            +
                @property
         
     | 
| 
      
 1166 
     | 
    
         
            +
                def xorigin_local(self):
         
     | 
| 
      
 1167 
     | 
    
         
            +
                    return self._origin_local[0]
         
     | 
| 
      
 1168 
     | 
    
         
            +
             
     | 
| 
      
 1169 
     | 
    
         
            +
                @xorigin_local.setter
         
     | 
| 
      
 1170 
     | 
    
         
            +
                def xorigin_local(self, value):
         
     | 
| 
      
 1171 
     | 
    
         
            +
                    self._origin_local[0] = value
         
     | 
| 
      
 1172 
     | 
    
         
            +
             
     | 
| 
      
 1173 
     | 
    
         
            +
                @property
         
     | 
| 
      
 1174 
     | 
    
         
            +
                def yorigin_local(self):
         
     | 
| 
      
 1175 
     | 
    
         
            +
                    return self._origin_local[1]
         
     | 
| 
      
 1176 
     | 
    
         
            +
             
     | 
| 
      
 1177 
     | 
    
         
            +
                @yorigin_local.setter
         
     | 
| 
      
 1178 
     | 
    
         
            +
                def yorigin_local(self, value):
         
     | 
| 
      
 1179 
     | 
    
         
            +
                    self._origin_local[1] = value
         
     | 
| 
      
 1180 
     | 
    
         
            +
             
     | 
| 
       989 
1181 
     | 
    
         
             
                def add_props_to_sizer(self, frame:wx.Frame, sizer:wx.BoxSizer):
         
     | 
| 
       990 
1182 
     | 
    
         
             
                    """ Add the properties to a sizer """
         
     | 
| 
       991 
1183 
     | 
    
         | 
| 
         @@ -1013,8 +1205,9 @@ class Matplolib_line_properties(): 
     | 
|
| 
       1013 
1205 
     | 
    
         
             
                    self._line = None
         
     | 
| 
       1014 
1206 
     | 
    
         | 
| 
       1015 
1207 
     | 
    
         
             
            class PRESET_LAYOUTS(Enum):
         
     | 
| 
       1016 
     | 
    
         
            -
                DEFAULT = (1,1)
         
     | 
| 
       1017 
     | 
    
         
            -
                MAT2X2  = (2,2)
         
     | 
| 
      
 1208 
     | 
    
         
            +
                DEFAULT = (1,1, 'auto')
         
     | 
| 
      
 1209 
     | 
    
         
            +
                MAT2X2  = (2,2, 'auto')
         
     | 
| 
      
 1210 
     | 
    
         
            +
                DEFAULT_EQUAL = (1,1, 'equal')
         
     | 
| 
       1018 
1211 
     | 
    
         
             
            class Matplotlib_Figure(wx.Frame):
         
     | 
| 
       1019 
1212 
     | 
    
         
             
                """  Matplotlib Figure with wx Frame """
         
     | 
| 
       1020 
1213 
     | 
    
         | 
| 
         @@ -1043,7 +1236,8 @@ class Matplotlib_Figure(wx.Frame): 
     | 
|
| 
       1043 
1236 
     | 
    
         | 
| 
       1044 
1237 
     | 
    
         
             
                    self.wx_exists = wx.App.Get() is not None
         
     | 
| 
       1045 
1238 
     | 
    
         | 
| 
       1046 
     | 
    
         
            -
                    self.fig =  
     | 
| 
      
 1239 
     | 
    
         
            +
                    self.fig = Figure()
         
     | 
| 
      
 1240 
     | 
    
         
            +
                    # self.fig.set_visible(False)
         
     | 
| 
       1047 
1241 
     | 
    
         
             
                    dpi = self.fig.get_dpi()
         
     | 
| 
       1048 
1242 
     | 
    
         
             
                    size_x, size_y = self.fig.get_size_inches()
         
     | 
| 
       1049 
1243 
     | 
    
         | 
| 
         @@ -1053,10 +1247,22 @@ class Matplotlib_Figure(wx.Frame): 
     | 
|
| 
       1053 
1247 
     | 
    
         
             
                    self.ax_dict:dict[str,Axes] = {}    # dict of axes
         
     | 
| 
       1054 
1248 
     | 
    
         
             
                    self.ax:list[Axes] = []             # list of axes -- always flatten
         
     | 
| 
       1055 
1249 
     | 
    
         
             
                    self.shown_props = None     # shown properties
         
     | 
| 
      
 1250 
     | 
    
         
            +
                    self._shiftdown = False
         
     | 
| 
      
 1251 
     | 
    
         
            +
             
     | 
| 
      
 1252 
     | 
    
         
            +
                    self._action = None
         
     | 
| 
      
 1253 
     | 
    
         
            +
                    self._keep_first_point = True
         
     | 
| 
       1056 
1254 
     | 
    
         | 
| 
       1057 
1255 
     | 
    
         
             
                    self.apply_layout(layout)   # apply the layout
         
     | 
| 
       1058 
1256 
     | 
    
         
             
                    pass
         
     | 
| 
       1059 
1257 
     | 
    
         | 
| 
      
 1258 
     | 
    
         
            +
                @property
         
     | 
| 
      
 1259 
     | 
    
         
            +
                def action(self):
         
     | 
| 
      
 1260 
     | 
    
         
            +
                    return self._action
         
     | 
| 
      
 1261 
     | 
    
         
            +
             
     | 
| 
      
 1262 
     | 
    
         
            +
                @action.setter
         
     | 
| 
      
 1263 
     | 
    
         
            +
                def action(self, value):
         
     | 
| 
      
 1264 
     | 
    
         
            +
                    self._action = value
         
     | 
| 
      
 1265 
     | 
    
         
            +
             
     | 
| 
       1060 
1266 
     | 
    
         
             
                def presets(self, which:PRESET_LAYOUTS = PRESET_LAYOUTS.DEFAULT):
         
     | 
| 
       1061 
1267 
     | 
    
         
             
                    """ Presets """
         
     | 
| 
       1062 
1268 
     | 
    
         | 
| 
         @@ -1102,12 +1308,12 @@ class Matplotlib_Figure(wx.Frame): 
     | 
|
| 
       1102 
1308 
     | 
    
         
             
                            # store the axes in a list -- So we can access them by index, not only by name
         
     | 
| 
       1103 
1309 
     | 
    
         
             
                            self.ax = [ax for ax in self.ax_dict.values()]
         
     | 
| 
       1104 
1310 
     | 
    
         
             
                        else:
         
     | 
| 
       1105 
     | 
    
         
            -
                            # Tuple or list of  
     | 
| 
       1106 
     | 
    
         
            -
                            if len(layout) !=  
     | 
| 
       1107 
     | 
    
         
            -
                                logging.warning('Layout must be a tuple or a list of  
     | 
| 
      
 1311 
     | 
    
         
            +
                            # Tuple or list of 3 elements - subplots
         
     | 
| 
      
 1312 
     | 
    
         
            +
                            if len(layout) != 3:
         
     | 
| 
      
 1313 
     | 
    
         
            +
                                logging.warning('Layout must be a tuple or a list of 3 elements (nbrows:int, nbcols:int, aspect_ratio:str|float)')
         
     | 
| 
       1108 
1314 
     | 
    
         
             
                                return
         
     | 
| 
       1109 
1315 
     | 
    
         | 
| 
       1110 
     | 
    
         
            -
                            self.nbrows, self.nbcols = layout
         
     | 
| 
      
 1316 
     | 
    
         
            +
                            self.nbrows, self.nbcols, ratio = layout
         
     | 
| 
       1111 
1317 
     | 
    
         
             
                            if self.nbrows*self.nbcols == 1:
         
     | 
| 
       1112 
1318 
     | 
    
         
             
                                # Convert to list -- subplots returns a single Axes but we want a list
         
     | 
| 
       1113 
1319 
     | 
    
         
             
                                self.ax = [self.fig.subplots(self.nbrows, self.nbcols)]
         
     | 
| 
         @@ -1115,6 +1321,14 @@ class Matplotlib_Figure(wx.Frame): 
     | 
|
| 
       1115 
1321 
     | 
    
         
             
                                # Flatten the axes -- sbplots returns a 2D array of Axes but we want a list
         
     | 
| 
       1116 
1322 
     | 
    
         
             
                                self.ax = self.fig.subplots(self.nbrows, self.nbcols).flatten()
         
     | 
| 
       1117 
1323 
     | 
    
         | 
| 
      
 1324 
     | 
    
         
            +
                            for curax in self.ax:
         
     | 
| 
      
 1325 
     | 
    
         
            +
                                if ratio == 'auto':
         
     | 
| 
      
 1326 
     | 
    
         
            +
                                    curax.set_aspect('auto')
         
     | 
| 
      
 1327 
     | 
    
         
            +
                                elif ratio == 'equal':
         
     | 
| 
      
 1328 
     | 
    
         
            +
                                    curax.set_aspect('equal')
         
     | 
| 
      
 1329 
     | 
    
         
            +
                                else:
         
     | 
| 
      
 1330 
     | 
    
         
            +
                                    curax.set_aspect(ratio)
         
     | 
| 
      
 1331 
     | 
    
         
            +
             
     | 
| 
       1118 
1332 
     | 
    
         
             
                            # store the axes in a dict -- So we can access them by name, not only by index
         
     | 
| 
       1119 
1333 
     | 
    
         
             
                            self.ax_dict = {f'{i}':ax for i, ax in enumerate(self.ax)}
         
     | 
| 
       1120 
1334 
     | 
    
         
             
                            for key,ax in self.ax_dict.items():
         
     | 
| 
         @@ -1192,6 +1406,7 @@ class Matplotlib_Figure(wx.Frame): 
     | 
|
| 
       1192 
1406 
     | 
    
         
             
                    self._canvas.mpl_connect('motion_notify_event', self.UpdateStatusBar)
         
     | 
| 
       1193 
1407 
     | 
    
         
             
                    self._canvas.mpl_connect('button_press_event', self.OnClickCanvas)
         
     | 
| 
       1194 
1408 
     | 
    
         
             
                    self._canvas.mpl_connect('key_press_event', self.OnKeyCanvas)
         
     | 
| 
      
 1409 
     | 
    
         
            +
                    self._canvas.mpl_connect('key_release_event', self.OnKeyRelease)
         
     | 
| 
       1195 
1410 
     | 
    
         | 
| 
       1196 
1411 
     | 
    
         
             
                    # Toolbar - Matplotlib
         
     | 
| 
       1197 
1412 
     | 
    
         
             
                    # --------------------
         
     | 
| 
         @@ -1280,6 +1495,9 @@ class Matplotlib_Figure(wx.Frame): 
     | 
|
| 
       1280 
1495 
     | 
    
         
             
                    self._add_row = wx.Button(win, -1, 'Add rows')
         
     | 
| 
       1281 
1496 
     | 
    
         
             
                    self._add_row.Bind(wx.EVT_BUTTON, self.add_row_to_grid)
         
     | 
| 
       1282 
1497 
     | 
    
         | 
| 
      
 1498 
     | 
    
         
            +
                    self._new_line = wx.Button(win, -1, 'New line')
         
     | 
| 
      
 1499 
     | 
    
         
            +
                    self._new_line.Bind(wx.EVT_BUTTON, self.onnew_line)
         
     | 
| 
      
 1500 
     | 
    
         
            +
             
     | 
| 
       1283 
1501 
     | 
    
         
             
                    self._add_line = wx.Button(win, -1, 'Add line')
         
     | 
| 
       1284 
1502 
     | 
    
         
             
                    self._add_line.Bind(wx.EVT_BUTTON, self.onadd_line)
         
     | 
| 
       1285 
1503 
     | 
    
         | 
| 
         @@ -1287,10 +1505,19 @@ class Matplotlib_Figure(wx.Frame): 
     | 
|
| 
       1287 
1505 
     | 
    
         
             
                    self._del_line.Bind(wx.EVT_BUTTON, self.ondel_line)
         
     | 
| 
       1288 
1506 
     | 
    
         | 
| 
       1289 
1507 
     | 
    
         
             
                    self._sizer_xls.Add(self._xls, 1, wx.EXPAND)
         
     | 
| 
       1290 
     | 
    
         
            -
             
     | 
| 
       1291 
     | 
    
         
            -
                    self. 
     | 
| 
       1292 
     | 
    
         
            -
                    self. 
     | 
| 
       1293 
     | 
    
         
            -
             
     | 
| 
      
 1508 
     | 
    
         
            +
             
     | 
| 
      
 1509 
     | 
    
         
            +
                    self._sizer_update_add = wx.BoxSizer(wx.HORIZONTAL)
         
     | 
| 
      
 1510 
     | 
    
         
            +
                    self._sizer_add_remove = wx.BoxSizer(wx.HORIZONTAL)
         
     | 
| 
      
 1511 
     | 
    
         
            +
             
     | 
| 
      
 1512 
     | 
    
         
            +
                    self._sizer_xls.Add(self._sizer_update_add, 0, wx.EXPAND)
         
     | 
| 
      
 1513 
     | 
    
         
            +
                    self._sizer_xls.Add(self._sizer_add_remove, 0, wx.EXPAND)
         
     | 
| 
      
 1514 
     | 
    
         
            +
             
     | 
| 
      
 1515 
     | 
    
         
            +
                    self._sizer_update_add.Add(self._update_xy, 1, wx.EXPAND)
         
     | 
| 
      
 1516 
     | 
    
         
            +
                    self._sizer_update_add.Add(self._add_row, 1, wx.EXPAND)
         
     | 
| 
      
 1517 
     | 
    
         
            +
             
     | 
| 
      
 1518 
     | 
    
         
            +
                    self._sizer_add_remove.Add(self._new_line, 1, wx.EXPAND)
         
     | 
| 
      
 1519 
     | 
    
         
            +
                    self._sizer_add_remove.Add(self._add_line, 1, wx.EXPAND)
         
     | 
| 
      
 1520 
     | 
    
         
            +
                    self._sizer_add_remove.Add(self._del_line, 1, wx.EXPAND)
         
     | 
| 
       1294 
1521 
     | 
    
         | 
| 
       1295 
1522 
     | 
    
         
             
                    # Properties sizer
         
     | 
| 
       1296 
1523 
     | 
    
         
             
                    # ---------------
         
     | 
| 
         @@ -1396,7 +1623,11 @@ class Matplotlib_Figure(wx.Frame): 
     | 
|
| 
       1396 
1623 
     | 
    
         | 
| 
       1397 
1624 
     | 
    
         
             
                @property
         
     | 
| 
       1398 
1625 
     | 
    
         
             
                def cur_line(self) -> Line2D:
         
     | 
| 
       1399 
     | 
    
         
            -
             
     | 
| 
      
 1626 
     | 
    
         
            +
             
     | 
| 
      
 1627 
     | 
    
         
            +
                    if self._line_current.GetSelection() == -1:
         
     | 
| 
      
 1628 
     | 
    
         
            +
                        return None
         
     | 
| 
      
 1629 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 1630 
     | 
    
         
            +
                        return self.cur_ax.get_lines()[int(self._line_current.GetSelection())]
         
     | 
| 
       1400 
1631 
     | 
    
         | 
| 
       1401 
1632 
     | 
    
         
             
                def get_figax(self):
         
     | 
| 
       1402 
1633 
     | 
    
         | 
| 
         @@ -1447,6 +1678,10 @@ class Matplotlib_Figure(wx.Frame): 
     | 
|
| 
       1447 
1678 
     | 
    
         
             
                def show_curline_properties(self):
         
     | 
| 
       1448 
1679 
     | 
    
         
             
                    # self.cur_line_properties.ui()
         
     | 
| 
       1449 
1680 
     | 
    
         
             
                    self._hide_all_props()
         
     | 
| 
      
 1681 
     | 
    
         
            +
             
     | 
| 
      
 1682 
     | 
    
         
            +
                    if self._line_current.GetSelection() == -1:
         
     | 
| 
      
 1683 
     | 
    
         
            +
                        return
         
     | 
| 
      
 1684 
     | 
    
         
            +
             
     | 
| 
       1450 
1685 
     | 
    
         
             
                    self.cur_line_properties.show_props()
         
     | 
| 
       1451 
1686 
     | 
    
         
             
                    # self.Layout()
         
     | 
| 
       1452 
1687 
     | 
    
         
             
                    self._sizer_grid_props.Layout()
         
     | 
| 
         @@ -1519,13 +1754,25 @@ class Matplotlib_Figure(wx.Frame): 
     | 
|
| 
       1519 
1754 
     | 
    
         | 
| 
       1520 
1755 
     | 
    
         
             
                    if event.key == 'escape':
         
     | 
| 
       1521 
1756 
     | 
    
         
             
                        self._axes_properties[int(self._ax_current.GetSelection())].reset_selection()
         
     | 
| 
      
 1757 
     | 
    
         
            +
                    elif event.key == 'shift':
         
     | 
| 
      
 1758 
     | 
    
         
            +
                        self._shiftdown = True
         
     | 
| 
      
 1759 
     | 
    
         
            +
                    elif event.key == 'enter':
         
     | 
| 
      
 1760 
     | 
    
         
            +
                        if self.action is not None:
         
     | 
| 
      
 1761 
     | 
    
         
            +
                            action, callback = self.action
         
     | 
| 
      
 1762 
     | 
    
         
            +
                            if action == 'Digitize':
         
     | 
| 
      
 1763 
     | 
    
         
            +
                                callback((0,0), 'End Digitize')
         
     | 
| 
      
 1764 
     | 
    
         
            +
             
     | 
| 
      
 1765 
     | 
    
         
            +
                def OnKeyRelease(self, event:KeyEvent):
         
     | 
| 
      
 1766 
     | 
    
         
            +
                    if event.key == 'shift':
         
     | 
| 
      
 1767 
     | 
    
         
            +
                        self._shiftdown = False
         
     | 
| 
       1522 
1768 
     | 
    
         | 
| 
       1523 
1769 
     | 
    
         
             
                def OnClickCanvas(self, event:MouseEvent):
         
     | 
| 
       1524 
1770 
     | 
    
         | 
| 
       1525 
1771 
     | 
    
         
             
                    rclick = event.button == 3
         
     | 
| 
       1526 
1772 
     | 
    
         
             
                    lclick = event.button == 1
         
     | 
| 
      
 1773 
     | 
    
         
            +
                    middle = event.button == 2
         
     | 
| 
       1527 
1774 
     | 
    
         | 
| 
       1528 
     | 
    
         
            -
                    if not rclick:
         
     | 
| 
      
 1775 
     | 
    
         
            +
                    if not (rclick or middle):
         
     | 
| 
       1529 
1776 
     | 
    
         
             
                        return
         
     | 
| 
       1530 
1777 
     | 
    
         | 
| 
       1531 
1778 
     | 
    
         
             
                    if event.inaxes:
         
     | 
| 
         @@ -1533,21 +1780,81 @@ class Matplotlib_Figure(wx.Frame): 
     | 
|
| 
       1533 
1780 
     | 
    
         
             
                        idx= ax.get_figure().axes.index(event.inaxes)
         
     | 
| 
       1534 
1781 
     | 
    
         
             
                        x, y = event.xdata, event.ydata
         
     | 
| 
       1535 
1782 
     | 
    
         | 
| 
       1536 
     | 
    
         
            -
                         
     | 
| 
       1537 
     | 
    
         
            -
             
     | 
| 
       1538 
     | 
    
         
            -
             
     | 
| 
       1539 
     | 
    
         
            -
             
     | 
| 
       1540 
     | 
    
         
            -
             
     | 
| 
       1541 
     | 
    
         
            -
             
     | 
| 
       1542 
     | 
    
         
            -
             
     | 
| 
       1543 
     | 
    
         
            -
             
     | 
| 
       1544 
     | 
    
         
            -
             
     | 
| 
       1545 
     | 
    
         
            -
                                 
     | 
| 
       1546 
     | 
    
         
            -
             
     | 
| 
       1547 
     | 
    
         
            -
             
     | 
| 
       1548 
     | 
    
         
            -
             
     | 
| 
       1549 
     | 
    
         
            -
             
     | 
| 
       1550 
     | 
    
         
            -
             
     | 
| 
      
 1783 
     | 
    
         
            +
                        if middle:
         
     | 
| 
      
 1784 
     | 
    
         
            +
                            if self.action is not None:
         
     | 
| 
      
 1785 
     | 
    
         
            +
                                action, callback = self.action
         
     | 
| 
      
 1786 
     | 
    
         
            +
                                if action == 'Digitize':
         
     | 
| 
      
 1787 
     | 
    
         
            +
                                    callback((0,0), 'End Digitize')
         
     | 
| 
      
 1788 
     | 
    
         
            +
             
     | 
| 
      
 1789 
     | 
    
         
            +
                        if rclick:
         
     | 
| 
      
 1790 
     | 
    
         
            +
             
     | 
| 
      
 1791 
     | 
    
         
            +
                            if self._shiftdown:
         
     | 
| 
      
 1792 
     | 
    
         
            +
                                # add a point to the current line, update the grid and plot
         
     | 
| 
      
 1793 
     | 
    
         
            +
                                xy = self.cur_line.get_xydata()
         
     | 
| 
      
 1794 
     | 
    
         
            +
             
     | 
| 
      
 1795 
     | 
    
         
            +
                                if xy.shape[0] == 1:
         
     | 
| 
      
 1796 
     | 
    
         
            +
                                    if self._keep_first_point:
         
     | 
| 
      
 1797 
     | 
    
         
            +
                                        xy = np.vstack((xy, [x,y]))
         
     | 
| 
      
 1798 
     | 
    
         
            +
                                    else:
         
     | 
| 
      
 1799 
     | 
    
         
            +
                                        xy = np.asarray([[x,y]])
         
     | 
| 
      
 1800 
     | 
    
         
            +
                                        self._keep_first_point = True
         
     | 
| 
      
 1801 
     | 
    
         
            +
                                else:
         
     | 
| 
      
 1802 
     | 
    
         
            +
                                    xy = np.vstack((xy, [x,y]))
         
     | 
| 
      
 1803 
     | 
    
         
            +
             
     | 
| 
      
 1804 
     | 
    
         
            +
                                self.cur_line.set_data(xy[:,0], xy[:,1])
         
     | 
| 
      
 1805 
     | 
    
         
            +
                                self.fill_grid_with_xy_np(self.cur_line_properties.get_xydata())
         
     | 
| 
      
 1806 
     | 
    
         
            +
                                self._canvas.draw()
         
     | 
| 
      
 1807 
     | 
    
         
            +
             
     | 
| 
      
 1808 
     | 
    
         
            +
                            if self.action is not None:
         
     | 
| 
      
 1809 
     | 
    
         
            +
             
     | 
| 
      
 1810 
     | 
    
         
            +
                                action, callback = self.action
         
     | 
| 
      
 1811 
     | 
    
         
            +
             
     | 
| 
      
 1812 
     | 
    
         
            +
                                if action == 'Digitize':
         
     | 
| 
      
 1813 
     | 
    
         
            +
                                    if not self._shiftdown:
         
     | 
| 
      
 1814 
     | 
    
         
            +
                                        logging.warning('Shift must be down to digitize')
         
     | 
| 
      
 1815 
     | 
    
         
            +
                                elif action == 'Ref X':
         
     | 
| 
      
 1816 
     | 
    
         
            +
                                    if not self._shiftdown:
         
     | 
| 
      
 1817 
     | 
    
         
            +
                                        logging.warning('Shift must be down to set X reference')
         
     | 
| 
      
 1818 
     | 
    
         
            +
                                    else:
         
     | 
| 
      
 1819 
     | 
    
         
            +
                                        callback((x,y), action)
         
     | 
| 
      
 1820 
     | 
    
         
            +
                                elif action == 'Ref Y':
         
     | 
| 
      
 1821 
     | 
    
         
            +
                                    if not self._shiftdown:
         
     | 
| 
      
 1822 
     | 
    
         
            +
                                        logging.warning('Shift must be down to set Y reference')
         
     | 
| 
      
 1823 
     | 
    
         
            +
                                    else:
         
     | 
| 
      
 1824 
     | 
    
         
            +
                                        callback((x,y), action)
         
     | 
| 
      
 1825 
     | 
    
         
            +
                                elif action == 'Origin':
         
     | 
| 
      
 1826 
     | 
    
         
            +
                                    if not self._shiftdown:
         
     | 
| 
      
 1827 
     | 
    
         
            +
                                        logging.warning('Shift must be down to set origin')
         
     | 
| 
      
 1828 
     | 
    
         
            +
                                    else:
         
     | 
| 
      
 1829 
     | 
    
         
            +
                                        callback((x,y), action)
         
     | 
| 
      
 1830 
     | 
    
         
            +
             
     | 
| 
      
 1831 
     | 
    
         
            +
                            elif not self._shiftdown:
         
     | 
| 
      
 1832 
     | 
    
         
            +
                                # Find the closest line and select it
         
     | 
| 
      
 1833 
     | 
    
         
            +
             
     | 
| 
      
 1834 
     | 
    
         
            +
                                lines = ax.get_lines()
         
     | 
| 
      
 1835 
     | 
    
         
            +
                                if len(lines) == 0:
         
     | 
| 
      
 1836 
     | 
    
         
            +
                                    logging.warning('No lines !')
         
     | 
| 
      
 1837 
     | 
    
         
            +
                                    return
         
     | 
| 
      
 1838 
     | 
    
         
            +
             
     | 
| 
      
 1839 
     | 
    
         
            +
                                dist_min = 1e6
         
     | 
| 
      
 1840 
     | 
    
         
            +
                                line_min = None
         
     | 
| 
      
 1841 
     | 
    
         
            +
             
     | 
| 
      
 1842 
     | 
    
         
            +
                                for line in lines:
         
     | 
| 
      
 1843 
     | 
    
         
            +
                                    xy = line.get_xydata()
         
     | 
| 
      
 1844 
     | 
    
         
            +
                                    if xy.shape[0] == 0:
         
     | 
| 
      
 1845 
     | 
    
         
            +
                                        continue
         
     | 
| 
      
 1846 
     | 
    
         
            +
             
     | 
| 
      
 1847 
     | 
    
         
            +
                                    dist = np.linalg.norm(xy - np.array([x,y]), axis=1)
         
     | 
| 
      
 1848 
     | 
    
         
            +
                                    idx_min = np.argmin(dist)
         
     | 
| 
      
 1849 
     | 
    
         
            +
                                    if dist[idx_min] < dist_min:
         
     | 
| 
      
 1850 
     | 
    
         
            +
                                        dist_min = dist[idx_min]
         
     | 
| 
      
 1851 
     | 
    
         
            +
                                        line_min = line
         
     | 
| 
      
 1852 
     | 
    
         
            +
             
     | 
| 
      
 1853 
     | 
    
         
            +
                                self._ax_current.SetSelection(idx)
         
     | 
| 
      
 1854 
     | 
    
         
            +
                                self._fill_lines_ax(idx = lines.index(line_min))
         
     | 
| 
      
 1855 
     | 
    
         
            +
                                self._axes_properties[idx].select_line(lines.index(line_min))
         
     | 
| 
      
 1856 
     | 
    
         
            +
             
     | 
| 
      
 1857 
     | 
    
         
            +
                                self.fill_grid_with_xy_np(self.cur_line_properties.get_xydata())
         
     | 
| 
       1551 
1858 
     | 
    
         | 
| 
       1552 
1859 
     | 
    
         
             
                        self.show_curline_properties()
         
     | 
| 
       1553 
1860 
     | 
    
         | 
| 
         @@ -1572,6 +1879,27 @@ class Matplotlib_Figure(wx.Frame): 
     | 
|
| 
       1572 
1879 
     | 
    
         
             
                        grid.SetCellValue(i, colx, str(xy[i,0]))
         
     | 
| 
       1573 
1880 
     | 
    
         
             
                        grid.SetCellValue(i, coly, str(xy[i,1]))
         
     | 
| 
       1574 
1881 
     | 
    
         | 
| 
      
 1882 
     | 
    
         
            +
                def fill_grid_with_xy_np(self, xy:np.ndarray, grid:CpGrid = None, colx:int= 0, coly:int= 1):
         
     | 
| 
      
 1883 
     | 
    
         
            +
             
     | 
| 
      
 1884 
     | 
    
         
            +
                    if grid is None:
         
     | 
| 
      
 1885 
     | 
    
         
            +
                        grid = self._xls
         
     | 
| 
      
 1886 
     | 
    
         
            +
             
     | 
| 
      
 1887 
     | 
    
         
            +
                    grid.ClearGrid()
         
     | 
| 
      
 1888 
     | 
    
         
            +
             
     | 
| 
      
 1889 
     | 
    
         
            +
                    if grid.GetNumberRows() < len(xy):
         
     | 
| 
      
 1890 
     | 
    
         
            +
                        grid.AppendRows(len(xy)-grid.GetNumberRows())
         
     | 
| 
      
 1891 
     | 
    
         
            +
                    elif grid.GetNumberRows() > len(xy):
         
     | 
| 
      
 1892 
     | 
    
         
            +
                        grid.DeleteRows(len(xy), grid.GetNumberRows()-len(xy))
         
     | 
| 
      
 1893 
     | 
    
         
            +
             
     | 
| 
      
 1894 
     | 
    
         
            +
                    for i in range(len(xy)):
         
     | 
| 
      
 1895 
     | 
    
         
            +
                        grid.SetCellValue(i, colx, str(xy[i,0]))
         
     | 
| 
      
 1896 
     | 
    
         
            +
                        grid.SetCellValue(i, coly, str(xy[i,1]))
         
     | 
| 
      
 1897 
     | 
    
         
            +
             
     | 
| 
      
 1898 
     | 
    
         
            +
                def get_xy_from_grid(self):
         
     | 
| 
      
 1899 
     | 
    
         
            +
                    """ Get the xy from the grid """
         
     | 
| 
      
 1900 
     | 
    
         
            +
             
     | 
| 
      
 1901 
     | 
    
         
            +
                    return self._get_xy_from_grid(self._xls)
         
     | 
| 
      
 1902 
     | 
    
         
            +
             
     | 
| 
       1575 
1903 
     | 
    
         
             
                def update_line_from_grid(self, event):
         
     | 
| 
       1576 
1904 
     | 
    
         | 
| 
       1577 
1905 
     | 
    
         
             
                    line = self.cur_line
         
     | 
| 
         @@ -1588,7 +1916,8 @@ class Matplotlib_Figure(wx.Frame): 
     | 
|
| 
       1588 
1916 
     | 
    
         
             
                        xy[i,0] = float(self._xls.GetCellValue(i, 0))
         
     | 
| 
       1589 
1917 
     | 
    
         
             
                        xy[i,1] = float(self._xls.GetCellValue(i, 1))
         
     | 
| 
       1590 
1918 
     | 
    
         | 
| 
       1591 
     | 
    
         
            -
                     
     | 
| 
      
 1919 
     | 
    
         
            +
                    self.cur_line_properties.set_xydata(xy)
         
     | 
| 
      
 1920 
     | 
    
         
            +
                    self._canvas.draw()
         
     | 
| 
       1592 
1921 
     | 
    
         
             
                    self.update_layout()
         
     | 
| 
       1593 
1922 
     | 
    
         | 
| 
       1594 
1923 
     | 
    
         
             
                def add_row_to_grid(self, event):
         
     | 
| 
         @@ -1609,6 +1938,23 @@ class Matplotlib_Figure(wx.Frame): 
     | 
|
| 
       1609 
1938 
     | 
    
         
             
                    xy = self._get_xy_from_grid(self._xls)
         
     | 
| 
       1610 
1939 
     | 
    
         
             
                    self.add_line(xy, self.cur_ax)
         
     | 
| 
       1611 
1940 
     | 
    
         | 
| 
      
 1941 
     | 
    
         
            +
                def onnew_line(self, event):
         
     | 
| 
      
 1942 
     | 
    
         
            +
                    """ Add a plot to the current ax """
         
     | 
| 
      
 1943 
     | 
    
         
            +
                    self.new_line()
         
     | 
| 
      
 1944 
     | 
    
         
            +
             
     | 
| 
      
 1945 
     | 
    
         
            +
                def new_line(self, ax:Axes=None, **kwargs) -> Matplolib_line_properties:
         
     | 
| 
      
 1946 
     | 
    
         
            +
                    """ Add a plot to the current ax """
         
     | 
| 
      
 1947 
     | 
    
         
            +
             
     | 
| 
      
 1948 
     | 
    
         
            +
                    curline = self.cur_line
         
     | 
| 
      
 1949 
     | 
    
         
            +
                    if curline is not None:
         
     | 
| 
      
 1950 
     | 
    
         
            +
                        xy = curline.get_xydata()
         
     | 
| 
      
 1951 
     | 
    
         
            +
                        xy = np.asarray([[xy[0,0],xy[0,1]]])
         
     | 
| 
      
 1952 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 1953 
     | 
    
         
            +
                        xy = np.asarray([[0,0]])
         
     | 
| 
      
 1954 
     | 
    
         
            +
             
     | 
| 
      
 1955 
     | 
    
         
            +
                    self._keep_first_point = False
         
     | 
| 
      
 1956 
     | 
    
         
            +
                    return self.add_line(xy, ax, **kwargs)
         
     | 
| 
      
 1957 
     | 
    
         
            +
             
     | 
| 
       1612 
1958 
     | 
    
         
             
                def _get_xy_from_grid(self, grid:CpGrid, colx:int= 0, coly:int= 1):
         
     | 
| 
       1613 
1959 
     | 
    
         
             
                    """ Get the xy from a grid """
         
     | 
| 
       1614 
1960 
     | 
    
         | 
| 
         @@ -1627,7 +1973,7 @@ class Matplotlib_Figure(wx.Frame): 
     | 
|
| 
       1627 
1973 
     | 
    
         | 
| 
       1628 
1974 
     | 
    
         
             
                    return xy
         
     | 
| 
       1629 
1975 
     | 
    
         | 
| 
       1630 
     | 
    
         
            -
                def add_line(self, xy:np.ndarray, ax:Axes=None, **kwargs):
         
     | 
| 
      
 1976 
     | 
    
         
            +
                def add_line(self, xy:np.ndarray, ax:Axes=None, **kwargs) -> Matplolib_line_properties:
         
     | 
| 
       1631 
1977 
     | 
    
         
             
                    """ Add a plot to the current ax """
         
     | 
| 
       1632 
1978 
     | 
    
         | 
| 
       1633 
1979 
     | 
    
         
             
                    ax, idx_ax = self.get_ax_idx(ax)
         
     | 
| 
         @@ -1637,23 +1983,44 @@ class Matplotlib_Figure(wx.Frame): 
     | 
|
| 
       1637 
1983 
     | 
    
         
             
                    cur_ax_prop:Matplotlib_ax_properties = self._axes_properties[idx_ax]
         
     | 
| 
       1638 
1984 
     | 
    
         
             
                    cur_ax_prop._lines.append(Matplolib_line_properties(ax.get_lines()[-1], cur_ax_prop))
         
     | 
| 
       1639 
1985 
     | 
    
         
             
                    cur_ax_prop._lines[-1].add_props_to_sizer(self._collaps_pane.GetPane(), self._sizer_grid_props)
         
     | 
| 
      
 1986 
     | 
    
         
            +
             
     | 
| 
      
 1987 
     | 
    
         
            +
                    self._fill_lines_ax(len(ax.get_lines())-1)
         
     | 
| 
      
 1988 
     | 
    
         
            +
             
     | 
| 
       1640 
1989 
     | 
    
         
             
                    self.update_layout()
         
     | 
| 
      
 1990 
     | 
    
         
            +
                    self._canvas.SetFocus()
         
     | 
| 
      
 1991 
     | 
    
         
            +
             
     | 
| 
      
 1992 
     | 
    
         
            +
                    return self.cur_ax_properties._lines[-1]
         
     | 
| 
      
 1993 
     | 
    
         
            +
             
     | 
| 
      
 1994 
     | 
    
         
            +
                def add_image(self, image:np.ndarray | str, ax:Axes= None, **kwargs):
         
     | 
| 
      
 1995 
     | 
    
         
            +
             
     | 
| 
      
 1996 
     | 
    
         
            +
                    ax, idx_ax = self.get_ax_idx(ax)
         
     | 
| 
      
 1997 
     | 
    
         
            +
             
     | 
| 
      
 1998 
     | 
    
         
            +
                    if isinstance(image, str):
         
     | 
| 
      
 1999 
     | 
    
         
            +
                        image = ImageOps.flip(Image.open(image))
         
     | 
| 
      
 2000 
     | 
    
         
            +
                        ax.axis('off')  # clear x-axis and y-axis
         
     | 
| 
      
 2001 
     | 
    
         
            +
             
     | 
| 
      
 2002 
     | 
    
         
            +
                    ax.imshow(image, **kwargs)
         
     | 
| 
      
 2003 
     | 
    
         
            +
             
     | 
| 
      
 2004 
     | 
    
         
            +
                    self.update_layout()
         
     | 
| 
      
 2005 
     | 
    
         
            +
                    self._canvas.SetFocus()
         
     | 
| 
       1641 
2006 
     | 
    
         | 
| 
       1642 
2007 
     | 
    
         
             
                def ondel_line(self, event):
         
     | 
| 
       1643 
2008 
     | 
    
         
             
                    """ Remove a plot from the current ax """
         
     | 
| 
       1644 
2009 
     | 
    
         | 
| 
      
 2010 
     | 
    
         
            +
                    if self._line_current.GetSelection() == -1:
         
     | 
| 
      
 2011 
     | 
    
         
            +
                        return
         
     | 
| 
      
 2012 
     | 
    
         
            +
             
     | 
| 
       1645 
2013 
     | 
    
         
             
                    dlg = wx.MessageDialog(self, _('Do you want to remove the selected line?\n\nSuch action is irrevocable !\n\nPlease consider to set "Visible" to "False" to hide data'), _('Remove line'), wx.YES_NO | wx.ICON_QUESTION | wx.NO_DEFAULT)
         
     | 
| 
       1646 
2014 
     | 
    
         | 
| 
       1647 
2015 
     | 
    
         
             
                    ret = dlg.ShowModal()
         
     | 
| 
       1648 
2016 
     | 
    
         
             
                    if ret == wx.ID_NO:
         
     | 
| 
       1649 
2017 
     | 
    
         
             
                        return
         
     | 
| 
       1650 
2018 
     | 
    
         | 
| 
       1651 
     | 
    
         
            -
                    if self._line_current.GetSelection() == -1:
         
     | 
| 
       1652 
     | 
    
         
            -
                        return
         
     | 
| 
       1653 
     | 
    
         
            -
             
     | 
| 
       1654 
2019 
     | 
    
         
             
                    idx = self._line_current.GetSelection()
         
     | 
| 
       1655 
2020 
     | 
    
         
             
                    self.del_line(idx)
         
     | 
| 
       1656 
2021 
     | 
    
         | 
| 
      
 2022 
     | 
    
         
            +
                    self._fill_lines_ax()
         
     | 
| 
      
 2023 
     | 
    
         
            +
             
     | 
| 
       1657 
2024 
     | 
    
         
             
                def del_line(self, idx:int):
         
     | 
| 
       1658 
2025 
     | 
    
         
             
                    """ Delete a line """
         
     | 
| 
       1659 
2026 
     | 
    
         |