diff --git a/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer0_elementary/images/.$MLPro-BF-Plot_class_diagram.drawio.bkp b/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer0_elementary/images/.$MLPro-BF-Plot_class_diagram.drawio.bkp
new file mode 100644
index 000000000..ae530c13c
--- /dev/null
+++ b/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer0_elementary/images/.$MLPro-BF-Plot_class_diagram.drawio.bkp
@@ -0,0 +1 @@
+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
\ No newline at end of file
diff --git a/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer0_elementary/images/MLPro-BF-Plot_class_diagram.drawio b/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer0_elementary/images/MLPro-BF-Plot_class_diagram.drawio
index a0e9cd6df..a4625b332 100644
--- a/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer0_elementary/images/MLPro-BF-Plot_class_diagram.drawio
+++ b/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer0_elementary/images/MLPro-BF-Plot_class_diagram.drawio
@@ -1 +1 @@
-7V1pc5s6F/41nvbeGWdYvH70kuRN46RunLVfGBmETYMRZYnt/vpXAoHBEg6OwelNSDOpEVjb85yjoyNxVJMHi9W5A+z5FdKgWZMEbVWThzVJkgSxgf8jKeswRZTkVpgycwyNpm0SJsYfSBMFmuobGnRTD3oImZ5hpxNVZFlQ9VJpwHHQMv2Yjsx0qTaYQSZhogKTTX0wNG9OGyZHzSA3/geN2TwqutWkTZ4C9XnmIN+iBVrIguGdBYjyoY1050BDy0SSfFqTBw5CXvhpsRpAk3Rs1GUPF+sHc/TcOv/2w/0N7vqXt9f39TCzs32+ErfOgZb35qxXt6fz+7tL+6nRfrgZPD7Jj+Pnukzzdr111JdQw11LL5HjzdEMWcA83aT2g+6CJFsBX22eGSFk40QRJ/6CnremPAG+h3DS3FuY9K6OLG+ATOTgaw3qwDdxs/rQ0nqECzhxaiL1OUw6M8zoazm7IWoS8h2Vtgmd9QY396fd58upNO/rxqnkP9HuEjzgzKC3o48i/EnHJOhGe/kcogX0nDV+wIEm8IyXNCcBpfYsfm6DEf5AYeJDtqvaL8D0aUljE3kemJqQwdJdGgsTWJD2eQSrjK+Bacws/FnFnQkxEP0X6HgGFqkeveERMPvq3DC1EVgjn3SR62Fxia76c+QYf3C2IAII33Y8irrUSj0xId+kjHGgi58ZRziKcdIIuB59RkWmCWzXmAYVJo8sME6G1cdNRYsooxQRY/kMq+Kg51gZBKTDRIpIV5NkDcCOrsZPJu601A6c6uQO7b2z9DfPgh98f+YAzYAbKifv7cdV0vdwtZNc9G6Dwk81dSO6Xm7UnizQtHlS4wkdIZuQtLgbrJuBNSNEisrDuaUKFDkFii1OgVIrXRwwMc0s4ME+Ac1lxCBuai7J6Dntn1d2e/gw/A0fliNV7T36HMkYKOPR91ulN7i9uD/Ft2pyj+h8PDTVBlKtJzACg1HwEsJhQt3LFA3XBqphzUbBM8PGJuWG9gJJQvi7uhnQcm5oGrQC2noglNeQuDYyLC/opmYf/+JaDYSTZq2JKzTA1+LmGv+Sxx1MOQvzFhgBuSAWmyUkopPSrDXCBEHIoONO3fI6HddplF+jn7yDfHm1IVc5i1IW6JPb3vWwN/p+vQU8ucCPCbeOzyrMCv/98G++O/6dLPzve6OLoXJ/cfowiQlgGriXIgIEvT2sKHAgBTrvToFuFgWGp2e9u9FtQIIK5wNxFsUjAi2c/1HaF7I7VUaz7w8/W41ny4uNpQ3Oyovh+hjBP3BLx39grDcTptKQbhwR6cvVhXCqXfwS7r9PjJv+uP5N4c1xFBtPchTXg7aiYgOSTFkixElvVYAfBHj7iIA3lvLj1fTp4faH5T8Nmp1OUzuvs1ZcCDjOfY7IbIFirRlqBfaBJrvw3gO2nIW2Cz0PQ7GBm3g2JnFiBfshsMtHhH38gHruyn/6vX5u25ryKAzk60yljpaWohsz36kG8UJn5kfE++dMugPw959e/fe3y/l6cSWvp5l4G5bhGYHRplWAFwh494iA38xbYPWtf99D94Pm+vpbv94TeIBvyfUZvayAPgBo+ZhON26V2fGbgdQ0glWHxKIP65F/Be8FRi5Yb6IA3warS3WRIYHMkkDmAG6CKTTHyMXaB5H8nfDZLSK8hnVpqOZ1pXUOB5U7u+ZIb6CqFeUraXDmVJt6086A6ZJb/1TSfRgPWo3jSff50xzqQ3t+Lde7C0d0F2vB4hBhBr20gf4VoyzUa1JrFnZFZagXSIBuTgJsr7AVRgDWz+YyBAhUQp5JW6UQDuRDI9p/cAw+cKssM3wIxgWCfsgDauXJPWrfycPrYBvNgHCCVEsWCQTRmqtwyIecrAsHpaAawdcqFh7Iwrw+4UYBw9LlfUO/q/fc76vx3Wx4edtbjn9mDEuRVQKIUccMS9W08nDg867vFaF+uO7C1o7hiKwHOMCDoR6KLxMLA5XkH7rEH22xeDd/Mbu+GxNAgx4wTMWEL9AMOZBMqWhQIA0aR6TB07DevV1dtOF5Wz/roqb80+/XG+wENbBDQuuD0f2fwNd0lB0+7SPifnUjCCbw2y1JEH+g7g912f/BGfh15KhQ0WdfP5dQM6DlxTsT3JaQE9wiBncuuJw9HRW6RaEb+QrfDV3WUexA3YHuPDl5RME2/V5gq8vDz+lHLAH85hHdSFzwWbeBkkK/QvhAhKMd/e82M+MsGcSeIUXS+M6hUrxC+TxHsdPo8/kpj2EqtnPvLOoeTkjuNjKONbEhpFwR8rMRstHMR8ginJZcQu7UkFZFyM9GyM4RCcmtMutE8W0NeDA2yP/911ael8D5BIiX7zTrSDnxLsJE4+6k5xjhCcBjIy0h92mhH7yHHtrx4RPR8ygvbzXF45lsXIKyLoIUQeWKoJ+boN2ck9wiRkz+2wq7CWpVBP3UBO3KRyQo18/GmnQOXOBeT/hYqd9t42UNX37/4PCX74Lrto/oguOC32S1UwJ9Yt99bIxZES8B5bxvVpSGMrsFJoWyXKF8OMqiIL33Ymh7N8xWBXMRMDeOuCo6MTyt8Xh300T+uWb4wvOztKqzIUsYVElIOptt714xpOJwexS4WjJsHS+2VDuK4xRt/WMHt0aH11FSAaYNt6fYnV/YmDYj2gQtjJjT+u2jcKgPOEQA3SQJbhSyMEoTk7ejPUNh1tMUFNFTpMB6mA1xjYoNe8VmMYIzSCIJ9uK8nO3ccT9MOWlhe7Yqwnw5T8prPaPr6Z55raUtXkN3to/XFqxoLG5ptJ6kJGc2/RrMUwIHeOLTP9kVoK19tRVcuPD/YEEUozV17bA72KSsZqUeuyCNsx00w2a2myvbQpOC4rGUGFqwD/rIFbiBQCNqxEP4j092b8R9FsK+H0HTopuF1J78208qipDDVEqq8sDzHGPqe8GbdFg/SkIY5oKM7sWhdA2XhJP+1DRUops3hZ6FxUWITUk9jIVtwgWJBantrZWKBPSN8PGK2NnNCaUUl1QjXs5UVbYeKAabAJgzw5pDxwi6+zWQ5oC03XC3YcKDsAOzYSlWElJNUJi+LRRNXhWU/WSEsh8brtgACjor6s+zZN3/HgFgu1R4S5PTvEo0/+qd6JTR9qIUa97K8mdNidfTc02glnPcsxM8ZyLZLB1A0tJBaJnpTKslkHQmyiztm62wtVtBavXgJ25Aciqwc2bxuvfy/Wz6KGZ4wqgfQhsGMWEFYrtsQcUJC52ALeul/gi/0db9OKhA3uAD6RDUQRTlcC4hSnvj8moEaYpZXWxGyx50KlaXRM5uvyYHuOYO3GiBYxS+EkNL6550u91W/K+dKliUhBNBkAWx2Wnjvy1hK6x1GGWb5rhhBlNIs3HSaXTE6F9b3quUMEb366V0t4IjIF13YeormEpgnXiCejIyO2c7/DEVi40AhBluxGG/OMZ8CWG3sV2EWp2IiO6gxd8rJMKnFBJZOpE7jZYgi23yt1GKjOwuZF8RWSf6eJfAFEZqdqGfYXEVrj4zXL3eUaHKDVc/7TQbTZIhJxx9bD9khLIvz76I7r7uUeRtNtni9n86VD1fGthdBYw0fKIQSrs1xiHR6Hn0KiCCEr/C7Ep8peL2UHG6LvFVnNaatpqtv1XFVTouQxzYvQmVjstSGf8ZHcduRah0XKGnDv2NOq6y47LEgd2yUem4LJXxF+q4c81UX5B9v+r8elhIFy+iOOdFwhw7yMa1J1VUTeAGbhgsfARmYGnA0WgwY7JNh9zzLZX0LEbVW5+wXupTi2Dhxt83g2hpAv5I/B+LKdS0ODuyi5iTxQQG3zBdRGNx6nXfqLuq4RsMATcKS8zwYSfP5ivCKIuPQUs7txODAYf0aSZLmYMDS7tijlaTpbTekVus3pF4G4W6O7xJeYmoTx4XZ/+7WDxNfjuWd9vT/cc7DhGHWIzHlBX4ztepfvICHAP57skIAW0CXiC7Rawajwsejzf0fuWEwLKo2t3yfOY+BlDuSh9oSP4lDS6fz//Uu8ovaT6uPy276Db7FMDbp/GpMniqRcEhvwzWqmmoXxh5+a9vqWRZt1O7FH7Yn7TD7MurD7nQsusiSWhPxxtoT23DRVoF7h5xvvK+yVAWuOz6QBpc5YqFt0b2NQCrQjl/RITjocytMSvCn3m+VAyo3Zwb2guYL3ErzEpufHKArWi4I2tRkGZivk48bA4S65Uf5aLQv7birW1Sp+1xosCXMm1laVjU5BSEgrN252hJOit6Y6/YyCC2YmMovLCAOGR3yYjoxozuxv/axuW1/ym4y6KdaF/wvPx5iin55RitCjkQ0e2LCxa43ODex3tlpyw9JuaNHyWWZoSwy7LR2RfuB3z3qrSJQt53okvDkV16CjAM5FNR1xWW+bHMHUeyLCzZVfUEltCusMyPZTvvq49lmf+sfk1hqSzwbK4CNP9ZQbnjN5cFKCucC/SCOztE0sbzANv3wigosZVU4Vv4UX9FvKvMrTI7kLqAvo/uYnhtgKtFwdWRsyCvloRXmm0oCz+YwVd45z8EMKc8FxFMhltldnvHOFzTxIhByw1eLqVrn9FK6FQ/IZP8k8Tk/gQnZyxyBswh3wJusMYZZHgFPJJuGtMThivV6mW+bWhSFIsm4hJnLzx3jaZdAJe4kbOi9dQtMmWeE1itUx6yTvnaWuQuopdFypaQ5mTudcpm5yNtHeJKB2d75EC5vzh9UKThtl8rXPWQhh9voSNvPNbdCqbwJczSzrLi7J+kqMsZqMsV6oeinvdo5fJQZ7cJUtSvM1C/rlA/FPW8BxeWdmAZbyfKfW90MQygn0TAVygfgrIovrdwS2yUqhcjCD8RLnriXvpwIJcHZ95zZovwaPHrzIZnAyu4OWh4sZmrkvSTXnCzwjcnvrkjppaGL8cHjVxlFQMcvUFd4ZkHz9yn1ZeGJ2tbETzXFZ5vmiCJR1wiEupLR/qmdsW+pP88t59nxvmAs0OMOFsq+XwjnnmP7S0NT9YKDvCs5PONDowj2kdcPCUWz/jY9QrSt0Ca94iL0iDlr8orGrTJ6l6F6f6YyuIRzSIupuzCvAY9YJiKCV+gWaH6JlTlIxpHL5bU7A1Ua61N5zemdKVPLq85gyl+vMLyLVi2jmgY8Q8WYsGMz+UJAdUMtUI0P6J5Hb7lTUWrt1tKwLUh5rSPCni/hV9lzvEr0QsupMkK6+4t4wRXW0n5IXvRBa6PEL+8UUKpHO8YLVUs4XSzsLz1EcvjuRfKL/CoLeRP0MpFMWMGQQsVSik028QttdhtG6zEjv3gp/eVOIjkNN3F1v5bafGlg0iE883+IAfY8yukQfLE/wE=
\ No newline at end of file
+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
\ No newline at end of file
diff --git a/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer0_elementary/images/MLPro-BF-Plot_class_diagram.drawio.png b/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer0_elementary/images/MLPro-BF-Plot_class_diagram.drawio.png
index 082030af4..2e9433b72 100644
Binary files a/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer0_elementary/images/MLPro-BF-Plot_class_diagram.drawio.png and b/doc/rtd/content/99_appendices/appendix2/sub/core/mlpro_bf/layer0_elementary/images/MLPro-BF-Plot_class_diagram.drawio.png differ
diff --git a/src/mlpro/bf/math/geometry/hypercuboid.py b/src/mlpro/bf/math/geometry/hypercuboid.py
index 984d142a9..48e410d0b 100644
--- a/src/mlpro/bf/math/geometry/hypercuboid.py
+++ b/src/mlpro/bf/math/geometry/hypercuboid.py
@@ -8,10 +8,11 @@
## -- 2024-05-29 0.0.0 DA Creation
## -- 2024-06-03 1.0.0 DA First implementation
## -- 2024-06-05 1.0.1 DA Stabilization of Hypercuboid.set()
+## -- 2024-06-26 1.1.0 DA Refactoring of attribute color
## -------------------------------------------------------------------------------------------------
"""
-Ver. 1.0.1 (2024-06-05)
+Ver. 1.1.0 (2024-06-26)
This module provides a property class for the geometric shape 'hypercuboid'.
@@ -79,7 +80,6 @@ def __init__( self,
p_properties = p_properties,
p_visualize = p_visualize )
- self.color = self.C_PLOT_COLOR
self.alpha = self.C_PLOT_ALPHA
self.fill = self.C_PLOT_FILL
self.linewidth = self.C_PLOT_LINEWIDTH
@@ -139,35 +139,40 @@ def _update_plot_2d(self, p_settings: PlotSettings, **p_kwargs):
if self.value is None: return
boundaries = self.value
center_geo = self.center_geo.value
+
+
+ # 2 Determine the color of the cuboid
+ if self.color is None: self.color = self.C_PLOT_COLOR
+ color = self.color
self.center_geo.color = self.color
if self._plot_2d_rectangle is None:
- # 2 Init all plot objects
+ # 3 Init all plot objects
- # 2.1 Init 2d rectangle
+ # 3.1 Init 2d rectangle
self._plot_2d_rectangle = Rectangle( xy = ( boundaries[0][0], boundaries[1][0] ),
width = boundaries[0][1] - boundaries[0][0],
height = boundaries[1][1] - boundaries[1][0],
fill = self.fill,
- edgecolor = self.color,
- color = self.color,
- facecolor = self.color,
+ edgecolor = color,
+ color = color,
+ facecolor = color,
linewidth = self.linewidth,
visible = True,
alpha = self.alpha )
p_settings.axes.add_patch(self._plot_2d_rectangle)
- # 2.2 Init 2d crosshair through the geometric center
+ # 3.2 Init 2d crosshair through the geometric center
self._plot_line1 = p_settings.axes.plot( [ center_geo[0], center_geo[0] ],
[ boundaries[1][0], boundaries[1][1] ],
- color = self.color,
+ color = color,
linestyle = 'dashed',
lw = 0.5 )[0]
self._plot_line2 = p_settings.axes.plot( [ boundaries[0][0], boundaries[0][1] ],
[ center_geo[1], center_geo[1] ],
- color = self.color,
+ color = color,
linestyle = 'dashed',
lw = 0.5 )[0]
@@ -179,9 +184,9 @@ def _update_plot_2d(self, p_settings: PlotSettings, **p_kwargs):
width = boundaries[0][1] - boundaries[0][0],
height = boundaries[1][1] - boundaries[1][0] )
- self._plot_2d_rectangle.set( edgecolor = self.color,
- facecolor = self.color,
- color = self.color )
+ self._plot_2d_rectangle.set( edgecolor = color,
+ facecolor = color,
+ color = color )
# 3.2 Update crosshair lines
self._plot_line1.set_data( [ center_geo[0], center_geo[0] ],
@@ -189,8 +194,8 @@ def _update_plot_2d(self, p_settings: PlotSettings, **p_kwargs):
self._plot_line2.set_data( [ boundaries[0][0], boundaries[0][1] ],
[ center_geo[1], center_geo[1] ] )
- self._plot_line1.set( color = self.color )
- self._plot_line2.set( color = self.color )
+ self._plot_line1.set( color = color )
+ self._plot_line2.set( color = color )
## -------------------------------------------------------------------------------------------------
@@ -200,17 +205,22 @@ def _update_plot_3d(self, p_settings: PlotSettings, **p_kwargs):
if self.value is None: return
b = self.value
center_geo = self.center_geo.value
- self.center_geo.color = self.color
+
+ # 2 Determine the color of the cuboid
+ if self.color is None: self.color = self.C_PLOT_COLOR
+ color = self.color
+ self.center_geo.color = self.color
+
if self._plot_3d_polycollection is None:
- # 2 Init all plot objects
+ # 3 Init all plot objects
- # 2.1 Init 3d cuboid
+ # 3.1 Init 3d cuboid
self._plot_3d_polycollection = Poly3DCollection( verts= [],
linewidths=self.linewidth,
- edgecolors=self.color,
- facecolors=self.color,
+ edgecolors=color,
+ facecolors=color,
alpha = self.alpha )
self._plot_settings.axes.add_collection(self._plot_3d_polycollection)
@@ -219,19 +229,19 @@ def _update_plot_3d(self, p_settings: PlotSettings, **p_kwargs):
self._plot_line1 = p_settings.axes.plot( [ center_geo[0], center_geo[0] ],
[ center_geo[1], center_geo[1] ],
[ b[2][0], b[2][1] ],
- color = self.color,
+ color = color,
linestyle = 'dashed',
lw = 0.5 )[0]
self._plot_line2 = p_settings.axes.plot( [ center_geo[0], center_geo[0] ],
[ b[1][0], b[1][1] ],
[ center_geo[2], center_geo[2] ],
- color = self.color,
+ color = color,
linestyle = 'dashed',
lw = 0.5 )[0]
self._plot_line3 = p_settings.axes.plot( [ b[0][0], b[0][1] ],
[ center_geo[1], center_geo[1] ],
[ center_geo[2], center_geo[2] ],
- color = self.color,
+ color = color,
linestyle = 'dashed',
lw = 0.5 )[0]
@@ -247,9 +257,9 @@ def _update_plot_3d(self, p_settings: PlotSettings, **p_kwargs):
[ center_geo[1], center_geo[1] ],
[ center_geo[2], center_geo[2] ] )
- self._plot_line1.set( color = self.color )
- self._plot_line2.set( color = self.color )
- self._plot_line3.set( color = self.color )
+ self._plot_line1.set( color = color )
+ self._plot_line2.set( color = color )
+ self._plot_line3.set( color = color )
# 4 Update the 3d cuboid
@@ -285,8 +295,8 @@ def _update_plot_3d(self, p_settings: PlotSettings, **p_kwargs):
self._plot_3d_polycollection.set_verts(verts)
- self._plot_3d_polycollection.set( edgecolor = self.color,
- facecolor = self.color )
+ self._plot_3d_polycollection.set( edgecolor = color,
+ facecolor = color )
## -------------------------------------------------------------------------------------------------
diff --git a/src/mlpro/bf/math/geometry/point.py b/src/mlpro/bf/math/geometry/point.py
index d866d4775..7092e8050 100644
--- a/src/mlpro/bf/math/geometry/point.py
+++ b/src/mlpro/bf/math/geometry/point.py
@@ -19,10 +19,11 @@
## -- 2024-05-31 1.7.1 DA Improved the stability of the plot methods
## -- 2024-06-03 1.8.0 DA Class Point: new attributes color, marker
## -- 2024-06-05 1.8.1 DA Bugfix in Point._remove_plot_2d()
+## -- 2024-06-26 1.9.0 DA Refactoring
## -------------------------------------------------------------------------------------------------
"""
-Ver. 1.8.1 (2024-06-05)
+Ver. 1.9.0 (2024-06-26)
This module provides a property class for the geometric shape 'point'.
@@ -65,7 +66,6 @@ class Point (Property):
def init_plot(self, p_figure: Figure = None, p_plot_settings: PlotSettings = None, **p_kwargs):
self._plot_pos = None
self._plot_vel = None
- self.color = self.C_PLOT_COLOR
self.marker = self.C_PLOT_MARKER
super().init_plot(p_figure, p_plot_settings, **p_kwargs)
@@ -80,10 +80,15 @@ def _update_plot_2d(self, p_settings: PlotSettings, **p_kwargs):
if self._plot_pos is not None:
self._plot_pos.remove()
+ if self.color is not None:
+ color = self.color
+ else:
+ color = self.C_PLOT_COLOR
+
self._plot_pos, = p_settings.axes.plot( point_pos[0],
point_pos[1],
marker=self.marker,
- color=self.color,
+ color=color,
linestyle='',
markersize=3 )
@@ -100,7 +105,7 @@ def _update_plot_2d(self, p_settings: PlotSettings, **p_kwargs):
point_pos[1],
point_vel[0],
point_vel[1],
- color=self.color )
+ color=color )
## -------------------------------------------------------------------------------------------------
@@ -113,11 +118,16 @@ def _update_plot_3d(self, p_settings: PlotSettings, **p_kwargs):
if self._plot_pos is not None:
self._plot_pos.remove()
+ if self.color is not None:
+ color = self.color
+ else:
+ color = self.C_PLOT_COLOR
+
self._plot_pos, = p_settings.axes.plot( point_pos[0],
point_pos[1],
point_pos[2],
marker=self.marker,
- color=self.color,
+ color=color,
linestyle='',
markersize=3 )
@@ -140,7 +150,7 @@ def _update_plot_3d(self, p_settings: PlotSettings, **p_kwargs):
np.array([point_vel[2]]),
length = len,
normalize = True,
- color=self.color )
+ color=color )
## -------------------------------------------------------------------------------------------------
diff --git a/src/mlpro/bf/math/properties.py b/src/mlpro/bf/math/properties.py
index 6e808737d..a80a0b911 100644
--- a/src/mlpro/bf/math/properties.py
+++ b/src/mlpro/bf/math/properties.py
@@ -33,10 +33,11 @@
## -- 2024-06-05 1.1.0 DA New method Properties.replace_property()
## -- 2024-06-06 1.2.0 DA New custom method Properties._update_property_links()
## -- 2024-06-16 1.3.0 DA New method Properties.get_property_definitions()
+## -- 2024-06-26 1.4.0 DA New method Properties.set_plot_color()
## -------------------------------------------------------------------------------------------------
"""
-Ver. 1.3.0 (2024-06-16)
+Ver. 1.4.0 (2024-06-26)
This module provides a systematics for enriched managed properties. MLPro's enriched properties
store any data like class attributes and they can be used like class attributes. They extend the
@@ -428,16 +429,31 @@ def set_plot_settings(self, p_plot_settings : PlotSettings ):
if not link:
prop.set_plot_settings( p_plot_settings = p_plot_settings )
-
+
+## -------------------------------------------------------------------------------------------------
+ def set_plot_color(self, p_color : str):
+
+ Plottable.set_plot_color( self, p_color = p_color )
+
+ for (prop, link) in self.get_properties().values():
+ if not link:
+ prop.set_plot_color( p_color = p_color )
+
+
## -------------------------------------------------------------------------------------------------
def init_plot(self, p_figure: Figure = None, p_plot_settings: PlotSettings = None):
if not self.get_visualization(): return
Plottable.init_plot(self, p_figure = p_figure, p_plot_settings = p_plot_settings )
+ try:
+ if not self._plot_initialized: return
+ except:
+ return
for (prop, link) in self.get_properties().values():
- if not link: prop.init_plot( p_figure = self._figure, p_plot_settings = p_plot_settings)
+ if not link:
+ prop.init_plot( p_figure = self._figure, p_plot_settings = p_plot_settings)
## -------------------------------------------------------------------------------------------------
@@ -445,8 +461,11 @@ def update_plot( self, **p_kwargs ):
if not self.get_visualization(): return
+ if ( self._plot_settings.detail_level > 0 ) and ( self._plot_settings.detail_level < self.plot_detail_level ): return
+
for (prop, link) in self.get_properties().values():
- if not link: prop.update_plot(**p_kwargs)
+ if not link:
+ prop.update_plot(**p_kwargs)
Plottable.update_plot(self, **p_kwargs )
@@ -468,6 +487,9 @@ def renormalize(self, p_normalizer : Normalizer ):
for (prop, link) in self.get_properties().values():
if not link: prop.renormalize( p_normalizer = p_normalizer )
+
+ color = property( fget = Plottable.get_plot_color, fset = set_plot_color )
+
diff --git a/src/mlpro/bf/plot.py b/src/mlpro/bf/plot.py
index 1ccb207ad..5a194ff35 100644
--- a/src/mlpro/bf/plot.py
+++ b/src/mlpro/bf/plot.py
@@ -43,10 +43,18 @@
## -- 2024-05-22 2.13.0 DA New method PlotSettings.copy()
## -- 2024-06-04 2.13.1 DA/SK Turned on TKAgg for Mac
## -- 2024-06-24 2.14.0 DA New auto-managed attribute Plottable._plot_first_time : bool
+## -- 2024-06-25 2.15.0 DA Class Plottable:
+## -- - removed method set_plot_detail_level()
+## -- - added methods assign_plot_detail_level(),
+## -- get_plot_detail_level() and related property plot_detail_level
+## -- - added new constant attribute C_PLOT_DETAIL_LEVEL
+## -- 2024-06-26 2.16.0 DA - Refactoring, corrections, adjustments
+## -- - New property Plottable.color
+## -- - Class PlotSettings: removed parameter p_plot_depth
## -------------------------------------------------------------------------------------------------
"""
-Ver. 2.14.0 (2024-06-24)
+Ver. 2.16.0 (2024-06-26)
This module provides various classes related to data plotting.
@@ -105,9 +113,6 @@ class PlotSettings:
p_plot_horizon : int
Optional plot horizon for ND plot. A value > 0 limits the number of data entities shown
in the plot. Default = 500.
- p_plot_depth : int
- Optional plot depth in case of hierarchical plotting. A value of 0 means that the plot
- depth is unlimited. Default = 0.
p_data_horizon : int
Optional data horizon for ND plot. A value > 0 limits the number of data entities buffered
internally for plotting. Default = 1000.
@@ -139,7 +144,6 @@ def __init__( self,
p_size_y : int = 1,
p_step_rate : int = 1,
p_plot_horizon : int = 500,
- p_plot_depth : int = 0,
p_data_horizon : int = 1000,
p_detail_level : int = 0,
p_force_fg : bool = True,
@@ -157,7 +161,6 @@ def __init__( self,
self.size_x = p_size_x
self.size_y = p_size_y
self.step_rate = p_step_rate
- self.plot_depth = p_plot_depth
self.detail_level = p_detail_level
self.force_fg = p_force_fg
self.id = p_id
@@ -182,8 +185,8 @@ def copy(self):
p_size_y = self.size_y,
p_step_rate = self.step_rate,
p_plot_horizon = self.plot_horizon,
- p_plot_depth = self.plot_depth,
p_data_horizon = self.data_horizon,
+ p_detail_level = self.detail_level,
p_force_fg = self.force_fg,
p_id = self.id,
p_view_autoselect = self.view_autoselect,
@@ -222,18 +225,30 @@ class Plottable:
Custom list of views that are supported/implemented (see class PlotSettings)
C_PLOT_DEFAULT_VIEW : str = ''
Custom attribute for the default view. See class PlotSettings for more details.
+ C_PLOT_DETAIL_LEVEL : int = 0
+ Custom attribute for the assigned detail level. See method assign_plot_detail_level() for
+ more details.
+ color : str
+ Plot color. See also: https://matplotlib.org/stable/gallery/color/named_colors.html
+ plot_detail_level : int
+ Own plot detail level.
"""
C_PLOT_ACTIVE : bool = False
C_PLOT_STANDALONE : bool = True
C_PLOT_VALID_VIEWS : list = []
C_PLOT_DEFAULT_VIEW : str = PlotSettings.C_VIEW_ND
+ C_PLOT_DETAIL_LEVEL : int = 0
## -------------------------------------------------------------------------------------------------
def __init__(self, p_visualize:bool=False):
- self._visualize = self.C_PLOT_ACTIVE and p_visualize
+ self._visualize = self.C_PLOT_ACTIVE and p_visualize
self._plot_settings : PlotSettings = None
- self._plot_first_time : bool = True
+ self.plot_detail_level = self.C_PLOT_DETAIL_LEVEL
+ self._plot_initialized : bool = False
+ self._plot_first_time : bool = True
+ self._plot_own_figure : bool = False
+ self._plot_color = None
## -------------------------------------------------------------------------------------------------
@@ -268,15 +283,12 @@ def set_plot_settings(self, p_plot_settings : PlotSettings ):
raise ImplementationError('Please check attribute C_PLOT_DEFAULT_VIEW')
self._plot_step_counter = 0
- self.set_plot_step_rate(p_step_rate=self._plot_settings.step_rate)
- self.set_plot_detail_level(p_detail_level=self._plot_settings.detail_level)
## -------------------------------------------------------------------------------------------------
def init_plot( self,
p_figure:Figure = None,
- p_plot_settings : PlotSettings = None,
- **p_kwargs):
+ p_plot_settings : PlotSettings = None ) -> bool:
"""
Initializes the plot functionalities of the class.
@@ -286,6 +298,7 @@ def init_plot( self,
Optional MatPlotLib host figure, where the plot shall be embedded. The default is None.
p_plot_settings : PlotSettings
Optional plot settings. If None, the default view is plotted (see attribute C_PLOT_DEFAULT_VIEW).
+
"""
# 1 Plot functionality turned on? Initialization already called?
@@ -294,6 +307,11 @@ def init_plot( self,
except:
return
+ try:
+ if ( p_plot_settings.detail_level > 0 ) and ( p_plot_settings.detail_level < self.plot_detail_level ): return
+ except:
+ self.plot_detail_level = self.C_PLOT_DETAIL_LEVEL
+
try:
if self._plot_initialized: return
except:
@@ -320,7 +338,7 @@ def init_plot( self,
else:
self._figure : Figure = p_figure
-
+
# 4 Call of all initialization methods of the required views
view = self._plot_settings.view
try:
@@ -352,11 +370,44 @@ def get_visualization(self) -> bool:
## -------------------------------------------------------------------------------------------------
def set_plot_step_rate(self, p_step_rate:int):
- if p_step_rate > 0: self._plot_step_rate = p_step_rate
+ if p_step_rate > 0: self._plot_settings.step_rate = p_step_rate
## -------------------------------------------------------------------------------------------------
- def set_plot_detail_level(self, p_detail_level:int):
+ def get_plot_color(self):
+ try:
+ return self._plot_color
+ except:
+ self._plot_color = None
+ return self._plot_color
+
+
+## -------------------------------------------------------------------------------------------------
+ def set_plot_color(self, p_color : str):
+ self._plot_color = p_color
+
+
+## -------------------------------------------------------------------------------------------------
+ def get_plot_detail_level(self) -> int:
+ try:
+ return self._plot_detail_level
+ except:
+ self.assign_plot_detail_level( p_detail_level = self.C_PLOT_DETAIL_LEVEL )
+ return self._plot_detail_level
+
+
+## -------------------------------------------------------------------------------------------------
+ def assign_plot_detail_level(self, p_detail_level:int):
+ """
+ Assigns an own plot detail level. Plots are carried out only, if the specified detail level
+ is less or equal to self._plot_settings.detail_level or self._plot_settings.detail_level = 0.
+
+ Parameters
+ ----------
+ p_detail_level : int
+ Integer detail level >=0 to be assigned.
+ """
+
self._plot_detail_level = max(0, p_detail_level)
@@ -519,17 +570,24 @@ def update_plot(self, **p_kwargs):
except:
return
+
# 1 Plot already initialized?
try:
if not self._plot_initialized: self.init_plot()
except:
self.init_plot()
- # 2 Call of all required plot methods
+
+ # 2 Check the assigned/required detail level
+ if ( self._plot_settings.detail_level > 0 ) and ( self._plot_settings.detail_level < self.plot_detail_level ): return
+
+
+ # 3 Call of all required plot methods
view = self._plot_settings.view
self._plot_methods[view][1](p_settings=self._plot_settings, **p_kwargs)
- # 3 Update content of own(!) figure after self._plot_step_rate calls
+
+ # 4 Update content of own(!) figure after self._plot_step_rate calls
self.refresh_plot(p_force=False)
@@ -594,7 +652,7 @@ def remove_plot(self, p_refresh:bool = True):
# 1 Plot functionality turned on?
try:
- if ( not self.C_PLOT_ACTIVE ) or ( not self._visualize ): return
+ if not self._plot_initialized: return
except:
return
@@ -635,6 +693,10 @@ def _remove_plot_nd(self):
pass
+ color = property( fget = get_plot_color, fset = set_plot_color )
+ plot_detail_level = property( fget = get_plot_detail_level, fset = assign_plot_detail_level )
+
+
diff --git a/src/mlpro/oa/streams/tasks/clusteranalyzers/clusters/basics.py b/src/mlpro/oa/streams/tasks/clusteranalyzers/clusters/basics.py
index 0fb2a6bcf..4180b0fa4 100644
--- a/src/mlpro/oa/streams/tasks/clusteranalyzers/clusters/basics.py
+++ b/src/mlpro/oa/streams/tasks/clusteranalyzers/clusters/basics.py
@@ -104,6 +104,11 @@ def __init__( self,
KWArgs.__init__( self, **p_kwargs )
Properties.__init__( self, p_properties = p_properties, p_visualize = p_visualize )
Id.__init__( self, p_id = p_id )
+
+
+## -------------------------------------------------------------------------------------------------
+ def set_plot_color(self, p_color):
+ Properties.set_plot_color( self, p_color = p_color)
## -------------------------------------------------------------------------------------------------
@@ -144,4 +149,7 @@ def get_influence(self, p_inst : Instance ) -> float:
A value 0 means that the cluster has no influence on the instance at all.
"""
- raise NotImplementedError
\ No newline at end of file
+ raise NotImplementedError
+
+
+ color = property( fget = Properties.get_plot_color, fset = set_plot_color )
\ No newline at end of file
diff --git a/src/mlpro/oa/streams/tasks/clusteranalyzers/clusters/properties/centroid.py b/src/mlpro/oa/streams/tasks/clusteranalyzers/clusters/properties/centroid.py
index 7685fcdaa..76aea9e16 100644
--- a/src/mlpro/oa/streams/tasks/clusteranalyzers/clusters/properties/centroid.py
+++ b/src/mlpro/oa/streams/tasks/clusteranalyzers/clusters/properties/centroid.py
@@ -10,10 +10,11 @@
## -- 2024-05-30 0.3.0 DA Global aliases: new boolean param ValuePrev
## -- 2024-05-31 0.4.0 DA Improved the stability of the plot methods
## -- 2024-06-13 0.5.0 DA New property definitions cprop_centroid_prev*
+## -- 2024-06-26 0.6.0 DA Refactoring
## -------------------------------------------------------------------------------------------------
"""
-Ver. 0.5.0 (2024-06-13)
+Ver. 0.6.0 (2024-06-26)
This module provides ...
@@ -110,10 +111,16 @@ def _update_plot_2d(self, p_settings: PlotSettings, **p_kwargs):
# 0 Intro
if self.value is None: return
- super()._update_plot_2d(p_settings, **p_kwargs)
- # 1 Get coordinates
+ # 1 Plot the point
+ color = self.color
+ self.color = None
+ super()._update_plot_2d(p_settings, **p_kwargs)
+ self.color = color
+
+
+ # 2 Get line coordinates
centroid = self.value
ax_xlim = p_settings.axes.get_xlim()
ax_ylim = p_settings.axes.get_ylim()
@@ -121,12 +128,18 @@ def _update_plot_2d(self, p_settings: PlotSettings, **p_kwargs):
ylim = [ min( ax_ylim[0], centroid[1] ), max(ax_ylim[1], centroid[1] ) ]
- # 2 Plot a crosshair
- if self._plot_line1 is None:
- # 2.1 Add initial crosshair lines
- cluster_id = self.id
+ # 3 Determine the color of the crosshair
+ cluster_id = self.id
+ if self.color is None:
col_id = cluster_id % len(Cluster.C_CLUSTER_COLORS)
color = Cluster.C_CLUSTER_COLORS[col_id]
+ else:
+ color = self.color
+
+
+ # 4 Plot a crosshair
+ if self._plot_line1 is None:
+ # 4.1 Add initial crosshair lines
label = ' C' + str(cluster_id) + ' '
self._plot_line1 = p_settings.axes.plot( xlim, [centroid[1],centroid[1]], color=color, linestyle='dashed', lw=1, label=label)[0]
self._plot_line2 = p_settings.axes.plot( [centroid[0],centroid[0]], ylim, color=color, linestyle='dashed', lw=1)[0]
@@ -137,14 +150,16 @@ def _update_plot_2d(self, p_settings: PlotSettings, **p_kwargs):
self._plot_line2_t2 = p_settings.axes.text(centroid[0], ylim[1], label, ha='center', va='bottom',color=color )
p_settings.axes.legend(title='Clusters', alignment='left', loc='upper right', shadow=True, draggable=True)
else:
- # 2.2 Update data of crosshair lines
+ # 4.2 Update data of crosshair lines
self._plot_line1.set_data( xlim, [centroid[1],centroid[1]] )
+ self._plot_line1.set_color( color )
self._plot_line2.set_data( [centroid[0],centroid[0]], ylim )
- self._plot_line1_t1.set(position=(centroid[0], centroid[1]) )
- self._plot_line1_t2.set(position=(xlim[0], centroid[1]))
- self._plot_line1_t3.set(position=(xlim[1], centroid[1]))
- self._plot_line2_t1.set(position=(centroid[0], ylim[0]))
- self._plot_line2_t2.set(position=(centroid[0], ylim[1]))
+ self._plot_line2.set_color( color )
+ self._plot_line1_t1.set(position=(centroid[0], centroid[1]), color=color)
+ self._plot_line1_t2.set(position=(xlim[0], centroid[1]), color=color)
+ self._plot_line1_t3.set(position=(xlim[1], centroid[1]), color=color)
+ self._plot_line2_t1.set(position=(centroid[0], ylim[0]), color=color)
+ self._plot_line2_t2.set(position=(centroid[0], ylim[1]), color=color)
## -------------------------------------------------------------------------------------------------
@@ -152,7 +167,13 @@ def _update_plot_3d(self, p_settings: PlotSettings, **p_kwargs):
# 0 Intro
if self.value is None: return
- super()._update_plot_3d(p_settings, **p_kwargs)
+
+
+ # 1 Plot the point
+ color = self.color
+ self.color = None
+ super()._update_plot_3d(p_settings, **p_kwargs)
+ self.color = color
# 1 Get coordinates
@@ -179,14 +200,22 @@ def _update_plot_3d(self, p_settings: PlotSettings, **p_kwargs):
l2_t1_ha='left'
l3_t1_va='top'
+
+ # 3 Determine the color of the crosshair
+ cluster_id = self.id
+ if self.color is None:
+ col_id = cluster_id % len(Cluster.C_CLUSTER_COLORS)
+ color = Cluster.C_CLUSTER_COLORS[col_id]
+ else:
+ color = self.color
- # 3 Plot a crosshair with label texts
+
+ # 4 Plot a crosshair with label texts
if self._plot_line1 is None:
- # 3.1 Add initial crosshair lines
+ # 4.1 Add initial crosshair lines
cluster_id = self.get_id()
- col_id = cluster_id % len(Cluster.C_CLUSTER_COLORS)
- color = Cluster.C_CLUSTER_COLORS[col_id]
+
label = ' C' + str(cluster_id) + ' '
self._plot_line1 = p_settings.axes.plot( xlim, [centroid[1],centroid[1]], [centroid[2],centroid[2]], color=color, linestyle='dashed', lw=1, label=label)[0]
self._plot_line2 = p_settings.axes.plot( [centroid[0],centroid[0]], ylim, [centroid[2],centroid[2]], color=color, linestyle='dashed', lw=1)[0]
@@ -199,15 +228,18 @@ def _update_plot_3d(self, p_settings: PlotSettings, **p_kwargs):
p_settings.axes.legend(title='Clusters', alignment='left', loc='right', shadow=True, draggable=True)
else:
- # 3.2 Update data of crosshair lines
+ # 4.2 Update data of crosshair lines
self._plot_line1.set_data_3d( xlim, [centroid[1],centroid[1]], [centroid[2],centroid[2]] )
+ self._plot_line1.set_color( color )
self._plot_line2.set_data_3d( [centroid[0],centroid[0]], ylim, [centroid[2],centroid[2]] )
+ self._plot_line2.set_color( color )
self._plot_line3.set_data_3d( [centroid[0],centroid[0]], [centroid[1],centroid[1]], zlim )
+ self._plot_line3.set_color( color )
- self._plot_line1_t1.set(position_3d=(centroid[0], centroid[1], centroid[2]))
- self._plot_line1_t2.set(position_3d=(xlim[0], centroid[1], centroid[2]), ha=l1_t2_ha)
- self._plot_line2_t1.set(position_3d=(centroid[0], ylim[0], centroid[2]), ha=l2_t1_ha)
- self._plot_line3_t1.set(position_3d=(centroid[0], centroid[1], zlim[0]), va=l3_t1_va)
+ self._plot_line1_t1.set(position_3d=(centroid[0], centroid[1], centroid[2]), color=color)
+ self._plot_line1_t2.set(position_3d=(xlim[0], centroid[1], centroid[2]), ha=l1_t2_ha, color=color)
+ self._plot_line2_t1.set(position_3d=(centroid[0], ylim[0], centroid[2]), ha=l2_t1_ha, color=color)
+ self._plot_line3_t1.set(position_3d=(centroid[0], centroid[1], zlim[0]), va=l3_t1_va, color=color)
## -------------------------------------------------------------------------------------------------
diff --git a/test/howtos/bf/howto_bf_streams_111_stream_task_window_2d.py b/test/howtos/bf/howto_bf_streams_111_stream_task_window_2d.py
index 5b3019065..74254a21a 100644
--- a/test/howtos/bf/howto_bf_streams_111_stream_task_window_2d.py
+++ b/test/howtos/bf/howto_bf_streams_111_stream_task_window_2d.py
@@ -116,7 +116,7 @@ def _setup(self, p_mode, p_visualize:bool, p_logging):
if __name__ == '__main__':
myscenario.init_plot( p_plot_settings=PlotSettings( p_view=PlotSettings.C_VIEW_ND,
p_plot_horizon=100,
- p_data_horizon=150) )
+ p_data_horizon=150 ) )
input('Press ENTER to start stream processing...')
myscenario.run()