Using Highcharts Stock for Python


Introduction to Highcharts Stock and Highcharts for Python

Highcharts Stock is the gold-standard in JavaScript data visualization libraries for time-series and stock price data, 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 demo gallery to see some examples of what you can do with Highcharts Stock.

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

Highcharts Stock for Python will not render data visualizations itself - that’s what Highcharts Stock (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 Stock 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 Highcharts Stock for Python 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 Stock 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 Stock 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 Highcharts Stock for Python. You can find the complete list in our comprehensive Highcharts Stock 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 Stock for Python instance to Highcharts Stock-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 Stock-compatible JavaScript code using JavaScript object literal notation.

Return type:

str

to_json(self, filename=None, encoding='utf-8')

Convert the Highcharts Stock for Python instance to Highcharts Stock-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 Stock-compatible JSON representation of the object.

Return type:

str or bytes

Note

Highcharts Stock 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 Stock for Python object into a Highcharts Stock-compatible dict object.

Returns:

Highcharts Stock-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 descendants 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 (#5) 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 Stock for Python library closely matches the structure of the Highcharts Stock options object (see the relevant reference documentation).

At the root of the library - importable from highcharts_stock - you will find the highcharts_stock.highcharts module. This module is a catch-all importable module, which allows you to easily access the most-commonly-used Highcharts Stock for Python classes and modules.

Note

Whlie you can access all of the Highcharts Stock for Python classes from highcharts_stock.highcharts, if you want to more precisely navigate to specific class definitions you can do fairly easily using the module organization and naming conventions used in the library.

This is the recommended best practice to maximize performance.

In the root of the highcharts_stock library you can find universally-shared class definitions, like .metaclasses which contains the HighchartsMeta and JavaScriptDict definitions, or .decorators which define method/property decorators that are used throughout the library.

The .utility_classes module contains class definitions for classes that are referenced or used throughout the other class definitions.

And you can find the Highcharts Stock options object and all of its properties defined in the .options module, with specific (complicated or extensive) sub-modules 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 Stock 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 Stock has a lot of properties. For example, I 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 Highcharts Stock for Python - 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 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 Stock for Python

Tip

Best Practice!

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

# Import classes using precise module indications. For example:
from highcharts_stock.chart import Chart
from highcharts_stock.global_options.shared_options import SharedStockOptions
from highcharts_stock.options import HighchartsStockOptions
from highcharts_stock.options.plot_options.bar import BarOptions
from highcharts_stock.options.series.bar import BarSeries

Use Shared Options

One of the most challenging aspects of Highcharts Core and Highcharts Stock is their sheer breadth of functionality and configurability. That’s simultaneously their greatest strength, and their 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 SharedStockOptions class. This 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.

Warning

SharedStockOptions is a sub-class of SharedOptions which extends its properties and methods with properties/methods that are only available in the Highcharts Stock API.

However, this class is fully backwards-compatible with the Highcharts Core API if you leave the Stock-specific methods and properties set to None (their default).

As with all Highcharts for Python objects, you can instantiate them 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_stock.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 Stock 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
| ———— hlc-template-01.js
| ———— hlc-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 hlc-template-01.js and hlc-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_stock.highcharts import Chart
from highcharts_stock.options.series.hlc import HLCSeries

type_1_chart = Chart.from_js_literal(
    '../../project_resources/highcharts_config/hlc-template-01.js'
)
type_2_chart = Chart.from_js_literal(
    '../../project_resources/highcharts_config/hlc-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(HLCSeries.from_csv('../../project_resources/data_files/data-file-01.csv'))
type_2_chart.add_series(HLCSeries.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 Highcharts Stock Features

Highcharts Stock extends Highcharts Core with numerous features that add significant interactivity to your visualizations. These key features include:

Stock tools are a custom toolbar that can be displayed on your chart which allows your users to interact with your chart in various ways. Using event bindings tied to the stock tools, you can toggle annotations, toggle technical indicators, or control the chart’s zoom level.

Stock Tools Example

To display the stock tools in your chart, you can use the HighchartsStockOptions.stock_tools setting, which can be configured using a StockTools instance.

my_stock_tools = StockTools(gui = { 'enabled': True })
my_options = HighchartsStockOptions(stock_tools = my_stock_tools)
my_chart = Chart.from_options(my_options)

Working with Data

Obviously, if you are going to use Highcharts Stock for Python and Highcharts Stock 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.

As a result, Highcharts (JS) and Highcharts for Python both represent the data points in series as a list of data point objects in the data property within the series:

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.

Warning

Technical indicators provided by Highcharts Stock for Python do not support the .from_array() method because their data gets populated dynamically based on the series indicated in their .linked_to property.

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

Note

The HighchartsStockOptions is a sub-class of the Highcharts Core for Python HighchartsOptions class, and is fully backwards-compatible with it.

This means that you can use them interchangeably when using Highcharts Stock for Python, as the HighchartsStockOptions class merely extends its parent with a number of methods and properties that are specifically supported by Highcharts Stock.

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:

Using Technical Indicators

One of the most valuable aspects of Highcharts Stock is the inclusion of over 40 technical indicators. These are additional analytical tools which can be overlaid on your visualization to provide insights into the data you are looking at.

For example, are you hoping to understand whether the trajectory of a stock price is about to change? Or do you want to determine whether a given asset has been under-or-over sold? Or maybe you want to plot a simple linear regression against your primary series? You can do all of these and more using the technical indicators provided by Highcharts Stock.

Technical indicators are series in their own right, and can be added to your chart the same as you would add any other series. However, unlike traditional series they do not have a .data property, since they do not receive any data points. Instead, they reference the primary series whose data should be used to calculate the indicator via their .linked_to property.

You can add a series using the following methods:

Note

All standard series (descending from SeriesBase) have an .add_indicator() method which can be used to easily configure a new indicator tied to the series in question.

# Given a series instance in the variable "my_series"

# Create a Chart instance
my_chart = Chart.from_series(my_series)

# Adds a new Simple Moving Average indicator to the chart, based off of the
# "my_series" series.

my_chart = my_series.add_indicator(my_chart, indicator_name = 'sma')
Method Signature
.add_indicator(chart, indicator_name, indicator_kwargs=None)
Parameters:
  • chart (Chart) – The chart object in which the series is rendered and to which the indicator should be appended.

  • indicator_name (str) – The name of the indicator that should be added to the series and chart. For the list of supported indicators, please review the Indicator List.

  • indicator_kwargs (dict or None) – Keyword arguments to apply when instantiating the new indicator series. Defaults to None.

Returns:

chart with a new indicator series included in its list of configured series.

Return type:

Chart


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_stock.chart import Chart
from highcharts_stock.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 SharedStockOptions.

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_stock.chart import Chart
from highcharts_stock.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.

Stock Chart vs Regular Chart

When using Highcharts Stock for Python you have the choice to render your charts using the Highcharts Stock chart constructor or the standard Highcharts Core chart constructor.

The difference between these two constructors relates to the features available in the chart. The Highcharts Stock chart will be visualized including the navigator component, and can support time series scrollbars, even if the specific chart you are visualizing does not need or use them. A regular Highcharts JS chart cannot be displayed with either of these elements.

It is entirely your decision, but you should know that Highcharts JS does not support any of the technical indicators supported by Highcharts Stock, and also does not support candlestick, HLC, or OHLC series types.

However, Highcharts Stock can visualize all of the series types offered by Highcharts Core.

When working with your Chart object, you can set the .is_stock_chart property to True to force the chart to be rendered using the (JavaScript) Highcharts.stockChart() constructor.

If you wish to force the use of the (JavaScript) Highcharts.chart() constructor, you can explicitly set .is_stock_chart to False after populating the chart’s .options property.

If you do not set this property explicitly, Highcharts Stock for Python will make a determination based on the contents of the .options property. If that that property is set to a HighchartsStockOptions instance, the .is_stock_chart property will be set to True, unless explicitly overridden in your code.


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 Highcharts Stock for Python, 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_stock.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.