exergyflow 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.
- exergyflow-0.1.0/LICENSE +21 -0
- exergyflow-0.1.0/MANIFEST.in +9 -0
- exergyflow-0.1.0/PKG-INFO +151 -0
- exergyflow-0.1.0/README.md +98 -0
- exergyflow-0.1.0/docs/CHEATSHEET.md +103 -0
- exergyflow-0.1.0/docs/STEP_BY_STEP.md +61 -0
- exergyflow-0.1.0/docs/diagram.svg +1302 -0
- exergyflow-0.1.0/exergyflow/__init__.py +16 -0
- exergyflow-0.1.0/exergyflow/grassmann_diagram.py +346 -0
- exergyflow-0.1.0/exergyflow/grassmann_geometry.py +214 -0
- exergyflow-0.1.0/exergyflow/grassmann_layout.py +814 -0
- exergyflow-0.1.0/exergyflow/grassmann_render.py +709 -0
- exergyflow-0.1.0/exergyflow/grassmann_types.py +156 -0
- exergyflow-0.1.0/exergyflow.egg-info/PKG-INFO +151 -0
- exergyflow-0.1.0/exergyflow.egg-info/SOURCES.txt +19 -0
- exergyflow-0.1.0/exergyflow.egg-info/dependency_links.txt +1 -0
- exergyflow-0.1.0/exergyflow.egg-info/requires.txt +2 -0
- exergyflow-0.1.0/exergyflow.egg-info/top_level.txt +1 -0
- exergyflow-0.1.0/pyproject.toml +75 -0
- exergyflow-0.1.0/requirements.txt +2 -0
- exergyflow-0.1.0/setup.cfg +4 -0
exergyflow-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Juan Andrés Gómez González
|
|
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,151 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: exergyflow
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Sankey and Grassmann diagrams for energy and exergy analysis
|
|
5
|
+
Author-email: Juan Andrés Gómez González <ja.gomez@uniandes.edu.co>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 Juan Andrés Gómez González
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/GOMGON777/exergyflow
|
|
29
|
+
Project-URL: Issues, https://github.com/GOMGON777/exergyflow/issues
|
|
30
|
+
Keywords: exergy,energy,grassmann,grassmann diagram,grassmann diagrams,sankey,sankey diagram,sankey diagrams,thermodynamics,thermodynamic analysis,visualization,flow visualization,data visualization,engineering,process engineering,thermal systems,exergy analysis,energy analysis,flow diagram,scientific visualization,python sankey,python exergy,python thermodynamics,brayton cycle,rankine cycle
|
|
31
|
+
Classifier: Development Status :: 3 - Alpha
|
|
32
|
+
Classifier: Intended Audience :: Science/Research
|
|
33
|
+
Classifier: Intended Audience :: Education
|
|
34
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
35
|
+
Classifier: Programming Language :: Python :: 3
|
|
36
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
41
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
42
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
43
|
+
Classifier: Topic :: Scientific/Engineering
|
|
44
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
45
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
46
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
47
|
+
Requires-Python: >=3.9
|
|
48
|
+
Description-Content-Type: text/markdown
|
|
49
|
+
License-File: LICENSE
|
|
50
|
+
Requires-Dist: matplotlib>=3.7
|
|
51
|
+
Requires-Dist: numpy>=1.23
|
|
52
|
+
Dynamic: license-file
|
|
53
|
+
|
|
54
|
+
# ExergyFlow
|
|
55
|
+
|
|
56
|
+
Grassmann/Sankey diagrams for energy and exergy analysis
|
|
57
|
+
|
|
58
|
+

|
|
59
|
+
|
|
60
|
+
## Install
|
|
61
|
+
```bash
|
|
62
|
+
python -m pip install exergyflow
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Quickstart
|
|
66
|
+
```python
|
|
67
|
+
from exergyflow import Diagram, DiagramConfig, RouteSegment
|
|
68
|
+
d = Diagram(DiagramConfig(auto_scale=True, auto_scale_target=1.0))
|
|
69
|
+
d.add_process("P1")
|
|
70
|
+
d.add_flow("F1", 10, source=None, target="P1")
|
|
71
|
+
d.add_flow("F2", 5, source="P1", target=None)
|
|
72
|
+
route1 = [RouteSegment(kind='rect', length=0.25, direction='right'),
|
|
73
|
+
RouteSegment(kind='elbow', length=0.25, turn='rightup'),
|
|
74
|
+
RouteSegment(kind='rect', length=0.5, direction='up')]
|
|
75
|
+
d.add_flow("F3", 2, source="P1", target=None, route=route1)
|
|
76
|
+
fig, ax = d.draw()
|
|
77
|
+
fig.savefig("diagram.png", dpi=300, bbox_inches="tight")
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Real engineering example
|
|
81
|
+
A simplified Brayton flow sketch (values illustrative):
|
|
82
|
+
```python
|
|
83
|
+
from exergyflow import Diagram, DiagramConfig, RouteSegment
|
|
84
|
+
|
|
85
|
+
cfg = DiagramConfig(flow_value_unit="kW", flow_value_format=".0f",
|
|
86
|
+
auto_scale=True, auto_scale_target=2.0)
|
|
87
|
+
d = Diagram(cfg)
|
|
88
|
+
|
|
89
|
+
# Processes
|
|
90
|
+
d.add_process("Compressor", direction="up", length=2.5,
|
|
91
|
+
label_rotation=90, color="#59a2d3")
|
|
92
|
+
d.add_process("Combustor", direction="right", length=2.5, color="#59a2d3")
|
|
93
|
+
d.add_process("Turbine", direction="down", label_rotation=-90, color="#59a2d3")
|
|
94
|
+
|
|
95
|
+
# Routes
|
|
96
|
+
route_work_out = [
|
|
97
|
+
RouteSegment(kind='rect', length=0.25, direction='down'),
|
|
98
|
+
RouteSegment(kind='elbow', length=0.5, turn='downright'),
|
|
99
|
+
RouteSegment(kind='rect', length=2.5, direction='right')
|
|
100
|
+
]
|
|
101
|
+
route_exhaust = [
|
|
102
|
+
RouteSegment(kind='rect', length=1.5, direction='down'),
|
|
103
|
+
RouteSegment(kind='elbow', length=0.5, turn='downright'),
|
|
104
|
+
RouteSegment(kind='rect', length=2.6, direction='right')
|
|
105
|
+
]
|
|
106
|
+
route_air = [
|
|
107
|
+
RouteSegment(kind='rect', length=3.5, direction='right'),
|
|
108
|
+
RouteSegment(kind='elbow', length=0.5, turn='rightup'),
|
|
109
|
+
RouteSegment(kind='rect', length=0.5, direction='up')
|
|
110
|
+
]
|
|
111
|
+
|
|
112
|
+
# Flows
|
|
113
|
+
d.add_flow("Work_out", 220, source="Turbine",
|
|
114
|
+
target=None, label="W_t", route=route_work_out)
|
|
115
|
+
d.add_flow("Exhaust", 180, source="Turbine", target=None,
|
|
116
|
+
label="E_exh", route=route_exhaust)
|
|
117
|
+
d.add_flow("Work_in", 80, source="Turbine",
|
|
118
|
+
target="Compressor", label="W_c", cycle_breaker=True, label_dy=-0.3)
|
|
119
|
+
d.add_flow("Air", 280, source=None,
|
|
120
|
+
target="Compressor", label="E_air", route=route_air)
|
|
121
|
+
d.add_flow("Compressed", 300, source="Compressor",
|
|
122
|
+
target="Combustor", label="E_2", label_dy=0.2)
|
|
123
|
+
d.add_flow("Fuel", 700, source=None,
|
|
124
|
+
target="Combustor", length=7.75, label="E_f")
|
|
125
|
+
d.add_flow("Hot_gas", 560, source="Combustor",
|
|
126
|
+
target="Turbine", label="E_3", label_dy=0.2)
|
|
127
|
+
fig, ax = d.draw()
|
|
128
|
+
fig.savefig("brayton.svg", dpi=300, bbox_inches="tight")
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Advantages
|
|
132
|
+
- Built for thermodynamic energy and exergy conventions, including imbalance triangles and process-aware flow direction rules.
|
|
133
|
+
- Auto-layout for fast drafts, manual routing for publication-grade control.
|
|
134
|
+
- Matplotlib-native output for crisp vector export (SVG/PDF) without extra tooling.
|
|
135
|
+
- Deterministic layout and explicit routing rules help reproduce figures consistently.
|
|
136
|
+
- Built-in unit formatting for labels keeps diagrams engineering-ready.
|
|
137
|
+
|
|
138
|
+
## Details
|
|
139
|
+
- Supported Python versions: 3.9–3.14 (see `pyproject.toml`).
|
|
140
|
+
- `flow_label_mode` options: `name_value_units` (default), `value_units`, `value_only`.
|
|
141
|
+
- Units formatting: `flow_value_unit`, `flow_value_format`, `flow_value_unit_sep`.
|
|
142
|
+
- Auto-layout expects a DAG; use `cycle_breaker=True` on a process→process flow to break cycles.
|
|
143
|
+
- Manual routing must alternate `rect` and `elbow` segments and start/end with `rect`.
|
|
144
|
+
- Matplotlib-native output: export PNG, SVG, or PDF via `fig.savefig(...)`.
|
|
145
|
+
|
|
146
|
+
## Docs
|
|
147
|
+
- [Step-by-step guide](docs/STEP_BY_STEP.md)
|
|
148
|
+
- [Cheatsheet](docs/CHEATSHEET.md)
|
|
149
|
+
|
|
150
|
+
## Adavanced example
|
|
151
|
+
For an advanced example see: [Example script](examples/grassmann_example.py)
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# ExergyFlow
|
|
2
|
+
|
|
3
|
+
Grassmann/Sankey diagrams for energy and exergy analysis
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
```bash
|
|
9
|
+
python -m pip install exergyflow
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Quickstart
|
|
13
|
+
```python
|
|
14
|
+
from exergyflow import Diagram, DiagramConfig, RouteSegment
|
|
15
|
+
d = Diagram(DiagramConfig(auto_scale=True, auto_scale_target=1.0))
|
|
16
|
+
d.add_process("P1")
|
|
17
|
+
d.add_flow("F1", 10, source=None, target="P1")
|
|
18
|
+
d.add_flow("F2", 5, source="P1", target=None)
|
|
19
|
+
route1 = [RouteSegment(kind='rect', length=0.25, direction='right'),
|
|
20
|
+
RouteSegment(kind='elbow', length=0.25, turn='rightup'),
|
|
21
|
+
RouteSegment(kind='rect', length=0.5, direction='up')]
|
|
22
|
+
d.add_flow("F3", 2, source="P1", target=None, route=route1)
|
|
23
|
+
fig, ax = d.draw()
|
|
24
|
+
fig.savefig("diagram.png", dpi=300, bbox_inches="tight")
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Real engineering example
|
|
28
|
+
A simplified Brayton flow sketch (values illustrative):
|
|
29
|
+
```python
|
|
30
|
+
from exergyflow import Diagram, DiagramConfig, RouteSegment
|
|
31
|
+
|
|
32
|
+
cfg = DiagramConfig(flow_value_unit="kW", flow_value_format=".0f",
|
|
33
|
+
auto_scale=True, auto_scale_target=2.0)
|
|
34
|
+
d = Diagram(cfg)
|
|
35
|
+
|
|
36
|
+
# Processes
|
|
37
|
+
d.add_process("Compressor", direction="up", length=2.5,
|
|
38
|
+
label_rotation=90, color="#59a2d3")
|
|
39
|
+
d.add_process("Combustor", direction="right", length=2.5, color="#59a2d3")
|
|
40
|
+
d.add_process("Turbine", direction="down", label_rotation=-90, color="#59a2d3")
|
|
41
|
+
|
|
42
|
+
# Routes
|
|
43
|
+
route_work_out = [
|
|
44
|
+
RouteSegment(kind='rect', length=0.25, direction='down'),
|
|
45
|
+
RouteSegment(kind='elbow', length=0.5, turn='downright'),
|
|
46
|
+
RouteSegment(kind='rect', length=2.5, direction='right')
|
|
47
|
+
]
|
|
48
|
+
route_exhaust = [
|
|
49
|
+
RouteSegment(kind='rect', length=1.5, direction='down'),
|
|
50
|
+
RouteSegment(kind='elbow', length=0.5, turn='downright'),
|
|
51
|
+
RouteSegment(kind='rect', length=2.6, direction='right')
|
|
52
|
+
]
|
|
53
|
+
route_air = [
|
|
54
|
+
RouteSegment(kind='rect', length=3.5, direction='right'),
|
|
55
|
+
RouteSegment(kind='elbow', length=0.5, turn='rightup'),
|
|
56
|
+
RouteSegment(kind='rect', length=0.5, direction='up')
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
# Flows
|
|
60
|
+
d.add_flow("Work_out", 220, source="Turbine",
|
|
61
|
+
target=None, label="W_t", route=route_work_out)
|
|
62
|
+
d.add_flow("Exhaust", 180, source="Turbine", target=None,
|
|
63
|
+
label="E_exh", route=route_exhaust)
|
|
64
|
+
d.add_flow("Work_in", 80, source="Turbine",
|
|
65
|
+
target="Compressor", label="W_c", cycle_breaker=True, label_dy=-0.3)
|
|
66
|
+
d.add_flow("Air", 280, source=None,
|
|
67
|
+
target="Compressor", label="E_air", route=route_air)
|
|
68
|
+
d.add_flow("Compressed", 300, source="Compressor",
|
|
69
|
+
target="Combustor", label="E_2", label_dy=0.2)
|
|
70
|
+
d.add_flow("Fuel", 700, source=None,
|
|
71
|
+
target="Combustor", length=7.75, label="E_f")
|
|
72
|
+
d.add_flow("Hot_gas", 560, source="Combustor",
|
|
73
|
+
target="Turbine", label="E_3", label_dy=0.2)
|
|
74
|
+
fig, ax = d.draw()
|
|
75
|
+
fig.savefig("brayton.svg", dpi=300, bbox_inches="tight")
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Advantages
|
|
79
|
+
- Built for thermodynamic energy and exergy conventions, including imbalance triangles and process-aware flow direction rules.
|
|
80
|
+
- Auto-layout for fast drafts, manual routing for publication-grade control.
|
|
81
|
+
- Matplotlib-native output for crisp vector export (SVG/PDF) without extra tooling.
|
|
82
|
+
- Deterministic layout and explicit routing rules help reproduce figures consistently.
|
|
83
|
+
- Built-in unit formatting for labels keeps diagrams engineering-ready.
|
|
84
|
+
|
|
85
|
+
## Details
|
|
86
|
+
- Supported Python versions: 3.9–3.14 (see `pyproject.toml`).
|
|
87
|
+
- `flow_label_mode` options: `name_value_units` (default), `value_units`, `value_only`.
|
|
88
|
+
- Units formatting: `flow_value_unit`, `flow_value_format`, `flow_value_unit_sep`.
|
|
89
|
+
- Auto-layout expects a DAG; use `cycle_breaker=True` on a process→process flow to break cycles.
|
|
90
|
+
- Manual routing must alternate `rect` and `elbow` segments and start/end with `rect`.
|
|
91
|
+
- Matplotlib-native output: export PNG, SVG, or PDF via `fig.savefig(...)`.
|
|
92
|
+
|
|
93
|
+
## Docs
|
|
94
|
+
- [Step-by-step guide](docs/STEP_BY_STEP.md)
|
|
95
|
+
- [Cheatsheet](docs/CHEATSHEET.md)
|
|
96
|
+
|
|
97
|
+
## Adavanced example
|
|
98
|
+
For an advanced example see: [Example script](examples/grassmann_example.py)
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# ExergyFlow Cheatsheet
|
|
2
|
+
|
|
3
|
+
Quick reference for `DiagramConfig`, `Diagram.add_process(...)`, and `Diagram.add_flow(...)`.
|
|
4
|
+
|
|
5
|
+
## Core Concepts
|
|
6
|
+
- **Diagram**: container for processes and flows; supports auto-layout and auto-routing.
|
|
7
|
+
- **Process**: a rectangular block that can show imbalance via a right triangle.
|
|
8
|
+
- **Flow**: a magnitude drawn as a band (rectangles + elbows); width scales with value.
|
|
9
|
+
|
|
10
|
+
## Key Rules
|
|
11
|
+
- Flow routes must start/end with a `rect` and alternate `rect`/`elbow`.
|
|
12
|
+
- Elbows are quarter-annulus turns; thickness equals the flow width.
|
|
13
|
+
- Elbow turns use labels like `rightup`, `rightdown`, `leftup`, `leftdown`, `upright`, `downright`, `upleft`, `downleft` which correspond to the change in direction (e.g. rightup is an elbow that changes the flow direction from right to up).
|
|
14
|
+
- `label_rotation` is in degrees; for flows, vertical segments auto-rotate to 90 if `None`.
|
|
15
|
+
- Process directions: `right`, `left`, `up`, `down`.
|
|
16
|
+
- Inlet flows must end with a direction that matches the process direction.
|
|
17
|
+
- Outlet flows must start with a direction that matches the process direction.
|
|
18
|
+
|
|
19
|
+
### RouteSegment (for manual `route`)
|
|
20
|
+
|
|
21
|
+
| Field | Type | Notes |
|
|
22
|
+
| --- | --- | --- |
|
|
23
|
+
| `kind` | `str` | `rect` or `elbow`. |
|
|
24
|
+
| `length` | `float` | Rect: section length. Elbow: inner radius. |
|
|
25
|
+
| `direction` | `str \| None` | Required for `rect`: `right`, `left`, `up`, `down`. |
|
|
26
|
+
| `turn` | `str \| None` | Required for `elbow`: `rightup`, `rightdown`, `leftup`, `leftdown`, `upright`, `downright`, `upleft`, `downleft` |
|
|
27
|
+
|
|
28
|
+
Manual routes must alternate `rect`/`elbow` segments and start/end with `rect`.
|
|
29
|
+
|
|
30
|
+
## DiagramConfig
|
|
31
|
+
Create with `DiagramConfig(...)` and pass into `Diagram(config=...)`.
|
|
32
|
+
|
|
33
|
+
| Field | Type | Default | Notes |
|
|
34
|
+
| --- | --- | --- | --- |
|
|
35
|
+
| `scale` | `float` | `1.0` | Multiplies all flow magnitudes for drawing. |
|
|
36
|
+
| `auto_scale` | `bool` | `False` | Auto-scales flows so the largest value maps to `auto_scale_target`. |
|
|
37
|
+
| `auto_scale_target` | `float` | `1.0` | Target width for the largest flow when `auto_scale=True`. |
|
|
38
|
+
| `flow_label_mode` | `str` | `"name_value_units"` | Options: `name_value_units`, `value_units`, `value_only`. |
|
|
39
|
+
| `flow_value_format` | `str \| None` | `None` | Python format spec, e.g. `".2f"` or `".3g"`. |
|
|
40
|
+
| `flow_value_unit` | `str \| None` | `None` | Unit label appended when enabled by `flow_label_mode`. |
|
|
41
|
+
| `flow_value_unit_sep` | `str` | `" "` | Separator between value and unit. |
|
|
42
|
+
| `render_min_flow_width` | `float` | `0.0` | Minimum visible thickness for drawing only. |
|
|
43
|
+
| `flow_label_style` | `dict` | `{"fontsize": 8, "color": "black"}` | Matplotlib text kwargs for flow labels. |
|
|
44
|
+
| `process_label_style` | `dict` | `{"fontsize": 9, "color": "black"}` | Matplotlib text kwargs for process labels. |
|
|
45
|
+
| `triangle_label_style` | `dict` | `{"fontsize": 8, "color": "black"}` | Matplotlib text kwargs for imbalance labels. |
|
|
46
|
+
| `flow_gap` | `float` | `0.0` | Gap between stacked flows on a process edge. |
|
|
47
|
+
| `layer_gap` | `float` | `2.0` | Gap between layout layers (auto-layout). |
|
|
48
|
+
| `process_gap` | `float` | `1.0` | Gap between processes within a layer (auto-layout). |
|
|
49
|
+
| `elbow_inner_radius` | `float` | `0.5` | Inner radius for elbow turns (auto-routing). |
|
|
50
|
+
| `layout_direction` | `str` | `"right"` | Global layout direction: `right`, `left`, `up`, `down`. |
|
|
51
|
+
| `min_straight` | `float` | `0.2` | Minimum straight length between elbows (auto-routing). |
|
|
52
|
+
|
|
53
|
+
## Diagram.add_process(...)
|
|
54
|
+
|
|
55
|
+
| Parameter | Type | Default | Notes |
|
|
56
|
+
| --- | --- | --- | --- |
|
|
57
|
+
| `name` | `str` | required | Unique process name. |
|
|
58
|
+
| `direction` | `str \| None` | `DiagramConfig.layout_direction` | `right`, `left`, `up`, `down`. |
|
|
59
|
+
| `length` | `float \| None` | `1.8` | Process length along its direction. |
|
|
60
|
+
| `color` | `str \| None` | `"#cfd8dc"` | Fill color. |
|
|
61
|
+
| `triangle_side` | `str \| None` | `None` | If direction is `right/left`: `top` or `bottom`. If `up/down`: `left` or `right`. |
|
|
62
|
+
| `overlay` | `bool \| None` | `False` | Draws an outline-only overlay rectangle. |
|
|
63
|
+
| `overlay_height` | `float \| None` | `None` | Overlay size perpendicular to process direction. |
|
|
64
|
+
| `overlay_edgecolor` | `str \| None` | `None` | Overlay border color. |
|
|
65
|
+
| `overlay_linewidth` | `float \| None` | `None` | Overlay border width. |
|
|
66
|
+
| `overlay_linestyle` | `str \| None` | `None` | Overlay border style. |
|
|
67
|
+
| `overlay_alpha` | `float \| None` | `None` | Overlay border opacity. |
|
|
68
|
+
| `label_dx` | `float` | `0.0` | X offset for the process label. |
|
|
69
|
+
| `label_dy` | `float` | `0.0` | Y offset for the process label. |
|
|
70
|
+
| `label_rotation` | `float \| None` | `None` | Rotation in degrees for the process label. |
|
|
71
|
+
| `triangle_label` | `str \| None` | `None` | Optional label prefix for imbalance triangle. |
|
|
72
|
+
| `triangle_label_dx` | `float` | `0.0` | X offset for triangle label. |
|
|
73
|
+
| `triangle_label_dy` | `float` | `0.0` | Y offset for triangle label. |
|
|
74
|
+
| `x` | `float \| None` | `None` | Fixed X position (skips auto-layout if set). |
|
|
75
|
+
| `y` | `float \| None` | `None` | Fixed Y position (skips auto-layout if set). |
|
|
76
|
+
|
|
77
|
+
## Diagram.add_flow(...)
|
|
78
|
+
|
|
79
|
+
| Parameter | Type | Default | Notes |
|
|
80
|
+
| --- | --- | --- | --- |
|
|
81
|
+
| `name` | `str` | required | Unique flow name. |
|
|
82
|
+
| `value` | `float` | required | Flow magnitude (must be non‑negative). |
|
|
83
|
+
| `source` | `str \| None` | `None` | Source process name or `None`/`"source"`. |
|
|
84
|
+
| `target` | `str \| None` | `None` | Target process name or `None`/`"sink"`. |
|
|
85
|
+
| `color` | `str \| None` | `"#7fb3d5"` | Flow fill color. |
|
|
86
|
+
| `length` | `float \| None` | `2.2` | Default straight length (used when no manual route). |
|
|
87
|
+
| `inlet_tri_height` | `float \| None` | `0.3` | Multiplier of flow width for inlet triangle depth. |
|
|
88
|
+
| `outlet_tri_height` | `float \| None` | `0.6` | Multiplier of flow width for outlet triangle depth. |
|
|
89
|
+
| `label_dx` | `float` | `0.0` | X offset for flow label. |
|
|
90
|
+
| `label_dy` | `float` | `0.0` | Y offset for flow label. |
|
|
91
|
+
| `label_rotation` | `float \| None` | `None` | Rotation in degrees for flow label. |
|
|
92
|
+
| `cycle_breaker` | `bool` | `False` | Marks a process→process flow to break layout cycles. |
|
|
93
|
+
| `route` | `list[RouteSegment] \| None` | `None` | Manual route; skips auto-routing. |
|
|
94
|
+
| `label` | `str \| None` | `None` | Custom label name used in `name = value` mode. |
|
|
95
|
+
|
|
96
|
+
## Where Things Live
|
|
97
|
+
- `exergyflow/grassmann_types.py`: dataclasses and config
|
|
98
|
+
- `exergyflow/grassmann_geometry.py`: geometry helpers
|
|
99
|
+
- `exergyflow/grassmann_layout.py`: auto layout + routing
|
|
100
|
+
- `exergyflow/grassmann_render.py`: drawing engine
|
|
101
|
+
- `exergyflow/grassmann_diagram.py`: public API
|
|
102
|
+
- `examples/grassmann_example.py`: example usage
|
|
103
|
+
- `docs/diagram.svg`: example output (generated by the example script)
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Step-by-Step: Build a Grassmann/Sankey Diagram
|
|
2
|
+
|
|
3
|
+
This guide walks you through creating a diagram from scratch using the public API.
|
|
4
|
+
|
|
5
|
+
**Step 1: Install dependencies**
|
|
6
|
+
```bash
|
|
7
|
+
python -m pip install exergyflow
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
**Step 2: Import the API**
|
|
11
|
+
```python
|
|
12
|
+
from exergyflow import Diagram, DiagramConfig, RouteSegment
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
**Step 3: Define a configuration (optional but recommended)**
|
|
16
|
+
```python
|
|
17
|
+
cfg = DiagramConfig(
|
|
18
|
+
auto_scale=True,
|
|
19
|
+
auto_scale_target=1.0,
|
|
20
|
+
flow_value_unit="kW",
|
|
21
|
+
flow_value_format=".2f",
|
|
22
|
+
flow_label_style={"fontsize": 8, "color": "#1d3557"},
|
|
23
|
+
process_label_style={"fontsize": 9, "fontweight": "bold"},
|
|
24
|
+
triangle_label_style={"fontsize": 8, "color": "#444444"},
|
|
25
|
+
)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Step 4: Create the diagram and add processes**
|
|
29
|
+
```python
|
|
30
|
+
d = Diagram(config=cfg)
|
|
31
|
+
|
|
32
|
+
d.add_process("P1", direction="right", length=1.6)
|
|
33
|
+
d.add_process("P2", direction="right", length=1.2)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Step 5: Add flows**
|
|
37
|
+
Use `source=None` for a source and `target=None` for a sink.
|
|
38
|
+
```python
|
|
39
|
+
d.add_flow("F1", 10, source=None, target="P1")
|
|
40
|
+
d.add_flow("F2", 8, source="P1", target="P2", label="Q_in")
|
|
41
|
+
d.add_flow("F3", 2, source="P1", target=None)
|
|
42
|
+
d.add_flow("F4", 6, source="P2", target=None)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Step 6: (Optional) Add a manual route**
|
|
46
|
+
Manual routes must alternate `rect` and `elbow`, and start/end with `rect`.
|
|
47
|
+
```python
|
|
48
|
+
route = [
|
|
49
|
+
RouteSegment(kind="rect", length=1.5, direction="right"),
|
|
50
|
+
RouteSegment(kind="elbow", length=0.4, turn="rightup"),
|
|
51
|
+
RouteSegment(kind="rect", length=1.0, direction="up"),
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
d.add_flow("F5", 3, source="P1", target="P2", route=route)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Step 7: Draw and save**
|
|
58
|
+
```python
|
|
59
|
+
fig, ax = d.draw()
|
|
60
|
+
fig.savefig("diagram.png", dpi=300, bbox_inches="tight")
|
|
61
|
+
```
|