eea.plotly 1.5__tar.gz → 1.7__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.
- {eea_plotly-1.5/eea.plotly.egg-info → eea_plotly-1.7}/PKG-INFO +13 -2
- {eea_plotly-1.5 → eea_plotly-1.7}/docs/HISTORY.txt +11 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/browser/preview.py +4 -1
- eea_plotly-1.7/eea/plotly/browser/preview_adapter/soer_miniature.py +159 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/deserializer/dxcontent.py +4 -1
- eea_plotly-1.7/eea/plotly/io_json.py +12 -0
- eea_plotly-1.7/eea/plotly/version.txt +1 -0
- {eea_plotly-1.5 → eea_plotly-1.7/eea.plotly.egg-info}/PKG-INFO +13 -2
- {eea_plotly-1.5 → eea_plotly-1.7}/eea.plotly.egg-info/SOURCES.txt +1 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea.plotly.egg-info/requires.txt +1 -1
- {eea_plotly-1.5 → eea_plotly-1.7}/setup.py +1 -1
- eea_plotly-1.5/eea/plotly/browser/preview_adapter/soer_miniature.py +0 -80
- eea_plotly-1.5/eea/plotly/version.txt +0 -1
- {eea_plotly-1.5 → eea_plotly-1.7}/CONTRIBUTING.md +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/MANIFEST.in +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/README.rst +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/docs/LICENSE.GPL +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/docs/LICENSE.txt +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/__init__.py +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/README.txt +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/__init__.py +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/behaviors.py +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/browser/__init__.py +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/browser/configure.zcml +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/browser/controlpanel.py +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/browser/preview_adapter/adapter.py +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/browser/pt/visualization_view.pt +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/configure.zcml +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/controlpanel.py +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/deserializer/blocks.py +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/deserializer/configure.zcml +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/deserializer/dxfields.py +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/interfaces.py +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/io_csv.py +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/__init__.py +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/bg/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/bg/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/cs/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/cs/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/da/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/da/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/de/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/de/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/eea.pot +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/el/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/el/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/en/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/en/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/es/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/es/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/et/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/et/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/eu/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/eu/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/fi/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/fi/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/fr/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/fr/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/hr/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/hr/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/hu/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/hu/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/is/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/is/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/it/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/it/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/kl/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/kl/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/lt/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/lt/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/lv/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/lv/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/mt/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/mt/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/nl/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/nl/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/no/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/no/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/pl/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/pl/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/plone-manual.pot +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/pt/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/pt/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/pt_BR/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/pt_BR/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/ro/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/ro/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/ru/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/ru/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/sk/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/sk/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/sl/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/sl/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/sv/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/sv/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/tr/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/tr/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/update.sh +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/zh_TW/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/locales/zh_TW/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/permissions.zcml +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/profiles/default/browserlayer.xml +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/profiles/default/controlpanel.json +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/profiles/default/controlpanel.xml +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/profiles/default/metadata.xml +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/profiles/default/registry.xml +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/profiles/default/rolemap.xml +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/profiles/default/types/visualization.xml +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/profiles/default/types.xml +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/profiles/uninstall/browserlayer.xml +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/profiles/uninstall/controlpanel.xml +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/profiles/uninstall/registry.xml +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/profiles.zcml +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/restapi/__init__.py +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/restapi/configure.zcml +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/restapi/controlpanel/__init__.py +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/restapi/controlpanel/configure.zcml +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/restapi/controlpanel/get.py +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/restapi/controlpanel/reset.py +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/restapi/visualization/configure.zcml +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/restapi/visualization/get.py +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/serializer/blocks.py +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/serializer/configure.zcml +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/serializer/dxfields.py +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/serializer/utils.py +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/setuphandlers.py +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/tests/__init__.py +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/tests/base.py +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/tests/test_doctests.py +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/upgrades/__init__.py +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/upgrades/configure.zcml +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea/plotly/utils.py +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea.plotly.egg-info/dependency_links.txt +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea.plotly.egg-info/entry_points.txt +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea.plotly.egg-info/namespace_packages.txt +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea.plotly.egg-info/not-zip-safe +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/eea.plotly.egg-info/top_level.txt +0 -0
- {eea_plotly-1.5 → eea_plotly-1.7}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: eea.plotly
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.7
|
|
4
4
|
Summary: volto-plotlycharts backend support
|
|
5
5
|
Home-page: https://github.com/eea/eea.plotly
|
|
6
6
|
Author: European Environment Agency: IDM2 A-Team
|
|
@@ -23,7 +23,7 @@ Requires-Dist: setuptools
|
|
|
23
23
|
Requires-Dist: plone.volto
|
|
24
24
|
Requires-Dist: collective.folderishtypes
|
|
25
25
|
Requires-Dist: plotly==5.24.1
|
|
26
|
-
Requires-Dist: kaleido
|
|
26
|
+
Requires-Dist: kaleido==0.2.1
|
|
27
27
|
Provides-Extra: test
|
|
28
28
|
Requires-Dist: plone.app.testing; extra == "test"
|
|
29
29
|
Dynamic: author
|
|
@@ -145,6 +145,17 @@ EEA_ - European Environment Agency (EU)
|
|
|
145
145
|
Changelog
|
|
146
146
|
=========
|
|
147
147
|
|
|
148
|
+
1.7 - (2025-07-06)
|
|
149
|
+
---------------------------
|
|
150
|
+
* Change: soer_miniature improved logic
|
|
151
|
+
[razvanMiu]
|
|
152
|
+
|
|
153
|
+
1.6 - (2025-06-24)
|
|
154
|
+
---------------------------
|
|
155
|
+
* Change: pin kaleido version to 0.2.1
|
|
156
|
+
* Refactor: soer_miniature adapter logic (new step functions, data trimming, axis ranges)
|
|
157
|
+
[razvanMiu]
|
|
158
|
+
|
|
148
159
|
1.5 - (2025-06-05)
|
|
149
160
|
---------------------------
|
|
150
161
|
* Change: soer_miniature: hide xaxis ticklabels if no data
|
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
Changelog
|
|
2
2
|
=========
|
|
3
3
|
|
|
4
|
+
1.7 - (2025-07-06)
|
|
5
|
+
---------------------------
|
|
6
|
+
* Change: soer_miniature improved logic
|
|
7
|
+
[razvanMiu]
|
|
8
|
+
|
|
9
|
+
1.6 - (2025-06-24)
|
|
10
|
+
---------------------------
|
|
11
|
+
* Change: pin kaleido version to 0.2.1
|
|
12
|
+
* Refactor: soer_miniature adapter logic (new step functions, data trimming, axis ranges)
|
|
13
|
+
[razvanMiu]
|
|
14
|
+
|
|
4
15
|
1.5 - (2025-06-05)
|
|
5
16
|
---------------------------
|
|
6
17
|
* Change: soer_miniature: hide xaxis ticklabels if no data
|
|
@@ -9,6 +9,7 @@ from zope.publisher.interfaces import IPublishTraverse
|
|
|
9
9
|
from Products.Five.browser import BrowserView
|
|
10
10
|
from eea.plotly.controlpanel import IPlotlySettings
|
|
11
11
|
from eea.plotly.utils import sanitizeVisualization
|
|
12
|
+
from eea.plotly.io_json import JSONEncoder
|
|
12
13
|
|
|
13
14
|
from .preview_adapter.adapter import get_preview_adapter
|
|
14
15
|
|
|
@@ -74,7 +75,9 @@ class PlotlyPreview(BrowserView):
|
|
|
74
75
|
|
|
75
76
|
get_preview_adapter(self, self.name)
|
|
76
77
|
|
|
77
|
-
fig = pio.from_json(
|
|
78
|
+
fig = pio.from_json(
|
|
79
|
+
json.dumps(self.visualization, cls=JSONEncoder),
|
|
80
|
+
skip_invalid=True)
|
|
78
81
|
|
|
79
82
|
if "template" not in self.visualization["layout"]:
|
|
80
83
|
fig.update_layout(template=None)
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
""" SOER miniature theme for Plotly visualizations. """
|
|
2
|
+
import math
|
|
3
|
+
|
|
4
|
+
SOER_TRACES_COUNT = 5
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def nice_step(vmin, vmax, target_ticks=5):
|
|
8
|
+
"""Calculate a 'nice' step size for axis ticks, similar to Plotly/D3."""
|
|
9
|
+
span = abs(vmax - vmin)
|
|
10
|
+
if span == 0:
|
|
11
|
+
return 1 # fallback
|
|
12
|
+
|
|
13
|
+
raw_step = span / max(target_ticks - 1, 1)
|
|
14
|
+
magnitude = 10 ** math.floor(math.log10(raw_step))
|
|
15
|
+
residual = raw_step / magnitude
|
|
16
|
+
|
|
17
|
+
if residual <= 1:
|
|
18
|
+
nice_multiplier = 1
|
|
19
|
+
elif residual <= 2:
|
|
20
|
+
nice_multiplier = 2
|
|
21
|
+
elif residual <= 2.5:
|
|
22
|
+
nice_multiplier = 2.5
|
|
23
|
+
elif residual <= 5:
|
|
24
|
+
nice_multiplier = 5
|
|
25
|
+
else:
|
|
26
|
+
nice_multiplier = 10
|
|
27
|
+
|
|
28
|
+
return nice_multiplier * magnitude
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def exact_step(vmin, vmax, target_ticks=5):
|
|
32
|
+
"""Get the exact step size to have target_ticks between vmin and vmax."""
|
|
33
|
+
if target_ticks < 2:
|
|
34
|
+
raise ValueError("target_ticks must be at least 2 to define a range.")
|
|
35
|
+
return abs(vmax - vmin) / (target_ticks - 1)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def getMin(arr):
|
|
39
|
+
""" Get minimum value from array """
|
|
40
|
+
return min(float(v) for v in arr if v is not None)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def getMax(arr):
|
|
44
|
+
""" Get maximum value from array """
|
|
45
|
+
return max(float(v) for v in arr if v is not None)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def serialize(context):
|
|
49
|
+
""" Serialize the context for SOER miniature theme"""
|
|
50
|
+
if context.visualization is None:
|
|
51
|
+
return False
|
|
52
|
+
|
|
53
|
+
data = context.visualization["data"]
|
|
54
|
+
layout = context.visualization["layout"]
|
|
55
|
+
|
|
56
|
+
if len(data) < SOER_TRACES_COUNT:
|
|
57
|
+
layout["xaxis"]["showticklabels"] = False
|
|
58
|
+
return False
|
|
59
|
+
|
|
60
|
+
min_year = float("inf")
|
|
61
|
+
max_year = float("-inf")
|
|
62
|
+
first_val = None
|
|
63
|
+
new_x = []
|
|
64
|
+
new_y = []
|
|
65
|
+
new_text = []
|
|
66
|
+
|
|
67
|
+
if data[0].get("x") is not None and data[0].get("y") is not None:
|
|
68
|
+
x_len = len(data[0].get("x") or [])
|
|
69
|
+
y_len = len(data[0].get("y") or [])
|
|
70
|
+
text_len = len(data[0].get("text") or [])
|
|
71
|
+
|
|
72
|
+
for index, val in enumerate(data[0]["y"]):
|
|
73
|
+
if val and not first_val:
|
|
74
|
+
first_val = val
|
|
75
|
+
if not first_val:
|
|
76
|
+
continue
|
|
77
|
+
year = data[0]["x"][index] if index < x_len else None
|
|
78
|
+
text = data[0]["text"][index] if index < text_len else None
|
|
79
|
+
new_x.append(year)
|
|
80
|
+
new_y.append(val)
|
|
81
|
+
new_text.append(text)
|
|
82
|
+
if val and year > max_year:
|
|
83
|
+
max_year = year
|
|
84
|
+
if val and year < min_year:
|
|
85
|
+
min_year = year
|
|
86
|
+
|
|
87
|
+
data[0]["x"] = new_x
|
|
88
|
+
data[0]["y"] = new_y
|
|
89
|
+
data[0]["text"] = new_text
|
|
90
|
+
y_len = len(data[0]["y"])
|
|
91
|
+
y4_len = len(data[4].get("y") or [])
|
|
92
|
+
|
|
93
|
+
if y4_len >= y_len:
|
|
94
|
+
data[4]["x"] = new_x
|
|
95
|
+
data[4]["y"] = data[4]["y"][y4_len - y_len:y4_len + 1]
|
|
96
|
+
elif data[4].get("x") is None or data[4].get("y") is None:
|
|
97
|
+
data[4] = {
|
|
98
|
+
"type": "scatter",
|
|
99
|
+
"x": new_x,
|
|
100
|
+
"y": [None] * len(new_y),
|
|
101
|
+
"visible": True,
|
|
102
|
+
"marker": {
|
|
103
|
+
"color": "rgba(0, 0, 0, 1)",
|
|
104
|
+
"line": {
|
|
105
|
+
"color": "rgba(0, 0, 0, 1)"
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
data[4]["y"][len(data[4]["y"]) - 1] = new_y[-1]
|
|
110
|
+
|
|
111
|
+
layout["xaxis"]["tickmode"] = "array"
|
|
112
|
+
layout["xaxis"]["tickvals"] = [min_year, max_year, 2030]
|
|
113
|
+
layout["xaxis"]["range"] = [
|
|
114
|
+
min_year - 2, 2032]
|
|
115
|
+
layout["xaxis"]["autorange"] = True
|
|
116
|
+
|
|
117
|
+
y_values = (
|
|
118
|
+
(data[0].get("y") or []) +
|
|
119
|
+
(data[1].get("y") or []) +
|
|
120
|
+
(data[4].get("y") or [])
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
if y_values:
|
|
124
|
+
top = (
|
|
125
|
+
layout.get("margin", {}).get("t") or
|
|
126
|
+
layout.get("template", {}).get("margin", {}).get("t")
|
|
127
|
+
) or 0
|
|
128
|
+
min_y = getMin(y_values)
|
|
129
|
+
max_y = getMax(y_values)
|
|
130
|
+
|
|
131
|
+
min_y = min_y if min_y < 0 else 0
|
|
132
|
+
max_y = max_y if max_y > 0 else 0
|
|
133
|
+
|
|
134
|
+
nticks = max(int((context.height - top) / 100), 2)
|
|
135
|
+
|
|
136
|
+
step = exact_step(min_y, max_y, nticks)
|
|
137
|
+
|
|
138
|
+
layout["yaxis"]["tickmode"] = "linear"
|
|
139
|
+
layout["yaxis"]["nticks"] = nticks
|
|
140
|
+
layout["yaxis"]["tick0"] = min_y - step
|
|
141
|
+
layout["yaxis"]["dtick"] = step
|
|
142
|
+
|
|
143
|
+
layout["yaxis"]["range"] = [
|
|
144
|
+
min_y - step, max_y + 2 * step]
|
|
145
|
+
layout["yaxis"]["autorange"] = False
|
|
146
|
+
|
|
147
|
+
if "text" in data[0]:
|
|
148
|
+
data[0]["text"] = [
|
|
149
|
+
(t if t is None else " " + str(t))
|
|
150
|
+
for t in data[0]["text"]]
|
|
151
|
+
|
|
152
|
+
data[1]["x"] = None
|
|
153
|
+
data[1]["y"] = None
|
|
154
|
+
data[2]["x"] = None
|
|
155
|
+
data[2]["y"] = None
|
|
156
|
+
data[3]["x"] = None
|
|
157
|
+
data[3]["y"] = None
|
|
158
|
+
|
|
159
|
+
return True
|
|
@@ -12,6 +12,7 @@ from zope.event import notify
|
|
|
12
12
|
from zope.lifecycleevent import Attributes, ObjectModifiedEvent
|
|
13
13
|
from eea.plotly.behaviors import IPlotlyVisualization
|
|
14
14
|
from eea.plotly.io_csv import CsvWriter
|
|
15
|
+
from eea.plotly.io_json import JSONEncoder
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
@implementer(IDeserializeFromJson)
|
|
@@ -99,7 +100,9 @@ class DeserializeVisualizationFromJson(DeserializeFromJson):
|
|
|
99
100
|
"data": self.context.visualization.get("data", []),
|
|
100
101
|
"layout": self.context.visualization.get("layout", {}),
|
|
101
102
|
"frames": self.context.visualization.get("frames", [])
|
|
102
|
-
}
|
|
103
|
+
},
|
|
104
|
+
cls=JSONEncoder
|
|
105
|
+
),
|
|
103
106
|
skip_invalid=True
|
|
104
107
|
)
|
|
105
108
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""JSON encoder that handles Decimal values."""
|
|
2
|
+
import decimal
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class JSONEncoder(json.JSONEncoder):
|
|
7
|
+
"""JSON encoder that handles Decimal values."""
|
|
8
|
+
|
|
9
|
+
def default(self, o):
|
|
10
|
+
if isinstance(o, decimal.Decimal):
|
|
11
|
+
return str(o)
|
|
12
|
+
return super().default(o)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.7
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: eea.plotly
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.7
|
|
4
4
|
Summary: volto-plotlycharts backend support
|
|
5
5
|
Home-page: https://github.com/eea/eea.plotly
|
|
6
6
|
Author: European Environment Agency: IDM2 A-Team
|
|
@@ -23,7 +23,7 @@ Requires-Dist: setuptools
|
|
|
23
23
|
Requires-Dist: plone.volto
|
|
24
24
|
Requires-Dist: collective.folderishtypes
|
|
25
25
|
Requires-Dist: plotly==5.24.1
|
|
26
|
-
Requires-Dist: kaleido
|
|
26
|
+
Requires-Dist: kaleido==0.2.1
|
|
27
27
|
Provides-Extra: test
|
|
28
28
|
Requires-Dist: plone.app.testing; extra == "test"
|
|
29
29
|
Dynamic: author
|
|
@@ -145,6 +145,17 @@ EEA_ - European Environment Agency (EU)
|
|
|
145
145
|
Changelog
|
|
146
146
|
=========
|
|
147
147
|
|
|
148
|
+
1.7 - (2025-07-06)
|
|
149
|
+
---------------------------
|
|
150
|
+
* Change: soer_miniature improved logic
|
|
151
|
+
[razvanMiu]
|
|
152
|
+
|
|
153
|
+
1.6 - (2025-06-24)
|
|
154
|
+
---------------------------
|
|
155
|
+
* Change: pin kaleido version to 0.2.1
|
|
156
|
+
* Refactor: soer_miniature adapter logic (new step functions, data trimming, axis ranges)
|
|
157
|
+
[razvanMiu]
|
|
158
|
+
|
|
148
159
|
1.5 - (2025-06-05)
|
|
149
160
|
---------------------------
|
|
150
161
|
* Change: soer_miniature: hide xaxis ticklabels if no data
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
""" SOER miniature theme for Plotly visualizations. """
|
|
2
|
-
import math
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
def nice_step(vmin, vmax, target_ticks=5):
|
|
6
|
-
""" Calculate a 'nice' step size for the axis ticks. """
|
|
7
|
-
span = abs(vmax - vmin)
|
|
8
|
-
if span == 0:
|
|
9
|
-
return 1 # arbitrary fallback
|
|
10
|
-
|
|
11
|
-
# Initial guess for raw step size
|
|
12
|
-
raw_step = span / target_ticks
|
|
13
|
-
|
|
14
|
-
# Determine the power of 10
|
|
15
|
-
magnitude = 10 ** math.floor(math.log10(raw_step))
|
|
16
|
-
residual = raw_step / magnitude
|
|
17
|
-
|
|
18
|
-
# Choose a nice multiplier
|
|
19
|
-
if residual < 1.5:
|
|
20
|
-
nice_multiplier = 1
|
|
21
|
-
elif residual < 3:
|
|
22
|
-
nice_multiplier = 2
|
|
23
|
-
elif residual < 7:
|
|
24
|
-
nice_multiplier = 5
|
|
25
|
-
else:
|
|
26
|
-
nice_multiplier = 10
|
|
27
|
-
|
|
28
|
-
return nice_multiplier * magnitude
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def getMin(arr):
|
|
32
|
-
""" Get minimum value from array """
|
|
33
|
-
return min(float(v) for v in arr if v is not None)
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def getMax(arr):
|
|
37
|
-
""" Get maximum value from array """
|
|
38
|
-
return max(float(v) for v in arr if v is not None)
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
def serialize(context):
|
|
42
|
-
""" Serialize the context for SOER miniature theme"""
|
|
43
|
-
|
|
44
|
-
# Solve x axis range
|
|
45
|
-
if context.visualization is None or len(context.visualization["data"]) < 2:
|
|
46
|
-
context.visualization["layout"]["xaxis"]["showticklabels"] = False
|
|
47
|
-
return False
|
|
48
|
-
|
|
49
|
-
years = context.visualization["data"][0].get("x", [])
|
|
50
|
-
tickvals = context.visualization["layout"]["xaxis"].get("tickvals", [])
|
|
51
|
-
|
|
52
|
-
if tickvals and years:
|
|
53
|
-
min_year = getMin(tickvals)
|
|
54
|
-
max_year = getMax(years)
|
|
55
|
-
|
|
56
|
-
context.visualization["layout"]["xaxis"]["range"] = [
|
|
57
|
-
min_year - 2, max_year + 2]
|
|
58
|
-
context.visualization["layout"]["xaxis"]["autorange"] = False
|
|
59
|
-
|
|
60
|
-
# Solve y axis range
|
|
61
|
-
|
|
62
|
-
y_values = context.visualization["data"][0].get(
|
|
63
|
-
"y", []) + context.visualization["data"][1].get("y", [])
|
|
64
|
-
|
|
65
|
-
if y_values:
|
|
66
|
-
min_y = getMin(y_values)
|
|
67
|
-
max_y = getMax(y_values)
|
|
68
|
-
|
|
69
|
-
step = nice_step(min_y, max_y, 10)
|
|
70
|
-
|
|
71
|
-
context.visualization["layout"]["yaxis"]["range"] = [
|
|
72
|
-
min_y - step, max_y + step]
|
|
73
|
-
context.visualization["layout"]["yaxis"]["autorange"] = False
|
|
74
|
-
|
|
75
|
-
if "text" in context.visualization["data"][0]:
|
|
76
|
-
context.visualization["data"][0]["text"] = [
|
|
77
|
-
(t if t is None else " " + str(t))
|
|
78
|
-
for t in context.visualization["data"][0]["text"]]
|
|
79
|
-
|
|
80
|
-
return True
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
1.5
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|