Highcharts Core for Python API Reference
API Design Patterns
Code Style: Python vs JavaScript Naming Conventions
There are only two hard things in Computer Science: cache invalidation and naming things. – Phil Karlton
Highcharts Core is a JavaScript library, and as such it adheres to the code conventions
that are popular (practically standard) when working in JavaScript. Chief among these
conventions is that variables and object properties (keys) are typically written in
camelCase
.
A lot of (digital) ink has been spilled writing about the pros and cons of camelCase
vs snake_case
. While I have a scientific evidence-based opinion on the matter, in
practice it is simply a convention that developers adopt in a particular programming
language. The issue, however, is that while JavaScript has adopted the camelCase
convention, Python generally skews towards the snake_case
convention.
For most Python developers, using snake_case
is the “default” mindset. Most of your
Python code will use snake_case
. So having to switch into camelcase
to interact
with Highcharts Core forces us to context switch, increases cognitive load, and is an
easy place for us to overlook things and make a mistake that can be quite annoying to
track down and fix later.
Therefore, when designing the Highcharts for Python Toolkit, we made several carefully considered design choices when it comes to naming conventions:
All Highcharts for Python classes follow the Pythonic
PascalCase
class-naming convention.All Highcharts for Python properties and methods follow the Pythonic
snake_case
property/method/variable/function-naming convention.All inputs to properties and methods support both
snake_case
andcamelCase
(akamixedCase
) convention by default.This means that you can take something directly from Highcharts JavaScript code and supply it to the Highcharts for Python Toolkit without having to convert case or conventions. But if you are constructing and configuring something directly in Python using explicit deserialization methods, you can use
snake_case
if you prefer (and most Python developers will prefer).For example, if you supply a JSON file to a
from_json()
method, that file can leverage Highcharts (JS) naturalcamelCase
convention OR Highcharts for Python’ssnake_case
convention.Warning
Note that this dual-convention support only applies to deserialization methods and does not apply to the Highcharts for Python
__init__()
class constructors. All__init__()
methods expectsnake_case
properties to be supplied as keywords.All outputs from serialization methods (e.g.
to_dict()
orto_js_literal()
) will produce outputs that are Highcharts (JS)-compatible, meaning that they apply thecamelCase
convention.
Tip
Best Practice
If you are using external files to provide templates or themes for your Highcharts
data visualizations, produce those external files using Highcharts JS’ natural
camelCase
convention. That will make it easier to re-use them elsewhere within a
JavaScript context if you need to in the future.
Standard Methods
Every single object supported by the
Highcharts Core JavaScript API corresponds to a Python
class in Highcharts Core for Python. These classes generally inherit from the
HighchartsMeta
metaclass, which
provides each class with a number of standard methods.
These methods are the “workhorses” of the Highcharts for Python Toolkit and you will be relying heavily on them when using the library. Thankfully, their signatures and behavior is generally consistent - even if what happens “under the hood” is class-specific at times.
Deserialization Methods
- classmethod from_js_literal(cls, as_string_or_file, allow_snake_case=True)
Convert a JavaScript object defined using JavaScript object literal notation into a Highcharts for Python Python object, typically descended from
HighchartsMeta
.
- Parameters:
cls (
type
) – The class object itself.as_string_or_file (
str
) – The JavaScript object you wish to convert. Expects either astr
containing the JavaScript object, or a path to a file which consists of the object.allow_snake_case (
bool
) – IfTrue
, allows keys inas_string_or_file
to apply thesnake_case
convention. IfFalse
, will ignore keys that apply thesnake_case
convention and only process keys that use thecamelCase
convention. Defaults toTrue
.- Returns:
A Highcharts for Python object corresponding to the JavaScript object supplied in
as_string_or_file
.- Return type:
Descendent of
HighchartsMeta
- classmethod from_json(cls, as_json_or_file, allow_snake_case=True)
Convert a Highcharts JS object represented as JSON (in either
str
orbytes
form, or as a file name) into a Highcharts for Python object, typically descended fromHighchartsMeta
.
- Parameters:
cls (
type
) – The class object itself.as_json_or_file (
str
orbytes
) – The JSON object you wish to convert, or a filename that contains the JSON object that you wish to convert.allow_snake_case (
bool
) – IfTrue
, allows keys inas_json
to apply thesnake_case
convention. IfFalse
, will ignore keys that apply thesnake_case
convention and only process keys that use thecamelCase
convention. Defaults toTrue
.- Returns:
A Highcharts for Python Python object corresponding to the JSON object supplied in
as_json
.- Return type:
Descendent of
HighchartsMeta
- classmethod from_dict(cls, as_dict, allow_snake_case=True)
Convert a
dict
representation of a Highcharts JS object into a Python object representation, typically descended fromHighchartsMeta
.
Serialization Methods
- to_js_literal(self, filename=None, encoding='utf-8')
Convert the Highcharts for Python instance to Highcharts JS-compatible JavaScript code using JavaScript object literal notation.
- Parameters:
- Returns:
Highcharts JS-compatible JavaScript code using JavaScript object literal notation.
- Return type:
- to_json(self, filename=None, encoding='utf-8')
Convert the Highcharts for Python instance to Highcharts JS-compatible JSON.
Warning
While similar, JSON is inherently different from JavaScript object literal notation. In particular, it cannot include JavaScript functions. This means if you try to convert a Highcharts for Python object to JSON, any properties that are
CallbackFunction
instances will not be included. If you want to convert those functions, please use.to_js_literal()
instead.
- Parameters:
- Returns:
Highcharts JS-compatible JSON representation of the object.
- Return type:
Note
Highcharts for Python works with different JSON encoders. If your environment has orjson, for example, the result will be returned as a
bytes
instance. Otherwise, the library will fallback to various other JSON encoders until finally falling back to the Python standard library’s JSON encoder/decoder.
Other Convenience Methods
- copy(self, other, overwrite=True, **kwargs)
Copy the properties from
self
toother
.
- Parameters:
other (
HighchartsMeta
) – The target instance to which the properties of this instance should be copied.overwrite (
bool
) – ifTrue
, properties inother
that are already set will be overwritten by their counterparts inself
. Defaults toTrue
.kwargs – Additional keyword arguments. Some special descendents of
HighchartsMeta
may have special implementations of this method which rely on additional keyword arguments.- Returns:
A mutated version of
other
with new property values- Raises:
HighchartsValueError – if
other
is not the same class as (or subclass of)self
Handling Default Values
Explicit is better than implicit. – The Zen of Python
Highcharts has a lot of default values. These
default values are generally applied if a JavaScript property is undefined
(missing or
otherwise not specified), which is different from the JavaScript value of null
.
While our Pythonic instinct is to:
indicate those default values explicitly in the Highcharts for Python code as keyword argument defaults, and
return those default values in the serialized form of any Highcharts for Python objects
doing so would introduce a massive problem: It would bloat data transferred on the wire unnecessarily.
The way that Highcharts (JS) handles defaults is an elegant compromise between explicitness and the practical reality of making your code readable. Why make a property explicit in a configuration string if you don’t care about it? Purity is only valuable to a point. And with thousands of properties across the Highcharts (JS) suite, nobody wants to transmit or maintain thousands of property configurations if it can be avoided.
For that reason, the Highcharts for Python Toolkit explicitly breaks Pythonic
convention: when an object’s property returns None
, that has the
equivalent meaning of “Highcharts (JS) will apply the Highcharts default for this
property”. These properties will not be serialized, either to a JS literal, nor to a
dict
, nor to JSON. This has the advantage of maintaining consistent
behavior with the Highcharts (JS) suite while
still providing an internally consistent logic to follow.
Module Structure
The structure of the Highcharts Core for Python library closely matches the structure of the Highcharts Core options object (see the relevant reference documentation).
At the root of the library - importable from highcharts_core
you will find the
highcharts_core.highcharts
module. This module is a catch-all importable module,
which allows you to easily access the most-commonly-used Highcharts for Python classes and
modules.
Note
Whlie you can access all of the Highcharts Core for Python classes from
highcharts_core.highcharts
, if you want to more precisely navigate to specific
class definitions you can do fairly easily using the folder organization and naming
conventions used in the library.
This is the recommended best practice to maximize performance.
In the root of the highcharts_core
library you can find universally-shared
class definitions, like .metaclasses
which
contains the HighchartsMeta
definition and the JavaScriptDict
definition or .decorators
which define
method/property decorators that are used throughout the library.
The .utility_classes
folder contains class
definitions for classes that are referenced or used throughout the other class
definitions.
And you can find the Highcharts Core options
object and all of its
properties defined in the .options
module, with
specific (complicated or extensive) sub-folders providing property-specific classes
(e.g. the .options.plot_options
module defines all of the different configuration options for different series types,
while the .options.series
module defines all
of the classes that represent series of data in a given chart).
Class Structures and Inheritance
Highcharts for Python objects re-use many of the same properties. This is one of the
strengths of the Highcharts API, in that it is internally consistent and that behavior
configured on one object should be readily transferrable to a second object provided it
shares the same properties. However, Highcharts has a lot of properties. We estimate
that the options.plotOptions
objects and their sub-properties have close to 3,000
properties. But because they are heavily repeated, those 3,000 or so properties can be
reduced to only 421 unique property names. That’s almost an 85% reduction.
DRY is an important principle in software development. Can you imagine propagating changes in seven places (on average) in your code? That would be a maintenance nightmare! And it is exactly the kind of maintenance nightmare that class inheritance was designed to fix.
For that reason, the Highcharts for Python Toolkit classes have a deeply nested
inheritance structure. This is important to understand both for evaluating
isinstance()
checks in your code, or for understanding how to
further subclass Highcharts for Python components.
See also
For more details, please review the API documentation, in particular the class inheritance diagrams included for each documented class.
Warning
Certain sections of the Highcharts for Python Toolkit - in particular the
options.series
classes - rely heavily on
multiple inheritance. This is a known anti-pattern in Python development as it runs the
risk of encountering the diamond of death inheritance problem. This complicates
the process of inheriting methods or properties from parent classes when properties or
methods share names across multiple parents.
We know this the diamond of death is an anti-pattern, but it was a necessary one to minimize code duplication and maximize consistency. For that reason, we implemented it properly despite the anti-pattern, using some advanced Python concepts to navigate the Python MRO (Method Resolution Order) system cleanly. However, an awareness of the pattern used may prove helpful if your code inherits from the Highcharts for Python classes.
See also
For a more in-depth discussion of how the anti-pattern was implemented safely and reliably, please review the Contributor Guidelines.
Core Components
Library Internals
While most users will be interacting with the Core Components of Highcharts for Python, you may need (or choose to) work with various internals of the library. If you’re Contributing to Highcharts for Python to the library, then you will definitely need to familiarize yourself with these internals.