Skip to content

Commit 8ddc0fe

Browse files
authored
Merge pull request #166 from highcharts-for-python/develop
Release Candidate v.1.7
2 parents 06e76b4 + dc4fa8b commit 8ddc0fe

File tree

14 files changed

+338
-16
lines changed

14 files changed

+338
-16
lines changed

CHANGES.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,21 @@
11

2+
Release 1.7.0
3+
=========================================
4+
5+
* **ENHANCEMENT:** Align the API to **Highcharts (JS) v.11.4** (#163). In particular, this includes:
6+
* Added ``Accessibility.high_contrast_mode`` support.
7+
* Added ``OrganizationOptions.hanging_side`` support.
8+
* Added ``SankeyOptions.node_distance`` support.
9+
* Added ``TreegraphOptions.node_distance`` support.
10+
* Adjusted diagram (``ArcDiagramOptions``, ``TreegraphOptions``, ``DependencyWheelOptions``, and
11+
``SankeyOptions``) ``.node_width`` support and documentation.
12+
* Added ``NodeOptions.height`` support.
13+
14+
* **ENHANCEMENT:** Added ``utility_functions.datetime64_to_datetime()`` function to convert
15+
``numpy.datetime64`` to ``datetime.datetime`` (needed to close #162).
16+
17+
--------------------
18+
219
Release 1.6.0
320
=========================================
421

README.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ visualization library, with full integration into the robust Python ecosystem, i
1515
dataframe.
1616
* ...and even more use-case specific integrations across the broader toolkit.
1717

18-
The library supports Highcharts (JS) v.10.2 and higher, including Highcharts (JS) v.11.3.0.
18+
The library supports Highcharts (JS) v.10.2 and higher, including Highcharts (JS) v.11.4.0.
1919

2020
**COMPLETE DOCUMENTATION:** https://core-docs.highchartspython.com/en/latest/index.html
2121

@@ -291,7 +291,7 @@ Hello World, and Basic Usage
291291
# EXAMPLE 1.
292292
# Using dicts
293293
my_chart.title = {
294-
'align': 'center'
294+
'align': 'center',
295295
'floating': True,
296296
'text': 'The Title for My Chart',
297297
'use_html': False,

docs/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ Highcharts Core for Python
3737

3838
.. sidebar:: Version Compatibility
3939

40-
**Latest Highcharts (JS) version supported:** v.11.3.0
40+
**Latest Highcharts (JS) version supported:** v.11.4.0
4141

4242
**Highcharts Core for Python** is designed to be compatible with:
4343

highcharts_core/__version__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '1.6.0'
1+
__version__ = '1.7.0'

highcharts_core/options/accessibility/__init__.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ def __init__(self, **kwargs):
4040
self._custom_components = None
4141
self._description = None
4242
self._enabled = True
43+
self._high_contrast_mode = None
4344
self._high_contrast_theme = None
4445
self._keyboard_navigation = None
4546
self._landmark_verbosity = None
@@ -53,6 +54,7 @@ def __init__(self, **kwargs):
5354
self.custom_components = kwargs.get('custom_components', None)
5455
self.description = kwargs.get('description', None)
5556
self.enabled = kwargs.get('enabled', None)
57+
self.high_contrast_mode = kwargs.get('high_contrast_mode', None)
5658
self.high_contrast_theme = kwargs.get('high_contrast_theme', None)
5759
self.keyboard_navigation = kwargs.get('keyboard_navigation', None)
5860
self.landmark_verbosity = kwargs.get('landmark_verbosity', None)
@@ -174,6 +176,25 @@ def enabled(self, value):
174176
else:
175177
self._enabled = bool(value)
176178

179+
@property
180+
def high_contrast_mode(self) -> Optional[str]:
181+
"""Controls how
182+
:meth:`.high_contrast_theme <highcharts_core.options.accessibility.Accessibility.high_contrast_theme>`
183+
is applied.
184+
185+
.. note::
186+
187+
Defaults to ``'auto'``, which applies the high contrast theme when the user's system has a
188+
high contrast theme active.
189+
190+
:rtype: :class:`str <python:str>` or :obj:`None <python:None>`
191+
"""
192+
return self._high_contrast_mode
193+
194+
@high_contrast_mode.setter
195+
def high_contrast_mode(self, value):
196+
self._high_contrast_mode = validators.string(value, allow_empty = True)
197+
177198
@property
178199
def high_contrast_theme(self) -> Any:
179200
"""Theme to apply to the chart when Windows High Contrast Mode is detected.
@@ -356,6 +377,7 @@ def _get_kwargs_from_dict(cls, as_dict):
356377
'custom_components': as_dict.get('customComponents', None),
357378
'description': as_dict.get('description', None),
358379
'enabled': as_dict.get('enabled', None),
380+
'high_contrast_mode': as_dict.get('highContrastMode', None),
359381
'high_contrast_theme': as_dict.get('highContrastTheme', None),
360382
'keyboard_navigation': as_dict.get('keyboardNavigation', None),
361383
'landmark_verbosity': as_dict.get('landmarkVerbosity', None),
@@ -374,6 +396,7 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
374396
'customComponents': self.custom_components,
375397
'description': self.description,
376398
'enabled': self.enabled,
399+
'highContrastMode': self.high_contrast_mode,
377400
'highContrastTheme': self.high_contrast_theme,
378401
'keyboardNavigation': self.keyboard_navigation,
379402
'landmarkVerbosity': self.landmark_verbosity,

highcharts_core/options/plot_options/arcdiagram.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -221,16 +221,32 @@ def min_link_width(self, value):
221221
minimum = 0)
222222

223223
@property
224-
def node_width(self) -> Optional[int | float | Decimal]:
224+
def node_width(self) -> Optional[str | int | float | Decimal]:
225225
"""The pixel width of each node in a sankey diagram or dependency wheel, or the
226-
height in case the chart is inverted. Defaults to ``20``.
226+
height in case the chart is inverted.
227227
228-
:rtype: numeric or :obj:`None <python:None>`
228+
Can be a number or a percentage string.
229+
230+
Defaults to ``20``.
231+
232+
:rtype: :class:`str <python:str>` or numeric or :obj:`None <python:None>`
229233
"""
230234
return self._node_width
231235

232236
@node_width.setter
233237
def node_width(self, value):
238+
if value is None:
239+
self._node_width = None
240+
else:
241+
try:
242+
value = validators.string(value)
243+
if "%" not in value:
244+
raise ValueError
245+
except (TypeError, ValueError):
246+
value = validators.numeric(value)
247+
248+
self._node_width = value
249+
234250
self._node_width = validators.numeric(value,
235251
allow_empty = True,
236252
minimum = 0)

highcharts_core/options/plot_options/dependencywheel.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -277,19 +277,31 @@ def node_padding(self, value):
277277
allow_empty = True)
278278

279279
@property
280-
def node_width(self) -> Optional[int | float | Decimal]:
280+
def node_width(self) -> Optional[str | int | float | Decimal]:
281281
"""The pixel width of each node in a sankey diagram or dependency wheel, or the
282-
height in case the chart is inverted. Defaults to ``20``.
282+
height in case the chart is inverted.
283283
284-
:rtype: numeric or :obj:`None <python:None>`
284+
Can be a number or a percentage string.
285+
286+
Defaults to ``20``.
287+
288+
:rtype: :class:`str <python:str>` or numeric or :obj:`None <python:None>`
285289
"""
286290
return self._node_width
287291

288292
@node_width.setter
289293
def node_width(self, value):
290-
self._node_width = validators.numeric(value,
291-
allow_empty = True,
292-
minimum = 0)
294+
if value is None:
295+
self._node_width = None
296+
else:
297+
try:
298+
value = validators.string(value)
299+
if "%" not in value:
300+
raise ValueError
301+
except (TypeError, ValueError):
302+
value = validators.numeric(value)
303+
304+
self._node_width = value
293305

294306
@property
295307
def start_angle(self) -> Optional[int | float | Decimal]:

highcharts_core/options/plot_options/organization.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class OrganizationOptions(BarOptions):
3636
def __init__(self, **kwargs):
3737
self._hanging_indent = None
3838
self._hanging_indent_translation = None
39+
self._hanging_side = None
3940
self._levels = None
4041
self._link_color = None
4142
self._link_line_width = None
@@ -48,6 +49,7 @@ def __init__(self, **kwargs):
4849

4950
self.hanging_indent = kwargs.get('hanging_indent', None)
5051
self.hanging_indent_translation = kwargs.get('hanging_indent_translation', None)
52+
self.hanging_side = kwargs.get('hanging_side', None)
5153
self.levels = kwargs.get('levels', None)
5254
self.link_color = kwargs.get('link_color', None)
5355
self.link_line_width = kwargs.get('link_line_width', None)
@@ -138,6 +140,36 @@ def hanging_indent_translation(self, value):
138140

139141
self._hanging_indent_translation = value
140142

143+
@property
144+
def hanging_side(self) -> Optional[str]:
145+
"""Whether links connecting hanging nodes should be drawn on the left or right side.
146+
147+
Accepts ``'left'`` or ``'right'``. Defaults to ``'left'``.
148+
149+
.. tip::
150+
151+
Useful for RTL (Right-to-Left) layouts.
152+
153+
.. note::
154+
155+
Only affects inverted (vertical) charts.
156+
157+
:rtype: :class:`str <python:str>` or :obj:`None <python:None>`
158+
"""
159+
return self._hanging_side
160+
161+
@hanging_side.setter
162+
def hanging_side(self, value):
163+
if not value:
164+
self._hanging_side = None
165+
else:
166+
value = validators.string(value, allow_empty = False)
167+
value = value.lower()
168+
if value not in ['left', 'right']:
169+
raise errors.HighchartsValueError(f'hanging_side expects a value of "left", '
170+
f'or "right". Received: {value}')
171+
self._hanging_side = value
172+
141173
@property
142174
def levels(self) -> Optional[List[LevelOptions]]:
143175
"""Set options on specific levels. Takes precedence over series options, but not
@@ -380,6 +412,7 @@ def _get_kwargs_from_dict(cls, as_dict):
380412

381413
'hanging_indent': as_dict.get('hangingIndent', None),
382414
'hanging_indent_translation': as_dict.get('hangingIndentTranslation', None),
415+
'hanging_side': as_dict.get('hangingSide', None),
383416
'levels': as_dict.get('levels', None),
384417
'link_color': as_dict.get('linkColor', None),
385418
'link_line_width': as_dict.get('linkLineWidth', None),
@@ -397,6 +430,7 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
397430
untrimmed = {
398431
'hangingIndent': self.hanging_indent,
399432
'hangingIndentTranslation': self.hanging_indent_translation,
433+
'hangingSide': self.hanging_side,
400434
'levels': self.levels,
401435
'linkColor': self.link_color,
402436
'linkLineWidth': self.link_line_width,

highcharts_core/options/plot_options/sankey.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from typing import Optional
2+
from decimal import Decimal
23

34
from validator_collection import validators
45

@@ -36,9 +37,11 @@ class SankeyOptions(DependencyWheelOptions):
3637
def __init__(self, **kwargs):
3738
self._link_color_mode = None
3839
self._node_alignment = None
40+
self._node_distance = None
3941

4042
self.link_color_mode = kwargs.get('link_color_mode', None)
4143
self.node_alignment = kwargs.get('node_alignment', None)
44+
self.node_distance = kwargs.get('node_distance', None)
4245

4346
super().__init__(**kwargs)
4447

@@ -104,6 +107,72 @@ def node_alignment(self, value):
104107
f'"bottom". Received "{value}"')
105108
self._node_alignment = value
106109

110+
@property
111+
def node_distance(self) -> Optional[str | int | float | Decimal]:
112+
"""The distance between nodes in a sankey diagram in the longitudinal direction.
113+
Defaults to ``30``.
114+
115+
.. note::
116+
117+
The longitudinal direction means the direction that the chart flows - in a
118+
horizontal chart the distance is horizontal, in an inverted chart (vertical),
119+
the distance is vertical.
120+
121+
If a number is given, it denotes pixels. If a percentage string is given, the
122+
distance is a percentage of the rendered node width. A value of 100% will render
123+
equal widths for the nodes and the gaps between them.
124+
125+
.. note::
126+
127+
This option applies only when the ``.node_width`` option is ``'auto'``, making
128+
the node width respond to the number of columns.
129+
130+
:rtype: :class:`str <python:str>` or numeric or :obj:`None <python:None>`
131+
"""
132+
return self._node_distance
133+
134+
@node_distance.setter
135+
def node_distance(self, value):
136+
if value is None:
137+
self._node_distance = None
138+
else:
139+
try:
140+
value = validators.string(value)
141+
if "%" not in value:
142+
raise ValueError
143+
except (TypeError, ValueError):
144+
value = validators.numeric(value)
145+
146+
self._node_distance = value
147+
148+
@property
149+
def node_width(self) -> Optional[str | int | float | Decimal]:
150+
"""The pixel width of each node in a sankey diagram, or the height in case
151+
the chart is inverted. Defaults to ``20``.
152+
153+
Can be a number, a percentage string, or ``'auto'``. If ``'auto'``, the nodes
154+
are sized to fill up the plot area in the longitudinal direction, regardless
155+
of the number of levels.
156+
157+
:rtype: :class:`str <python:str>` or numeric or :obj:`None <python:None>`
158+
"""
159+
return self._node_width
160+
161+
@node_width.setter
162+
def node_width(self, value):
163+
if value is None:
164+
self._node_width = None
165+
else:
166+
try:
167+
value = validators.string(value)
168+
value = value.lower()
169+
if value != 'auto' and "%" not in value:
170+
raise ValueError
171+
except (TypeError, ValueError):
172+
value = validators.numeric(value)
173+
174+
self._node_width = value
175+
107176
@classmethod
108177
def _get_kwargs_from_dict(cls, as_dict):
109178
kwargs = {
@@ -159,6 +228,7 @@ def _get_kwargs_from_dict(cls, as_dict):
159228

160229
'link_color_mode': as_dict.get('linkColorMode', None),
161230
'node_alignment': as_dict.get('nodeAlignment', None),
231+
'node_distance': as_dict.get('nodeDistance', None),
162232
}
163233

164234
return kwargs
@@ -167,6 +237,7 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
167237
untrimmed = {
168238
'linkColorMode': self.link_color_mode,
169239
'nodeAlignment': self.node_alignment,
240+
'nodeDistance': self.node_distance,
170241
}
171242
parent_as_dict = super()._to_untrimmed_dict(in_cls = in_cls)
172243

0 commit comments

Comments
 (0)