icplot 0.4.0__tar.gz → 0.5.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.
- icplot-0.5.0/LICENSE +21 -0
- {icplot-0.4.0/src/icplot.egg-info → icplot-0.5.0}/PKG-INFO +16 -17
- {icplot-0.4.0 → icplot-0.5.0}/README.md +10 -2
- icplot-0.5.0/pyproject.toml +124 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/charts/tree.py +1 -1
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/converter/image.py +14 -9
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/geometry/mesh/mesh.py +0 -1
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/geometry/mesh/openfoam/blockmesh.py +3 -4
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/geometry/mesh/openfoam/foamfile.py +1 -1
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/geometry/mesh/openfoam/polymesh.py +4 -1
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/geometry/mesh/shapes.py +0 -2
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/geometry/mesh/vertex.py +0 -2
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/geometry/shapes.py +0 -2
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/graph/plot_group.py +0 -1
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/graph/series.py +0 -3
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/renderer/charts/pgfgantt.py +1 -1
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/renderer/formats/mermaid.py +5 -4
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/renderer/formats/tex.py +7 -4
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/renderer/graph/matplotlib.py +15 -6
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/renderer/graph/mpl.py +3 -1
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/renderer/graph/renderer.py +9 -5
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/renderer/render.py +0 -1
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/theme/color.py +1 -1
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/theme/theme_generator.py +2 -0
- {icplot-0.4.0 → icplot-0.5.0/src/icplot.egg-info}/PKG-INFO +16 -17
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot.egg-info/requires.txt +0 -11
- {icplot-0.4.0 → icplot-0.5.0}/test/test_image.py +0 -1
- icplot-0.4.0/LICENSE +0 -232
- icplot-0.4.0/pyproject.toml +0 -197
- {icplot-0.4.0 → icplot-0.5.0}/setup.cfg +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/__init__.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/charts/__init__.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/charts/gantt.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/converter/__init__.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/converter/cli.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/converter/convert.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/geometry/__init__.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/geometry/base.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/geometry/mesh/__init__.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/geometry/mesh/cell.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/geometry/mesh/edge.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/geometry/mesh/openfoam/__init__.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/geometry/mesh/operations.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/geometry/mesh/vtk.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/geometry/operations.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/geometry/transform.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/graph/__init__.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/graph/axis.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/graph/plot.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/main_cli.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/py.typed +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/renderer/__init__.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/renderer/charts/svggantt.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/renderer/cli.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/renderer/config.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/renderer/formats/__init__.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/renderer/formats/plantuml.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/renderer/frontmatter.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/renderer/graph/__init__.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/renderer/graph/color.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/renderer/graph/vtk.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/renderer/scene/cairo.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/renderer/video.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/scene.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/theme/__init__.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/theme/cli.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/theme/templates/puml.j2 +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/theme/templates/tikz.j2 +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/theme/theme.json +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot/theme/theme.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot.egg-info/SOURCES.txt +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot.egg-info/dependency_links.txt +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot.egg-info/entry_points.txt +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/src/icplot.egg-info/top_level.txt +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/test/test_cairo.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/test/test_frontmatter.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/test/test_gantt_chart.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/test/test_geometry.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/test/test_line_plots.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/test/test_mermaid.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/test/test_meshing.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/test/test_openfoam.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/test/test_plot_group.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/test/test_polymesh.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/test/test_puml.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/test/test_tex.py +0 -0
- {icplot-0.4.0 → icplot-0.5.0}/test/test_tree.py +0 -0
icplot-0.5.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Irish Centre for High End Computing
|
|
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.
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: icplot
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Utilities for generating plots and graphics for technical reports.
|
|
5
|
-
Author
|
|
6
|
-
|
|
7
|
-
Project-URL:
|
|
5
|
+
Author: Irish Centre for High End Computing
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Repository, https://git.ichec.ie/platform-engineering/modules/documentation/ichec-plot
|
|
8
|
+
Project-URL: Homepage, https://git.ichec.ie/platform-engineering/modules/documentation/ichec-plot
|
|
8
9
|
Keywords: Publishing,Technical Reports,Graphics
|
|
9
10
|
Classifier: Development Status :: 3 - Alpha
|
|
10
11
|
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
Classifier: License :: OSI Approved ::
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
13
|
Classifier: Operating System :: OS Independent
|
|
13
14
|
Classifier: Topic :: System :: Distributed Computing
|
|
14
15
|
Requires-Python: >=3.10
|
|
@@ -17,16 +18,6 @@ License-File: LICENSE
|
|
|
17
18
|
Requires-Dist: iccore==0.2.3
|
|
18
19
|
Requires-Dist: graphviz
|
|
19
20
|
Requires-Dist: Jinja2
|
|
20
|
-
Provides-Extra: test
|
|
21
|
-
Requires-Dist: pytest; extra == "test"
|
|
22
|
-
Requires-Dist: pytest-cov; extra == "test"
|
|
23
|
-
Requires-Dist: pytest-sugar; extra == "test"
|
|
24
|
-
Requires-Dist: black; extra == "test"
|
|
25
|
-
Requires-Dist: isort; extra == "test"
|
|
26
|
-
Requires-Dist: mypy; extra == "test"
|
|
27
|
-
Requires-Dist: flake8; extra == "test"
|
|
28
|
-
Requires-Dist: pylint; extra == "test"
|
|
29
|
-
Requires-Dist: types-PyYAML; extra == "test"
|
|
30
21
|
Provides-Extra: cairo
|
|
31
22
|
Requires-Dist: CairoSVG; extra == "cairo"
|
|
32
23
|
Provides-Extra: scene
|
|
@@ -55,6 +46,14 @@ Dynamic: license-file
|
|
|
55
46
|
|
|
56
47
|
This is a library used at [The Irish Centre for High End Computing (ICHEC)](https://www.ichec.ie) for generating plots, diagrams and other graphics for technical documents.
|
|
57
48
|
|
|
49
|
+
# Scope #
|
|
50
|
+
|
|
51
|
+
The library is **frozen to what its consumers use** — the `ichec-handbook`
|
|
52
|
+
build tool and `ichec-flow`. That means `converter`, `renderer`, `theme` and
|
|
53
|
+
`graph`: fixes and maintenance yes, new capability no (planning#136). The
|
|
54
|
+
`geometry`/`mesh` 3D and OpenFOAM code is still here but is scheduled to move
|
|
55
|
+
to a module of its own, and its optional-dependency weight goes with it.
|
|
56
|
+
|
|
58
57
|
# Features #
|
|
59
58
|
|
|
60
59
|
The project has three primary modules:
|
|
@@ -167,7 +166,7 @@ brew install imagemagick cairo
|
|
|
167
166
|
|
|
168
167
|
# Copyright #
|
|
169
168
|
|
|
170
|
-
Copyright
|
|
169
|
+
Copyright 2026 Irish Centre for High End Computing
|
|
171
170
|
|
|
172
|
-
The software in this repository can be used under the conditions of the
|
|
171
|
+
The software in this repository can be used under the conditions of the MIT license, which is available for reading in the accompanying LICENSE file.
|
|
173
172
|
|
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
This is a library used at [The Irish Centre for High End Computing (ICHEC)](https://www.ichec.ie) for generating plots, diagrams and other graphics for technical documents.
|
|
4
4
|
|
|
5
|
+
# Scope #
|
|
6
|
+
|
|
7
|
+
The library is **frozen to what its consumers use** — the `ichec-handbook`
|
|
8
|
+
build tool and `ichec-flow`. That means `converter`, `renderer`, `theme` and
|
|
9
|
+
`graph`: fixes and maintenance yes, new capability no (planning#136). The
|
|
10
|
+
`geometry`/`mesh` 3D and OpenFOAM code is still here but is scheduled to move
|
|
11
|
+
to a module of its own, and its optional-dependency weight goes with it.
|
|
12
|
+
|
|
5
13
|
# Features #
|
|
6
14
|
|
|
7
15
|
The project has three primary modules:
|
|
@@ -114,7 +122,7 @@ brew install imagemagick cairo
|
|
|
114
122
|
|
|
115
123
|
# Copyright #
|
|
116
124
|
|
|
117
|
-
Copyright
|
|
125
|
+
Copyright 2026 Irish Centre for High End Computing
|
|
118
126
|
|
|
119
|
-
The software in this repository can be used under the conditions of the
|
|
127
|
+
The software in this repository can be used under the conditions of the MIT license, which is available for reading in the accompanying LICENSE file.
|
|
120
128
|
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "icplot"
|
|
3
|
+
dynamic = ["version"]
|
|
4
|
+
license = { text = "MIT" }
|
|
5
|
+
authors = [
|
|
6
|
+
{ name="Irish Centre for High End Computing"},
|
|
7
|
+
]
|
|
8
|
+
description = "Utilities for generating plots and graphics for technical reports."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
classifiers = [
|
|
12
|
+
"Development Status :: 3 - Alpha",
|
|
13
|
+
"Programming Language :: Python :: 3",
|
|
14
|
+
"License :: OSI Approved :: MIT License",
|
|
15
|
+
"Operating System :: OS Independent",
|
|
16
|
+
"Topic :: System :: Distributed Computing"
|
|
17
|
+
]
|
|
18
|
+
keywords = ["Publishing", "Technical Reports", "Graphics"]
|
|
19
|
+
|
|
20
|
+
# Core is deliberately light: only what every import path needs. The heavy
|
|
21
|
+
# rendering backends (matplotlib/vtk/scipy/moviepy/wand) are optional extras
|
|
22
|
+
# so consumers that only use the converter or diagram renderer (e.g. the
|
|
23
|
+
# handbook build) can install a small footprint. Use icplot[all] for the
|
|
24
|
+
# previous behaviour of pulling every backend.
|
|
25
|
+
dependencies = ["iccore==0.2.3",
|
|
26
|
+
"graphviz",
|
|
27
|
+
"Jinja2"]
|
|
28
|
+
|
|
29
|
+
[project.urls]
|
|
30
|
+
Repository = "https://git.ichec.ie/platform-engineering/modules/documentation/ichec-plot"
|
|
31
|
+
Homepage = "https://git.ichec.ie/platform-engineering/modules/documentation/ichec-plot"
|
|
32
|
+
|
|
33
|
+
[project.optional-dependencies]
|
|
34
|
+
# svg/pdf conversion (converter.svg_to_png / svg_to_pdf). CairoSVG pulls
|
|
35
|
+
# cairocffi, which dlopens libcairo at runtime (no C build step needed).
|
|
36
|
+
cairo = [
|
|
37
|
+
"CairoSVG"
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
# vector scene drawing (renderer.scene.cairo). pycairo (module `cairo`)
|
|
41
|
+
# builds against libcairo — needs the cairo headers + a C toolchain at install.
|
|
42
|
+
scene = ["pycairo"]
|
|
43
|
+
|
|
44
|
+
# raster conversion via ImageMagick bindings (converter.pdf_to_png);
|
|
45
|
+
# falls back to the `magick` CLI if wand is absent
|
|
46
|
+
imagemagick = ["wand"]
|
|
47
|
+
|
|
48
|
+
# 2D plotting backend (icplot.renderer.graph / icplot.charts)
|
|
49
|
+
plot = ["matplotlib"]
|
|
50
|
+
|
|
51
|
+
# 3D / mesh backend (icplot.geometry.mesh, vtk graph backend)
|
|
52
|
+
vtk = ["vtk"]
|
|
53
|
+
|
|
54
|
+
# geometry transforms (icplot.geometry.operations)
|
|
55
|
+
geometry = ["scipy"]
|
|
56
|
+
|
|
57
|
+
# video assembly (icplot.renderer.video)
|
|
58
|
+
video = ["moviepy"]
|
|
59
|
+
|
|
60
|
+
# convenience aggregate — every backend (pre-split behaviour)
|
|
61
|
+
all = [
|
|
62
|
+
"CairoSVG",
|
|
63
|
+
"pycairo",
|
|
64
|
+
"wand",
|
|
65
|
+
"matplotlib",
|
|
66
|
+
"vtk",
|
|
67
|
+
"scipy",
|
|
68
|
+
"moviepy"
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
[build-system]
|
|
72
|
+
requires = ["setuptools>=64", "setuptools-scm>=8"]
|
|
73
|
+
build-backend = "setuptools.build_meta"
|
|
74
|
+
|
|
75
|
+
# Version derived from the git tag (setuptools-scm). fallback_version keeps
|
|
76
|
+
# non-release jobs building on the shallow CI checkout, which has no tags.
|
|
77
|
+
[tool.setuptools_scm]
|
|
78
|
+
fallback_version = "0.0.0"
|
|
79
|
+
|
|
80
|
+
# Development toolchain (uv-native, PEP 735). CI installs it with
|
|
81
|
+
# `uv sync --group dev`. Deliberately free of the rendering backends: the lint
|
|
82
|
+
# job runs in the standard slim image, and pycairo has no wheel there — it
|
|
83
|
+
# builds against libcairo headers. The test job adds the backends with
|
|
84
|
+
# `--extra all` in an image that has those headers.
|
|
85
|
+
[dependency-groups]
|
|
86
|
+
dev = [
|
|
87
|
+
"ruff",
|
|
88
|
+
"mypy",
|
|
89
|
+
"pytest",
|
|
90
|
+
"pytest-cov",
|
|
91
|
+
"pytest-sugar",
|
|
92
|
+
"types-PyYAML",
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
[project.scripts]
|
|
96
|
+
icplot = "icplot.main_cli:main_cli"
|
|
97
|
+
|
|
98
|
+
[tool.setuptools.package-data]
|
|
99
|
+
"icplot" = ["py.typed", "controlDict", "theme/theme.json", "theme/templates/*.j2"]
|
|
100
|
+
|
|
101
|
+
[tool.setuptools.packages.find]
|
|
102
|
+
where = ["src"]
|
|
103
|
+
|
|
104
|
+
[tool.mypy]
|
|
105
|
+
ignore_missing_imports = true
|
|
106
|
+
|
|
107
|
+
[tool.ruff]
|
|
108
|
+
line-length = 88
|
|
109
|
+
target-version = "py310"
|
|
110
|
+
src = ["src", "test"]
|
|
111
|
+
|
|
112
|
+
[tool.ruff.lint]
|
|
113
|
+
# E/W pycodestyle, F pyflakes, I import-sort (was isort), N pep8-naming,
|
|
114
|
+
# UP pyupgrade, B bugbear. Extend deliberately, not by pulling in "ALL".
|
|
115
|
+
select = ["E", "W", "F", "I", "N", "UP", "B"]
|
|
116
|
+
|
|
117
|
+
[tool.ruff.lint.isort]
|
|
118
|
+
known-first-party = ["icplot"]
|
|
119
|
+
|
|
120
|
+
[tool.pytest.ini_options]
|
|
121
|
+
testpaths = ["test",]
|
|
122
|
+
log_cli = 1
|
|
123
|
+
log_cli_level = "debug"
|
|
124
|
+
addopts = "--cov=icplot --cov-report term --cov-fail-under=55 --cov-report xml:coverage.xml --cov-report html"
|
|
@@ -45,19 +45,24 @@ def _get_out_filename(source: Path, target: Path | None, extension: str) -> Path
|
|
|
45
45
|
return source.parent / f"{source.stem}.{extension}"
|
|
46
46
|
|
|
47
47
|
|
|
48
|
-
#
|
|
49
|
-
#
|
|
50
|
-
# This ensures proper handling when converting PDFs/SVGs,
|
|
51
|
-
# as some versions of ImageMagick ignore or misapply `-alpha off` if it
|
|
52
|
-
# appears before the input file.
|
|
48
|
+
# `-alpha off` must come *after* the source file: some ImageMagick versions
|
|
49
|
+
# ignore or misapply it when it precedes the input.
|
|
53
50
|
def _pdf_to_png(source: Path, target: Path | None = None, resolution: int = 300):
|
|
54
51
|
|
|
55
52
|
outfile = _get_out_filename(source, target, "png")
|
|
56
53
|
os.makedirs(outfile.parent, exist_ok=True)
|
|
57
|
-
cmd =
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
54
|
+
cmd = [
|
|
55
|
+
"magick",
|
|
56
|
+
"-density",
|
|
57
|
+
str(resolution),
|
|
58
|
+
"-background",
|
|
59
|
+
"white",
|
|
60
|
+
str(source),
|
|
61
|
+
"-alpha",
|
|
62
|
+
"off",
|
|
63
|
+
str(outfile),
|
|
64
|
+
]
|
|
65
|
+
subprocess.run(cmd, check=True)
|
|
61
66
|
|
|
62
67
|
|
|
63
68
|
def pdf_to_png(source: Path, target: Path | None = None, resolution: int = 300):
|
|
@@ -125,8 +125,7 @@ def generate_mesh(mesh: Mesh, case_dir: Path):
|
|
|
125
125
|
if not control_dict.exists():
|
|
126
126
|
shutil.copy(Path(__file__).parent / "controlDict", control_dict)
|
|
127
127
|
|
|
128
|
-
cmd =
|
|
129
|
-
subprocess.run(cmd, cwd=case_dir,
|
|
128
|
+
cmd = ["blockMesh", "-case", str(case_dir)]
|
|
129
|
+
subprocess.run(cmd, cwd=case_dir, check=True)
|
|
130
130
|
|
|
131
|
-
cmd
|
|
132
|
-
subprocess.run(cmd, cwd=case_dir, shell=True, check=True)
|
|
131
|
+
subprocess.run(cmd + ["-write-vtk"], cwd=case_dir, check=True)
|
|
@@ -53,7 +53,10 @@ class Polymesh:
|
|
|
53
53
|
class PolymeshPatch:
|
|
54
54
|
name: str
|
|
55
55
|
faces: tuple[Face, ...]
|
|
56
|
-
|
|
56
|
+
# Mirrors the field name in OpenFOAM's own polyMesh/boundary file, which
|
|
57
|
+
# this class both parses and writes back out — renaming it to snake_case
|
|
58
|
+
# would put the Python attribute out of step with the format on disk.
|
|
59
|
+
startFace: int # noqa: N815
|
|
57
60
|
type: str = "patch"
|
|
58
61
|
|
|
59
62
|
def has_face(self, face: Face) -> bool:
|
|
@@ -102,7 +102,6 @@ def _close_circle(inner_mesh: Mesh, outer_mesh: Mesh, num_circumferential: int)
|
|
|
102
102
|
new_cells = []
|
|
103
103
|
count = 0
|
|
104
104
|
for idx in range(num_circumferential):
|
|
105
|
-
|
|
106
105
|
next_id = idx + 1
|
|
107
106
|
if next_id == num_circumferential:
|
|
108
107
|
next_id = 0
|
|
@@ -317,7 +316,6 @@ def mesh_cuboids(
|
|
|
317
316
|
for cuboid in cuboids:
|
|
318
317
|
vert_ids = []
|
|
319
318
|
for p in cuboid.points:
|
|
320
|
-
|
|
321
319
|
if not verts:
|
|
322
320
|
verts.append(Vertex.from_point(p, 0))
|
|
323
321
|
vert_ids.append(0)
|
|
@@ -57,7 +57,6 @@ def find_closest(verts: list[Vertex], point: Point) -> int:
|
|
|
57
57
|
min_id = -1
|
|
58
58
|
min_distance = 0.0
|
|
59
59
|
for idx, v in enumerate(verts):
|
|
60
|
-
|
|
61
60
|
distance = v.get_distance(point)
|
|
62
61
|
|
|
63
62
|
if idx == 0:
|
|
@@ -80,7 +79,6 @@ def find_closest_vertex(verts: tuple[Vertex, ...], v: Vertex) -> Vertex:
|
|
|
80
79
|
min_id = -1
|
|
81
80
|
min_distance = 0.0
|
|
82
81
|
for idx, vert in enumerate(verts):
|
|
83
|
-
|
|
84
82
|
distance = vert.get_vertex_distance(v)
|
|
85
83
|
|
|
86
84
|
if idx == 0:
|
|
@@ -26,13 +26,11 @@ class Shape:
|
|
|
26
26
|
|
|
27
27
|
@dataclass(frozen=True)
|
|
28
28
|
class Circle(Shape):
|
|
29
|
-
|
|
30
29
|
radius: float = 1.0
|
|
31
30
|
|
|
32
31
|
|
|
33
32
|
@dataclass(frozen=True)
|
|
34
33
|
class Annulus(Shape):
|
|
35
|
-
|
|
36
34
|
outer_radius: float = 1.0
|
|
37
35
|
inner_radius: float = 0.5
|
|
38
36
|
angle: float = 360 # degrees
|
|
@@ -16,13 +16,11 @@ from icplot.theme.color import Color
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
class PlotSeriesBase(BaseModel, frozen=True):
|
|
19
|
-
|
|
20
19
|
min_value: float | None = None
|
|
21
20
|
max_value: float | None = None
|
|
22
21
|
|
|
23
22
|
|
|
24
23
|
class PlotSeriesCreate(PlotSeriesBase, frozen=True):
|
|
25
|
-
|
|
26
24
|
measurement: str
|
|
27
25
|
unit_name: str = ""
|
|
28
26
|
|
|
@@ -36,7 +34,6 @@ class PlotSeriesCreate(PlotSeriesBase, frozen=True):
|
|
|
36
34
|
|
|
37
35
|
|
|
38
36
|
class PlotSeriesPublic(PlotSeriesBase, frozen=True):
|
|
39
|
-
|
|
40
37
|
measurement: MeasurementPublicWithUnits
|
|
41
38
|
unit: UnitPublic
|
|
42
39
|
x: MeasurementPublicWithUnits | None
|
|
@@ -40,7 +40,7 @@ def _ganttbar(milestone) -> str:
|
|
|
40
40
|
|
|
41
41
|
def render(gantt: GanttChart, theme: "Theme | None" = None) -> str:
|
|
42
42
|
|
|
43
|
-
with open(Path(__file__).parent / "pgfgantt.tex",
|
|
43
|
+
with open(Path(__file__).parent / "pgfgantt.tex", encoding="utf-8") as f:
|
|
44
44
|
template = f.read()
|
|
45
45
|
|
|
46
46
|
milestones = gantt.milestones
|
|
@@ -6,6 +6,7 @@ Mermaid must already be set up on the system, eg. via the npm ecosystem.
|
|
|
6
6
|
|
|
7
7
|
import logging
|
|
8
8
|
import os
|
|
9
|
+
import shlex
|
|
9
10
|
import shutil
|
|
10
11
|
import subprocess
|
|
11
12
|
from pathlib import Path
|
|
@@ -39,9 +40,9 @@ def render(ctx: RenderContext):
|
|
|
39
40
|
if not browser_config and (env_path := os.environ.get("MMDC_PUPPETEER_CONFIG")):
|
|
40
41
|
browser_config = Path(env_path)
|
|
41
42
|
|
|
42
|
-
cmd =
|
|
43
|
+
cmd = ["mmdc", "-i", str(ctx.source), "-o", str(output_path)]
|
|
43
44
|
if browser_config:
|
|
44
|
-
cmd +=
|
|
45
|
-
logger.debug("Command: %s", cmd)
|
|
46
|
-
subprocess.run(cmd,
|
|
45
|
+
cmd += ["-p", str(browser_config)]
|
|
46
|
+
logger.debug("Command: %s", shlex.join(cmd))
|
|
47
|
+
subprocess.run(cmd, check=True)
|
|
47
48
|
logger.info("Done: %s", output_path.name)
|
|
@@ -5,6 +5,7 @@ This module has functionality for publishing Tex documents
|
|
|
5
5
|
import hashlib
|
|
6
6
|
import logging
|
|
7
7
|
import os
|
|
8
|
+
import shlex
|
|
8
9
|
import shutil
|
|
9
10
|
import subprocess
|
|
10
11
|
from pathlib import Path
|
|
@@ -38,12 +39,11 @@ def _run_commands(ctx: RenderContext, work_dir: Path):
|
|
|
38
39
|
logger.debug("Engine: %s | work_dir: %s", ctx.config.tex.build_engine, work_dir)
|
|
39
40
|
|
|
40
41
|
if ctx.config.tex.build_engine == "pdflatex":
|
|
41
|
-
cmd =
|
|
42
|
-
logger.info("Command: %s",
|
|
42
|
+
cmd = [ctx.config.tex.build_engine, *extra_flags, str(ctx.source)]
|
|
43
|
+
logger.info("Command: %s", shlex.join(cmd))
|
|
43
44
|
with open(work_dir / "stdout.txt", "w", encoding="utf-8") as f:
|
|
44
45
|
subprocess.run(
|
|
45
46
|
cmd,
|
|
46
|
-
shell=True,
|
|
47
47
|
check=True,
|
|
48
48
|
cwd=work_dir,
|
|
49
49
|
env=tex_env,
|
|
@@ -91,7 +91,10 @@ def render(ctx: RenderContext):
|
|
|
91
91
|
ctx.config.tex.build_engine,
|
|
92
92
|
)
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
# Names a build directory, so collision resistance is all that is wanted.
|
|
95
|
+
path_hash = hashlib.md5(
|
|
96
|
+
str(ctx.source).encode(), usedforsecurity=False
|
|
97
|
+
).hexdigest()[:8]
|
|
95
98
|
work_dir = ctx.build_dir / f"{ctx.source.stem}_{path_hash}"
|
|
96
99
|
work_dir.mkdir(exist_ok=True, parents=True)
|
|
97
100
|
|
|
@@ -2,9 +2,9 @@ import logging
|
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
from typing import cast
|
|
4
4
|
|
|
5
|
-
from icplot.graph.series import LinePlotSeries # NOQA
|
|
6
5
|
from icplot.graph.series import (
|
|
7
6
|
ImageSeries,
|
|
7
|
+
LinePlotSeries, # NOQA
|
|
8
8
|
PlotSeries,
|
|
9
9
|
ScatterPlotSeries,
|
|
10
10
|
)
|
|
@@ -33,6 +33,11 @@ class MatplotlibColorMap(ColorMap):
|
|
|
33
33
|
super().__init__(label, mpl.colormaps[label])
|
|
34
34
|
|
|
35
35
|
|
|
36
|
+
# Module-level singleton rather than a constructed default argument, which
|
|
37
|
+
# would be built once at import time and shared silently across every call.
|
|
38
|
+
_DEFAULT_COLORMAP = MatplotlibColorMap("gist_rainbow")
|
|
39
|
+
|
|
40
|
+
|
|
36
41
|
def str_exact_values_formatter(x, pos):
|
|
37
42
|
"""
|
|
38
43
|
When using log scale, axis ticks come out as scientific notation by default,
|
|
@@ -158,9 +163,10 @@ def _render(fig, path: Path | None = None):
|
|
|
158
163
|
plt.switch_backend("Agg")
|
|
159
164
|
|
|
160
165
|
|
|
161
|
-
def render(
|
|
162
|
-
|
|
163
|
-
|
|
166
|
+
def render(plot: Plot, path: Path | None = None, cmap=None):
|
|
167
|
+
|
|
168
|
+
if cmap is None:
|
|
169
|
+
cmap = _DEFAULT_COLORMAP
|
|
164
170
|
|
|
165
171
|
colors = get_series_colors(cmap, plot)
|
|
166
172
|
|
|
@@ -169,7 +175,8 @@ def render(
|
|
|
169
175
|
if len(plot.y_axes) > 1:
|
|
170
176
|
axs.append(ax.twinx())
|
|
171
177
|
|
|
172
|
-
|
|
178
|
+
# colors is derived from plot.series, so the two are the same length.
|
|
179
|
+
for series, color in zip(plot.series, colors, strict=True):
|
|
173
180
|
_plot_series(axs, series, color)
|
|
174
181
|
|
|
175
182
|
_set_decorations(axs, plot)
|
|
@@ -185,7 +192,9 @@ def render_grid(
|
|
|
185
192
|
rows, cols, series = plot.get_subplots(num_samples)
|
|
186
193
|
fig, axs = plt.subplots(rows, cols)
|
|
187
194
|
|
|
188
|
-
|
|
195
|
+
# strict=False keeps the existing behaviour: plt.subplots(rows, cols) can
|
|
196
|
+
# return more axes than there are series when the grid is not full.
|
|
197
|
+
for ax, series_item in zip(axs, series, strict=False):
|
|
189
198
|
_plot_series(ax, series_item)
|
|
190
199
|
|
|
191
200
|
_render(fig, path)
|
|
@@ -151,7 +151,9 @@ def plot_array(path: Path, series: PlotSeriesPublic, data_series: Series):
|
|
|
151
151
|
raise RuntimeError("Attempted to plot series with missing data")
|
|
152
152
|
|
|
153
153
|
for idx, (x, values) in enumerate(
|
|
154
|
-
zip
|
|
154
|
+
# strict=False preserves the existing zip-to-shortest behaviour; the
|
|
155
|
+
# x array and the measurement array are not guaranteed equal length.
|
|
156
|
+
zip(data_series.get_array(data_series.x).data, array.data, strict=False)
|
|
155
157
|
):
|
|
156
158
|
fig, ax = plt.subplots()
|
|
157
159
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import os
|
|
2
|
+
from collections.abc import Callable
|
|
2
3
|
from pathlib import Path
|
|
3
|
-
from typing import Any
|
|
4
|
+
from typing import Any
|
|
4
5
|
|
|
5
6
|
from iccore.data import Series
|
|
6
7
|
from iccore.data.series import convert_units
|
|
@@ -16,7 +17,6 @@ from . import mpl, vtk
|
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
class PlotConfig(BaseModel, frozen=True):
|
|
19
|
-
|
|
20
20
|
series_attr: str
|
|
21
21
|
x_attr: str
|
|
22
22
|
plots: dict[str, Plot]
|
|
@@ -39,7 +39,6 @@ def make_plots(
|
|
|
39
39
|
# Each 'y attribute' in the config corresponds to a 'plot' of this
|
|
40
40
|
# attribute's values.
|
|
41
41
|
for y_attr, plot_template in config.plots.items():
|
|
42
|
-
|
|
43
42
|
series = []
|
|
44
43
|
for label in series_labels:
|
|
45
44
|
# Get results for this series
|
|
@@ -55,7 +54,7 @@ def make_plots(
|
|
|
55
54
|
)
|
|
56
55
|
if not points:
|
|
57
56
|
continue
|
|
58
|
-
x, y = [list(xy) for xy in zip(*points)]
|
|
57
|
+
x, y = [list(xy) for xy in zip(*points, strict=True)]
|
|
59
58
|
|
|
60
59
|
if label in config.colormap:
|
|
61
60
|
series.append(
|
|
@@ -79,13 +78,18 @@ def plot(
|
|
|
79
78
|
results: list[Any],
|
|
80
79
|
config: PlotConfig,
|
|
81
80
|
point_func: Callable,
|
|
82
|
-
output_dir: Path =
|
|
81
|
+
output_dir: Path | None = None,
|
|
83
82
|
):
|
|
84
83
|
"""
|
|
85
84
|
For a given set of results and plot config generate the
|
|
86
85
|
corresponding plots and render them to files.
|
|
87
86
|
"""
|
|
88
87
|
|
|
88
|
+
# Resolved per call, not once at import: the previous default froze the
|
|
89
|
+
# working directory at the moment this module was first imported.
|
|
90
|
+
if output_dir is None:
|
|
91
|
+
output_dir = Path(os.getcwd())
|
|
92
|
+
|
|
89
93
|
for p in make_plots(results, config, point_func):
|
|
90
94
|
render(p, output_dir / f"{p.name}.svg")
|
|
91
95
|
|
|
@@ -100,6 +100,8 @@ def generate_theme(output_dir: Path, theme_path: Path, template_dir: Path) -> No
|
|
|
100
100
|
|
|
101
101
|
env = Environment(
|
|
102
102
|
loader=FileSystemLoader(str(template_dir)),
|
|
103
|
+
# Targets are PlantUML and TeX, not HTML — escaping would corrupt them.
|
|
104
|
+
autoescape=False,
|
|
103
105
|
keep_trailing_newline=True,
|
|
104
106
|
trim_blocks=True,
|
|
105
107
|
lstrip_blocks=True,
|