Documentation / Hardware

Charts

Series, two Y axes, scatter with a real X, and a window that is an hour rather than a count.

A chart is the widget with the most moving parts, so it has its own page. It holds one or more series; each series is fed by a Push onto chart binding from a variable, and the chart decides what the axes mean and how many readings it keeps.

Chart settings and the series editor for a two-series chart with a secondary axis: the humidity series is measured against the right-hand axis.
Chart settings and the series editor for a two-series chart with a secondary axis: the humidity series is measured against the right-hand axis.

Series

Under Chart data in the Inspector, each series has a name, a colour, a list of design-time values (what the canvas draws, and the initial points on the device), and - once a secondary axis exists - which axis it is measured against. A scatter chart's series also has a list of design-time X values. Add as many series as you have things to plot; the feed for each is a binding.

Feeding it

Select the chart, add a Data binding, choose the variable, set Drives to Push onto chart and pick the Series. Every refresh in which the variable is due, its value is appended with lv_chart_set_next_value(). A temperature line and a humidity line are two bindings on one chart pointed at two series.

Two Y axes

Switch on Secondary Y axis and the chart gains a right-hand axis with its own range (Secondary Y range min / max), and each series gains the Measured against choice. That is what lets 0-50 °C sit beside 400-2000 ppm CO2 without one of them drawing as a flat line along the bottom. The canvas draws the second axis's labels on the right. The validator warns when a series is measured against a secondary axis the chart does not have.

Scatter and the X axis

A Scatter chart plots each point at an X as well as a Y. The X range is set on the chart (X range min / max), and X from names the variable every point takes its X from - one setting for the whole chart, because a chart has one X axis. Left empty, each reading keeps the X it already had and the series stacks on one column, which the validator warns about.

The points a series starts with can each have an X in the series editor. One you give no X is placed by its position in the series, evenly from X min to X max - so a chart you have just switched to Scatter keeps its shape, on the canvas and on the device alike.

A time axis

Point X from at a variable reading a real-time clock - the DS3231's Unix time channel - and the scatter chart becomes a time axis. Two details make that work on a microcontroller:

The rolling window

Rolling window is either The last N points - N is the chart's point count, and When full decides whether new points shift the old ones left or overwrite them circularly - or A span of time in seconds. With a time span, the firmware paces the pushes so the point count covers the span: an hour across 120 points is one reading every 30 seconds, whatever the refresh rate. The Inspector shows the resulting cadence under the setting, and the validator warns if it is faster than the refresh loop can deliver. On a scatter chart with a time axis the X range also rolls, so the last hour is always what is on screen.

Ticks and labels

Major and minor tick lengths and counts, whether the X and primary Y axes are labelled, and the axis font size. Minor tick count is the number of steps between two major ticks. A secondary Y axis is labelled down the right-hand side whenever the primary one is.

The two tick counts divide every axis alike unless you switch on X axis has its own ticks. Then they are the Y axes', and X major tick count and X minor tick count divide the X axis - twelve months along the bottom of a chart whose side reads 0, 25, 50, 75, 100. The tick lengths stay shared.

What the X axis reads. A scatter chart has an X value for every point, so its axis shows its X range. A line or bar chart spaces its points evenly and has no X values at all, so the numbers under it are yours to choose with X axis numbers:

The numbers are whole, evenly spread across the major ticks and rounded towards zero, and they are fixed when the design is exported: this is a label, not a clock. An axis that follows real time is a scatter chart with an X from variable, above.

The widget's box is the plot and its axes. The numbers are drawn beside the chart, not inside it, so the chart itself is narrower than the box by its Y axis and shorter by its X axis. The canvas shows the division, and what you size and align is the whole thing. Switch a label off and the plot takes that room back. A Play Animation that moves or sizes a chart is given numbers for the whole thing too.

How an axis is built depends on the LVGL version, because LVGL 9 took axes out of the chart:

The chart's Ticks style part colours the tick lines and the numbers on both. On LVGL 9 only its default state is used - a scale is not pressed with its chart - and the Errors tab says so when another state carries styles. Inside a flex container LVGL 9 is told how much room the axes take, so the layout matches the canvas; LVGL 8 has no way to say it, and the validator warns.

An LVGL 9 or MicroPython export made before October 2026 has no axes: the canvas drew them and the export did not. Export again to get them. A chart whose labels were on is drawn smaller than it was, by the room they take - switch Label on X axis and Label on Primary Y axis off to keep a bare chart at its full size.

A line or scatter chart has a dot on every point. Point size sets how big - 7 px unless you change it, and 0 draws the line alone, which is what a trend of sixty readings wants. The dot is the Indicator part, drawn in the series' colour. A scatter chart's points are joined in the order they were given unless the Items line width is 0. A bar is as wide as what is left once the gaps are taken out - the Main part's column padding between points, the Items part's between two series at one point - so many bars in a narrow chart are thin.

Generated code, briefly

The screen file creates the chart, sets its type, point count, division lines, ranges (primary, secondary and X where used), update mode and ticks, then adds each series on its axis and fills in the design-time values. app_logic.cpp holds a per-chart pacing timer and, for a scatter chart, the X origin; each push is one lv_chart_set_next_value() or, with an X source, lv_chart_set_next_value2(), followed by lv_chart_set_range() on the X axis when the window is a time span.