eea.plotly 2.0__tar.gz → 2.2__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-2.0/eea.plotly.egg-info → eea_plotly-2.2}/PKG-INFO +13 -1
- {eea_plotly-2.0 → eea_plotly-2.2}/docs/HISTORY.txt +12 -0
- eea_plotly-2.2/eea/__init__.py +4 -0
- eea_plotly-2.2/eea/plotly/__init__.py +9 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/behaviors.py +2 -2
- eea_plotly-2.2/eea/plotly/browser/__init__.py +1 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/browser/controlpanel.py +3 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/browser/preview.py +14 -23
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/browser/preview_adapter/adapter.py +3 -5
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/browser/preview_adapter/soer_miniature.py +19 -24
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/controlpanel.py +16 -28
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/deserializer/blocks.py +7 -7
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/deserializer/dxcontent.py +23 -28
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/deserializer/dxfields.py +3 -5
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/interfaces.py +5 -4
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/io_csv.py +6 -7
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/io_json.py +1 -0
- eea_plotly-2.2/eea/plotly/locales/__init__.py +1 -0
- eea_plotly-2.2/eea/plotly/restapi/__init__.py +1 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/restapi/controlpanel/get.py +6 -17
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/restapi/controlpanel/reset.py +8 -10
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/restapi/visualization/get.py +6 -9
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/serializer/blocks.py +21 -25
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/serializer/dxfields.py +3 -3
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/serializer/utils.py +8 -12
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/setuphandlers.py +12 -15
- eea_plotly-2.2/eea/plotly/tests/__init__.py +1 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/tests/base.py +14 -20
- eea_plotly-2.2/eea/plotly/tests/test_doctests.py +31 -0
- eea_plotly-2.2/eea/plotly/upgrades/__init__.py +1 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/utils.py +11 -12
- eea_plotly-2.2/eea/plotly/version.txt +1 -0
- {eea_plotly-2.0 → eea_plotly-2.2/eea.plotly.egg-info}/PKG-INFO +13 -1
- {eea_plotly-2.0 → eea_plotly-2.2}/setup.py +20 -20
- eea_plotly-2.0/eea/__init__.py +0 -3
- eea_plotly-2.0/eea/plotly/__init__.py +0 -10
- eea_plotly-2.0/eea/plotly/browser/__init__.py +0 -2
- eea_plotly-2.0/eea/plotly/locales/__init__.py +0 -2
- eea_plotly-2.0/eea/plotly/restapi/__init__.py +0 -2
- eea_plotly-2.0/eea/plotly/tests/__init__.py +0 -2
- eea_plotly-2.0/eea/plotly/tests/test_doctests.py +0 -30
- eea_plotly-2.0/eea/plotly/upgrades/__init__.py +0 -2
- eea_plotly-2.0/eea/plotly/version.txt +0 -1
- {eea_plotly-2.0 → eea_plotly-2.2}/CONTRIBUTING.md +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/MANIFEST.in +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/README.rst +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/docs/LICENSE.GPL +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/docs/LICENSE.txt +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/README.txt +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/browser/configure.zcml +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/browser/pt/visualization_view.pt +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/configure.zcml +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/deserializer/configure.zcml +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/bg/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/bg/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/cs/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/cs/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/da/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/da/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/de/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/de/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/eea.pot +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/el/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/el/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/en/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/en/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/es/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/es/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/et/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/et/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/eu/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/eu/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/fi/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/fi/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/fr/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/fr/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/hr/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/hr/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/hu/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/hu/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/is/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/is/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/it/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/it/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/kl/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/kl/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/lt/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/lt/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/lv/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/lv/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/mt/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/mt/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/nl/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/nl/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/no/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/no/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/pl/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/pl/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/plone-manual.pot +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/pt/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/pt/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/pt_BR/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/pt_BR/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/ro/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/ro/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/ru/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/ru/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/sk/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/sk/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/sl/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/sl/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/sv/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/sv/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/tr/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/tr/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/update.sh +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/zh_TW/LC_MESSAGES/eea.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/locales/zh_TW/LC_MESSAGES/plone.po +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/permissions.zcml +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/profiles/default/browserlayer.xml +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/profiles/default/controlpanel.json +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/profiles/default/controlpanel.xml +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/profiles/default/metadata.xml +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/profiles/default/registry.xml +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/profiles/default/rolemap.xml +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/profiles/default/types/visualization.xml +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/profiles/default/types.xml +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/profiles/uninstall/browserlayer.xml +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/profiles/uninstall/controlpanel.xml +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/profiles/uninstall/registry.xml +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/profiles.zcml +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/restapi/configure.zcml +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/restapi/controlpanel/__init__.py +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/restapi/controlpanel/configure.zcml +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/restapi/visualization/configure.zcml +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/serializer/configure.zcml +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea/plotly/upgrades/configure.zcml +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea.plotly.egg-info/SOURCES.txt +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea.plotly.egg-info/dependency_links.txt +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea.plotly.egg-info/entry_points.txt +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea.plotly.egg-info/namespace_packages.txt +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea.plotly.egg-info/not-zip-safe +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea.plotly.egg-info/requires.txt +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/eea.plotly.egg-info/top_level.txt +0 -0
- {eea_plotly-2.0 → eea_plotly-2.2}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: eea.plotly
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2
|
|
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
|
|
@@ -145,6 +145,18 @@ EEA_ - European Environment Agency (EU)
|
|
|
145
145
|
Changelog
|
|
146
146
|
=========
|
|
147
147
|
|
|
148
|
+
2.2 - (2025-11-20)
|
|
149
|
+
---------------------------
|
|
150
|
+
* Change: better handle of backward compatibility, ref #293767
|
|
151
|
+
[razvanMiu]
|
|
152
|
+
|
|
153
|
+
2.1 - (2025-11-18)
|
|
154
|
+
---------------------------
|
|
155
|
+
* Change: Replace Python linting to ruff
|
|
156
|
+
[mihaidobrescu1111 = refs #286821]
|
|
157
|
+
* Change: Add plone6 tests
|
|
158
|
+
[mihaidobrescu1111 = refs #293593]
|
|
159
|
+
|
|
148
160
|
2.0 - (2025-08-27)
|
|
149
161
|
---------------------------
|
|
150
162
|
* Change: fix csv file data decoding
|
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
Changelog
|
|
2
2
|
=========
|
|
3
3
|
|
|
4
|
+
2.2 - (2025-11-20)
|
|
5
|
+
---------------------------
|
|
6
|
+
* Change: better handle of backward compatibility, ref #293767
|
|
7
|
+
[razvanMiu]
|
|
8
|
+
|
|
9
|
+
2.1 - (2025-11-18)
|
|
10
|
+
---------------------------
|
|
11
|
+
* Change: Replace Python linting to ruff
|
|
12
|
+
[mihaidobrescu1111 = refs #286821]
|
|
13
|
+
* Change: Add plone6 tests
|
|
14
|
+
[mihaidobrescu1111 = refs #293593]
|
|
15
|
+
|
|
4
16
|
2.0 - (2025-08-27)
|
|
5
17
|
---------------------------
|
|
6
18
|
* Change: fix csv file data decoding
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""behavior module"""
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
|
|
@@ -17,7 +17,7 @@ VIZ_SCHEMA = json.dumps({"type": "object", "properties": {}})
|
|
|
17
17
|
|
|
18
18
|
@provider(IFormFieldProvider)
|
|
19
19
|
class IPlotlyVisualization(model.Schema):
|
|
20
|
-
"""
|
|
20
|
+
"""A plotly visualization behavior provider"""
|
|
21
21
|
|
|
22
22
|
visualization = JSONField(
|
|
23
23
|
title="Visualization", required=False, default={}, schema=VIZ_SCHEMA
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Browser"""
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"""Control panel module"""
|
|
2
|
+
|
|
2
3
|
from plone.app.registry.browser.controlpanel import ControlPanelFormWrapper
|
|
3
4
|
from plone.app.registry.browser.controlpanel import RegistryEditForm
|
|
4
5
|
|
|
@@ -7,6 +8,7 @@ from eea.plotly.controlpanel import IPlotlySettings
|
|
|
7
8
|
|
|
8
9
|
class PlotlyRegistryEditForm(RegistryEditForm):
|
|
9
10
|
"""Plotly Registry Edit Form"""
|
|
11
|
+
|
|
10
12
|
schema = IPlotlySettings
|
|
11
13
|
id = "plotly"
|
|
12
14
|
label = "Plotly Settings"
|
|
@@ -14,4 +16,5 @@ class PlotlyRegistryEditForm(RegistryEditForm):
|
|
|
14
16
|
|
|
15
17
|
class PlotlyControlPanelFormWrapper(ControlPanelFormWrapper):
|
|
16
18
|
"""Plotly Control Panel Form Wrapper"""
|
|
19
|
+
|
|
17
20
|
form = PlotlyRegistryEditForm
|
|
@@ -15,12 +15,13 @@ from .preview_adapter.adapter import get_preview_adapter
|
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
def deepUpdate(original, update):
|
|
18
|
-
"""
|
|
18
|
+
"""Recursively update a dictionary with another dictionary."""
|
|
19
19
|
for key, value in update.items():
|
|
20
|
-
if
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
if (
|
|
21
|
+
isinstance(value, dict)
|
|
22
|
+
and key in original
|
|
23
|
+
and isinstance(original[key], dict)
|
|
24
|
+
):
|
|
24
25
|
deepUpdate(original[key], value)
|
|
25
26
|
elif key in original:
|
|
26
27
|
original[key] = value
|
|
@@ -44,17 +45,12 @@ class PlotlyPreview(BrowserView):
|
|
|
44
45
|
|
|
45
46
|
if not self.visualization:
|
|
46
47
|
self.request.response.setStatus(404)
|
|
47
|
-
return {
|
|
48
|
-
"message": "Visualization is not defined",
|
|
49
|
-
"type": "NotFound"
|
|
50
|
-
}
|
|
48
|
+
return {"message": "Visualization is not defined", "type": "NotFound"}
|
|
51
49
|
|
|
52
50
|
if self.name:
|
|
53
51
|
theme = None
|
|
54
52
|
themes = api.portal.get_registry_record(
|
|
55
|
-
"themes",
|
|
56
|
-
interface=IPlotlySettings,
|
|
57
|
-
default=[]
|
|
53
|
+
"themes", interface=IPlotlySettings, default=[]
|
|
58
54
|
)
|
|
59
55
|
for t in themes:
|
|
60
56
|
if t.get("id") == self.name:
|
|
@@ -63,11 +59,10 @@ class PlotlyPreview(BrowserView):
|
|
|
63
59
|
if theme and "layout" in self.visualization:
|
|
64
60
|
data = theme.get("data", {})
|
|
65
61
|
layout = theme.get("layout", {})
|
|
66
|
-
for trIndex, tr in enumerate(
|
|
67
|
-
self.visualization.get("data", [])):
|
|
62
|
+
for trIndex, tr in enumerate(self.visualization.get("data", [])):
|
|
68
63
|
trType = tr.get("type", "")
|
|
69
64
|
if trType in data:
|
|
70
|
-
newTrIndex = min(trIndex, len(data[trType])-1)
|
|
65
|
+
newTrIndex = min(trIndex, len(data[trType]) - 1)
|
|
71
66
|
newTr = data[trType][newTrIndex]
|
|
72
67
|
deepUpdate(tr, newTr)
|
|
73
68
|
deepUpdate(self.visualization["layout"], layout)
|
|
@@ -76,21 +71,17 @@ class PlotlyPreview(BrowserView):
|
|
|
76
71
|
get_preview_adapter(self, self.name)
|
|
77
72
|
|
|
78
73
|
fig = pio.from_json(
|
|
79
|
-
json.dumps(self.visualization, cls=JSONEncoder),
|
|
80
|
-
|
|
74
|
+
json.dumps(self.visualization, cls=JSONEncoder), skip_invalid=True
|
|
75
|
+
)
|
|
81
76
|
|
|
82
77
|
if "template" not in self.visualization["layout"]:
|
|
83
78
|
fig.update_layout(template=None)
|
|
84
79
|
|
|
85
|
-
image = fig.to_image(
|
|
86
|
-
format="svg", width=self.width, height=self.height)
|
|
80
|
+
image = fig.to_image(format="svg", width=self.width, height=self.height)
|
|
87
81
|
|
|
88
82
|
sh = self.request.response.setHeader
|
|
89
83
|
|
|
90
|
-
sh(
|
|
91
|
-
"Content-Type",
|
|
92
|
-
"image/svg+xml"
|
|
93
|
-
)
|
|
84
|
+
sh("Content-Type", "image/svg+xml")
|
|
94
85
|
sh("Content-Disposition", "inline; filename=%s.svg" % "x")
|
|
95
86
|
|
|
96
87
|
return image
|
|
@@ -1,14 +1,12 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Preview adapter for Plotly browser."""
|
|
2
2
|
|
|
3
3
|
adapters = {
|
|
4
|
-
"soer_miniature": (
|
|
5
|
-
"eea.plotly.browser.preview_adapter.soer_miniature.serialize"
|
|
6
|
-
),
|
|
4
|
+
"soer_miniature": ("eea.plotly.browser.preview_adapter.soer_miniature.serialize"),
|
|
7
5
|
}
|
|
8
6
|
|
|
9
7
|
|
|
10
8
|
def get_preview_adapter(context, name):
|
|
11
|
-
"""
|
|
9
|
+
"""Get the preview adapter for a given name.
|
|
12
10
|
|
|
13
11
|
Args:
|
|
14
12
|
name (str): The name of the preview adapter.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""SOER miniature theme for Plotly visualizations."""
|
|
2
|
+
|
|
2
3
|
import math
|
|
3
4
|
|
|
4
5
|
SOER_TRACES_COUNT = 5
|
|
@@ -36,7 +37,7 @@ def exact_step(vmin, vmax, target_ticks=5):
|
|
|
36
37
|
|
|
37
38
|
|
|
38
39
|
def toFloat(v):
|
|
39
|
-
"""
|
|
40
|
+
"""Convert value to float"""
|
|
40
41
|
try:
|
|
41
42
|
return float(v)
|
|
42
43
|
except ValueError:
|
|
@@ -44,17 +45,17 @@ def toFloat(v):
|
|
|
44
45
|
|
|
45
46
|
|
|
46
47
|
def getMin(arr):
|
|
47
|
-
"""
|
|
48
|
+
"""Get minimum value from array"""
|
|
48
49
|
return min(toFloat(v) for v in arr if v is not None)
|
|
49
50
|
|
|
50
51
|
|
|
51
52
|
def getMax(arr):
|
|
52
|
-
"""
|
|
53
|
+
"""Get maximum value from array"""
|
|
53
54
|
return max(toFloat(v) for v in arr if v is not None)
|
|
54
55
|
|
|
55
56
|
|
|
56
57
|
def serialize(context):
|
|
57
|
-
"""
|
|
58
|
+
"""Serialize the context for SOER miniature theme"""
|
|
58
59
|
if context.visualization is None:
|
|
59
60
|
return False
|
|
60
61
|
|
|
@@ -62,8 +63,8 @@ def serialize(context):
|
|
|
62
63
|
layout = context.visualization["layout"]
|
|
63
64
|
|
|
64
65
|
top = (
|
|
65
|
-
layout.get("margin", {}).get("t")
|
|
66
|
-
layout.get("template", {}).get("margin", {}).get("t")
|
|
66
|
+
layout.get("margin", {}).get("t")
|
|
67
|
+
or layout.get("template", {}).get("margin", {}).get("t")
|
|
67
68
|
) or 0
|
|
68
69
|
nticks = max(int((context.height - top) / 100), 2)
|
|
69
70
|
|
|
@@ -89,7 +90,7 @@ def serialize(context):
|
|
|
89
90
|
layout["template"]["layout"]["annotationdefaults"] = {
|
|
90
91
|
"showarrow": False,
|
|
91
92
|
"xref": "paper",
|
|
92
|
-
"yref": "paper"
|
|
93
|
+
"yref": "paper",
|
|
93
94
|
}
|
|
94
95
|
return False
|
|
95
96
|
|
|
@@ -150,7 +151,7 @@ def serialize(context):
|
|
|
150
151
|
|
|
151
152
|
if y4_len >= y_len:
|
|
152
153
|
data[4]["x"] = new_x
|
|
153
|
-
data[4]["y"] = data[4]["y"][y4_len - y_len:y4_len + 1]
|
|
154
|
+
data[4]["y"] = data[4]["y"][y4_len - y_len : y4_len + 1]
|
|
154
155
|
elif data[4].get("x") is None or data[4].get("y") is None:
|
|
155
156
|
data[4] = {
|
|
156
157
|
"type": "scatter",
|
|
@@ -159,24 +160,21 @@ def serialize(context):
|
|
|
159
160
|
"visible": True,
|
|
160
161
|
"marker": {
|
|
161
162
|
"color": "rgba(0, 0, 0, 1)",
|
|
162
|
-
"line": {
|
|
163
|
-
|
|
164
|
-
}
|
|
165
|
-
}
|
|
163
|
+
"line": {"color": "rgba(0, 0, 0, 1)"},
|
|
164
|
+
},
|
|
166
165
|
}
|
|
167
166
|
data[4]["y"][len(data[4]["y"]) - 1] = new_y[-1]
|
|
168
167
|
|
|
169
168
|
layout["xaxis"]["tickmode"] = "array"
|
|
170
169
|
layout["xaxis"]["tickvals"] = [min_year, max_year, 2030]
|
|
171
|
-
layout["xaxis"]["range"] = [
|
|
172
|
-
min_year - 2, 2032]
|
|
170
|
+
layout["xaxis"]["range"] = [min_year - 2, 2032]
|
|
173
171
|
layout["xaxis"]["autorange"] = True
|
|
174
172
|
|
|
175
173
|
y_values = (
|
|
176
|
-
(data[0].get("y") or [])
|
|
177
|
-
(data[1].get("y") or [])
|
|
178
|
-
(data[4].get("y") or [])
|
|
179
|
-
((trace_6.get("y") or []) if trace_6 else [])
|
|
174
|
+
(data[0].get("y") or [])
|
|
175
|
+
+ (data[1].get("y") or [])
|
|
176
|
+
+ (data[4].get("y") or [])
|
|
177
|
+
+ ((trace_6.get("y") or []) if trace_6 else [])
|
|
180
178
|
)
|
|
181
179
|
|
|
182
180
|
if y_values:
|
|
@@ -193,14 +191,11 @@ def serialize(context):
|
|
|
193
191
|
layout["yaxis"]["tick0"] = min_y - step
|
|
194
192
|
layout["yaxis"]["dtick"] = step
|
|
195
193
|
|
|
196
|
-
layout["yaxis"]["range"] = [
|
|
197
|
-
min_y - step, max_y + 2 * step]
|
|
194
|
+
layout["yaxis"]["range"] = [min_y - step, max_y + 2 * step]
|
|
198
195
|
layout["yaxis"]["autorange"] = False
|
|
199
196
|
|
|
200
197
|
if "text" in data[0]:
|
|
201
|
-
data[0]["text"] = [
|
|
202
|
-
(t if t is None else " " + str(t))
|
|
203
|
-
for t in data[0]["text"]]
|
|
198
|
+
data[0]["text"] = [(t if t is None else " " + str(t)) for t in data[0]["text"]]
|
|
204
199
|
|
|
205
200
|
data[1]["x"] = None
|
|
206
201
|
data[1]["y"] = None
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"""Plotly Controlpanel API"""
|
|
2
|
+
|
|
2
3
|
import json
|
|
3
4
|
from zope.interface import Interface
|
|
4
5
|
from zope.component import adapter
|
|
@@ -7,58 +8,45 @@ from plone.restapi.controlpanels import RegistryConfigletPanel
|
|
|
7
8
|
from eea.plotly.interfaces import IPlotlyLayer
|
|
8
9
|
from eea.plotly import EEAMessageFactory as _
|
|
9
10
|
|
|
10
|
-
TEMPLATES_SCHEMA = json.dumps(
|
|
11
|
-
"type": "array",
|
|
12
|
-
|
|
13
|
-
"type": "object",
|
|
14
|
-
"properties": {}
|
|
15
|
-
}
|
|
16
|
-
})
|
|
11
|
+
TEMPLATES_SCHEMA = json.dumps(
|
|
12
|
+
{"type": "array", "items": {"type": "object", "properties": {}}}
|
|
13
|
+
)
|
|
17
14
|
|
|
18
|
-
THEMES_SCHEMA = json.dumps(
|
|
19
|
-
"type": "array",
|
|
20
|
-
|
|
21
|
-
"type": "object",
|
|
22
|
-
"properties": {}
|
|
23
|
-
}
|
|
24
|
-
})
|
|
15
|
+
THEMES_SCHEMA = json.dumps(
|
|
16
|
+
{"type": "array", "items": {"type": "object", "properties": {}}}
|
|
17
|
+
)
|
|
25
18
|
|
|
26
19
|
|
|
27
20
|
class IPlotlySettings(Interface):
|
|
28
21
|
"""Client settings for EEA Plotly."""
|
|
22
|
+
|
|
29
23
|
themes = JSONField(
|
|
30
|
-
title=_(
|
|
31
|
-
description=_(
|
|
32
|
-
u"The JSON representation of plotly themes."
|
|
33
|
-
),
|
|
24
|
+
title=_("Themes"),
|
|
25
|
+
description=_("The JSON representation of plotly themes."),
|
|
34
26
|
schema=THEMES_SCHEMA,
|
|
35
27
|
default=[],
|
|
36
28
|
widget="plotly_themes",
|
|
37
|
-
required=False
|
|
29
|
+
required=False,
|
|
38
30
|
)
|
|
39
31
|
|
|
40
32
|
templates = JSONField(
|
|
41
|
-
title=_(
|
|
42
|
-
description=_(
|
|
43
|
-
u"The JSON representation of plotly templates."
|
|
44
|
-
),
|
|
33
|
+
title=_("Templates"),
|
|
34
|
+
description=_("The JSON representation of plotly templates."),
|
|
45
35
|
schema=TEMPLATES_SCHEMA,
|
|
46
36
|
default=[],
|
|
47
37
|
widget="plotly_templates",
|
|
48
|
-
required=False
|
|
38
|
+
required=False,
|
|
49
39
|
)
|
|
50
40
|
|
|
51
41
|
|
|
52
42
|
@adapter(Interface, IPlotlyLayer)
|
|
53
43
|
class PlotlyControlpanel(RegistryConfigletPanel):
|
|
54
44
|
"""Plotly Control Panel"""
|
|
45
|
+
|
|
55
46
|
schema = IPlotlySettings
|
|
56
47
|
schema_prefix = None
|
|
57
48
|
configlet_id = "plotly"
|
|
58
49
|
configlet_category_id = "Products"
|
|
59
50
|
title = "Plotly Settings"
|
|
60
51
|
group = "Products"
|
|
61
|
-
data = {
|
|
62
|
-
"themes": [],
|
|
63
|
-
"templates": []
|
|
64
|
-
}
|
|
52
|
+
data = {"themes": [], "templates": []}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""block-related utils"""
|
|
2
2
|
|
|
3
3
|
from plone.restapi.behaviors import IBlocks
|
|
4
4
|
from plone.restapi.interfaces import IBlockFieldDeserializationTransformer
|
|
@@ -22,11 +22,11 @@ class EmbedVisualizationDeserializationTransformer:
|
|
|
22
22
|
self.request = request
|
|
23
23
|
|
|
24
24
|
def __call__(self, value):
|
|
25
|
-
delProperty(value,
|
|
26
|
-
delProperty(value,
|
|
27
|
-
delProperty(value,
|
|
28
|
-
if
|
|
29
|
-
value[
|
|
30
|
-
context=self.context, link=getLink(value[
|
|
25
|
+
delProperty(value, "visualization")
|
|
26
|
+
delProperty(value, "properties")
|
|
27
|
+
delProperty(value, "image_scales")
|
|
28
|
+
if "vis_url" in value:
|
|
29
|
+
value["vis_url"] = path2uid(
|
|
30
|
+
context=self.context, link=getLink(value["vis_url"])
|
|
31
31
|
)
|
|
32
32
|
return value
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Deserialize Plotly visualization from JSON"""
|
|
2
|
+
|
|
2
3
|
from io import StringIO
|
|
3
4
|
import json
|
|
4
5
|
import plotly.io as pio
|
|
@@ -18,7 +19,7 @@ from eea.plotly.io_json import JSONEncoder
|
|
|
18
19
|
@implementer(IDeserializeFromJson)
|
|
19
20
|
@adapter(IPlotlyVisualization, Interface)
|
|
20
21
|
class DeserializeVisualizationFromJson(DeserializeFromJson):
|
|
21
|
-
"""
|
|
22
|
+
"""Deserialize Plotly visualization from JSON"""
|
|
22
23
|
|
|
23
24
|
def jsonToBinary(self, data):
|
|
24
25
|
"""Convert JSON data to binary"""
|
|
@@ -50,34 +51,29 @@ class DeserializeVisualizationFromJson(DeserializeFromJson):
|
|
|
50
51
|
|
|
51
52
|
CsvWriter(output).writerows(rows)
|
|
52
53
|
|
|
53
|
-
return output.getvalue().encode(
|
|
54
|
+
return output.getvalue().encode("utf-8")
|
|
54
55
|
|
|
55
56
|
def __call__(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
super().__call__(
|
|
60
|
-
validate_all, data, create, mask_validation_errors
|
|
61
|
-
)
|
|
57
|
+
self, validate_all=False, data=None, create=False, mask_validation_errors=True
|
|
58
|
+
):
|
|
59
|
+
super().__call__(validate_all, data, create, mask_validation_errors)
|
|
62
60
|
|
|
63
61
|
ok = False
|
|
64
62
|
for interface, names in self.modified.items():
|
|
65
|
-
if (
|
|
66
|
-
|
|
63
|
+
if (
|
|
64
|
+
interface == IPlotlyVisualization
|
|
65
|
+
and "IPlotlyVisualization.visualization" in names
|
|
66
|
+
):
|
|
67
67
|
ok = True
|
|
68
68
|
break
|
|
69
69
|
|
|
70
70
|
if not ok:
|
|
71
71
|
return self.context
|
|
72
72
|
|
|
73
|
-
data = self.jsonToBinary(self.context.visualization.get(
|
|
74
|
-
"dataSources", {})
|
|
75
|
-
)
|
|
73
|
+
data = self.jsonToBinary(self.context.visualization.get("dataSources", {}))
|
|
76
74
|
|
|
77
75
|
self.context.file = NamedBlobFile(
|
|
78
|
-
data=data if data else b"",
|
|
79
|
-
filename="data.csv",
|
|
80
|
-
contentType="text/csv"
|
|
76
|
+
data=data if data else b"", filename="data.csv", contentType="text/csv"
|
|
81
77
|
)
|
|
82
78
|
|
|
83
79
|
if "dataSources" in self.context.visualization:
|
|
@@ -89,28 +85,27 @@ class DeserializeVisualizationFromJson(DeserializeFromJson):
|
|
|
89
85
|
Attributes(
|
|
90
86
|
IPlotlyVisualization,
|
|
91
87
|
"IPlotlyVisualization.visualization",
|
|
92
|
-
"IPlotlyVisualization.file"
|
|
88
|
+
"IPlotlyVisualization.file",
|
|
93
89
|
)
|
|
94
90
|
)
|
|
95
91
|
notify(ObjectModifiedEvent(self.context, *modified))
|
|
96
92
|
|
|
97
93
|
# Handle preview image
|
|
98
94
|
fig = pio.from_json(
|
|
99
|
-
json.dumps(
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
95
|
+
json.dumps(
|
|
96
|
+
{
|
|
97
|
+
"data": self.context.visualization.get("data", []),
|
|
98
|
+
"layout": self.context.visualization.get("layout", {}),
|
|
99
|
+
"frames": self.context.visualization.get("frames", []),
|
|
100
|
+
},
|
|
101
|
+
cls=JSONEncoder,
|
|
105
102
|
),
|
|
106
|
-
skip_invalid=True
|
|
103
|
+
skip_invalid=True,
|
|
107
104
|
)
|
|
108
105
|
|
|
109
106
|
image = fig.to_image(format="svg", width=1200, height=900)
|
|
110
107
|
self.context.preview_image = NamedBlobImage(
|
|
111
|
-
data=image,
|
|
112
|
-
filename="preview.svg",
|
|
113
|
-
contentType="image/svg+xml"
|
|
108
|
+
data=image, filename="preview.svg", contentType="image/svg+xml"
|
|
114
109
|
)
|
|
115
110
|
|
|
116
111
|
return self.context
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""dxfields deserializers"""
|
|
2
2
|
|
|
3
3
|
from zope.component import adapter
|
|
4
4
|
from zope.interface import implementer
|
|
@@ -19,10 +19,8 @@ class VisualizationFieldDeserializer(DefaultFieldDeserializer):
|
|
|
19
19
|
def __call__(self, value):
|
|
20
20
|
value = sanitizeVisualization(value)
|
|
21
21
|
|
|
22
|
-
if
|
|
22
|
+
if "provider_url" in value:
|
|
23
23
|
url = value["provider_url"]
|
|
24
|
-
value["provider_url"] = path2uid(
|
|
25
|
-
context=self.context, link=getLink(url)
|
|
26
|
-
)
|
|
24
|
+
value["provider_url"] = path2uid(context=self.context, link=getLink(url))
|
|
27
25
|
|
|
28
26
|
return value
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
"""Module where all interfaces, events and exceptions live."""
|
|
2
|
+
|
|
2
3
|
from zope.interface import Interface
|
|
3
4
|
from zope.publisher.interfaces.browser import IDefaultBrowserLayer
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
class IPlotlyLayer(IDefaultBrowserLayer):
|
|
7
|
-
"""
|
|
8
|
+
"""Marker interface that defines a browser layer."""
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
class IPlotlyVisualizationField(Interface):
|
|
11
|
-
"""
|
|
12
|
+
"""Marker interface for plotly visualization JSON field"""
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
class IPlotlyFileField(Interface):
|
|
15
|
-
"""
|
|
16
|
+
"""Marker interface for plotly file field"""
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
class IPlotlyVisualization(Interface):
|
|
19
|
-
"""
|
|
20
|
+
"""Marker interface for plotly visualization"""
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"""CSV reader/writer that handles NULL values."""
|
|
2
|
+
|
|
2
3
|
import csv
|
|
3
|
-
|
|
4
|
+
|
|
5
|
+
NULL = "NULL"
|
|
4
6
|
|
|
5
7
|
|
|
6
8
|
class CsvWriter:
|
|
@@ -15,10 +17,7 @@ class CsvWriter:
|
|
|
15
17
|
|
|
16
18
|
def writerow(self, row):
|
|
17
19
|
"""Write a single row to the CSV file."""
|
|
18
|
-
self.csv_writer.writerow(
|
|
19
|
-
[item if item is not None else NULL
|
|
20
|
-
for item in row]
|
|
21
|
-
)
|
|
20
|
+
self.csv_writer.writerow([item if item is not None else NULL for item in row])
|
|
22
21
|
|
|
23
22
|
def writerows(self, rows):
|
|
24
23
|
"""Write multiple rows to the CSV file."""
|
|
@@ -31,10 +30,10 @@ class CsvReader:
|
|
|
31
30
|
|
|
32
31
|
def __init__(self, *args, **kwrds):
|
|
33
32
|
try:
|
|
34
|
-
inputEntity = args[0] or kwrds.get(
|
|
33
|
+
inputEntity = args[0] or kwrds.get("csvfile")
|
|
35
34
|
sample = inputEntity.read(1024)
|
|
36
35
|
inputEntity.seek(0)
|
|
37
|
-
dialect = csv.Sniffer().sniff(sample, delimiters=
|
|
36
|
+
dialect = csv.Sniffer().sniff(sample, delimiters=",;\t|")
|
|
38
37
|
except (csv.Error, TypeError):
|
|
39
38
|
# No dialect found, use default
|
|
40
39
|
dialect = csv.excel
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""i18n"""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Restapi"""
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"""RestAPI enpoint @plotly GET"""
|
|
2
|
+
|
|
2
3
|
from plone import api
|
|
3
4
|
from plone.restapi.services import Service
|
|
4
5
|
from zope.interface import implementer
|
|
@@ -15,27 +16,18 @@ class PlotlySettingsGet(Service):
|
|
|
15
16
|
def reply(self):
|
|
16
17
|
"""Reply"""
|
|
17
18
|
if not IPlotlyLayer.providedBy(self.request):
|
|
18
|
-
return {
|
|
19
|
-
"themes": [],
|
|
20
|
-
"templates": []
|
|
21
|
-
}
|
|
19
|
+
return {"themes": [], "templates": []}
|
|
22
20
|
|
|
23
21
|
themes = api.portal.get_registry_record(
|
|
24
|
-
"themes",
|
|
25
|
-
interface=IPlotlySettings,
|
|
26
|
-
default=[]
|
|
22
|
+
"themes", interface=IPlotlySettings, default=[]
|
|
27
23
|
)
|
|
28
24
|
|
|
29
25
|
templates = api.portal.get_registry_record(
|
|
30
|
-
"templates",
|
|
31
|
-
interface=IPlotlySettings,
|
|
32
|
-
default=[]
|
|
26
|
+
"templates", interface=IPlotlySettings, default=[]
|
|
33
27
|
)
|
|
34
28
|
|
|
35
29
|
for template in templates:
|
|
36
|
-
layout = template.get(
|
|
37
|
-
"visualization", {}).get(
|
|
38
|
-
"layout", None)
|
|
30
|
+
layout = template.get("visualization", {}).get("layout", None)
|
|
39
31
|
if layout:
|
|
40
32
|
themeId = layout.get("template", {}).get("id", None)
|
|
41
33
|
if not themeId and themes:
|
|
@@ -45,7 +37,4 @@ class PlotlySettingsGet(Service):
|
|
|
45
37
|
if theme.get("id") == themeId:
|
|
46
38
|
layout["template"] = theme
|
|
47
39
|
|
|
48
|
-
return {
|
|
49
|
-
"themes": themes,
|
|
50
|
-
"templates": templates
|
|
51
|
-
}
|
|
40
|
+
return {"themes": themes, "templates": templates}
|