jarvisplot 1.3.1__tar.gz → 1.3.3__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.
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/JarvisPLOT.egg-info/PKG-INFO +11 -10
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/JarvisPLOT.egg-info/SOURCES.txt +23 -1
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/PKG-INFO +11 -10
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/README.md +10 -9
- jarvisplot-1.3.3/jarvisplot/Figure/adapters.py +6 -0
- jarvisplot-1.3.1/jarvisplot/Figure/adapters.py → jarvisplot-1.3.3/jarvisplot/Figure/adapters_rect.py +1 -72
- jarvisplot-1.3.3/jarvisplot/Figure/adapters_ternary.py +89 -0
- jarvisplot-1.3.3/jarvisplot/Figure/colorbar_runtime.py +221 -0
- jarvisplot-1.3.3/jarvisplot/Figure/config_runtime.py +88 -0
- jarvisplot-1.3.3/jarvisplot/Figure/figure.py +1009 -0
- jarvisplot-1.3.3/jarvisplot/Figure/layer_runtime.py +282 -0
- jarvisplot-1.3.3/jarvisplot/Figure/layout_runtime.py +228 -0
- jarvisplot-1.3.3/jarvisplot/Figure/load_data.py +169 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/Figure/preprocessor.py +17 -428
- jarvisplot-1.3.3/jarvisplot/Figure/preprocessor_runtime.py +483 -0
- jarvisplot-1.3.1/jarvisplot/Figure/load_data.py → jarvisplot-1.3.3/jarvisplot/Figure/profile_runtime.py +21 -138
- jarvisplot-1.3.3/jarvisplot/Figure/style_runtime.py +40 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/cache_store.py +7 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/config.py +4 -3
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/core.py +38 -283
- jarvisplot-1.3.3/jarvisplot/core_assets.py +63 -0
- jarvisplot-1.3.3/jarvisplot/core_runtime.py +319 -0
- jarvisplot-1.3.3/jarvisplot/data_loader.py +520 -0
- jarvisplot-1.3.3/jarvisplot/data_loader_hdf5.py +316 -0
- jarvisplot-1.3.3/jarvisplot/data_loader_runtime.py +1131 -0
- jarvisplot-1.3.3/jarvisplot/data_loader_summary.py +164 -0
- jarvisplot-1.3.3/jarvisplot/utils/expression.py +66 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/utils/interpolator.py +6 -22
- jarvisplot-1.3.3/jarvisplot/utils/pathing.py +31 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/pyproject.toml +1 -1
- jarvisplot-1.3.3/tests/test_data_loader_contracts.py +445 -0
- jarvisplot-1.3.3/tests/test_docs_status_labels.py +46 -0
- jarvisplot-1.3.3/tests/test_figure_contracts.py +237 -0
- jarvisplot-1.3.3/tests/test_parse_data_metadata.py +153 -0
- jarvisplot-1.3.3/tests/test_pathing_contracts.py +75 -0
- jarvisplot-1.3.3/tests/test_template_json.py +10 -0
- jarvisplot-1.3.1/jarvisplot/Figure/figure.py +0 -1891
- jarvisplot-1.3.1/jarvisplot/data_loader.py +0 -1669
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/JarvisPLOT.egg-info/dependency_links.txt +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/JarvisPLOT.egg-info/entry_points.txt +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/JarvisPLOT.egg-info/requires.txt +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/JarvisPLOT.egg-info/top_level.txt +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/Figure/__init__.py +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/Figure/cards/std_axes_adapter_config.json +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/Figure/data_pipelines.py +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/Figure/helper.py +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/Figure/method_registry.py +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/__init__.py +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/cards/a4paper/1x1/ternary.json +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/cards/a4paper/2x1/rect.json +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/cards/a4paper/2x1/rect5x1.json +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/cards/a4paper/2x1/rect_cmap.json +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/cards/a4paper/2x1/ternary.json +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/cards/a4paper/2x1/ternary_cmap.json +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/cards/a4paper/4x1/rect.json +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/cards/a4paper/4x1/rect_cmap.json +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/cards/a4paper/4x1/ternary.json +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/cards/a4paper/4x1/ternary_cmap.json +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/cards/args.json +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/cards/colors/colormaps.json +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/cards/default/output.json +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/cards/gambit/1x1/ternary.json +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/cards/gambit/2x1/rect_cmap.json +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/cards/gambit/2x1/ternary.json +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/cards/gambit/2x1/ternary_cmap.json +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/cards/icons/JarvisHEP.png +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/cards/icons/gambit.png +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/cards/icons/gambit_small.png +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/cards/style_preference.json +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/cli.py +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/client.py +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/inner_func.py +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/memtrace.py +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/utils/__init__.py +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/jarvisplot/utils/cmaps.py +0 -0
- {jarvisplot-1.3.1 → jarvisplot-1.3.3}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: JarvisPLOT
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.3
|
|
4
4
|
Summary: Jarvis-PLOT: YAML-driven plotting engine
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -121,18 +121,19 @@ jplot ./bin/SUSYRun2_GEWMSSM.yaml
|
|
|
121
121
|
### Documentation
|
|
122
122
|
[https://pengxuan-zhu-phys.github.io/Jarvis-Docs/](https://pengxuan-zhu-phys.github.io/Jarvis-Docs/)
|
|
123
123
|
|
|
124
|
-
###
|
|
124
|
+
### Repository Docs
|
|
125
125
|
|
|
126
|
-
Tracked
|
|
126
|
+
Tracked project docs live in `docs/`.
|
|
127
127
|
|
|
128
|
-
- `docs/
|
|
129
|
-
- `docs/
|
|
130
|
-
- `docs/
|
|
131
|
-
- `docs/
|
|
132
|
-
- `docs/
|
|
133
|
-
- `docs/dev/
|
|
128
|
+
- `docs/README.md` - repo doc index
|
|
129
|
+
- `docs/context/JARVIS_PLOT_CONTEXT.md` - primary Codex-facing boundary doc
|
|
130
|
+
- `docs/context/CODE_MAP_JARVIS_PLOT.md` - concrete code owner map
|
|
131
|
+
- `docs/context/JARVIS_PLOT_FRAMEWORK_LOGIC.md` - runtime execution contract
|
|
132
|
+
- `docs/roadmap/IMPLEMENTATION_ROADMAP.md` - active backlog and future work list
|
|
133
|
+
- `docs/dev/DEVELOPER_RULES.md` - current pipeline and cache rules
|
|
134
|
+
- `docs/dev/MEMORY_OPTIMIZATION_GUIDE.md` - narrow-table memory notes
|
|
134
135
|
|
|
135
|
-
|
|
136
|
+
Read the context docs and roadmap before changing parsing, transforms, rendering, or layout-related behavior.
|
|
136
137
|
|
|
137
138
|
---
|
|
138
139
|
|
|
@@ -12,17 +12,31 @@ jarvisplot/cli.py
|
|
|
12
12
|
jarvisplot/client.py
|
|
13
13
|
jarvisplot/config.py
|
|
14
14
|
jarvisplot/core.py
|
|
15
|
+
jarvisplot/core_assets.py
|
|
16
|
+
jarvisplot/core_runtime.py
|
|
15
17
|
jarvisplot/data_loader.py
|
|
18
|
+
jarvisplot/data_loader_hdf5.py
|
|
19
|
+
jarvisplot/data_loader_runtime.py
|
|
20
|
+
jarvisplot/data_loader_summary.py
|
|
16
21
|
jarvisplot/inner_func.py
|
|
17
22
|
jarvisplot/memtrace.py
|
|
18
23
|
jarvisplot/Figure/__init__.py
|
|
19
24
|
jarvisplot/Figure/adapters.py
|
|
25
|
+
jarvisplot/Figure/adapters_rect.py
|
|
26
|
+
jarvisplot/Figure/adapters_ternary.py
|
|
27
|
+
jarvisplot/Figure/colorbar_runtime.py
|
|
28
|
+
jarvisplot/Figure/config_runtime.py
|
|
20
29
|
jarvisplot/Figure/data_pipelines.py
|
|
21
30
|
jarvisplot/Figure/figure.py
|
|
22
31
|
jarvisplot/Figure/helper.py
|
|
32
|
+
jarvisplot/Figure/layer_runtime.py
|
|
33
|
+
jarvisplot/Figure/layout_runtime.py
|
|
23
34
|
jarvisplot/Figure/load_data.py
|
|
24
35
|
jarvisplot/Figure/method_registry.py
|
|
25
36
|
jarvisplot/Figure/preprocessor.py
|
|
37
|
+
jarvisplot/Figure/preprocessor_runtime.py
|
|
38
|
+
jarvisplot/Figure/profile_runtime.py
|
|
39
|
+
jarvisplot/Figure/style_runtime.py
|
|
26
40
|
jarvisplot/Figure/cards/std_axes_adapter_config.json
|
|
27
41
|
jarvisplot/cards/args.json
|
|
28
42
|
jarvisplot/cards/style_preference.json
|
|
@@ -47,4 +61,12 @@ jarvisplot/cards/icons/gambit.png
|
|
|
47
61
|
jarvisplot/cards/icons/gambit_small.png
|
|
48
62
|
jarvisplot/utils/__init__.py
|
|
49
63
|
jarvisplot/utils/cmaps.py
|
|
50
|
-
jarvisplot/utils/
|
|
64
|
+
jarvisplot/utils/expression.py
|
|
65
|
+
jarvisplot/utils/interpolator.py
|
|
66
|
+
jarvisplot/utils/pathing.py
|
|
67
|
+
tests/test_data_loader_contracts.py
|
|
68
|
+
tests/test_docs_status_labels.py
|
|
69
|
+
tests/test_figure_contracts.py
|
|
70
|
+
tests/test_parse_data_metadata.py
|
|
71
|
+
tests/test_pathing_contracts.py
|
|
72
|
+
tests/test_template_json.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: JarvisPLOT
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.3
|
|
4
4
|
Summary: Jarvis-PLOT: YAML-driven plotting engine
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -121,18 +121,19 @@ jplot ./bin/SUSYRun2_GEWMSSM.yaml
|
|
|
121
121
|
### Documentation
|
|
122
122
|
[https://pengxuan-zhu-phys.github.io/Jarvis-Docs/](https://pengxuan-zhu-phys.github.io/Jarvis-Docs/)
|
|
123
123
|
|
|
124
|
-
###
|
|
124
|
+
### Repository Docs
|
|
125
125
|
|
|
126
|
-
Tracked
|
|
126
|
+
Tracked project docs live in `docs/`.
|
|
127
127
|
|
|
128
|
-
- `docs/
|
|
129
|
-
- `docs/
|
|
130
|
-
- `docs/
|
|
131
|
-
- `docs/
|
|
132
|
-
- `docs/
|
|
133
|
-
- `docs/dev/
|
|
128
|
+
- `docs/README.md` - repo doc index
|
|
129
|
+
- `docs/context/JARVIS_PLOT_CONTEXT.md` - primary Codex-facing boundary doc
|
|
130
|
+
- `docs/context/CODE_MAP_JARVIS_PLOT.md` - concrete code owner map
|
|
131
|
+
- `docs/context/JARVIS_PLOT_FRAMEWORK_LOGIC.md` - runtime execution contract
|
|
132
|
+
- `docs/roadmap/IMPLEMENTATION_ROADMAP.md` - active backlog and future work list
|
|
133
|
+
- `docs/dev/DEVELOPER_RULES.md` - current pipeline and cache rules
|
|
134
|
+
- `docs/dev/MEMORY_OPTIMIZATION_GUIDE.md` - narrow-table memory notes
|
|
134
135
|
|
|
135
|
-
|
|
136
|
+
Read the context docs and roadmap before changing parsing, transforms, rendering, or layout-related behavior.
|
|
136
137
|
|
|
137
138
|
---
|
|
138
139
|
|
|
@@ -101,18 +101,19 @@ jplot ./bin/SUSYRun2_GEWMSSM.yaml
|
|
|
101
101
|
### Documentation
|
|
102
102
|
[https://pengxuan-zhu-phys.github.io/Jarvis-Docs/](https://pengxuan-zhu-phys.github.io/Jarvis-Docs/)
|
|
103
103
|
|
|
104
|
-
###
|
|
104
|
+
### Repository Docs
|
|
105
105
|
|
|
106
|
-
Tracked
|
|
106
|
+
Tracked project docs live in `docs/`.
|
|
107
107
|
|
|
108
|
-
- `docs/
|
|
109
|
-
- `docs/
|
|
110
|
-
- `docs/
|
|
111
|
-
- `docs/
|
|
112
|
-
- `docs/
|
|
113
|
-
- `docs/dev/
|
|
108
|
+
- `docs/README.md` - repo doc index
|
|
109
|
+
- `docs/context/JARVIS_PLOT_CONTEXT.md` - primary Codex-facing boundary doc
|
|
110
|
+
- `docs/context/CODE_MAP_JARVIS_PLOT.md` - concrete code owner map
|
|
111
|
+
- `docs/context/JARVIS_PLOT_FRAMEWORK_LOGIC.md` - runtime execution contract
|
|
112
|
+
- `docs/roadmap/IMPLEMENTATION_ROADMAP.md` - active backlog and future work list
|
|
113
|
+
- `docs/dev/DEVELOPER_RULES.md` - current pipeline and cache rules
|
|
114
|
+
- `docs/dev/MEMORY_OPTIMIZATION_GUIDE.md` - narrow-table memory notes
|
|
114
115
|
|
|
115
|
-
|
|
116
|
+
Read the context docs and roadmap before changing parsing, transforms, rendering, or layout-related behavior.
|
|
116
117
|
|
|
117
118
|
---
|
|
118
119
|
|
jarvisplot-1.3.1/jarvisplot/Figure/adapters.py → jarvisplot-1.3.3/jarvisplot/Figure/adapters_rect.py
RENAMED
|
@@ -13,6 +13,7 @@ from .helper import _auto_clip, _mask_by_extend, voronoi_finite_polygons_2d, _cl
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
# —— Basic Adapter: Forward to the underlying Axes, merge default parameters, perform automatic clipping ——
|
|
16
|
+
|
|
16
17
|
class StdAxesAdapter:
|
|
17
18
|
def __init__(self, ax: Axes, defaults: Optional[Dict[str, Dict[str, Any]]] = None,
|
|
18
19
|
clip_path=None):
|
|
@@ -963,75 +964,3 @@ class StdAxesAdapter:
|
|
|
963
964
|
return [palette[i % len(palette)] for i in range(n)]
|
|
964
965
|
|
|
965
966
|
# —— Ternary 适配器:在 Std 基础上增加 (a,b,c)->(x,y) 投影 ——
|
|
966
|
-
class TernaryAxesAdapter(StdAxesAdapter):
|
|
967
|
-
def __init__(self, ax: Axes, defaults: Optional[Dict[str, Any]] = None,
|
|
968
|
-
clip_path=None):
|
|
969
|
-
# Allow a flat defaults dict like {"facecolor": "..."} and keep it internal.
|
|
970
|
-
d = dict(defaults) if isinstance(defaults, dict) else {}
|
|
971
|
-
facecolor = d.pop("facecolor", None)
|
|
972
|
-
|
|
973
|
-
super().__init__(ax, defaults=d or None, clip_path=clip_path)
|
|
974
|
-
|
|
975
|
-
if facecolor is not None:
|
|
976
|
-
self.set_facecolor(facecolor)
|
|
977
|
-
|
|
978
|
-
self.status = "init"
|
|
979
|
-
|
|
980
|
-
def set_facecolor(self, color, zorder=-100):
|
|
981
|
-
self.ax.fill(
|
|
982
|
-
[0.0, 1.0, 0.5],
|
|
983
|
-
[0.0, 0.0, 1.0],
|
|
984
|
-
facecolor=color,
|
|
985
|
-
edgecolor="none",
|
|
986
|
-
zorder=zorder
|
|
987
|
-
)
|
|
988
|
-
|
|
989
|
-
@staticmethod
|
|
990
|
-
def _lbr_to_xy(a, b, c):
|
|
991
|
-
s = (a + b + c)
|
|
992
|
-
s = np.where(s == 0.0, 1.0, s) # 避免除零
|
|
993
|
-
aa, bb, cc = a/s, b/s, c/s
|
|
994
|
-
x = bb + 0.5 * cc
|
|
995
|
-
y = cc
|
|
996
|
-
return x, y
|
|
997
|
-
|
|
998
|
-
def scatter(self, **kwargs):
|
|
999
|
-
if {"left", "right", "bottom"}.issubset(kwargs.keys()):
|
|
1000
|
-
x, y = self._lbr_to_xy(kwargs.pop('left'), kwargs.pop('right'), kwargs.pop('bottom'))
|
|
1001
|
-
kwargs['x'] = x
|
|
1002
|
-
kwargs['y'] = y
|
|
1003
|
-
return super().scatter(**kwargs)
|
|
1004
|
-
|
|
1005
|
-
def grid_profile(self, **kwargs):
|
|
1006
|
-
if {"left", "right", "bottom"}.issubset(kwargs.keys()):
|
|
1007
|
-
x, y = self._lbr_to_xy(kwargs.pop('left'), kwargs.pop('right'), kwargs.pop('bottom'))
|
|
1008
|
-
kwargs['x'] = x
|
|
1009
|
-
kwargs['y'] = y
|
|
1010
|
-
return super().grid_profile(**kwargs)
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
def plot(self, **kwargs):
|
|
1014
|
-
if {"left", "right", "bottom"}.issubset(kwargs.keys()):
|
|
1015
|
-
x, y = self._lbr_to_xy(kwargs.pop('left'), kwargs.pop('right'), kwargs.pop('bottom'))
|
|
1016
|
-
kwargs['x'] = x
|
|
1017
|
-
kwargs['y'] = y
|
|
1018
|
-
return super().plot(**kwargs)
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
def tricontour(self, **kwargs):
|
|
1022
|
-
if {"left", "right", "bottom"}.issubset(kwargs.keys()):
|
|
1023
|
-
x, y = self._lbr_to_xy(kwargs.pop('left'), kwargs.pop('right'), kwargs.pop('bottom'))
|
|
1024
|
-
kwargs['x'] = x
|
|
1025
|
-
kwargs['y'] = y
|
|
1026
|
-
return super().tricontour( **kwargs)
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
def tricontourf(self, **kwargs):
|
|
1030
|
-
if {"left", "right", "bottom"}.issubset(kwargs.keys()):
|
|
1031
|
-
x, y = self._lbr_to_xy(kwargs.pop('left'), kwargs.pop('right'), kwargs.pop('bottom'))
|
|
1032
|
-
kwargs['x'] = x
|
|
1033
|
-
kwargs['y'] = y
|
|
1034
|
-
|
|
1035
|
-
return super().tricontourf(**kwargs)
|
|
1036
|
-
# else:
|
|
1037
|
-
# raise ValueError("scatter() needs either (a,b,c) or (x,y) inputs")
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
from typing import Any, Dict, Optional
|
|
5
|
+
import numpy as np
|
|
6
|
+
import os
|
|
7
|
+
import json
|
|
8
|
+
|
|
9
|
+
from matplotlib.axes import Axes
|
|
10
|
+
from matplotlib.collections import PolyCollection
|
|
11
|
+
#
|
|
12
|
+
from .helper import _auto_clip, _mask_by_extend, voronoi_finite_polygons_2d, _clip_poly_to_rect
|
|
13
|
+
from .adapters_rect import StdAxesAdapter
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# —— Basic Adapter: Forward to the underlying Axes, merge default parameters, perform automatic clipping ——
|
|
17
|
+
|
|
18
|
+
class TernaryAxesAdapter(StdAxesAdapter):
|
|
19
|
+
def __init__(self, ax: Axes, defaults: Optional[Dict[str, Any]] = None,
|
|
20
|
+
clip_path=None):
|
|
21
|
+
# Allow a flat defaults dict like {"facecolor": "..."} and keep it internal.
|
|
22
|
+
d = dict(defaults) if isinstance(defaults, dict) else {}
|
|
23
|
+
facecolor = d.pop("facecolor", None)
|
|
24
|
+
|
|
25
|
+
super().__init__(ax, defaults=d or None, clip_path=clip_path)
|
|
26
|
+
|
|
27
|
+
if facecolor is not None:
|
|
28
|
+
self.set_facecolor(facecolor)
|
|
29
|
+
|
|
30
|
+
self.status = "init"
|
|
31
|
+
|
|
32
|
+
def set_facecolor(self, color, zorder=-100):
|
|
33
|
+
self.ax.fill(
|
|
34
|
+
[0.0, 1.0, 0.5],
|
|
35
|
+
[0.0, 0.0, 1.0],
|
|
36
|
+
facecolor=color,
|
|
37
|
+
edgecolor="none",
|
|
38
|
+
zorder=zorder
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
@staticmethod
|
|
42
|
+
def _lbr_to_xy(a, b, c):
|
|
43
|
+
s = (a + b + c)
|
|
44
|
+
s = np.where(s == 0.0, 1.0, s) # 避免除零
|
|
45
|
+
aa, bb, cc = a/s, b/s, c/s
|
|
46
|
+
x = bb + 0.5 * cc
|
|
47
|
+
y = cc
|
|
48
|
+
return x, y
|
|
49
|
+
|
|
50
|
+
def scatter(self, **kwargs):
|
|
51
|
+
if {"left", "right", "bottom"}.issubset(kwargs.keys()):
|
|
52
|
+
x, y = self._lbr_to_xy(kwargs.pop('left'), kwargs.pop('right'), kwargs.pop('bottom'))
|
|
53
|
+
kwargs['x'] = x
|
|
54
|
+
kwargs['y'] = y
|
|
55
|
+
return super().scatter(**kwargs)
|
|
56
|
+
|
|
57
|
+
def grid_profile(self, **kwargs):
|
|
58
|
+
if {"left", "right", "bottom"}.issubset(kwargs.keys()):
|
|
59
|
+
x, y = self._lbr_to_xy(kwargs.pop('left'), kwargs.pop('right'), kwargs.pop('bottom'))
|
|
60
|
+
kwargs['x'] = x
|
|
61
|
+
kwargs['y'] = y
|
|
62
|
+
return super().grid_profile(**kwargs)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def plot(self, **kwargs):
|
|
66
|
+
if {"left", "right", "bottom"}.issubset(kwargs.keys()):
|
|
67
|
+
x, y = self._lbr_to_xy(kwargs.pop('left'), kwargs.pop('right'), kwargs.pop('bottom'))
|
|
68
|
+
kwargs['x'] = x
|
|
69
|
+
kwargs['y'] = y
|
|
70
|
+
return super().plot(**kwargs)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def tricontour(self, **kwargs):
|
|
74
|
+
if {"left", "right", "bottom"}.issubset(kwargs.keys()):
|
|
75
|
+
x, y = self._lbr_to_xy(kwargs.pop('left'), kwargs.pop('right'), kwargs.pop('bottom'))
|
|
76
|
+
kwargs['x'] = x
|
|
77
|
+
kwargs['y'] = y
|
|
78
|
+
return super().tricontour( **kwargs)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def tricontourf(self, **kwargs):
|
|
82
|
+
if {"left", "right", "bottom"}.issubset(kwargs.keys()):
|
|
83
|
+
x, y = self._lbr_to_xy(kwargs.pop('left'), kwargs.pop('right'), kwargs.pop('bottom'))
|
|
84
|
+
kwargs['x'] = x
|
|
85
|
+
kwargs['y'] = y
|
|
86
|
+
|
|
87
|
+
return super().tricontourf(**kwargs)
|
|
88
|
+
# else:
|
|
89
|
+
# raise ValueError("scatter() needs either (a,b,c) or (x,y) inputs")
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any, Mapping
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import matplotlib.colors as mcolors
|
|
7
|
+
|
|
8
|
+
from ..utils.expression import eval_dataframe_expression
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def axc_is_horizontal(frame: Mapping[str, Any]) -> bool:
|
|
12
|
+
return str(frame.get("axc", {}).get("orientation", "")).lower() == "horizontal"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def axc_color_config(frame: Mapping[str, Any]) -> dict:
|
|
16
|
+
"""Return normalized frame.axc.color config with legacy fallbacks."""
|
|
17
|
+
out: dict[str, Any] = {}
|
|
18
|
+
axc_cfg = frame.get("axc", {}) if isinstance(frame, Mapping) else {}
|
|
19
|
+
color_cfg = axc_cfg.get("color", {})
|
|
20
|
+
if not isinstance(color_cfg, dict):
|
|
21
|
+
color_cfg = {}
|
|
22
|
+
|
|
23
|
+
if "cmap" in color_cfg:
|
|
24
|
+
out["cmap"] = color_cfg.get("cmap")
|
|
25
|
+
|
|
26
|
+
for key in ("vmin", "vmax"):
|
|
27
|
+
if key in color_cfg:
|
|
28
|
+
try:
|
|
29
|
+
val = float(color_cfg.get(key))
|
|
30
|
+
if np.isfinite(val):
|
|
31
|
+
out[key] = val
|
|
32
|
+
except Exception:
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
scale = color_cfg.get("scale", None)
|
|
36
|
+
if scale is None:
|
|
37
|
+
if axc_is_horizontal(frame):
|
|
38
|
+
scale = axc_cfg.get("xscale", axc_cfg.get("yscale", None))
|
|
39
|
+
else:
|
|
40
|
+
scale = axc_cfg.get("yscale", axc_cfg.get("xscale", None))
|
|
41
|
+
if isinstance(scale, str):
|
|
42
|
+
scale = scale.strip().lower()
|
|
43
|
+
if scale:
|
|
44
|
+
out["scale"] = scale
|
|
45
|
+
|
|
46
|
+
return out
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _coerce_scalar(v):
|
|
50
|
+
try:
|
|
51
|
+
vv = float(v)
|
|
52
|
+
if np.isfinite(vv):
|
|
53
|
+
return vv
|
|
54
|
+
except Exception:
|
|
55
|
+
pass
|
|
56
|
+
return None
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _resolve_norm(nv, *, vmin=None, vmax=None, logger=None):
|
|
60
|
+
if nv is None:
|
|
61
|
+
return None
|
|
62
|
+
if isinstance(nv, mcolors.Normalize):
|
|
63
|
+
return nv
|
|
64
|
+
if isinstance(nv, str):
|
|
65
|
+
key = nv.strip().lower()
|
|
66
|
+
if key in {"log", "lognorm"}:
|
|
67
|
+
if (vmin is None) or (vmax is None) or (vmin <= 0) or (vmax <= 0):
|
|
68
|
+
if logger:
|
|
69
|
+
logger.warning("axc log scale requires positive vmin/vmax; fallback to linear Normalize.")
|
|
70
|
+
return mcolors.Normalize(vmin=vmin, vmax=vmax)
|
|
71
|
+
return mcolors.LogNorm(vmin=vmin, vmax=vmax)
|
|
72
|
+
if key in {"twoslopenorm", "diverging"}:
|
|
73
|
+
return mcolors.TwoSlopeNorm(vcenter=0.0, vmin=vmin, vmax=vmax)
|
|
74
|
+
if key in {"symlog", "symlognorm"}:
|
|
75
|
+
return mcolors.SymLogNorm(linthresh=1.0, linscale=1.0, base=10, vmin=vmin, vmax=vmax)
|
|
76
|
+
return mcolors.Normalize(vmin=vmin, vmax=vmax)
|
|
77
|
+
if isinstance(nv, dict):
|
|
78
|
+
t = str(nv.get("type", "Normalize")).strip().lower()
|
|
79
|
+
_vmin = nv.get("vmin", vmin)
|
|
80
|
+
_vmax = nv.get("vmax", vmax)
|
|
81
|
+
if t in {"log", "lognorm"}:
|
|
82
|
+
if (_vmin is None) or (_vmax is None) or (_vmin <= 0) or (_vmax <= 0):
|
|
83
|
+
if logger:
|
|
84
|
+
logger.warning("axc log norm requires positive vmin/vmax; fallback to linear Normalize.")
|
|
85
|
+
return mcolors.Normalize(vmin=_vmin, vmax=_vmax)
|
|
86
|
+
return mcolors.LogNorm(vmin=_vmin, vmax=_vmax)
|
|
87
|
+
if t in {"twoslopenorm", "diverging"}:
|
|
88
|
+
vcenter = nv.get("vcenter", 0.0)
|
|
89
|
+
return mcolors.TwoSlopeNorm(vcenter=vcenter, vmin=_vmin, vmax=_vmax)
|
|
90
|
+
if t in {"symlog", "symlognorm"}:
|
|
91
|
+
linthresh = nv.get("linthresh", 1.0)
|
|
92
|
+
linscale = nv.get("linscale", 1.0)
|
|
93
|
+
base = nv.get("base", 10)
|
|
94
|
+
return mcolors.SymLogNorm(
|
|
95
|
+
linthresh=linthresh,
|
|
96
|
+
linscale=linscale,
|
|
97
|
+
base=base,
|
|
98
|
+
vmin=_vmin,
|
|
99
|
+
vmax=_vmax,
|
|
100
|
+
)
|
|
101
|
+
return mcolors.Normalize(vmin=_vmin, vmax=_vmax)
|
|
102
|
+
return mcolors.Normalize(vmin=vmin, vmax=vmax)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def collect_and_attach_colorbar(fig, style: dict, coor: dict, method_key: str, df):
|
|
106
|
+
axc = fig.axes.get("axc")
|
|
107
|
+
if axc is None or not hasattr(axc, "_cb"):
|
|
108
|
+
return style
|
|
109
|
+
|
|
110
|
+
s = dict(style)
|
|
111
|
+
colored_z_methods = {
|
|
112
|
+
"contour",
|
|
113
|
+
"contourf",
|
|
114
|
+
"tricontour",
|
|
115
|
+
"tricontourf",
|
|
116
|
+
"tripcolor",
|
|
117
|
+
"tripcolor_axes",
|
|
118
|
+
"pcolor",
|
|
119
|
+
"pcolormesh",
|
|
120
|
+
"imshow",
|
|
121
|
+
"voronoi",
|
|
122
|
+
"voronoif",
|
|
123
|
+
"grid_profile",
|
|
124
|
+
"grid_profiling",
|
|
125
|
+
}
|
|
126
|
+
uses_color = bool(s.get("cmap")) or ("c" in coor) or (("z" in coor) and (method_key in colored_z_methods))
|
|
127
|
+
if not uses_color:
|
|
128
|
+
return style
|
|
129
|
+
|
|
130
|
+
color_cfg = axc_color_config(fig.frame)
|
|
131
|
+
|
|
132
|
+
def _load_color_series():
|
|
133
|
+
arr = None
|
|
134
|
+
if isinstance(coor.get("z"), dict) and ("expr" in coor["z"]):
|
|
135
|
+
arr = eval_dataframe_expression(df, coor["z"]["expr"], logger=fig.logger)
|
|
136
|
+
elif isinstance(coor.get("c"), dict) and ("expr" in coor["c"]):
|
|
137
|
+
arr = eval_dataframe_expression(df, coor["c"]["expr"], logger=fig.logger)
|
|
138
|
+
elif "z" in s:
|
|
139
|
+
arr = s.get("z")
|
|
140
|
+
elif "c" in s and not isinstance(s.get("c"), str):
|
|
141
|
+
arr = s.get("c")
|
|
142
|
+
if arr is None:
|
|
143
|
+
return None
|
|
144
|
+
try:
|
|
145
|
+
arr = np.asarray(arr, dtype=float)
|
|
146
|
+
except Exception:
|
|
147
|
+
return None
|
|
148
|
+
arr = arr[np.isfinite(arr)]
|
|
149
|
+
return arr if arr.size else None
|
|
150
|
+
|
|
151
|
+
chosen_cmap = color_cfg.get("cmap", s.get("cmap"))
|
|
152
|
+
if chosen_cmap is not None:
|
|
153
|
+
s["cmap"] = chosen_cmap
|
|
154
|
+
fig.axc._cb["cmap"] = chosen_cmap
|
|
155
|
+
|
|
156
|
+
data_series = _load_color_series()
|
|
157
|
+
data_vmin = float(np.min(data_series)) if data_series is not None else None
|
|
158
|
+
data_vmax = float(np.max(data_series)) if data_series is not None else None
|
|
159
|
+
|
|
160
|
+
frame_vmin = _coerce_scalar(color_cfg.get("vmin", None))
|
|
161
|
+
frame_vmax = _coerce_scalar(color_cfg.get("vmax", None))
|
|
162
|
+
style_vmin = _coerce_scalar(s.get("vmin", None))
|
|
163
|
+
style_vmax = _coerce_scalar(s.get("vmax", None))
|
|
164
|
+
|
|
165
|
+
if frame_vmin is not None:
|
|
166
|
+
fig.axc._cb["vmin"] = frame_vmin
|
|
167
|
+
else:
|
|
168
|
+
cand_min = style_vmin if style_vmin is not None else data_vmin
|
|
169
|
+
if cand_min is not None:
|
|
170
|
+
cur_min = _coerce_scalar(fig.axc._cb.get("vmin", None))
|
|
171
|
+
fig.axc._cb["vmin"] = cand_min if cur_min is None else min(cur_min, cand_min)
|
|
172
|
+
|
|
173
|
+
if frame_vmax is not None:
|
|
174
|
+
fig.axc._cb["vmax"] = frame_vmax
|
|
175
|
+
else:
|
|
176
|
+
cand_max = style_vmax if style_vmax is not None else data_vmax
|
|
177
|
+
if cand_max is not None:
|
|
178
|
+
cur_max = _coerce_scalar(fig.axc._cb.get("vmax", None))
|
|
179
|
+
fig.axc._cb["vmax"] = cand_max if cur_max is None else max(cur_max, cand_max)
|
|
180
|
+
|
|
181
|
+
if (fig.axc._cb["vmin"] is not None) and (fig.axc._cb["vmax"] is not None):
|
|
182
|
+
vmin = float(fig.axc._cb["vmin"])
|
|
183
|
+
vmax = float(fig.axc._cb["vmax"])
|
|
184
|
+
if vmax < vmin:
|
|
185
|
+
vmin, vmax = vmax, vmin
|
|
186
|
+
fig.axc._cb["vmin"], fig.axc._cb["vmax"] = vmin, vmax
|
|
187
|
+
|
|
188
|
+
requested_scale = str(color_cfg.get("scale", "")).lower()
|
|
189
|
+
if requested_scale in {"linear", "norm", "normalize"}:
|
|
190
|
+
resolved = mcolors.Normalize(vmin=vmin, vmax=vmax)
|
|
191
|
+
elif requested_scale == "log":
|
|
192
|
+
resolved = _resolve_norm("lognorm", vmin=vmin, vmax=vmax, logger=fig.logger)
|
|
193
|
+
else:
|
|
194
|
+
user_norm = style.get("norm", None)
|
|
195
|
+
resolved = _resolve_norm(user_norm, vmin=vmin, vmax=vmax, logger=fig.logger)
|
|
196
|
+
if resolved is None:
|
|
197
|
+
resolved = mcolors.Normalize(vmin=vmin, vmax=vmax)
|
|
198
|
+
|
|
199
|
+
fig.axc._cb["norm"] = resolved
|
|
200
|
+
s["norm"] = fig.axc._cb["norm"]
|
|
201
|
+
if isinstance(fig.axc._cb["norm"], mcolors.LogNorm):
|
|
202
|
+
fig.axc._cb["mode"] = "log"
|
|
203
|
+
elif isinstance(fig.axc._cb["norm"], mcolors.TwoSlopeNorm):
|
|
204
|
+
fig.axc._cb["mode"] = "diverging"
|
|
205
|
+
elif isinstance(fig.axc._cb["norm"], mcolors.SymLogNorm):
|
|
206
|
+
fig.axc._cb["mode"] = "log"
|
|
207
|
+
else:
|
|
208
|
+
fig.axc._cb["mode"] = "norm"
|
|
209
|
+
|
|
210
|
+
if method_key in ("contour", "contourf", "tricontour", "tricontourf") and fig.axc._cb["levels"] is None:
|
|
211
|
+
lv = s.get("levels", 10)
|
|
212
|
+
if isinstance(lv, int) and fig.axc._cb["vmin"] is not None and fig.axc._cb["vmax"] is not None:
|
|
213
|
+
fig.axc._cb["levels"] = np.linspace(fig.axc._cb["vmin"], fig.axc._cb["vmax"], lv)
|
|
214
|
+
elif hasattr(lv, "__len__"):
|
|
215
|
+
fig.axc._cb["levels"] = lv
|
|
216
|
+
if "norm" in s and s["norm"] is not None:
|
|
217
|
+
s.pop("vmin", None)
|
|
218
|
+
s.pop("vmax", None)
|
|
219
|
+
s.pop("mode", None)
|
|
220
|
+
fig.axc._cb["used"] = uses_color
|
|
221
|
+
return s
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Mapping
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def apply_figure_config(fig, info: Mapping) -> bool:
|
|
8
|
+
"""Apply a YAML figure block to a Figure instance."""
|
|
9
|
+
if not isinstance(info, Mapping):
|
|
10
|
+
raise TypeError("from_dict expects a mapping/dict")
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
changed = True
|
|
14
|
+
if "name" in info:
|
|
15
|
+
fig.name = info["name"]
|
|
16
|
+
else:
|
|
17
|
+
changed = False
|
|
18
|
+
|
|
19
|
+
if "yaml_dir" in info:
|
|
20
|
+
fig._yaml_dir = info.get("yaml_dir")
|
|
21
|
+
elif "_yaml_dir" in info:
|
|
22
|
+
fig._yaml_dir = info.get("_yaml_dir")
|
|
23
|
+
elif "yaml_path" in info:
|
|
24
|
+
try:
|
|
25
|
+
fig._yaml_dir = str(Path(info.get("yaml_path")).expanduser().resolve().parent)
|
|
26
|
+
except Exception:
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
if "debug" in info:
|
|
30
|
+
fig.debug = info["debug"]
|
|
31
|
+
try:
|
|
32
|
+
fig.logger.debug("Loading plot -> {} in debug mode".format(fig.name))
|
|
33
|
+
except Exception:
|
|
34
|
+
pass
|
|
35
|
+
|
|
36
|
+
fig._enable = info.get("enable", True)
|
|
37
|
+
if not fig._enable:
|
|
38
|
+
fig.logger.warning("Skip plot -> {}".format(fig.name))
|
|
39
|
+
return False
|
|
40
|
+
|
|
41
|
+
if "style" in info:
|
|
42
|
+
style_tokens = info["style"]
|
|
43
|
+
else:
|
|
44
|
+
style_tokens = ["a4paper_2x1"]
|
|
45
|
+
fig.style = style_tokens
|
|
46
|
+
fig.logger.debug("Figure style loaded")
|
|
47
|
+
if style_tokens and "gambit" in str(style_tokens[0]).lower():
|
|
48
|
+
fig.mode = "gambit"
|
|
49
|
+
|
|
50
|
+
if "frame" in info:
|
|
51
|
+
fig.frame = info["frame"]
|
|
52
|
+
fig.logger.debug("Figure frame information loaded")
|
|
53
|
+
|
|
54
|
+
import matplotlib.pyplot as plt
|
|
55
|
+
|
|
56
|
+
plt.rcParams["mathtext.fontset"] = "stix"
|
|
57
|
+
fig.fig = plt.figure(**fig.frame["figure"])
|
|
58
|
+
|
|
59
|
+
if fig.print:
|
|
60
|
+
try:
|
|
61
|
+
if isinstance(fig.frame.get("axes"), dict):
|
|
62
|
+
fig.frame["axes"].pop("axlogo", None)
|
|
63
|
+
fig.frame.pop("axlogo", None)
|
|
64
|
+
except Exception:
|
|
65
|
+
pass
|
|
66
|
+
|
|
67
|
+
fig.load_axes()
|
|
68
|
+
|
|
69
|
+
if "layers" in info:
|
|
70
|
+
fig.layers = info["layers"]
|
|
71
|
+
else:
|
|
72
|
+
changed = False
|
|
73
|
+
|
|
74
|
+
return changed
|
|
75
|
+
except Exception as e:
|
|
76
|
+
if fig.logger:
|
|
77
|
+
try:
|
|
78
|
+
import traceback
|
|
79
|
+
|
|
80
|
+
fig.logger.error(
|
|
81
|
+
"Failed to configure figure '{}': {}".format(
|
|
82
|
+
getattr(fig, "name", "<noname>"), e
|
|
83
|
+
)
|
|
84
|
+
)
|
|
85
|
+
fig.logger.debug(traceback.format_exc())
|
|
86
|
+
except Exception:
|
|
87
|
+
pass
|
|
88
|
+
return False
|