FEMlium 0.1.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.
- femlium-0.1.0/AUTHORS +1 -0
- femlium-0.1.0/FEMlium.egg-info/PKG-INFO +79 -0
- femlium-0.1.0/FEMlium.egg-info/SOURCES.txt +22 -0
- femlium-0.1.0/FEMlium.egg-info/dependency_links.txt +1 -0
- femlium-0.1.0/FEMlium.egg-info/requires.txt +32 -0
- femlium-0.1.0/FEMlium.egg-info/top_level.txt +1 -0
- femlium-0.1.0/LICENSE +7 -0
- femlium-0.1.0/PKG-INFO +79 -0
- femlium-0.1.0/README.md +10 -0
- femlium-0.1.0/femlium/__init__.py +33 -0
- femlium-0.1.0/femlium/base_mesh_plotter.py +263 -0
- femlium-0.1.0/femlium/base_plotter.py +64 -0
- femlium-0.1.0/femlium/base_solution_plotter.py +384 -0
- femlium-0.1.0/femlium/dolfinx_plotter.py +206 -0
- femlium-0.1.0/femlium/domain_plotter.py +151 -0
- femlium-0.1.0/femlium/firedrake_plotter.py +200 -0
- femlium-0.1.0/femlium/meshio_plotter.py +90 -0
- femlium-0.1.0/femlium/numpy_plotter.py +14 -0
- femlium-0.1.0/femlium/utils/__init__.py +10 -0
- femlium-0.1.0/femlium/utils/colorbar_wrapper.py +34 -0
- femlium-0.1.0/femlium/utils/geojson_with_arrows.py +90 -0
- femlium-0.1.0/femlium/utils/transformer_wrapper.py +52 -0
- femlium-0.1.0/pyproject.toml +113 -0
- femlium-0.1.0/setup.cfg +4 -0
femlium-0.1.0/AUTHORS
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Francesco Ballarin <francesco.ballarin@unicatt.it>
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: FEMlium
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Interactive geographic plots of finite element data with folium
|
|
5
|
+
Author-email: Francesco Ballarin <francesco.ballarin@unicatt.it>
|
|
6
|
+
Maintainer-email: Francesco Ballarin <francesco.ballarin@unicatt.it>
|
|
7
|
+
License: Copyright 2021-2025 FEMlium authors and contributors
|
|
8
|
+
|
|
9
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
|
|
15
|
+
Project-URL: homepage, https://femlium.github.io
|
|
16
|
+
Project-URL: repository, https://github.com/FEMlium/FEMlium
|
|
17
|
+
Project-URL: issues, https://github.com/FEMlium/FEMlium/issues
|
|
18
|
+
Project-URL: funding, https://github.com/sponsors/francesco-ballarin
|
|
19
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
20
|
+
Classifier: Intended Audience :: Developers
|
|
21
|
+
Classifier: Intended Audience :: Science/Research
|
|
22
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
23
|
+
Classifier: Operating System :: POSIX
|
|
24
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
25
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
26
|
+
Classifier: Programming Language :: Python
|
|
27
|
+
Classifier: Programming Language :: Python :: 3
|
|
28
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
29
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
30
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
31
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
32
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
33
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
34
|
+
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
35
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
36
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
37
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
38
|
+
Requires-Python: >=3.9
|
|
39
|
+
Description-Content-Type: text/markdown
|
|
40
|
+
License-File: LICENSE
|
|
41
|
+
License-File: AUTHORS
|
|
42
|
+
Requires-Dist: branca
|
|
43
|
+
Requires-Dist: folium>=0.12.0
|
|
44
|
+
Requires-Dist: geojson
|
|
45
|
+
Requires-Dist: matplotlib
|
|
46
|
+
Requires-Dist: numpy
|
|
47
|
+
Requires-Dist: pyproj
|
|
48
|
+
Provides-Extra: backend-dolfinx
|
|
49
|
+
Requires-Dist: fenics-dolfinx>=0.8.0; extra == "backend-dolfinx"
|
|
50
|
+
Provides-Extra: backend-firedrake
|
|
51
|
+
Requires-Dist: firedrake>=2025.4.0; extra == "backend-firedrake"
|
|
52
|
+
Provides-Extra: docs
|
|
53
|
+
Requires-Dist: sphinx; extra == "docs"
|
|
54
|
+
Provides-Extra: lint
|
|
55
|
+
Requires-Dist: isort; extra == "lint"
|
|
56
|
+
Requires-Dist: nbqa; extra == "lint"
|
|
57
|
+
Requires-Dist: ruff; extra == "lint"
|
|
58
|
+
Requires-Dist: yamllint; extra == "lint"
|
|
59
|
+
Provides-Extra: tests
|
|
60
|
+
Requires-Dist: coverage[toml]; extra == "tests"
|
|
61
|
+
Requires-Dist: nbvalx[unit-tests]; extra == "tests"
|
|
62
|
+
Requires-Dist: pytest; extra == "tests"
|
|
63
|
+
Provides-Extra: tutorials
|
|
64
|
+
Requires-Dist: gmsh; extra == "tutorials"
|
|
65
|
+
Requires-Dist: meshio; extra == "tutorials"
|
|
66
|
+
Requires-Dist: nbvalx[notebooks]; extra == "tutorials"
|
|
67
|
+
Requires-Dist: viskex; extra == "tutorials"
|
|
68
|
+
Dynamic: license-file
|
|
69
|
+
|
|
70
|
+
## FEMlium – interactive visualization of finite element simulations on geographic maps with folium ##
|
|
71
|
+
<img src="https://femlium.github.io/_images/FEMlium-logo.png" alt="FEMlium – interactive visualization of finite element simulations on geographic maps with folium" width="150px">
|
|
72
|
+
|
|
73
|
+
**FEMlium** is a library that enables visualizing finite element simulations on geographic maps using **folium**. Supported finite element backends are dolfinx and firedrake.
|
|
74
|
+
|
|
75
|
+
**FEMlium** is currently developed and maintained at [Università Cattolica del Sacro Cuore](https://www.unicatt.it/) by [Prof. Francesco Ballarin](https://www.francescoballarin.it).
|
|
76
|
+
|
|
77
|
+
Like **folium**, **FEMlium** is freely available under the MIT license.
|
|
78
|
+
|
|
79
|
+
Visit [femlium.github.io](https://femlium.github.io/) for installation instructions and additional information.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
AUTHORS
|
|
2
|
+
LICENSE
|
|
3
|
+
README.md
|
|
4
|
+
pyproject.toml
|
|
5
|
+
FEMlium.egg-info/PKG-INFO
|
|
6
|
+
FEMlium.egg-info/SOURCES.txt
|
|
7
|
+
FEMlium.egg-info/dependency_links.txt
|
|
8
|
+
FEMlium.egg-info/requires.txt
|
|
9
|
+
FEMlium.egg-info/top_level.txt
|
|
10
|
+
femlium/__init__.py
|
|
11
|
+
femlium/base_mesh_plotter.py
|
|
12
|
+
femlium/base_plotter.py
|
|
13
|
+
femlium/base_solution_plotter.py
|
|
14
|
+
femlium/dolfinx_plotter.py
|
|
15
|
+
femlium/domain_plotter.py
|
|
16
|
+
femlium/firedrake_plotter.py
|
|
17
|
+
femlium/meshio_plotter.py
|
|
18
|
+
femlium/numpy_plotter.py
|
|
19
|
+
femlium/utils/__init__.py
|
|
20
|
+
femlium/utils/colorbar_wrapper.py
|
|
21
|
+
femlium/utils/geojson_with_arrows.py
|
|
22
|
+
femlium/utils/transformer_wrapper.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
branca
|
|
2
|
+
folium>=0.12.0
|
|
3
|
+
geojson
|
|
4
|
+
matplotlib
|
|
5
|
+
numpy
|
|
6
|
+
pyproj
|
|
7
|
+
|
|
8
|
+
[backend_dolfinx]
|
|
9
|
+
fenics-dolfinx>=0.8.0
|
|
10
|
+
|
|
11
|
+
[backend_firedrake]
|
|
12
|
+
firedrake>=2025.4.0
|
|
13
|
+
|
|
14
|
+
[docs]
|
|
15
|
+
sphinx
|
|
16
|
+
|
|
17
|
+
[lint]
|
|
18
|
+
isort
|
|
19
|
+
nbqa
|
|
20
|
+
ruff
|
|
21
|
+
yamllint
|
|
22
|
+
|
|
23
|
+
[tests]
|
|
24
|
+
coverage[toml]
|
|
25
|
+
nbvalx[unit-tests]
|
|
26
|
+
pytest
|
|
27
|
+
|
|
28
|
+
[tutorials]
|
|
29
|
+
gmsh
|
|
30
|
+
meshio
|
|
31
|
+
nbvalx[notebooks]
|
|
32
|
+
viskex
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
femlium
|
femlium-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright 2021-2025 FEMlium authors and contributors
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
femlium-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: FEMlium
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Interactive geographic plots of finite element data with folium
|
|
5
|
+
Author-email: Francesco Ballarin <francesco.ballarin@unicatt.it>
|
|
6
|
+
Maintainer-email: Francesco Ballarin <francesco.ballarin@unicatt.it>
|
|
7
|
+
License: Copyright 2021-2025 FEMlium authors and contributors
|
|
8
|
+
|
|
9
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
|
|
15
|
+
Project-URL: homepage, https://femlium.github.io
|
|
16
|
+
Project-URL: repository, https://github.com/FEMlium/FEMlium
|
|
17
|
+
Project-URL: issues, https://github.com/FEMlium/FEMlium/issues
|
|
18
|
+
Project-URL: funding, https://github.com/sponsors/francesco-ballarin
|
|
19
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
20
|
+
Classifier: Intended Audience :: Developers
|
|
21
|
+
Classifier: Intended Audience :: Science/Research
|
|
22
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
23
|
+
Classifier: Operating System :: POSIX
|
|
24
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
25
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
26
|
+
Classifier: Programming Language :: Python
|
|
27
|
+
Classifier: Programming Language :: Python :: 3
|
|
28
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
29
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
30
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
31
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
32
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
33
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
34
|
+
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
35
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
36
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
37
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
38
|
+
Requires-Python: >=3.9
|
|
39
|
+
Description-Content-Type: text/markdown
|
|
40
|
+
License-File: LICENSE
|
|
41
|
+
License-File: AUTHORS
|
|
42
|
+
Requires-Dist: branca
|
|
43
|
+
Requires-Dist: folium>=0.12.0
|
|
44
|
+
Requires-Dist: geojson
|
|
45
|
+
Requires-Dist: matplotlib
|
|
46
|
+
Requires-Dist: numpy
|
|
47
|
+
Requires-Dist: pyproj
|
|
48
|
+
Provides-Extra: backend-dolfinx
|
|
49
|
+
Requires-Dist: fenics-dolfinx>=0.8.0; extra == "backend-dolfinx"
|
|
50
|
+
Provides-Extra: backend-firedrake
|
|
51
|
+
Requires-Dist: firedrake>=2025.4.0; extra == "backend-firedrake"
|
|
52
|
+
Provides-Extra: docs
|
|
53
|
+
Requires-Dist: sphinx; extra == "docs"
|
|
54
|
+
Provides-Extra: lint
|
|
55
|
+
Requires-Dist: isort; extra == "lint"
|
|
56
|
+
Requires-Dist: nbqa; extra == "lint"
|
|
57
|
+
Requires-Dist: ruff; extra == "lint"
|
|
58
|
+
Requires-Dist: yamllint; extra == "lint"
|
|
59
|
+
Provides-Extra: tests
|
|
60
|
+
Requires-Dist: coverage[toml]; extra == "tests"
|
|
61
|
+
Requires-Dist: nbvalx[unit-tests]; extra == "tests"
|
|
62
|
+
Requires-Dist: pytest; extra == "tests"
|
|
63
|
+
Provides-Extra: tutorials
|
|
64
|
+
Requires-Dist: gmsh; extra == "tutorials"
|
|
65
|
+
Requires-Dist: meshio; extra == "tutorials"
|
|
66
|
+
Requires-Dist: nbvalx[notebooks]; extra == "tutorials"
|
|
67
|
+
Requires-Dist: viskex; extra == "tutorials"
|
|
68
|
+
Dynamic: license-file
|
|
69
|
+
|
|
70
|
+
## FEMlium – interactive visualization of finite element simulations on geographic maps with folium ##
|
|
71
|
+
<img src="https://femlium.github.io/_images/FEMlium-logo.png" alt="FEMlium – interactive visualization of finite element simulations on geographic maps with folium" width="150px">
|
|
72
|
+
|
|
73
|
+
**FEMlium** is a library that enables visualizing finite element simulations on geographic maps using **folium**. Supported finite element backends are dolfinx and firedrake.
|
|
74
|
+
|
|
75
|
+
**FEMlium** is currently developed and maintained at [Università Cattolica del Sacro Cuore](https://www.unicatt.it/) by [Prof. Francesco Ballarin](https://www.francescoballarin.it).
|
|
76
|
+
|
|
77
|
+
Like **folium**, **FEMlium** is freely available under the MIT license.
|
|
78
|
+
|
|
79
|
+
Visit [femlium.github.io](https://femlium.github.io/) for installation instructions and additional information.
|
femlium-0.1.0/README.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
## FEMlium – interactive visualization of finite element simulations on geographic maps with folium ##
|
|
2
|
+
<img src="https://femlium.github.io/_images/FEMlium-logo.png" alt="FEMlium – interactive visualization of finite element simulations on geographic maps with folium" width="150px">
|
|
3
|
+
|
|
4
|
+
**FEMlium** is a library that enables visualizing finite element simulations on geographic maps using **folium**. Supported finite element backends are dolfinx and firedrake.
|
|
5
|
+
|
|
6
|
+
**FEMlium** is currently developed and maintained at [Università Cattolica del Sacro Cuore](https://www.unicatt.it/) by [Prof. Francesco Ballarin](https://www.francescoballarin.it).
|
|
7
|
+
|
|
8
|
+
Like **folium**, **FEMlium** is freely available under the MIT license.
|
|
9
|
+
|
|
10
|
+
Visit [femlium.github.io](https://femlium.github.io/) for installation instructions and additional information.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Copyright (C) 2021-2025 by the FEMlium authors
|
|
2
|
+
#
|
|
3
|
+
# This file is part of FEMlium.
|
|
4
|
+
#
|
|
5
|
+
# SPDX-License-Identifier: MIT
|
|
6
|
+
"""FEMlium main module."""
|
|
7
|
+
|
|
8
|
+
from femlium.base_mesh_plotter import BaseMeshPlotter
|
|
9
|
+
from femlium.base_plotter import BasePlotter
|
|
10
|
+
from femlium.base_solution_plotter import BaseSolutionPlotter
|
|
11
|
+
from femlium.domain_plotter import DomainPlotter
|
|
12
|
+
from femlium.numpy_plotter import NumpyPlotter
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
import meshio
|
|
16
|
+
except ImportError: # pragma: no cover
|
|
17
|
+
pass
|
|
18
|
+
else:
|
|
19
|
+
from femlium.meshio_plotter import MeshioPlotter
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
import dolfinx
|
|
23
|
+
except ImportError:
|
|
24
|
+
pass
|
|
25
|
+
else:
|
|
26
|
+
from femlium.dolfinx_plotter import DolfinxPlotter
|
|
27
|
+
|
|
28
|
+
try:
|
|
29
|
+
import firedrake
|
|
30
|
+
except ImportError:
|
|
31
|
+
pass
|
|
32
|
+
else:
|
|
33
|
+
from femlium.firedrake_plotter import FiredrakePlotter
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# Copyright (C) 2021-2025 by the FEMlium authors
|
|
2
|
+
#
|
|
3
|
+
# This file is part of FEMlium.
|
|
4
|
+
#
|
|
5
|
+
# SPDX-License-Identifier: MIT
|
|
6
|
+
"""Base interface of a geographic plotter for mesh-related plots."""
|
|
7
|
+
|
|
8
|
+
import typing
|
|
9
|
+
|
|
10
|
+
import folium
|
|
11
|
+
import geojson
|
|
12
|
+
import numpy as np
|
|
13
|
+
import numpy.typing as npt
|
|
14
|
+
|
|
15
|
+
from femlium.base_plotter import BasePlotter
|
|
16
|
+
from femlium.utils import ColorbarWrapper
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class BaseMeshPlotter(BasePlotter):
|
|
20
|
+
"""Base interface of a geographic plotter for mesh-related plots."""
|
|
21
|
+
|
|
22
|
+
def add_mesh_to(
|
|
23
|
+
self, geo_map: folium.Map, vertices: npt.NDArray[np.float64], cells: npt.NDArray[np.int64],
|
|
24
|
+
cell_markers: typing.Optional[npt.NDArray[np.int64]] = None,
|
|
25
|
+
face_markers: typing.Optional[npt.NDArray[np.int64]] = None,
|
|
26
|
+
cell_colors: typing.Optional[typing.Union[str, dict[int, str]]] = None,
|
|
27
|
+
face_colors: typing.Optional[typing.Union[str, dict[int, str]]] = None,
|
|
28
|
+
face_weights: typing.Optional[typing.Union[int, dict[int, int]]] = None
|
|
29
|
+
) -> None:
|
|
30
|
+
"""
|
|
31
|
+
Add a triangular mesh to a folium map.
|
|
32
|
+
|
|
33
|
+
Parameters
|
|
34
|
+
----------
|
|
35
|
+
geo_map
|
|
36
|
+
Map to which the mesh plot should be added.
|
|
37
|
+
vertices
|
|
38
|
+
Matrix containing the coordinates of the vertices.
|
|
39
|
+
The matrix should have as many rows as vertices in the mesh, and two columns.
|
|
40
|
+
cells
|
|
41
|
+
Matrix containing the connectivity of the cells.
|
|
42
|
+
The matrix should have as many rows as cells in the mesh, and three columns.
|
|
43
|
+
cell_markers
|
|
44
|
+
Vector containing a marker (i.e., an integer number) for each cell.
|
|
45
|
+
The vector should have as many entries as cells in the mesh.
|
|
46
|
+
If not provided, the marker will be set to 0 everywhere.
|
|
47
|
+
face_markers
|
|
48
|
+
Matrix containing a marker (i.e., an integer number) for each face.
|
|
49
|
+
The matrix should have the same shape of the cells argument.
|
|
50
|
+
Given a row index r, the entry face_markers[r, 0] is the marker of the
|
|
51
|
+
face connecting the first and second vertex of the r-th cell.
|
|
52
|
+
Similarly, face_markers[r, 1] is the marker associated to the face connecting
|
|
53
|
+
the second and third vertex of the r-th cell. Finally, face_markers[r, 2] is
|
|
54
|
+
the marker associated to the face connecting the first and third vertex of the
|
|
55
|
+
r-th cell.
|
|
56
|
+
If not provided, the marker will be set to 0 everywhere.
|
|
57
|
+
cell_colors
|
|
58
|
+
If a dictionary is provided, it should contain key: value pairs defining the mapping
|
|
59
|
+
marker: color for cells.
|
|
60
|
+
If a string is provided instead of a dictionary, the same color will be used for all
|
|
61
|
+
cell markers.
|
|
62
|
+
If not provided, the cells will not be colored.
|
|
63
|
+
face_colors
|
|
64
|
+
If a dictionary is provided, it should contain key: value pairs defining the mapping
|
|
65
|
+
marker: color for faces.
|
|
66
|
+
If a string is provided instead of a dictionary, the same color will be used for all
|
|
67
|
+
face markers.
|
|
68
|
+
If not provided, a default black color will be used for faces.
|
|
69
|
+
face_weights
|
|
70
|
+
Line weight of each face. Input should be provided following a similar convention for
|
|
71
|
+
the face_colors argument.
|
|
72
|
+
If not provided, a unit weight will be used.
|
|
73
|
+
"""
|
|
74
|
+
if cell_markers is None:
|
|
75
|
+
cell_markers = np.zeros((cells.shape[0], ), dtype=np.int64)
|
|
76
|
+
else:
|
|
77
|
+
assert cell_markers.shape[0] == cells.shape[0]
|
|
78
|
+
|
|
79
|
+
if face_markers is None:
|
|
80
|
+
face_markers = np.zeros(cells.shape, dtype=np.int64)
|
|
81
|
+
else:
|
|
82
|
+
assert face_markers.shape == cells.shape
|
|
83
|
+
|
|
84
|
+
unique_cell_markers = np.unique(cell_markers).astype(int)
|
|
85
|
+
unique_face_markers = np.unique(face_markers).astype(int)
|
|
86
|
+
cell_colors = self._process_optional_argument_on_markers(cell_colors, "none", unique_cell_markers)
|
|
87
|
+
face_colors = self._process_optional_argument_on_markers(face_colors, "black", unique_face_markers)
|
|
88
|
+
face_weights = self._process_optional_argument_on_markers(face_weights, 1, unique_face_markers)
|
|
89
|
+
|
|
90
|
+
def style_function(x: dict[str, dict[str, typing.Any]]) -> dict[str, typing.Any]:
|
|
91
|
+
if x["geometry"]["type"] == "MultiPolygon":
|
|
92
|
+
return {
|
|
93
|
+
# Boundary properties
|
|
94
|
+
"stroke": x["properties"]["stroke"],
|
|
95
|
+
"color": x["properties"]["color"],
|
|
96
|
+
"weight": x["properties"]["weight"],
|
|
97
|
+
# Interior properties
|
|
98
|
+
"fill": x["properties"]["fill"],
|
|
99
|
+
"fillColor": x["properties"]["fillColor"],
|
|
100
|
+
"fillOpacity": x["properties"]["fillOpacity"]
|
|
101
|
+
}
|
|
102
|
+
elif x["geometry"]["type"] == "MultiLineString":
|
|
103
|
+
return {
|
|
104
|
+
"stroke": x["properties"]["stroke"],
|
|
105
|
+
"color": x["properties"]["color"],
|
|
106
|
+
"weight": x["properties"]["weight"]
|
|
107
|
+
}
|
|
108
|
+
else: # pragma: no cover
|
|
109
|
+
raise ValueError("Invalid type")
|
|
110
|
+
|
|
111
|
+
json = self._convert_mesh_to_geojson(
|
|
112
|
+
vertices, cells, cell_markers, face_markers, cell_colors, face_colors, face_weights)
|
|
113
|
+
folium.GeoJson(json, style_function=style_function).add_to(geo_map)
|
|
114
|
+
|
|
115
|
+
cell_colors_where_none = np.argwhere(cell_colors == "none")
|
|
116
|
+
cell_colors_not_none = np.delete(cell_colors, cell_colors_where_none)
|
|
117
|
+
cell_colors_values = np.arange(0, np.max(unique_cell_markers) + 1)
|
|
118
|
+
cell_colors_values_not_none = np.delete(cell_colors_values, cell_colors_where_none)
|
|
119
|
+
assert cell_colors_not_none.shape == cell_colors_values_not_none.shape
|
|
120
|
+
cell_colors_in_figure = np.delete(
|
|
121
|
+
cell_colors_not_none, np.setdiff1d(cell_colors_values_not_none, unique_cell_markers))
|
|
122
|
+
cell_colors_values_in_figure = np.delete(
|
|
123
|
+
cell_colors_values_not_none, np.setdiff1d(cell_colors_values_not_none, unique_cell_markers))
|
|
124
|
+
if np.unique(cell_colors_in_figure).shape[0] > 1:
|
|
125
|
+
colorbar = ColorbarWrapper(
|
|
126
|
+
colors=cell_colors_in_figure, values=cell_colors_values_in_figure, caption="Cell markers")
|
|
127
|
+
colorbar.add_to(geo_map)
|
|
128
|
+
|
|
129
|
+
face_colors_values = np.arange(0, np.max(unique_face_markers) + 1)
|
|
130
|
+
assert face_colors.shape == face_colors_values.shape
|
|
131
|
+
face_colors_in_figure = np.delete(
|
|
132
|
+
face_colors, np.setdiff1d(face_colors_values, unique_face_markers))
|
|
133
|
+
face_colors_values_in_figure = np.delete(
|
|
134
|
+
face_colors_values, np.setdiff1d(face_colors_values, unique_face_markers))
|
|
135
|
+
if np.unique(face_colors_in_figure).shape[0] > 1:
|
|
136
|
+
colorbar = ColorbarWrapper(
|
|
137
|
+
colors=face_colors_in_figure, values=face_colors_values_in_figure, caption="Face markers")
|
|
138
|
+
colorbar.add_to(geo_map)
|
|
139
|
+
|
|
140
|
+
def _convert_mesh_to_geojson(
|
|
141
|
+
self, vertices: npt.NDArray[np.float64], cells: npt.NDArray[np.int64],
|
|
142
|
+
cell_markers: npt.NDArray[np.int64], face_markers: npt.NDArray[np.int64],
|
|
143
|
+
cell_colors: typing.Union[str, dict[int, str]], face_colors: typing.Union[str, dict[int, str]],
|
|
144
|
+
face_weights: typing.Union[int, dict[int, int]]
|
|
145
|
+
) -> geojson.FeatureCollection:
|
|
146
|
+
"""
|
|
147
|
+
Convert a mesh to a geojson FeatureCollection.
|
|
148
|
+
|
|
149
|
+
Parameters
|
|
150
|
+
----------
|
|
151
|
+
vertices
|
|
152
|
+
Matrix containing the coordinates of the vertices.
|
|
153
|
+
The matrix should have as many rows as vertices in the mesh, and two columns.
|
|
154
|
+
cells
|
|
155
|
+
Matrix containing the connectivity of the cells.
|
|
156
|
+
The matrix should have as many rows as cells in the mesh, and three columns.
|
|
157
|
+
cell_markers
|
|
158
|
+
Vector containing a marker (i.e., an integer number) for each cell.
|
|
159
|
+
The vector should have as many entries as cells in the mesh.
|
|
160
|
+
face_markers
|
|
161
|
+
Vector containing a marker (i.e., an integer number) for each face.
|
|
162
|
+
The matrix should have the same shape of the cells argument.
|
|
163
|
+
cell_colors
|
|
164
|
+
Vector associating a cell marker to its color (i.e., a string).
|
|
165
|
+
The vector should have as many entries as the number of cell markers.
|
|
166
|
+
face_colors
|
|
167
|
+
Vector associating a face marker to its color (i.e., a string).
|
|
168
|
+
The vector should have as many entries as the number of face markers.
|
|
169
|
+
face_weights
|
|
170
|
+
Vector associating a face marker to its weight (i.e., a int).
|
|
171
|
+
The vector should have as many entries as the number of face markers.
|
|
172
|
+
|
|
173
|
+
Returns
|
|
174
|
+
-------
|
|
175
|
+
:
|
|
176
|
+
A geojson FeatureCollection representing the mesh.
|
|
177
|
+
"""
|
|
178
|
+
multipolygon_coordinates = dict()
|
|
179
|
+
multipolygon_properties = dict()
|
|
180
|
+
multiline_coordinates = dict()
|
|
181
|
+
multiline_properties = dict()
|
|
182
|
+
for c in range(cells.shape[0]):
|
|
183
|
+
coordinates = [self.transformer(*vertices[cells[c, v], :]) for v in range(3)]
|
|
184
|
+
coordinates.append(coordinates[0])
|
|
185
|
+
cell_face_markers = np.unique([face_markers[c, f] for f in range(3)]).astype(np.int64)
|
|
186
|
+
if cell_face_markers.shape[0] == 1:
|
|
187
|
+
cell_key = (cell_markers[c], True)
|
|
188
|
+
cell_properties = {
|
|
189
|
+
# Boundary properties
|
|
190
|
+
"stroke": True,
|
|
191
|
+
"color": face_colors[cell_face_markers[0]],
|
|
192
|
+
"weight": int(face_weights[cell_face_markers[0]]),
|
|
193
|
+
}
|
|
194
|
+
else:
|
|
195
|
+
cell_key = (cell_markers[c], False)
|
|
196
|
+
cell_properties = {
|
|
197
|
+
# Boundary properties
|
|
198
|
+
"stroke": False,
|
|
199
|
+
"color": None,
|
|
200
|
+
"weight": None
|
|
201
|
+
}
|
|
202
|
+
if cell_colors[cell_key[0]] != "none":
|
|
203
|
+
cell_properties.update({
|
|
204
|
+
# Interior properties
|
|
205
|
+
"fill": True,
|
|
206
|
+
"fillColor": cell_colors[cell_key[0]],
|
|
207
|
+
"fillOpacity": 1
|
|
208
|
+
})
|
|
209
|
+
else:
|
|
210
|
+
cell_properties.update({
|
|
211
|
+
# Interior properties
|
|
212
|
+
"fill": False,
|
|
213
|
+
"fillColor": None,
|
|
214
|
+
"fillOpacity": None
|
|
215
|
+
})
|
|
216
|
+
# Store current cell
|
|
217
|
+
if cell_key not in multipolygon_coordinates:
|
|
218
|
+
multipolygon_coordinates[cell_key] = list()
|
|
219
|
+
multipolygon_coordinates[cell_key].append([coordinates])
|
|
220
|
+
# Store current cell properties
|
|
221
|
+
if cell_key not in multipolygon_properties:
|
|
222
|
+
multipolygon_properties[cell_key] = cell_properties
|
|
223
|
+
else:
|
|
224
|
+
assert multipolygon_properties[cell_key] == cell_properties
|
|
225
|
+
# Store faces only if there are multiple face markers in this cell,
|
|
226
|
+
# otherwise the boundary representation of the cell is sufficient.
|
|
227
|
+
if not cell_key[1]:
|
|
228
|
+
for (f, pair) in enumerate(((0, 1), (1, 2), (0, 2))):
|
|
229
|
+
face_key = face_markers[c, f]
|
|
230
|
+
# Store current face
|
|
231
|
+
if face_key not in multiline_coordinates:
|
|
232
|
+
multiline_coordinates[face_key] = list()
|
|
233
|
+
multiline_coordinates[face_key].append([coordinates[pair[0]], coordinates[pair[1]]])
|
|
234
|
+
# Store current face properties
|
|
235
|
+
face_properties = {
|
|
236
|
+
"stroke": True,
|
|
237
|
+
"color": face_colors[face_markers[c, f]],
|
|
238
|
+
"weight": int(face_weights[face_markers[c, f]]),
|
|
239
|
+
}
|
|
240
|
+
if face_key not in multiline_properties:
|
|
241
|
+
multiline_properties[face_key] = face_properties
|
|
242
|
+
else:
|
|
243
|
+
assert multiline_properties[face_key] == face_properties
|
|
244
|
+
|
|
245
|
+
multipolygon_features = list()
|
|
246
|
+
for cell_key in multipolygon_coordinates.keys():
|
|
247
|
+
multipolygon = geojson.MultiPolygon(coordinates=multipolygon_coordinates[cell_key])
|
|
248
|
+
feature = geojson.Feature(
|
|
249
|
+
geometry=multipolygon,
|
|
250
|
+
properties=multipolygon_properties[cell_key]
|
|
251
|
+
)
|
|
252
|
+
multipolygon_features.append(feature)
|
|
253
|
+
|
|
254
|
+
multiline_features = list()
|
|
255
|
+
for face_key in multiline_coordinates.keys():
|
|
256
|
+
multiline = geojson.MultiLineString(coordinates=multiline_coordinates[face_key])
|
|
257
|
+
feature = geojson.Feature(
|
|
258
|
+
geometry=multiline,
|
|
259
|
+
properties=multiline_properties[face_key]
|
|
260
|
+
)
|
|
261
|
+
multiline_features.append(feature)
|
|
262
|
+
|
|
263
|
+
return geojson.FeatureCollection(multipolygon_features + multiline_features)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Copyright (C) 2021-2025 by the FEMlium authors
|
|
2
|
+
#
|
|
3
|
+
# This file is part of FEMlium.
|
|
4
|
+
#
|
|
5
|
+
# SPDX-License-Identifier: MIT
|
|
6
|
+
"""Interface of a geographic plotter."""
|
|
7
|
+
|
|
8
|
+
import typing
|
|
9
|
+
|
|
10
|
+
import numpy as np
|
|
11
|
+
import numpy.typing as npt
|
|
12
|
+
import pyproj
|
|
13
|
+
|
|
14
|
+
from femlium.utils import TransformerWrapper
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class BasePlotter:
|
|
18
|
+
"""
|
|
19
|
+
Interface of a geographic plotter.
|
|
20
|
+
|
|
21
|
+
Parameters
|
|
22
|
+
----------
|
|
23
|
+
transformer
|
|
24
|
+
Defines an optional transformation between coordinate reference systems (CRS) if
|
|
25
|
+
the input data use a different CRS than the output plot.
|
|
26
|
+
If not provided, the identity map is used.
|
|
27
|
+
|
|
28
|
+
Attributes
|
|
29
|
+
----------
|
|
30
|
+
transformer
|
|
31
|
+
Wrapper to the transformer object provided as first input parameter.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
def __init__(self, transformer: typing.Optional[pyproj.Transformer] = None) -> None:
|
|
35
|
+
self.transformer = TransformerWrapper(transformer)
|
|
36
|
+
|
|
37
|
+
@staticmethod
|
|
38
|
+
def _process_optional_argument_on_markers(
|
|
39
|
+
argument: typing.Any, default: typing.Any, unique_markers: npt.NDArray[typing.Any] # noqa: ANN401
|
|
40
|
+
) -> npt.NDArray[typing.Any]:
|
|
41
|
+
"""Fill optinal arguments related to markers with default value."""
|
|
42
|
+
expected_type = type(default)
|
|
43
|
+
assert isinstance(argument, (expected_type, dict)) or argument is None
|
|
44
|
+
if isinstance(argument, dict):
|
|
45
|
+
assert all(isinstance(value, expected_type) for (_, value) in argument.items())
|
|
46
|
+
|
|
47
|
+
if isinstance(default, str):
|
|
48
|
+
dtype = np.dtype(object) # otherwise np.dtype(str) only allows a single character
|
|
49
|
+
else:
|
|
50
|
+
dtype = np.dtype(expected_type)
|
|
51
|
+
|
|
52
|
+
assert np.min(unique_markers) >= 0
|
|
53
|
+
output = np.full(np.max(unique_markers) + 1, default, dtype=dtype)
|
|
54
|
+
for m in unique_markers:
|
|
55
|
+
if argument is None:
|
|
56
|
+
pass
|
|
57
|
+
elif isinstance(argument, expected_type):
|
|
58
|
+
output[m] = argument
|
|
59
|
+
elif isinstance(argument, dict):
|
|
60
|
+
if m in argument:
|
|
61
|
+
output[m] = argument[m]
|
|
62
|
+
else: # pragma: no cover
|
|
63
|
+
raise ValueError("Invalid argument provided")
|
|
64
|
+
return output
|