# Chart (lv_chart) (/widgets/chart)



Overview [#overview]

Charts visualize numeric data. They support:

* Multiple data series, added and removed at any time
* Up to four built-in axes (left/right Y, bottom/top X)
* Optional background division lines, cursors, and per-point markers
* Live updates through several update modes
* Scrolling and zooming
* Showing or hiding individual series, points, and cursors

Chart Basics [#chart-basics]

A chart is built from a few independent pieces, each covered in its own
section below:

* a **type** (line / curve / bar / stacked / scatter) — see [Chart type](#chart-type)
* one or more **data series**, each pinned to one of the four built-in
  axes — see [Data series](#data-series)
* a fixed **point count** that sizes every series' value array — see
  [Number of points](#number-of-points)
* optional **cursors** to mark a location on the chart — see [Cursor](#cursor)
* an **update mode** controlling how <ApiLink name="lv_chart_set_next_value" /> reshapes the
  series — see [Update modes](#update-modes)

Drawing order is back-to-front: background and division lines, then
data series in the order they were added, then cursors in the order they
were added. The most recently added series and cursor sit on top.

Styling [#styling]

* <ApiLink name="LV_PART_MAIN" /> The background of the chart. Uses the [typical
  background](/common-widget-features/styles/overview) and line style properties (for division lines).
  *Padding* makes the series area smaller. For BAR and STACKED charts `pad_column` sets the
  space between bars in the same data series.
* <ApiLink name="LV_PART_SCROLLBAR" /> A scrollbar used if the chart is zoomed. See
  [base widget](/widgets/base_widget)'s documentation for details.
* <ApiLink name="LV_PART_ITEMS" /> Refers to the LINE or BAR data series.

  * LINE chart: *line* properties are used by lines.
    `width`, `height`, `bg_color` and `radius` are used to set
    the appearance of points on the line.
  * Bar chart: The typical background properties are used to style the
    bars. `pad_column` sets the space between columns in the same data series.
* <ApiLink name="LV_PART_INDICATOR" /> Refers to points on LINE- and SCATTER-charts
  (small circles or squares \[with possibly-rounded corners]).
* <ApiLink name="LV_PART_CURSOR" /> *Line* properties are used to style cursors.
  `width`, `height`, `bg_color` and `radius` are used to set
  the appearance of the cursor's "point" showing its location.  If either `width`
  or `height` are set to 0, only the cursor's lines are drawn.

Chart type [#chart-type]

<LvglExample name="lv_example_chart_types" path="widgets/chart/lv_example_chart_types" />

For scatter charts each data point is an (X, Y) pair, and the series
binds to both an X axis and a Y axis with `LV_CHART_AXIS_PRIMARY_X | LV_CHART_AXIS_PRIMARY_Y`.
This C example also tints each point between red and blue based on its
position and fades older samples — both effects are driven from
<ApiLink name="LV_EVENT_DRAW_TASK_ADDED" />, so they stay in C even though the chart
itself is pure widget config:

<LvglExample name="lv_example_chart_scatter" path="widgets/chart/lv_example_chart_scatter" />

A chart can be one of the following types:

* <ApiLink name="LV_CHART_TYPE_NONE" />: Do not display any data. Can be used to hide chart's data.
* <ApiLink name="LV_CHART_TYPE_LINE" />: Draw lines between data points.  Data points
  can also be illustrated if their `width`, `height`, `bg_color` and `radius`
  styles (for <ApiLink name="LV_PART_ITEMS" />) are set and both `width` and
  `height` have non-zero values.
* <ApiLink name="LV_CHART_TYPE_CURVE" />: Similar to the LINE type, but it draws Bezier curves
  between data points.  <ApiLink name="LV_USE_VECTOR_GRAPHICS" /> and a draw unit (e.g. VGLite, or ThorVG for
  software rendering) need to be enabled. It also supports the `line_dash_gap/width` style
  properties.
* <ApiLink name="LV_CHART_TYPE_BAR" />: Draw individual vertical bars for each point in each series.
* <ApiLink name="LV_CHART_TYPE_STACKED" />: Draw vertical stacked bars where multiple data series
  are displayed as segments within a single bar for each data point. Supports only positive values.
* <ApiLink name="LV_CHART_TYPE_SCATTER" />: X/Y chart drawing point's and optionally
  lines between the points if line-width style values for
  <ApiLink name="LV_PART_ITEMS" /> is a non-zero value, and the point's Y-value is
  something other than <ApiLink name="LV_CHART_POINT_NONE" />.  (Drawing of individual points on a
  SCATTER chart can be suppressed if their Y-values are set to <ApiLink name="LV_CHART_POINT_NONE" />.)

Charts start their life as LINE charts.  You can change a chart's type with
<ApiLink name="lv_chart_set_type" display="lv_chart_set_type(chart, LV_CHART_TYPE_...)" />.

Data series [#data-series]

<LvglExample name="lv_example_chart_series" path="widgets/chart/lv_example_chart_series" />

You can add any number of data series to a chart by using

<ApiLink name="lv_chart_add_series" display="lv_chart_add_series(chart, color, axis)" />.

This allocates (and returns a pointer to) an <ApiLink name="lv_chart_series_t" /> structure
which remembers the `color` and `axis` you specified, and comes pre-allocated
with an array of `chart->point_cnt` `int32_t` Y-values, all set to
<ApiLink name="LV_CHART_POINT_NONE" />. (A SCATTER chart also comes with a pre-allocated array of
the same number of X-values.)

`axis` specifies which axis is used to scale its values, and may be one of the following:

* <ApiLink name="LV_CHART_AXIS_PRIMARY_Y" />: Left axis
* <ApiLink name="LV_CHART_AXIS_SECONDARY_Y" />: Right axis
* <ApiLink name="LV_CHART_AXIS_PRIMARY_X" />: Bottom axis
* <ApiLink name="LV_CHART_AXIS_SECONDARY_X" />: Top axis

When adding a data series to a SCATTER chart, bit-wise OR your selected Y axis
(primary or secondary) with one of the X-axis values.

If you wish to have the chart use your own Y-value array instead of the one provided,
you can do so with

<ApiLink name="lv_chart_set_series_ext_y_array" display="lv_chart_set_series_ext_y_array(chart, series, value_array)" />.

You are responsible for ensuring the array you provide contains at least
`chart->point_cnt` elements in it.

`value_array` should look like this: `int32_t * value_array[num_points]`.  Only
the array's pointer is saved in the series so its contents need to remain available
for the life of the series, i.e. the array needs to be global, static or dynamically
allocated.

<Callout type="info">
  Call <ApiLink name="lv_chart_refresh" display="lv_chart_refresh(chart)" /> when a chart's data has changed to
  signal that the chart should be re-rendered next time a display refresh occurs.
  You do not need to do this if you are using the provided value array(s) and
  setting values with `lv_chart_set_...value_...()` functions.  See below
  for more information about these functions.
</Callout>

A pointer to the Y-value array of a series can be obtained with
<ApiLink name="lv_chart_get_series_y_array" display="lv_chart_get_series_y_array(chart, series)" />.  This is true whether you are using
the provided Y-value array or provided your own.

For SCATTER-type charts,

* <ApiLink name="lv_chart_set_series_ext_x_array" display="lv_chart_set_series_ext_x_array(chart, series, value_array)" /> and
* <ApiLink name="lv_chart_get_series_x_array" display="lv_chart_get_series_x_array(chart, series)" />

can be used as well.

Modifying data [#modifying-data]

Four ways to write a series value:

| Function                                                                                                        | Use when                                                        |
| --------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
| <ApiLink name="lv_chart_set_series_value_by_id" display="lv_chart_set_series_value_by_id(chart, ser, id, v)" /> | updating one specific point by index                            |
| <ApiLink name="lv_chart_set_next_value" display="lv_chart_set_next_value(chart, ser, v)" />                     | streaming live data — paired with [Update modes](#update-modes) |
| <ApiLink name="lv_chart_set_all_values" display="lv_chart_set_all_values(chart, ser, v)" />                     | filling the whole series with one value                         |
| `ser->points[i] = v` + <ApiLink name="lv_chart_refresh" display="lv_chart_refresh(chart)" />                    | bulk writes where the helpers would be overhead                 |

Use <ApiLink name="LV_CHART_POINT_NONE" /> to hide a point. Scatter charts have
`_set_series_value_by_id2` / `_set_next_value2` variants that take both X
and Y.

Update modes [#update-modes]

<ApiLink name="lv_chart_set_next_value" /> writes into the series according to the chart's
update mode (set with <ApiLink name="lv_chart_set_update_mode" />):

* <ApiLink name="LV_CHART_UPDATE_MODE_SHIFT" /> — shift older points left, new value on the right.
* <ApiLink name="LV_CHART_UPDATE_MODE_CIRCULAR" /> — overwrite oldest in place, leaving a gap that marks the write head (ECG-style).

<LvglExample name="lv_example_chart_circular_gap" path="widgets/chart/lv_example_chart_circular_gap" />

Number of points [#number-of-points]

The number of points in the series can be modified by
<ApiLink name="lv_chart_set_point_count" display="lv_chart_set_point_count(chart, point_num)" />. The default value is 10.
Note: this affects the number of points processed when an external
value array is assigned to a series, so you also need to be sure any external
array so provided contains at least `point_num` elements.

Handling large numbers of points [#handling-large-numbers-of-points]

On LINE charts, if the number of points is greater than the pixels
horizontally, the Chart will draw only vertical lines to make the
drawing of large amount of data effective. If there are, let's say, 10
points to a pixel, LVGL searches the smallest and the largest value and
draws a vertical lines between them to ensure no peaks are missed.

Vertical range [#vertical-range]

You can specify the minimum and maximum values in Y-direction with
<ApiLink name="lv_chart_set_axis_range" display="lv_chart_set_axis_range(chart, axis, min, max)" />. `axis` can be
<ApiLink name="LV_CHART_AXIS_PRIMARY_Y" /> (left Y axis) or
<ApiLink name="LV_CHART_AXIS_SECONDARY_Y" /> (right Y axis).

The value of the points will be scaled proportionally. The default range
is: 0..100.

Division lines [#division-lines]

The number of horizontal and vertical division lines can be modified by
<ApiLink name="lv_chart_set_div_line_count" display="lv_chart_set_div_line_count(chart, hdiv_num, vdiv_num)" />. The default
settings are 3 horizontal and 5 vertical division lines. If there is a
visible border on a side and no padding on that side, the division line
would be drawn on top of the border and in this case it is not drawn so
as not to hide the chart border.

Override default start point for series [#override-default-start-point-for-series]

If you want a plot to start from a point other than the default which is
`point[0]` of the series, you can set an alternative index with the
function <ApiLink name="lv_chart_set_x_start_point" display="lv_chart_set_x_start_point(chart, series, id)" /> where `id` is
the new zero-based index position to start plotting from.

Note that <ApiLink name="LV_CHART_UPDATE_MODE_SHIFT" /> also changes the
`start_point`.

Tick marks and labels [#tick-marks-and-labels]

<LvglExample name="lv_example_chart_ticks_labels" path="widgets/chart/lv_example_chart_ticks_labels" />

With the help of [Scale](/widgets/scale), vertical and horizontal scales can be added
in a very flexible way.  See the [examples 2](#axis-ticks-and-labels-with-scrolling)
below to learn more.

Scrolling/Zooming [#scrollingzooming]

<LvglExample name="lv_example_chart_scrollable" path="widgets/chart/lv_example_chart_scrollable" />

To zoom the chart all you need to do is wrap it in a parent container and set the
chart's width and/or height to a larger value.  Doing this will cause the chart
to be scrollable in its parent --- the parent container provides the scrollable "view
window".

Cursor [#cursor]

<LvglExample name="lv_example_chart_cursor" path="widgets/chart/lv_example_chart_cursor" />

Add a cursor with <ApiLink name="lv_chart_add_cursor" display="lv_chart_add_cursor(chart, color, dir)" />. `dir` is one
or more `LV_DIR_*` values OR'd together — they pick which lines extend
from the cursor point. A new cursor starts hidden; place it with one of:

* <ApiLink name="lv_chart_set_cursor_pos" display="lv_chart_set_cursor_pos(chart, cursor, &point)" /> — anchor at `(x, y)` in chart coordinates; the cursor scrolls with the chart.
* <ApiLink name="lv_chart_set_cursor_point" display="lv_chart_set_cursor_point(chart, cursor, series, point_id)" /> — attach to a data point; the cursor follows it as values change.

Pass <ApiLink name="LV_CHART_POINT_NONE" /> as the `point_id` to hide without removing.
<ApiLink name="lv_chart_get_point_pos_by_id" /> returns a point's pixel coordinates if
you need to set up a cursor via <ApiLink name="lv_chart_set_cursor_pos" />.

Pressed-point tooltip [#pressed-point-tooltip]

<ApiLink name="LV_EVENT_VALUE_CHANGED" /> fires when the user presses a chart point;
<ApiLink name="lv_chart_get_pressed_point" /> returns the index. This C example reads that
index and floats a small tooltip with the pressed value above the chart —
the kind of inspection helper XML can't drive on its own because it
requires a callback.

<LvglExample name="lv_example_chart_pressed_tooltip" path="widgets/chart/lv_example_chart_pressed_tooltip" />

Drawing customisations [#drawing-customisations]

Chart styling stops at the part level — to vary appearance *per data point*
or paint custom shapes alongside the series, hook
<ApiLink name="LV_EVENT_DRAW_TASK_ADDED" />. The callback receives every draw task the chart
emits and may mutate the fill/stroke descriptors before they execute, or
draw extra shapes on the chart's layer.

Recolour bars between green and red based on their value:

<LvglExample name="lv_example_chart_recolor_bars" path="widgets/chart/lv_example_chart_recolor_bars" />

Add a vertical gradient fill beneath a line series and restyle the
division lines:

<LvglExample name="lv_example_chart_area_gradient" path="widgets/chart/lv_example_chart_area_gradient" />

Events [#events]

* <ApiLink name="LV_EVENT_VALUE_CHANGED" /> Sent when a new point on the chart is pressed.
  <ApiLink name="lv_chart_get_pressed_point" display="lv_chart_get_pressed_point(chart)" /> returns the zero-based index of
  the pressed point.

Learn more about [Events](/common-widget-features/events) emitted by all Widgets.
