Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,21 @@

Release 1.7.0
=========================================

* **ENHANCEMENT:** Align the API to **Highcharts (JS) v.11.4** (#163). In particular, this includes:
* Added ``Accessibility.high_contrast_mode`` support.
* Added ``OrganizationOptions.hanging_side`` support.
* Added ``SankeyOptions.node_distance`` support.
* Added ``TreegraphOptions.node_distance`` support.
* Adjusted diagram (``ArcDiagramOptions``, ``TreegraphOptions``, ``DependencyWheelOptions``, and
``SankeyOptions``) ``.node_width`` support and documentation.
* Added ``NodeOptions.height`` support.

* **ENHANCEMENT:** Added ``utility_functions.datetime64_to_datetime()`` function to convert
``numpy.datetime64`` to ``datetime.datetime`` (needed to close #162).

--------------------

Release 1.6.0
=========================================

Expand Down
4 changes: 2 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ visualization library, with full integration into the robust Python ecosystem, i
dataframe.
* ...and even more use-case specific integrations across the broader toolkit.

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

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

Expand Down Expand Up @@ -291,7 +291,7 @@ Hello World, and Basic Usage
# EXAMPLE 1.
# Using dicts
my_chart.title = {
'align': 'center'
'align': 'center',
'floating': True,
'text': 'The Title for My Chart',
'use_html': False,
Expand Down
2 changes: 1 addition & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Highcharts Core for Python

.. sidebar:: Version Compatibility

**Latest Highcharts (JS) version supported:** v.11.3.0
**Latest Highcharts (JS) version supported:** v.11.4.0

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

Expand Down
2 changes: 1 addition & 1 deletion highcharts_core/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '1.6.0'
__version__ = '1.7.0'
23 changes: 23 additions & 0 deletions highcharts_core/options/accessibility/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ def __init__(self, **kwargs):
self._custom_components = None
self._description = None
self._enabled = True
self._high_contrast_mode = None
self._high_contrast_theme = None
self._keyboard_navigation = None
self._landmark_verbosity = None
Expand All @@ -53,6 +54,7 @@ def __init__(self, **kwargs):
self.custom_components = kwargs.get('custom_components', None)
self.description = kwargs.get('description', None)
self.enabled = kwargs.get('enabled', None)
self.high_contrast_mode = kwargs.get('high_contrast_mode', None)
self.high_contrast_theme = kwargs.get('high_contrast_theme', None)
self.keyboard_navigation = kwargs.get('keyboard_navigation', None)
self.landmark_verbosity = kwargs.get('landmark_verbosity', None)
Expand Down Expand Up @@ -174,6 +176,25 @@ def enabled(self, value):
else:
self._enabled = bool(value)

@property
def high_contrast_mode(self) -> Optional[str]:
"""Controls how
:meth:`.high_contrast_theme <highcharts_core.options.accessibility.Accessibility.high_contrast_theme>`
is applied.

.. note::

Defaults to ``'auto'``, which applies the high contrast theme when the user's system has a
high contrast theme active.

:rtype: :class:`str <python:str>` or :obj:`None <python:None>`
"""
return self._high_contrast_mode

@high_contrast_mode.setter
def high_contrast_mode(self, value):
self._high_contrast_mode = validators.string(value, allow_empty = True)

@property
def high_contrast_theme(self) -> Any:
"""Theme to apply to the chart when Windows High Contrast Mode is detected.
Expand Down Expand Up @@ -356,6 +377,7 @@ def _get_kwargs_from_dict(cls, as_dict):
'custom_components': as_dict.get('customComponents', None),
'description': as_dict.get('description', None),
'enabled': as_dict.get('enabled', None),
'high_contrast_mode': as_dict.get('highContrastMode', None),
'high_contrast_theme': as_dict.get('highContrastTheme', None),
'keyboard_navigation': as_dict.get('keyboardNavigation', None),
'landmark_verbosity': as_dict.get('landmarkVerbosity', None),
Expand All @@ -374,6 +396,7 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
'customComponents': self.custom_components,
'description': self.description,
'enabled': self.enabled,
'highContrastMode': self.high_contrast_mode,
'highContrastTheme': self.high_contrast_theme,
'keyboardNavigation': self.keyboard_navigation,
'landmarkVerbosity': self.landmark_verbosity,
Expand Down
22 changes: 19 additions & 3 deletions highcharts_core/options/plot_options/arcdiagram.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,16 +221,32 @@ def min_link_width(self, value):
minimum = 0)

@property
def node_width(self) -> Optional[int | float | Decimal]:
def node_width(self) -> Optional[str | int | float | Decimal]:
"""The pixel width of each node in a sankey diagram or dependency wheel, or the
height in case the chart is inverted. Defaults to ``20``.
height in case the chart is inverted.

:rtype: numeric or :obj:`None <python:None>`
Can be a number or a percentage string.

Defaults to ``20``.

:rtype: :class:`str <python:str>` or numeric or :obj:`None <python:None>`
"""
return self._node_width

@node_width.setter
def node_width(self, value):
if value is None:
self._node_width = None
else:
try:
value = validators.string(value)
if "%" not in value:
raise ValueError
except (TypeError, ValueError):
value = validators.numeric(value)

self._node_width = value

self._node_width = validators.numeric(value,
allow_empty = True,
minimum = 0)
Expand Down
24 changes: 18 additions & 6 deletions highcharts_core/options/plot_options/dependencywheel.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,19 +277,31 @@ def node_padding(self, value):
allow_empty = True)

@property
def node_width(self) -> Optional[int | float | Decimal]:
def node_width(self) -> Optional[str | int | float | Decimal]:
"""The pixel width of each node in a sankey diagram or dependency wheel, or the
height in case the chart is inverted. Defaults to ``20``.
height in case the chart is inverted.

:rtype: numeric or :obj:`None <python:None>`
Can be a number or a percentage string.

Defaults to ``20``.

:rtype: :class:`str <python:str>` or numeric or :obj:`None <python:None>`
"""
return self._node_width

@node_width.setter
def node_width(self, value):
self._node_width = validators.numeric(value,
allow_empty = True,
minimum = 0)
if value is None:
self._node_width = None
else:
try:
value = validators.string(value)
if "%" not in value:
raise ValueError
except (TypeError, ValueError):
value = validators.numeric(value)

self._node_width = value

@property
def start_angle(self) -> Optional[int | float | Decimal]:
Expand Down
34 changes: 34 additions & 0 deletions highcharts_core/options/plot_options/organization.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class OrganizationOptions(BarOptions):
def __init__(self, **kwargs):
self._hanging_indent = None
self._hanging_indent_translation = None
self._hanging_side = None
self._levels = None
self._link_color = None
self._link_line_width = None
Expand All @@ -48,6 +49,7 @@ def __init__(self, **kwargs):

self.hanging_indent = kwargs.get('hanging_indent', None)
self.hanging_indent_translation = kwargs.get('hanging_indent_translation', None)
self.hanging_side = kwargs.get('hanging_side', None)
self.levels = kwargs.get('levels', None)
self.link_color = kwargs.get('link_color', None)
self.link_line_width = kwargs.get('link_line_width', None)
Expand Down Expand Up @@ -138,6 +140,36 @@ def hanging_indent_translation(self, value):

self._hanging_indent_translation = value

@property
def hanging_side(self) -> Optional[str]:
"""Whether links connecting hanging nodes should be drawn on the left or right side.

Accepts ``'left'`` or ``'right'``. Defaults to ``'left'``.

.. tip::

Useful for RTL (Right-to-Left) layouts.

.. note::

Only affects inverted (vertical) charts.

:rtype: :class:`str <python:str>` or :obj:`None <python:None>`
"""
return self._hanging_side

@hanging_side.setter
def hanging_side(self, value):
if not value:
self._hanging_side = None
else:
value = validators.string(value, allow_empty = False)
value = value.lower()
if value not in ['left', 'right']:
raise errors.HighchartsValueError(f'hanging_side expects a value of "left", '
f'or "right". Received: {value}')
self._hanging_side = value

@property
def levels(self) -> Optional[List[LevelOptions]]:
"""Set options on specific levels. Takes precedence over series options, but not
Expand Down Expand Up @@ -380,6 +412,7 @@ def _get_kwargs_from_dict(cls, as_dict):

'hanging_indent': as_dict.get('hangingIndent', None),
'hanging_indent_translation': as_dict.get('hangingIndentTranslation', None),
'hanging_side': as_dict.get('hangingSide', None),
'levels': as_dict.get('levels', None),
'link_color': as_dict.get('linkColor', None),
'link_line_width': as_dict.get('linkLineWidth', None),
Expand All @@ -397,6 +430,7 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
untrimmed = {
'hangingIndent': self.hanging_indent,
'hangingIndentTranslation': self.hanging_indent_translation,
'hangingSide': self.hanging_side,
'levels': self.levels,
'linkColor': self.link_color,
'linkLineWidth': self.link_line_width,
Expand Down
71 changes: 71 additions & 0 deletions highcharts_core/options/plot_options/sankey.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from typing import Optional
from decimal import Decimal

from validator_collection import validators

Expand Down Expand Up @@ -36,9 +37,11 @@ class SankeyOptions(DependencyWheelOptions):
def __init__(self, **kwargs):
self._link_color_mode = None
self._node_alignment = None
self._node_distance = None

self.link_color_mode = kwargs.get('link_color_mode', None)
self.node_alignment = kwargs.get('node_alignment', None)
self.node_distance = kwargs.get('node_distance', None)

super().__init__(**kwargs)

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

@property
def node_distance(self) -> Optional[str | int | float | Decimal]:
"""The distance between nodes in a sankey diagram in the longitudinal direction.
Defaults to ``30``.

.. note::

The longitudinal direction means the direction that the chart flows - in a
horizontal chart the distance is horizontal, in an inverted chart (vertical),
the distance is vertical.

If a number is given, it denotes pixels. If a percentage string is given, the
distance is a percentage of the rendered node width. A value of 100% will render
equal widths for the nodes and the gaps between them.

.. note::

This option applies only when the ``.node_width`` option is ``'auto'``, making
the node width respond to the number of columns.

:rtype: :class:`str <python:str>` or numeric or :obj:`None <python:None>`
"""
return self._node_distance

@node_distance.setter
def node_distance(self, value):
if value is None:
self._node_distance = None
else:
try:
value = validators.string(value)
if "%" not in value:
raise ValueError
except (TypeError, ValueError):
value = validators.numeric(value)

self._node_distance = value

@property
def node_width(self) -> Optional[str | int | float | Decimal]:
"""The pixel width of each node in a sankey diagram, or the height in case
the chart is inverted. Defaults to ``20``.

Can be a number, a percentage string, or ``'auto'``. If ``'auto'``, the nodes
are sized to fill up the plot area in the longitudinal direction, regardless
of the number of levels.

:rtype: :class:`str <python:str>` or numeric or :obj:`None <python:None>`
"""
return self._node_width

@node_width.setter
def node_width(self, value):
if value is None:
self._node_width = None
else:
try:
value = validators.string(value)
value = value.lower()
if value != 'auto' and "%" not in value:
raise ValueError
except (TypeError, ValueError):
value = validators.numeric(value)

self._node_width = value

@classmethod
def _get_kwargs_from_dict(cls, as_dict):
kwargs = {
Expand Down Expand Up @@ -159,6 +228,7 @@ def _get_kwargs_from_dict(cls, as_dict):

'link_color_mode': as_dict.get('linkColorMode', None),
'node_alignment': as_dict.get('nodeAlignment', None),
'node_distance': as_dict.get('nodeDistance', None),
}

return kwargs
Expand All @@ -167,6 +237,7 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
untrimmed = {
'linkColorMode': self.link_color_mode,
'nodeAlignment': self.node_alignment,
'nodeDistance': self.node_distance,
}
parent_as_dict = super()._to_untrimmed_dict(in_cls = in_cls)

Expand Down
Loading