Skip to main content
Version: v5

Charting Extensions

A charting extension supplies a chart view for one or more command routes. When openbb-charting is installed and a command has a view, the command gains a chart parameter; calling it with chart=True runs the view and stores the result in OBBject.chart. This guide adds a view for the obb.demo.prices command from Provider extensions. The matching rules are summarized in Extension types.

Write a view​

A view class holds one static method per route. The method name is the route with the leading / removed and every other / replaced by _, so /demo/prices becomes demo_prices. Only public functions defined in the same module as the class count as views. openbb_demo/demo_views.py:

"""Demo chart views."""

from typing import TYPE_CHECKING, Any

if TYPE_CHECKING:
from openbb_charting.core.openbb_figure import OpenBBFigure


class DemoViews:
"""Chart views for demo commands."""

@staticmethod
def demo_prices(**kwargs: Any) -> tuple["OpenBBFigure", dict[str, Any]]:
"""Chart closing prices returned by /demo/prices."""
from openbb_charting.core.openbb_figure import OpenBBFigure

rows = kwargs["obbject_item"]
fig = OpenBBFigure()
fig.add_scatter(x=[row.date for row in rows], y=[row.close for row in rows], name="Close")
content = fig.show(external=True).to_plotly_json()
return fig, content

Importing openbb_charting inside the method keeps the module importable when the package is installed without it.

The view receives keyword arguments only. obbject_item is the command's results, standard_params and extra_params are the parameters the command was called with, provider is the provider name, extra is the OBBject.extra dictionary, and charting_settings carries the user's chart and table style preferences. To make a chart configurable, add the option as a command parameter; it arrives in standard_params or extra_params.

The return value can take several forms. An OpenBBFigure, a subclass of the Plotly Figure, is serialized for you. A (figure, content) tuple stores content as the JSON form, or recomputes it when the figure is an OpenBBFigure. A Chart from openbb_core.app.model.charts.chart is stored as-is, which lets a view return non-Plotly output with its own format. If the view raises an unexpected exception, openbb-charting falls back to a generic line chart of the results.

Register the view​

Point an openbb_charting_extension entry point at the class. Declaring openbb-charting as an optional dependency keeps it out of installs that do not chart:

[project.optional-dependencies]
charting = ["openbb-charting"]

[project.entry-points."openbb_charting_extension"]
demo = "openbb_demo.demo_views:DemoViews"

The entry-point name is not used for matching, so views for several routers can live in one class and one entry point.

Use the chart​

Install the package with the extra and rebuild, so the generated obb.demo.prices method gains its chart parameter:

pip install -e ".[charting]"
openbb-build
from openbb import obb

output = obb.demo.prices(symbol="ABC", chart=True)
output.show()
output.chart.content

show() renders the figure, and output.chart.content is the JSON form. Over REST, GET /api/v1/demo/prices?symbol=ABC&chart=true returns the same chart.content in the response body; the figure object itself is not serialized. If the view fails, the command still returns its results and the error is reported as a warning, unless OPENBB_DEBUG_MODE is set.

output.charting.get_params() shows the view's docstring, which is the place to document the chart's options. openbb-charting covers the rest of the charting accessor.

Modify charts with hooks​

To change charts produced by views you do not own, register a ChartingHook under the openbb_charting_hooks entry-point group. A hook can override resolve_data, pre_figure, post_figure, pre_render, and post_render; each receives a HookContext with the route, figure, content, parameters, and settings, and may change it in place. routes limits a hook to specific routes, and hooks with a lower priority run first (the default is 100).

from openbb_core.app.charting import ChartingHook, HookContext


class Watermark(ChartingHook):
"""Add a watermark to demo charts."""

routes = ("/demo/prices",)

def post_figure(self, context: HookContext) -> None:
"""Annotate the figure and refresh its JSON content."""
context.figure.add_annotation(text="Internal use", showarrow=False)
context.content = context.figure.to_plotly_json()
[project.entry-points."openbb_charting_hooks"]
watermark = "my_package.hooks:Watermark"

The content is computed before post_figure runs, so a hook that edits the figure should also refresh context.content for the change to reach REST responses.