Using Highcharts Core for Python


Introduction to Highcharts and Highcharts for Python

Highcharts is the gold-standard in JavaScript data visualization libraries, enabling you to design rich, beautiful, and highly interactive data visualizations of (almost) any kind imaginable, and to render those visualizations in your web or mobile applications. Take a look at some of the customer showcases and the demo gallery to see what you can do with Highcharts.

The Highcharts for Python Toolkit is a Python wrapper for the Highcharts suite of JavaScript libraries, which means that it is designed to give developers working in Python a simple and Pythonic way of interacting with Highcharts (JS).

The Highcharts for Python Toolkit will not render data visualizations itself - that’s what Highcharts (JS) does - but it will allow you to:

  1. Configure your data visualizations in Python.

  2. Supply data you have in Python to your data visualizations.

  3. Programmatically produce the Highcharts JavaScript code that will actually render your data visualization.

  4. Programmatically download a static version of your visualization (as needed) within Python.

Tip

Think of the Highcharts for Python Toolkit as a translator to bridge your data visualization needs between Python and JavaScript.


Key Design Patterns in Highcharts for Python

Highcharts is a large, robust, and complicated JavaScript library. If in doubt, take a look at its extensive documentation and in particular its API reference [2].

Because the Highcharts for Python Toolkit wraps the Highcharts (JS) API, its design is heavily shaped by Highcharts JS’ own design - as one should expect.

However, one of the main goals of the Python toolkit is to make it easier for Python developers to leverage the Highcharts JavaScript libraries - in particular by providing a more Pythonic way of interacting with the framework.

Here are the notable design patterns that have been adopted that you should be aware of:

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:

  1. All Highcharts for Python classes follow the Pythonic PascalCase class-naming convention.

  2. All Highcharts for Python properties and methods follow the Pythonic snake_case property/method/variable/function-naming convention.

  3. All inputs to properties and methods support both snake_case and camelCase (aka mixedCase) 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) natural camelCase convention OR Highcharts for Python’s snake_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 expect snake_case properties to be supplied as keywords.

  4. All outputs from serialization methods (e.g. to_dict() or to_js_literal()) will produce outputs that are Highcharts (JS)-compatible, meaning that they apply the camelCase 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 JavaScript API corresponds to a Python class in the Highcharts for Python Toolkit. You can find the complete list in our comprehensive Highcharts Core for Python API Reference.

These classes generally inherit from the HighchartsMeta metaclass, which provides each class with a number of standard methods. These methods are the “workhorses” of Highcharts for Python and you will be relying heavily on them when using any of the libraries in the toolkit. Thankfully, their signatures and behavior is consistent - even if what happens “under the hood” is class-specific at times.

The standard methods exposed by the classes are:

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 a str containing the JavaScript object, or a path to a file which consists of the object.

  • allow_snake_case (bool) – If True, allows keys in as_string_or_file to apply the snake_case convention. If False, will ignore keys that apply the snake_case convention and only process keys that use the camelCase convention. Defaults to True.

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 or bytes form, or as a file name) into a Highcharts for Python object, typically descended from HighchartsMeta.

Parameters:
  • cls (type) – The class object itself.

  • as_json_or_file (str or bytes) – The JSON object you wish to convert, or a filename that contains the JSON object that you wish to convert.

  • allow_snake_case (bool) – If True, allows keys in as_json to apply the snake_case convention. If False, will ignore keys that apply the snake_case convention and only process keys that use the camelCase convention. Defaults to True.

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 from HighchartsMeta.

Parameters:
  • cls (type) – The class object itself.

  • as_dict (dict) – The dict representation of the object.

  • allow_snake_case (bool) – If True, allows keys in as_dict to apply the snake_case convention. If False, will ignore keys that apply the snake_case convention and only process keys that use the camelCase convention. Defaults to True.

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:
  • filename (Path-like or None) – If supplied, persists the JavaScript code to the file indicated. Defaults to None.

  • encoding (str) – Indicates the character encoding to use when producing the JavaScript literal string. Defaults to 'utf-8'.

Returns:

Highcharts JS-compatible JavaScript code using JavaScript object literal notation.

Return type:

str

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:
  • filename (Path-like or None) – If supplied, persists the JSON is persisted to the file indicated. Defaults to None.

  • encoding (str) – Indicates the character encoding to use when producing the JSON. Defaults to 'utf-8'.

Returns:

Highcharts JS-compatible JSON representation of the object.

Return type:

str or bytes

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.

to_dict(self)

Convert the Highcharts for Python object into a Highcharts JS-compatible dict object.

Returns:

Highcharts JS-compatible dict object

Return type:

dict

Other Convenience Methods

copy(self, other, overwrite=True, **kwargs)

Copy the properties from self to other.

Parameters:
  • other (HighchartsMeta) – The target instance to which the properties of this instance should be copied.

  • overwrite (bool) – if True, properties in other that are already set will be overwritten by their counterparts in self. Defaults to True.

  • 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.

Note

There’s an item on the Highcharts for Python roadmap (#12) to optionally surface defaults when explicitly requested. Not sure when it will be implemented, but we’ll get there at some point.

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.


Organizing Your Highcharts for Python Project

The Highcharts for Python Toolkit is a utility that can integrate with - quite literally - any frontend framework. Whether your Python application is relying on IPython (e.g. Jupyter Notebook [3] or Jupyter Labs [3]), Flask, Django, FastAPI, Pyramid, Tornado, or some completely home-grown solution all, Highcharts for Python needs is a place where Highcharts JavaScript code can be executed.

All of those frameworks mentioned have their own best practices for organizing their application structures, and those best practices should always take priority. Even in a data-centric application that will be relying heavily on Highcharts for Python, your application’s core business logic will be doing most of the heavy lifting and so your project’s organization should reflect that.

However, there are a number of best practices that we recommend for organizing your files and code to work with the Highcharts for Python Toolkit:

Warning

There are nine and sixty ways of constructing a tribal lay, and every single one of them is right! – Rudyard Kipling, In the Neolithic Age

The organizational model described below is just a suggestion, and you can (and likely will) depart from its principles and practices as you gain more experience using Highcharts for Python. There’s nothing wrong with that! It’s just a set of best practices that we’ve found work for us and which we therefore recommend.

Importing Highcharts for Python

Tip

Best Practice!

This method of importing Highcharts for Python objects yields the fastest performance for the import statement. However, it is more verbose and requires you to navigate the extensive Highcharts Core for Python API.

# Import classes using precise module indications. For example:
from highcharts_core.chart import Chart
from highcharts_core.global_options.shared_options import SharedOptions
from highcharts_core.options import HighchartsOptions
from highcharts_core.options.plot_options.bar import BarOptions
from highcharts_core.options.series.bar import BarSeries

Use Shared Options

One of the most challenging aspects of the Highcharts (JS) suite is its sheer breadth of functionality and configurability. That’s simultaneously the suite’s greatest strength and its greatest weakness. This is because it can be quite challenging to wrangle thousands of properties - especially when even a single visualization can use hundreds of those properties!

This is a challenge that we are keenly aware of, and one which we’ve given some thought to in the design of the Highcharts for Python Toolkit. A core principle you should use throughout your project is to practice DRY programming.

If your application will be generating multiple visualizations, they will likely need some consistent configurations.

For example, you will want each chart’s title position to be consistent, their color schemes to be consistent, their font sizing to be consistent, etc. In your code you want these configuration settings to be defined once and then applied to all of the visualizations you are producing.

This can be facilitated using the SharedOptions class. It generates a single set of global options which - when serialized to JavaScript - apply its configuration settings consistently across all data visualizations on the same page.

As with all Highcharts for Python objects, you can instantiate it in several ways:

Tip

Best practice!

We really like to use JS literals written as separate files in our codebase. It makes it super simple to instantiate a SharedOptions instance with one method call.

Let’s say you organize your files like so:

my_repository/
| — docs/
| — my_project/
| —— project_resources/
| ——— image_files/
| ——— data_files/
| ———— data-file-01.csv
| ———— data-file-02.csv
| ———— data-file-03.csv
| ——— highcharts_config/
| ———— shared_options.js
| ———— bar-template-01.js
| ———— bar-template-02.js
| ———— line-template.js
| ———— packed-bubble-template.js
| —— some_package/
| ——— __init__.py
| ——— package_module.py
| ——— another_module.py
| —— __init__.py
| —— __version__.py
| —— some_module.py
| — tests/
| — .gitignore
| — requirements.txt

You’ll notice that the organization has a project_resources folder. This is where you would put the various files that your application wlil reference, like your static images, or the files that contain data you might be using in your application. It also contains a highcharts_config folder, which contains several files with a .js extension. Of particular note is the file in bold, shared_options.js. This file should contain a JavaScript object literal version of the configuration settings you want to apply to all of your visualizations. This file might look something like this:

{
  chart: {
        backgroundColor: {
            linearGradient: {
              x1: 0,
              x2: 0,
              y1: 1,
              y2: 1
            },
            stops: [
                [0, 'rgb(255, 255, 255)'],
                [1, 'rgb(240, 240, 255)']
            ]
        },
        borderWidth: 2,
        plotBackgroundColor: 'rgba(255, 255, 255, .9)',
        plotBorderWidth: 1
  },
  caption: {
      align: 'center',
      floating: true,
      margin: 20,
      verticalAlign: 'top'
  },
  credits: {
      enabled: true,
      href: 'https://www.somewhere.com',
      style: {
          color: '#cccccc',
          fontSize: '8px'
      },
      text: 'Highcharts for Python'
  }
}

Now with this file, you can easily create a SharedOptions instance by executing:

from highcharts_core.highcharts import SharedOptions

my_shared_options = SharedOptions.from_js_literal('../../project_resources/highcharts_config/shared_options.js')

And that’s it! Now you have a SharedOptions instance that can be used to apply your configuration standards to all of your charts. You can do that by delivering its JavaScript output to your front-end by calling:

js_code_snippet = my_shared_options.to_js_literal()

which will produce a string as follows:

Highcharts.setOptions({
  caption: {
    align: 'center',
    floating: true,
    margin: 20,
    verticalAlign: 'top'
  },
  chart: {
    backgroundColor: {
      linearGradient: {
        x1: 0.0,
        x2: 0.0,
        y1: 1.0,
        y2: 1.0
      },
      stops: [
        [0, 'rgb(255, 255, 255)'],
        [1, 'rgb(240, 240, 255)']
      ]
    },
    borderWidth: 2,
    plotBackgroundColor: 'rgba(255, 255, 255, .9)',
    plotBorderWidth: 1
  },
  credits: {
    enabled: true,
    href: 'https://www.somewhere.com',
    style: {
      color: '#cccccc',
      fontSize: '8px'
    },
    text: 'Highcharts for Python'
  }
});

And now you can deliver js_code_snippet to your HTML template or wherever it will be rendered.

Use Templates to Get Started

While shared options are applied to all charts that are rendered on the same web page with the shared options JS code, certain types of visualizations may need special treatment. Sure, you can use the plot_options settings to configure chart type-specific options, but how can you efficiently use multiple charts of the same type that have different settings?

For example, let’s say you used shared options to set universal bar chart settings. But what happens if you know you’ll have different data shown in different bar charts? You can use a similar templating pattern for different sub-types of your charts.

Tip

Best practice!

We really like to use JS literals written as separate files in our codebase. It makes it super simple to instantiate a Highcharts for Python instance with one method call.

Let’s say you organize your files like so:

my_repository/
| — docs/
| — my_project/
| —— project_resources/
| ——— image_files/
| ——— data_files/
| ———— data-file-01.csv
| ———— data-file-02.csv
| ———— data-file-03.csv
| ——— highcharts_config/
| ———— shared_options.js
| ———— bar-template-01.js
| ———— bar-template-02.js
| ———— line-template.js
| ———— packed-bubble-template.js
| —— some_package/
| ——— __init__.py
| ——— package_module.py
| ——— another_module.py
| —— __init__.py
| —— __version__.py
| —— some_module.py
| — tests/
| — .gitignore
| — requirements.txt

As you can see, there are two JS literal files named bar-template-01.js and bar-template-02.js respectively. These template files can be used to significantly accelerate the configuration of our bar charts. Each template corresponds to one sub-type of bar chart that we know we will need. These sub-types may have different event functions, or more frequently use different formatting functions to make the data look the way we want it to look.

Now with these template files, we can easily create a pair of Chart instances by executing:

from highcharts_core.highcharts import Chart
from highcharts_core.options.series.bar import BarSeries

type_1_chart = Chart.from_js_literal(
    '../../project_resources/highcharts_config/bar-template-01.js'
)
type_2_chart = Chart.from_js_literal(
    '../../project_resources/highcharts_config/bar-template-02.js'
)

And that’s it! Now you have two chart instances which you can further modify. For example, you can add data to them by calling:

type_1_chart.container = 'chart1_div'
type_2_chart.container = 'chart2_div'

type_1_chart.add_series(BarSeries.from_csv('../../project_resources/data_files/data-file-01.csv'))
type_2_chart.add_series(BarSeries.from_csv('../../project_resources/data_files/data-file-02.csv'))

And then you can create the relevant JavaScript code to render the chart using:

type_1_chart_js = type_1_chart.to_js_literal()
type_2_chart_js = type_2_chart.to_js_literal()

And now you can deliver type_1_chart_js and type_2_chart_js to your HTML template or wherever it will be rendered.


Working with Data

Obviously, if you are going to use the Highcharts for Python Toolkit and Highcharts you will need to have data to visualize. Python is rapidly becoming the lingua franca in the world of data manipulation, transformation, and analysis and the Highcharts for Python Toolkit is designed to play well within that ecosystem, making it easy to visualize data from CSV files, from `pandas`_ dataframes, or PySpark [1] dataframes.

How Data is Represented

Highcharts (JS) supports two different ways of representing data: as an individual series comprised of individual data points, and as a set of instructions to read data dynamically from a CSV file or an HTML table.

See also

Highcharts organizes data into series. You can think of a series as a single line on a graph that shows a set of values. The set of values that make up the series are data points, which are defined by a set of properties that indicate the data point’s position on one or more axes.

Highcharts for Python represents data points in series in two fashions:

  1. As a list of data point objects in the data property within the series, or

Highcharts (JS)

Highcharts for Python

// Example Series Object
// (for a Line series type):
{
  data: [
    {
      id: 'first-data-point',
      x: 1,
      y: 123,
      // ...
      // optional additional properties
      // for styling/behavior go here
      // ...
    },
    {
      id: 'second-data-point',
      x: 2,
      y: 456,
      // ...
      // optional additional properties
      // for styling/behavior go here
      // ...
    },
    {
      id: 'third-data-point',
      x: 3,
      y: 789,
      // ...
      // optional additional properties
      // for styling/behavior go here
      // ...
    }
  ],
  // ...
  // other Series properties go here
  // to configure styling/behavior
}
# Corresponding LineSeries object
my_series = Series(data = [
    CartesianData(id = 'first-data-point1',
                  x = 1,
                  y = 123),
    CartesianData(id = 'second-data-point1',
                  x = 2,
                  y = 456),
    CartesianData(id = 'third-data-point1',
                  x = 3,
                  y = 789),
])
  1. As a single DataPointCollection object in the data property within the series, which in turn contains the individual data points.

Highcharts (JS)

Highcharts for Python

// Example Series Object
// (for a Line series type):
{
  data: [
    {
      name: 'first-data-point',
      x: 1,
      y: 123,
      // ...
      // optional additional properties
      // for styling/behavior go here
      // ...
    },
    {
      name: 'second-data-point',
      x: 2,
      y: 456,
      // ...
      // optional additional properties
      // for styling/behavior go here
      // ...
    },
    {
      name: 'third-data-point',
      x: 3,
      y: 789,
      // ...
      // optional additional properties
      // for styling/behavior go here
      // ...
    }
  ],
  // ...
  // other Series properties go here
  // to configure styling/behavior
}
# EXAMPLE 1. Corresponding LineSeries object, with data as an
# numpy.ndarray.

my_series = Series(data = CartesianDataCollection(
    ndarray = [
        [1, 123, 'first-data-point1'],
        [2, 456, 'second-data-point1'],
        [3, 789, 'third-data-point1'])
])

# EXAMPLE 2. Corresponding LineSeries object, with data as a
# primitive array.

my_series = Series(data = CartesianDataCollection(
    array = [
        [1, 123, 'first-data-point1'],
        [2, 456, 'second-data-point1'],
        [3, 789, 'third-data-point1'])
    ]
))

As you can see, Highcharts for Python represents its data the same way that Highcharts (JS) does. That should be expected. However, constructing tens, hundreds, or possibly thousands of data points individually in your code would be a nightmare. For that reason, the Highcharts for Python Toolkit natively supports vectorized numpy.ndarray values, and automatically assembles data point collections for easy management/manipulation. In addition, the Toolkit provides a number of convenience methods to make it easier to populate your series.

Populating Series Data

Every single Series class in Highcharts for Python features several different methods to either instantiate data points directly, load data (to an existing series instance), or to create a new series instance with data already loaded.

When working with a series instance, you can instantiate data points directly. These data points are stored in the .data setting, which always accepts/expects a list of data point instances (descended from DataBase).

Data points all have the same standard Highcharts for Python deserialization methods, so those make things very easy. However, they also have a special data point-specific deserialization method:

Expand Method Signature
classmethod .from_array(cls, value)

Creates a DataPointCollection instance if possible, or falls back to a collection of data point instances, parsing the contents of value as an array (iterable). This method is specifically used to parse data that is input to Highcharts for Python without property names, in an array-organized structure as described in the Highcharts (JS) documentation.

See also

The specific structure of the expected array is highly dependent on the type of data point that the series needs, which itself is dependent on the series type itself.

Please review the detailed series documentation for series type-specific details of relevant array structures.

Note

An example of how this works for a simple LineSeries (which uses CartesianData data points) would be:

my_series = LineSeries()

# EXAMPLE 1.
# A simple array of numerical values which correspond to the Y value of the data
# point, passed to the .from_array() method.

my_series = LineSeries.from_array([0, 5, 3, 5])

# EXAMPLE 2.
# A simple array of numerical values which correspond to the Y value of the data
# point, passed to the series data property.

my_series.data = [0, 5, 3, 5]

# EXAMPLE 3.
# A simple array of numerical values which correspond to the Y value of the data
# point, updated in the series using the .load_from_array() method.

my_series.load_from_array([0, 5, 3, 5])

# EXAMPLE 4.
# An array containing 2-member arrays (corresponding to the X and Y values of the
# data point), passed to the .from_array() class method.
my_series = LineSeries.from_array([
    [0, 0],
    [1, 5],
    [2, 3],
    [3, 5]
])

# EXAMPLE 5.
# An array containing 2-member arrays (corresponding to the X and Y values of the
# data point), passed to the series data property.
my_series.data = [
    [0, 0],
    [1, 5],
    [2, 3],
    [3, 5]
]

# EXAMPLE 6.
# An array of dict with named values, passed to the .from_array() class method.
my_series = LineSeries.from_array([
  {
      'x': 0,
      'y': 0,
      'name': 'Point1',
      'color': '#00FF00'
  },
  {
      'x': 1,
      'y': 5,
      'name': 'Point2',
      'color': '#CCC'
  },
  {
      'x': 2,
      'y': 3,
      'name': 'Point3',
      'color': '#999'
  },
  {
      'x': 3,
      'y': 5,
      'name': 'Point4',
      'color': '#000'
  }
])

# EXAMPLE 6.
# An array of dict with named values, passed to the series data property.
my_series.data = [
  {
      'x': 0,
      'y': 0,
      'name': 'Point1',
      'color': '#00FF00'
  },
  {
      'x': 1,
      'y': 5,
      'name': 'Point2',
      'color': '#CCC'
  },
  {
      'x': 2,
      'y': 3,
      'name': 'Point3',
      'color': '#999'
  },
  {
      'x': 3,
      'y': 5,
      'name': 'Point4',
      'color': '#000'
  }
]

# EXAMPLE 6.
# An array of dict with named values, passed to .load_from_array()
# method.
my_series.load_from_array([
  {
      'x': 0,
      'y': 0,
      'name': 'Point1',
      'color': '#00FF00'
  },
  {
      'x': 1,
      'y': 5,
      'name': 'Point2',
      'color': '#CCC'
  },
  {
      'x': 2,
      'y': 3,
      'name': 'Point3',
      'color': '#999'
  },
  {
      'x': 3,
      'y': 5,
      'name': 'Point4',
      'color': '#000'
  }
])
Parameters:

value (iterable) –

The value that should contain the data which will be converted into data point instances.

Note

If value is not an iterable, it will be converted into an iterable to be further de-serialized correctly.

Returns:

Collection of data point instances (descended from DataBase)

Return type:

list of DataBase-descendant instances or DataPointCollection instance

Adding Series to Charts

Now that you have constructed your series instances, you can add them to charts very easily. First, Highcharts for Python represents visualizations as instances of the Chart class. This class contains an options property, which itself contains an instance of HighchartsOptions.

Note

This structure - where the chart object contains an options object - is a little nested for some tastes, but it is the structure which Highcharts (JS) has adopted and so for the sake of consistency the Highcharts for Python Toolkit uses it as well.

To be visualized on your chart, you will need to add your series instances to the Chart.options.series property. You can do this in several ways:


Rendering Your Visualizations

Once you have created your Chart instance or instances, you can render them very easily. There are really only two ways to display your visualizations:

Rendering Highcharts Visualizations in Web Content

Highcharts is a suite of JavaScript libraries designed to enable rendering high-end data visualizations in a web context. They are designed and optimized to operate within a web browser. The Highcharts for Python Toolkit therefore fully supports this capability, and we’ve enabled it using the batteries included principle.

To render a Highcharts for Python visualization in a web context, all you need is for the browser to execute the output of the chart’s .to_js_literal() method.

That method will return a snippet of JavaScript code which when included in a web page will display the chart in full.

Warning

The .to_js_literal() method assumes that your web content already has all the <script/> tags which include the Highcharts (JS) modules your chart relies on.

If you need to generate the required <script/> tags for your chart, you can do so by calling:

# EXAMPLE 1.
# Get a list of <script/> tags.
list_of_script_tags = my_chart.get_script_tags()

# EXAMPLE 2.
# Get a string of <script/> tags.
script_tags_as_str = my_chart.get_script_tags(as_str = True)

# EXAMPLE 3.
# Get a list of the required Highcharts modules.
required_modules = my_chart.get_required_modules()

For example:

from highcharts_core.chart import Chart
from highcharts_core.options.series.area import LineSeries

my_chart = Chart(data = [0, 5, 3, 5], series_type = 'line')

as_js_literal = my_chart.to_js_literal()

# This will produce a string equivalent to:
#
# document.addEventListener('DOMContentLoaded', function() {
#   const myChart = Highcharts.chart('target_div', {
#      series: {
#          type: 'line',
#          data: [0, 5, 3, 5]
#      }
#   });
# });

Now you can use whatever front-end framework you are using to insert that string into your application’s HTML output (in an appropriate <script/> tag, of course).

Tip

The same principle applies to the use of SharedOptions.

It is recommended to place the JS literal form of your shared options before any of the charts that you will be visualizing.

Rendering Highcharts for Python in Jupyter Labs or Jupyter Notebooks

You can also render Highcharts for Python visualizations inside your Jupyter notebook. This is as simple as executing a single .display() call on your Chart instance:

from highcharts_core.chart import Chart
from highcharts_core.global_options.shared_options import SharedOptions

my_chart = Chart(data = [0, 5, 3, 5], series_type = 'line')

# Now this will render the contents of "my_chart" in your Jupyter Notebook
my_chart.display()

# You can also supply shared options to display to make sure that they are applied:
my_shared_options = SharedOptions()

# Now this will render the contents of "my_chart" in your Jupyter Notebook, but applying
# your shared options
my_chart.display(global_options = my_shared_options)
Method Signature
display(self, global_options=None, container=None, retries=5, interval=1000)

Display the chart in Jupyter Labs or Jupyter Notebooks.

Parameters:
  • global_options (SharedOptions or None) – The shared options to use when rendering the chart. Defaults to None

  • container (str or None) –

    The ID to apply to the HTML container when rendered in Jupyter Labs. Defaults to None, which applies the .container property if set, and 'highcharts_target_div' if not set.

    Note

    Highcharts for Python will append a 6-character random string to the value of container to ensure uniqueness of the chart’s container when rendering in a Jupyter Notebook/Labs context. The Chart instance will retain the mapping between container and the random string so long as the instance exists, thus allowing you to easily update the rendered chart by calling the .display() method again.

    If you wish to create a new chart from the instance that does not update the existing chart, then you can do so by specifying a new container value.

  • retries (int) – The number of times to retry rendering the chart. Used to avoid race conditions with the Highcharts script. Defaults to 5.

  • interval (int) – The number of milliseconds to wait between retrying rendering the chart. Defaults to 1000 (1 second).

Raises:

HighchartsDependencyError – if ipython is not available in the runtime environment

You can call the .display() method from anywhere within any notebook cell, and it will render the resulting chart in your notebook’s output. That’s it!

Caution

If IPython is not available in your runtime environment, calling .display() will raise a HighchartsDependencyError.


Downloading Your Visualizations

Sometimes you are not looking to produce an interactive web-based visualization of your data, but instead are looking to produce a static image of your visualization that can be downloaded, emailed, or embedded in some other documents.

With the Highcharts for Python Toolkit, that’s as simple as executing the Chart.download_chart() method.

When you have defined a Chart instance, you can download a static version of that chart or persist it to a file in your runtime environment. The actual file itself is produced using a Highcharts Export Server.



from highcharts_core.chart import Chart

my_chart = Chart(data = [0, 5, 3, 5],
                 series_type = 'line')

# Download a PNG version of the chart in memory within your Python code.
my_png_image = my_chart.download_chart(format = 'png')

# Download a PNG version of the chart and save it the file "/images/my-chart-file.png"
my_png_image = my_chart.download_chart(
    format = 'png',
    filename = '/images/my-chart-file.png'
)
Method Signature
.download_chart(self, filename=None, format='png', server_instance=None, scale=1, width=None, auth_user=None, auth_password=None, timeout=0.5, global_options=None, **kwargs)

Export a downloaded form of the chart using a Highcharts Export Server.

Parameters:
  • filename (Path-like or None) – The name of the file where the exported chart should (optionally) be persisted. Defaults to None.

  • server_instance (ExportServer or None) – Provide an already-configured ExportServer instance to use to programmatically produce the exported chart. Defaults to None, which causes Highcharts for Python to instantiate a new ExportServer instance with all applicable defaults.

  • format (str) –

    The format in which the exported chart should be returned. Defaults to 'png'.

    Accepts:

    • 'png'

    • 'jpeg'

    • 'pdf'

    • 'svg'

  • scale (numeric) –

    The scale factor by which the exported chart image should be scaled. Defaults to 1.

    Tip

    Use this setting to improve resolution when exporting PNG or JPEG images. For example, setting scale = 2 on a chart whose width is 600px will produce an image file with a width of 1200px.

    Warning

    If width is explicitly set, this setting will be overridden.

  • width (numeric or None) –

    The width that the exported chart should have. Defaults to None.

    Warning

    If explicitly set, this setting will override scale.

  • auth_user (str or None) – The username to use to authenticate against the Export Server, using basic authentication. Defaults to None.

  • auth_password (str or None) – The password to use to authenticate against the Export Server (using basic authentication). Defaults to None.

  • timeout (numeric or None) – The number of seconds to wait before issuing a timeout error. The timeout check is passed if bytes have been received on the socket in less than the timeout value. Defaults to 0.5.

  • global_options (HighchartsStockOptions, HighchartsOptions or None) – The global options which will be passed to the (JavaScript) Highcharts.setOptions() method, and which will be applied to the exported chart. Defaults to None.

Note

All other keyword arguments are as per the ExportServer constructor.

Returns:

The exported chart image, either as a bytes binary object or as a base-64 encoded string (depending on the use_base64 keyword argument).

Return type:

bytes or str

Warning

As of Highcharts for Python v.1.1.0, the Highcharts Export Server does not yet fully support all of the series types added in Highcharts (JS) v.11. Attempting to programmatically download one of those new as-yet-unsupported visualizations will generate a HighchartsUnsupportedExportError.