toucan-plot 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. toucan_plot-0.2.0/LICENSE +21 -0
  2. toucan_plot-0.2.0/PKG-INFO +16 -0
  3. toucan_plot-0.2.0/README.md +116 -0
  4. toucan_plot-0.2.0/pyproject.toml +22 -0
  5. toucan_plot-0.2.0/setup.cfg +4 -0
  6. toucan_plot-0.2.0/src/toucan_plot/__main__.py +4 -0
  7. toucan_plot-0.2.0/src/toucan_plot/assets/adjustments-dark.svg +1 -0
  8. toucan_plot-0.2.0/src/toucan_plot/assets/adjustments-light.svg +1 -0
  9. toucan_plot-0.2.0/src/toucan_plot/assets/arrow-autofit-height-dark.svg +1 -0
  10. toucan_plot-0.2.0/src/toucan_plot/assets/arrow-autofit-height-light.svg +1 -0
  11. toucan_plot-0.2.0/src/toucan_plot/assets/arrow-narrow-left-dark.svg +1 -0
  12. toucan_plot-0.2.0/src/toucan_plot/assets/arrow-narrow-left-light.svg +1 -0
  13. toucan_plot-0.2.0/src/toucan_plot/assets/arrow-narrow-right-dark.svg +1 -0
  14. toucan_plot-0.2.0/src/toucan_plot/assets/arrow-narrow-right-light.svg +1 -0
  15. toucan_plot-0.2.0/src/toucan_plot/assets/device-floppy-dark.svg +1 -0
  16. toucan_plot-0.2.0/src/toucan_plot/assets/device-floppy-light.svg +1 -0
  17. toucan_plot-0.2.0/src/toucan_plot/assets/hand-stop-dark.svg +1 -0
  18. toucan_plot-0.2.0/src/toucan_plot/assets/hand-stop-light.svg +1 -0
  19. toucan_plot-0.2.0/src/toucan_plot/assets/home-dark.svg +1 -0
  20. toucan_plot-0.2.0/src/toucan_plot/assets/home-light.svg +1 -0
  21. toucan_plot-0.2.0/src/toucan_plot/assets/ico/toucan-plot.ico +0 -0
  22. toucan_plot-0.2.0/src/toucan_plot/assets/layout-grid-add-dark.svg +1 -0
  23. toucan_plot-0.2.0/src/toucan_plot/assets/layout-grid-add-light.svg +1 -0
  24. toucan_plot-0.2.0/src/toucan_plot/assets/math-function-dark.svg +1 -0
  25. toucan_plot-0.2.0/src/toucan_plot/assets/math-function-light.svg +1 -0
  26. toucan_plot-0.2.0/src/toucan_plot/assets/ruler-measure-dark.svg +1 -0
  27. toucan_plot-0.2.0/src/toucan_plot/assets/ruler-measure-light.svg +1 -0
  28. toucan_plot-0.2.0/src/toucan_plot/assets/zoom-dark.svg +1 -0
  29. toucan_plot-0.2.0/src/toucan_plot/assets/zoom-light.svg +1 -0
  30. toucan_plot-0.2.0/src/toucan_plot/main.py +2047 -0
  31. toucan_plot-0.2.0/src/toucan_plot/utils/__init__.py +14 -0
  32. toucan_plot-0.2.0/src/toucan_plot/utils/loaders.py +219 -0
  33. toucan_plot-0.2.0/src/toucan_plot/utils/styles.py +55 -0
  34. toucan_plot-0.2.0/src/toucan_plot.egg-info/PKG-INFO +16 -0
  35. toucan_plot-0.2.0/src/toucan_plot.egg-info/SOURCES.txt +37 -0
  36. toucan_plot-0.2.0/src/toucan_plot.egg-info/dependency_links.txt +1 -0
  37. toucan_plot-0.2.0/src/toucan_plot.egg-info/entry_points.txt +2 -0
  38. toucan_plot-0.2.0/src/toucan_plot.egg-info/requires.txt +8 -0
  39. toucan_plot-0.2.0/src/toucan_plot.egg-info/top_level.txt +1 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Claudio Emanoel Barbosa Lima
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,16 @@
1
+ Metadata-Version: 2.4
2
+ Name: toucan-plot
3
+ Version: 0.2.0
4
+ Summary: A versatile PyQt6 and Matplotlib-based plotting tool for CSV and SMV data files.
5
+ License-Expression: MIT
6
+ Requires-Python: >=3.11
7
+ License-File: LICENSE
8
+ Requires-Dist: pyqt6>=6.0
9
+ Requires-Dist: matplotlib>=3.0
10
+ Requires-Dist: numpy>=1.20
11
+ Requires-Dist: pyqtdarktheme>=2.1.0
12
+ Requires-Dist: scienceplots>=2.2.1
13
+ Requires-Dist: python-can>=4.0
14
+ Requires-Dist: cantools>=39.0
15
+ Requires-Dist: asammdf>=7.0
16
+ Dynamic: license-file
@@ -0,0 +1,116 @@
1
+ # Toucan-Plot
2
+
3
+ An interactive PyQt6 + Matplotlib plotting tool for CSV, SMV, and CAN bus log files.
4
+
5
+ ![Python](https://img.shields.io/badge/python-3.11+-blue)
6
+ ![License](https://img.shields.io/badge/license-MIT-green)
7
+
8
+ ## Features
9
+
10
+ ### Supported File Formats
11
+
12
+ | Format | Description |
13
+ |--------|-------------|
14
+ | `.csv` / `.smv` | Comma or semicolon delimited data (auto-detected) |
15
+ | `.mf4` / `.mf4z` | ASAM MDF v4 measurement data (via asammdf) |
16
+ | `.blf` | CAN bus binary log |
17
+ | `.trc` | CAN bus trace log |
18
+ | `.asc` | CAN bus ASCII log |
19
+ | `.dbc` | CAN database for signal decoding (required with BLF/TRC/ASC) |
20
+
21
+ - Auto-detects `Time` / `timestamp` columns as the default X axis
22
+ - CAN signals are forward-fill interpolated and named as `Message.Signal`
23
+
24
+ ### Plot Interaction
25
+
26
+ - **Shared X axis** across all subplots with linked panning and zooming
27
+ - **Secondary Y axis** support per series
28
+ - **Double-click** a subplot to edit its series, or **right-click** for a context menu
29
+ - **Measure cursors** — two draggable vertical cursors with a live delta table
30
+ - **Expression evaluator** — create computed series from math expressions (e.g. `sin("series_A") + "series_B" * 2`)
31
+ - **Multi-file merge** — overlay series from different files, each in its own tab
32
+ - **X axis switching** — reassign the X column without losing subplot configuration
33
+ - **Per-series properties** (label, color, linewidth, linestyle, marker) persisted across all redraws
34
+ - Live mouse coordinates in the status bar
35
+
36
+ ### Toolbar
37
+
38
+ | Button | Action |
39
+ |--------|--------|
40
+ | Home | Auto-fit all axes |
41
+ | Back / Forward | Navigate view history |
42
+ | Pan | Pan mode |
43
+ | Zoom | Zoom rectangle mode |
44
+ | Customize | Matplotlib per-curve property editor |
45
+ | Save | Export figure to file |
46
+ | Add subplot | Open the series selector |
47
+ | Fit Y | Auto-fit Y axis keeping current X range |
48
+ | Measure | Toggle measure cursors |
49
+ | X axis | Select X axis column |
50
+
51
+ ### Menus
52
+
53
+ - **File → Open** (`Ctrl+O`) — open one or more files (multi-select)
54
+ - **File → Merge** (`Ctrl+M`) — append files to the current session
55
+ - **Style → Customize plot style** — preset, line mode, marker, text size, grid, legend
56
+ - **Style → Theme** — Dark / Light (icons swap automatically)
57
+
58
+ ### Right-Click Context Menu
59
+
60
+ - Add subplot above / below
61
+ - Delete subplot
62
+ - Legend: show/hide, position (14 options), orientation, text size
63
+ - Line style: plot / step
64
+
65
+ ### Style Presets
66
+
67
+ Four built-in presets: **Default**, **Style 1**, **IEEE**, **Other**.
68
+
69
+ ## Installation
70
+
71
+ ### From source (recommended)
72
+
73
+ ```shell
74
+ pip install .
75
+ ```
76
+
77
+ ### With uv
78
+
79
+ ```shell
80
+ uv pip install .
81
+ ```
82
+
83
+ ## Usage
84
+
85
+ ```shell
86
+ # Open a CSV file
87
+ toucan-plot data.csv
88
+
89
+ # Open an MF4 measurement file
90
+ toucan-plot recording.mf4
91
+
92
+ # Open a CAN log with DBC decoding
93
+ toucan-plot recording.blf signals.dbc
94
+
95
+ # Open multiple files (merge mode)
96
+ toucan-plot file1.csv file2.csv
97
+
98
+ # Launch without files
99
+ toucan-plot
100
+ ```
101
+
102
+ ## Requirements
103
+
104
+ - Python ≥ 3.11
105
+ - PyQt6
106
+ - Matplotlib
107
+ - NumPy
108
+ - pyqtdarktheme
109
+ - SciencePlots
110
+ - python-can (for CAN log files)
111
+ - cantools (for DBC decoding)
112
+ - asammdf (for MF4 files)
113
+
114
+ ## License
115
+
116
+ MIT
@@ -0,0 +1,22 @@
1
+ [project]
2
+ name = "toucan-plot"
3
+ version = "0.2.0"
4
+ description = "A versatile PyQt6 and Matplotlib-based plotting tool for CSV and SMV data files."
5
+ license = "MIT"
6
+ requires-python = ">=3.11"
7
+ dependencies = [
8
+ "pyqt6>=6.0",
9
+ "matplotlib>=3.0",
10
+ "numpy>=1.20",
11
+ "pyqtdarktheme>=2.1.0",
12
+ "scienceplots>=2.2.1",
13
+ "python-can>=4.0",
14
+ "cantools>=39.0",
15
+ "asammdf>=7.0",
16
+ ]
17
+
18
+ [project.scripts]
19
+ toucan-plot = "toucan_plot.main:main"
20
+
21
+ [tool.setuptools.package-data]
22
+ toucan_plot = ["assets/**/*.svg", "assets/**/*.ico"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,4 @@
1
+ from toucan_plot.main import main
2
+
3
+ if __name__ == "__main__":
4
+ main()
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-adjustments"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M4 10a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" /><path d="M6 4v4" /><path d="M6 12v8" /><path d="M10 16a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" /><path d="M12 4v10" /><path d="M12 18v2" /><path d="M16 7a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" /><path d="M18 4v1" /><path d="M18 9v11" /></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-adjustments"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M4 10a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" /><path d="M6 4v4" /><path d="M6 12v8" /><path d="M10 16a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" /><path d="M12 4v10" /><path d="M12 18v2" /><path d="M16 7a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" /><path d="M18 4v1" /><path d="M18 9v11" /></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-arrow-autofit-height"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M12 20h-6a2 2 0 0 1 -2 -2v-12a2 2 0 0 1 2 -2h6" /><path d="M18 14v7" /><path d="M18 3v7" /><path d="M15 18l3 3l3 -3" /><path d="M15 6l3 -3l3 3" /></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-arrow-autofit-height"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M12 20h-6a2 2 0 0 1 -2 -2v-12a2 2 0 0 1 2 -2h6" /><path d="M18 14v7" /><path d="M18 3v7" /><path d="M15 18l3 3l3 -3" /><path d="M15 6l3 -3l3 3" /></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-arrow-narrow-left"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M5 12l14 0" /><path d="M5 12l4 4" /><path d="M5 12l4 -4" /></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-arrow-narrow-left"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M5 12l14 0" /><path d="M5 12l4 4" /><path d="M5 12l4 -4" /></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-arrow-narrow-right"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M5 12l14 0" /><path d="M15 16l4 -4" /><path d="M15 8l4 4" /></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-arrow-narrow-right"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M5 12l14 0" /><path d="M15 16l4 -4" /><path d="M15 8l4 4" /></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#ffffff" class="icon icon-tabler icons-tabler-filled icon-tabler-device-floppy"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M16 3a1 1 0 0 1 .707 .293l4 4a1 1 0 0 1 .293 .707v10a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3v-12a3 3 0 0 1 3 -3h1v4a1 1 0 0 0 .883 .993l.117 .007h6a1 1 0 0 0 1 -1v-4zm-4 8a2.995 2.995 0 0 0 -2.995 2.898a1 1 0 0 0 -.005 .102a3 3 0 1 0 3 -3m1 -8v3h-4v-3z" /></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#000000" class="icon icon-tabler icons-tabler-filled icon-tabler-device-floppy"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M16 3a1 1 0 0 1 .707 .293l4 4a1 1 0 0 1 .293 .707v10a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3v-12a3 3 0 0 1 3 -3h1v4a1 1 0 0 0 .883 .993l.117 .007h6a1 1 0 0 0 1 -1v-4zm-4 8a2.995 2.995 0 0 0 -2.995 2.898a1 1 0 0 0 -.005 .102a3 3 0 1 0 3 -3m1 -8v3h-4v-3z" /></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-hand-stop"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M8 13v-7.5a1.5 1.5 0 0 1 3 0v6.5" /><path d="M11 5.5v-2a1.5 1.5 0 1 1 3 0v8.5" /><path d="M14 5.5a1.5 1.5 0 0 1 3 0v6.5" /><path d="M17 7.5a1.5 1.5 0 0 1 3 0v8.5a6 6 0 0 1 -6 6h-2h.208a6 6 0 0 1 -5.012 -2.7a69.74 69.74 0 0 1 -.196 -.3c-.312 -.479 -1.407 -2.388 -3.286 -5.728a1.5 1.5 0 0 1 .536 -2.022a1.867 1.867 0 0 1 2.28 .28l1.47 1.47" /></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-hand-stop"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M8 13v-7.5a1.5 1.5 0 0 1 3 0v6.5" /><path d="M11 5.5v-2a1.5 1.5 0 1 1 3 0v8.5" /><path d="M14 5.5a1.5 1.5 0 0 1 3 0v6.5" /><path d="M17 7.5a1.5 1.5 0 0 1 3 0v8.5a6 6 0 0 1 -6 6h-2h.208a6 6 0 0 1 -5.012 -2.7a69.74 69.74 0 0 1 -.196 -.3c-.312 -.479 -1.407 -2.388 -3.286 -5.728a1.5 1.5 0 0 1 .536 -2.022a1.867 1.867 0 0 1 2.28 .28l1.47 1.47" /></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-home"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M5 12l-2 0l9 -9l9 9l-2 0" /><path d="M5 12v7a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-7" /><path d="M9 21v-6a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v6" /></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-home"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M5 12l-2 0l9 -9l9 9l-2 0" /><path d="M5 12v7a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-7" /><path d="M9 21v-6a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v6" /></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-layout-grid-add"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M4 5a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1l0 -4" /><path d="M14 5a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1l0 -4" /><path d="M4 15a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1l0 -4" /><path d="M14 17h6m-3 -3v6" /></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-layout-grid-add"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M4 5a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1l0 -4" /><path d="M14 5a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1l0 -4" /><path d="M4 15a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1l0 -4" /><path d="M14 17h6m-3 -3v6" /></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-math-function"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M3 19a2 2 0 0 0 2 2c2 0 2 -4 3 -9s1 -9 3 -9a2 2 0 0 1 2 2" /><path d="M5 12h6" /><path d="M15 12l6 6" /><path d="M15 18l6 -6" /></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-math-function"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M3 19a2 2 0 0 0 2 2c2 0 2 -4 3 -9s1 -9 3 -9a2 2 0 0 1 2 2" /><path d="M5 12h6" /><path d="M15 12l6 6" /><path d="M15 18l6 -6" /></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-ruler-measure"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M19.875 12c.621 0 1.125 .512 1.125 1.143v5.714c0 .631 -.504 1.143 -1.125 1.143h-15.875a1 1 0 0 1 -1 -1v-5.857c0 -.631 .504 -1.143 1.125 -1.143h15.75" /><path d="M9 12v2" /><path d="M6 12v3" /><path d="M12 12v3" /><path d="M18 12v3" /><path d="M15 12v2" /><path d="M3 3v4" /><path d="M3 5h18" /><path d="M21 3v4" /></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-ruler-measure"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M19.875 12c.621 0 1.125 .512 1.125 1.143v5.714c0 .631 -.504 1.143 -1.125 1.143h-15.875a1 1 0 0 1 -1 -1v-5.857c0 -.631 .504 -1.143 1.125 -1.143h15.75" /><path d="M9 12v2" /><path d="M6 12v3" /><path d="M12 12v3" /><path d="M18 12v3" /><path d="M15 12v2" /><path d="M3 3v4" /><path d="M3 5h18" /><path d="M21 3v4" /></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-zoom"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M3 10a7 7 0 1 0 14 0a7 7 0 1 0 -14 0" /><path d="M21 21l-6 -6" /></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-zoom"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M3 10a7 7 0 1 0 14 0a7 7 0 1 0 -14 0" /><path d="M21 21l-6 -6" /></svg>