Chart (lv_chart)

Overview

Charts are a basic object to visualize data points. Currently Line charts (connect points with lines and/or draw points on them) and Bar charts are supported.

Charts can have:

  • division lines

  • 2 y axis

  • axis ticks and texts on ticks

  • cursors

  • scrolling and zooming

Parts and Styles

  • LV_PART_MAIN The background of the chart. Uses all the typical background and line (for the division lines) related style properties. Padding makes the series area smaller. For column charts pad_column sets the space between the columns of the adjacent indices.

  • LV_PART_SCROLLBAR The scrollbar used if the chart is zoomed. See the Base object's documentation for details.

  • LV_PART_ITEMS Refers to the line or bar series.

    • Line chart: The line properties are used by the lines. width, height, bg_color and radius is used to set the appearance of points.

    • Bar chart: The typical background properties are used to style the bars. pad_column sets the space between the columns on the same index.

  • LV_PART_INDICATOR Refers to the points on line and scatter chart (small circles or squares).

  • LV_PART_CURSOR Line properties are used to style the cursors. width, height, bg_color and radius are used to set the appearance of points.

  • LV_PART_TICKS Line and Text style properties are used to style the ticks

Usage

Chart type

The following data display types exist:

  • LV_CHART_TYPE_NONE Do not display any data. Can be used to hide the series.

  • LV_CHART_TYPE_LINE Draw lines between the data points and/or points (rectangles or circles) on the data points.

  • LV_CHART_TYPE_BAR - Draw bars.

  • LV_CHART_TYPE_SCATTER - X/Y chart drawing point's and lines between the points. .

You can specify the display type with lv_chart_set_type(chart, LV_CHART_TYPE_...).

Data series

You can add any number of series to the charts by lv_chart_add_series(chart, color, axis). This allocates an lv_chart_series_t structure which contains the chosen color and an array for the data points. axis can have the following values:

  • LV_CHART_AXIS_PRIMARY_Y Left axis

  • LV_CHART_AXIS_SECONDARY_Y Right axis

  • LV_CHART_AXIS_PRIMARY_X Bottom axis

  • LV_CHART_AXIS_SECONDARY_X Top axis

axis tells which axis's range should be used te scale the values.

lv_chart_set_ext_y_array(chart, ser, value_array) makes the chart use an external array for the given series. value_array should look like this: lv_coord_t * value_array[num_points]. The array size needs to be large enough to hold all the points of that series. The array's pointer will be saved in the chart so it needs to be global, static or dynamically allocated. Note: you should call lv_chart_refresh(chart) after the external data source has been updated to update the chart.

The value array of a series can be obtained with lv_chart_get_y_array(chart, ser), which can be used with ext_array or normal arrays.

For LV_CHART_TYPE_SCATTER type lv_chart_set_ext_x_array(chart, ser, value_array) and lv_chart_get_x_array(chart, ser) can be used as well.

Modify the data

You have several options to set the data of series:

  1. Set the values manually in the array like ser1->points[3] = 7 and refresh the chart with lv_chart_refresh(chart).

  2. Use lv_chart_set_value_by_id(chart, ser, id, value) where id is the index of the point you wish to update.

  3. Use the lv_chart_set_next_value(chart, ser, value).

  4. Initialize all points to a given value with: lv_chart_set_all_value(chart, ser, value).

Use LV_CHART_POINT_NONE as value to make the library skip drawing that point, column, or line segment.

For LV_CHART_TYPE_SCATTER type lv_chart_set_value_by_id2(chart, ser, id, value) and lv_chart_set_next_value2(chart, ser, x_valuem y_value) can be used as well.

Update modes

lv_chart_set_next_value can behave in two ways depending on update mode:

  • LV_CHART_UPDATE_MODE_SHIFT Shift old data to the left and add the new one to the right.

  • LV_CHART_UPDATE_MODE_CIRCULAR - Add the new data in circular fashion, like an ECG diagram.

The update mode can be changed with lv_chart_set_update_mode(chart, LV_CHART_UPDATE_MODE_...).

Number of points

The number of points in the series can be modified by lv_chart_set_point_count(chart, point_num). The default value is 10. Note: this also affects the number of points processed when an external buffer is assigned to a series, so you need to be sure the external array is large enough.

Handling large number 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

You can specify the minimum and maximum values in y-direction with lv_chart_set_range(chart, axis, min, max). axis can be LV_CHART_AXIS_PRIMARY (left axis) or LV_CHART_AXIS_SECONDARY (right axis).

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

Division lines

The number of horizontal and vertical division lines can be modified by 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 therefore it won't be drawn.

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 lv_chart_set_x_start_point(chart, ser, id) where id is the new index position to start plotting from.

Note that LV_CHART_UPDATE_MODE_SHIFT also changes the start_point.

Tick marks and labels

Ticks and labels can be added to the axis with lv_chart_set_axis_tick(chart, axis, major_len, minor_len, major_cnt, minor_cnt, label_en, draw_size).

  • axis can be LV_CHART_AXIS_X/PRIMARY_Y/SECONDARY_Y

  • major_len is the length of major ticks

  • minor_len is the length of minor ticks

  • major_cnt is the number of major ticks on the axis

  • minor_cnt in the number of minor ticks between two major ticks

  • label_en true: enable label drawing on major ticks

  • draw_size extra size required to draw the tick and labels (start with 20 px and increase if the ticks/labels are clipped)

Zoom

The chart can be zoomed independently in x and y directions with lv_chart_set_zoom_x(chart, factor) and lv_chart_set_zoom_y(chart, factor). If factor is 256 there is no zoom. 512 means double zoom, etc. Fractional values are also possible but < 256 value is not allowed.

Cursor

A cursor can be added with lv_chart_cursor_t * c1 = lv_chart_add_cursor(chart, color, dir);. The possible values of dir LV_DIR_NONE/RIGHT/UP/LEFT/DOWN/HOR/VER/ALL or their OR-ed values to tell in which direction(s) should the cursor be drawn.

lv_chart_set_cursor_pos(chart, cursor, &point) sets the position of the cursor. pos is a pointer to an lv_point_t variable. E.g. lv_point_t point = {10, 20};. If the chart is scrolled the cursor will remain in the same place.

lv_chart_get_point_pos_by_id(chart, series, id, &point_out) gets the coordinate of a given point. It's useful to place the cursor at a given point.

lv_chart_set_cursor_point(chart, cursor, series, point_id) sticks the cursor at a point. If the point's position changes (new value or scrolling) the cursor will move with the point.

Events

  • LV_EVENT_VALUE_CHANGED Sent when a new point is clicked pressed. lv_chart_get_pressed_point(chart) returns the zero-based index of the pressed point.

  • LV_EVENT_DRAW_PART_BEGIN and LV_EVENT_DRAW_PART_END are sent with the following types:

    • LV_CHART_DRAW_PART_DIV_LINE_INIT Used before/after drawn the div lines to add masks to any extra drawings. The following fields are set:

      • part: LV_PART_MAIN

      • line_dsc

    • LV_CHART_DRAW_PART_DIV_LINE_HOR, LV_CHART_DRAW_PART_DIV_LINE_VER Used for each horizontal and vertical division lines.

      • part: LV_PART_MAIN

      • id: index of the line

      • p1, p2: points of the line

      • line_dsc

    • LV_CHART_DRAW_PART_LINE_AND_POINT Used on line and scatter charts for lines and points.

      • part: LV_PART_ITEMS

      • id: index of the point

      • value: value of idth point

      • p1, p2: points of the line

      • draw_area: area of the point

      • line_dsc

      • rect_dsc

      • sub_part_ptr: pointer to the series

    • LV_CHART_DRAW_PART_BAR Used on bar charts for the rectangles.

      • part: LV_PART_ITEMS

      • id: index of the point

      • value: value of idth point

      • draw_area: area of the point

      • rect_dsc:

      • sub_part_ptr: pointer to the series

    • LV_CHART_DRAW_PART_CURSOR Used on cursor lines and points.

      • part: LV_PART_CURSOR

      • p1, p2: points of the line

      • line_dsc

      • rect_dsc

      • draw_area: area of the points

    • LV_CHART_DRAW_PART_TICK_LABEL Used on tick lines and labels.

      • part: LV_PART_TICKS

      • id: axis

      • value: value of the tick

      • text: value converted to decimal or NULL for minor ticks

      • line_dsc,

      • label_dsc,

See the events of the Base object too.

Learn more about Events.

Keys

No Keys are processed by the object type.

Learn more about Keys.

Example

Line Chart

C code  

 GitHub
#include "../../lv_examples.h"
#if LV_USE_CHART && LV_BUILD_EXAMPLES

void lv_example_chart_1(void)
{
    /*Create a chart*/
    lv_obj_t * chart;
    chart = lv_chart_create(lv_scr_act());
    lv_obj_set_size(chart, 200, 150);
    lv_obj_center(chart);
    lv_chart_set_type(chart, LV_CHART_TYPE_LINE);   /*Show lines and points too*/

    /*Add two data series*/
    lv_chart_series_t * ser1 = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_RED), LV_CHART_AXIS_PRIMARY_Y);
    lv_chart_series_t * ser2 = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_GREEN), LV_CHART_AXIS_SECONDARY_Y);

    /*Set the next points on 'ser1'*/
    lv_chart_set_next_value(chart, ser1, 10);
    lv_chart_set_next_value(chart, ser1, 10);
    lv_chart_set_next_value(chart, ser1, 10);
    lv_chart_set_next_value(chart, ser1, 10);
    lv_chart_set_next_value(chart, ser1, 10);
    lv_chart_set_next_value(chart, ser1, 10);
    lv_chart_set_next_value(chart, ser1, 10);
    lv_chart_set_next_value(chart, ser1, 30);
    lv_chart_set_next_value(chart, ser1, 70);
    lv_chart_set_next_value(chart, ser1, 90);

    /*Directly set points on 'ser2'*/
    ser2->y_points[0] = 90;
    ser2->y_points[1] = 70;
    ser2->y_points[2] = 65;
    ser2->y_points[3] = 65;
    ser2->y_points[4] = 65;
    ser2->y_points[5] = 65;
    ser2->y_points[6] = 65;
    ser2->y_points[7] = 65;
    ser2->y_points[8] = 65;
    ser2->y_points[9] = 65;

    lv_chart_refresh(chart); /*Required after direct set*/
}

#endif

MicroPython code  

 GitHub Simulator
# Create a chart
chart = lv.chart(lv.scr_act())
chart.set_size(200, 150)
chart.center()
chart.set_type(lv.chart.TYPE.LINE)   # Show lines and points too

# Add two data series
ser1 = chart.add_series(lv.palette_main(lv.PALETTE.RED), lv.chart.AXIS.PRIMARY_Y)
ser2 = chart.add_series(lv.palette_main(lv.PALETTE.GREEN), lv.chart.AXIS.SECONDARY_Y)
print(ser2)
# Set next points on ser1
chart.set_next_value(ser1,10)
chart.set_next_value(ser1,10)
chart.set_next_value(ser1,10)
chart.set_next_value(ser1,10)
chart.set_next_value(ser1,10)
chart.set_next_value(ser1,10)
chart.set_next_value(ser1,10)
chart.set_next_value(ser1,30)
chart.set_next_value(ser1,70)
chart.set_next_value(ser1,90)

# Directly set points on 'ser2'
ser2.y_points = [90, 70, 65, 65, 65, 65, 65, 65, 65, 65]
chart.refresh()      #  Required after direct set


Faded area line chart with custom division lines

C code  

 GitHub
#include "../../lv_examples.h"
#if LV_USE_CHART && LV_DRAW_COMPLEX && LV_BUILD_EXAMPLES

static lv_obj_t * chart1;
static lv_chart_series_t * ser1;
static lv_chart_series_t * ser2;

static void draw_event_cb(lv_event_t * e)
{
    lv_obj_t * obj = lv_event_get_target(e);

    /*Add the faded area before the lines are drawn*/
    lv_obj_draw_part_dsc_t * dsc = lv_event_get_draw_part_dsc(e);
    if(dsc->part == LV_PART_ITEMS) {
        if(!dsc->p1 || !dsc->p2) return;

        /*Add a line mask that keeps the area below the line*/
        lv_draw_mask_line_param_t line_mask_param;
        lv_draw_mask_line_points_init(&line_mask_param, dsc->p1->x, dsc->p1->y, dsc->p2->x, dsc->p2->y,
                                      LV_DRAW_MASK_LINE_SIDE_BOTTOM);
        int16_t line_mask_id = lv_draw_mask_add(&line_mask_param, NULL);

        /*Add a fade effect: transparent bottom covering top*/
        lv_coord_t h = lv_obj_get_height(obj);
        lv_draw_mask_fade_param_t fade_mask_param;
        lv_draw_mask_fade_init(&fade_mask_param, &obj->coords, LV_OPA_COVER, obj->coords.y1 + h / 8, LV_OPA_TRANSP,
                               obj->coords.y2);
        int16_t fade_mask_id = lv_draw_mask_add(&fade_mask_param, NULL);

        /*Draw a rectangle that will be affected by the mask*/
        lv_draw_rect_dsc_t draw_rect_dsc;
        lv_draw_rect_dsc_init(&draw_rect_dsc);
        draw_rect_dsc.bg_opa = LV_OPA_20;
        draw_rect_dsc.bg_color = dsc->line_dsc->color;

        lv_area_t a;
        a.x1 = dsc->p1->x;
        a.x2 = dsc->p2->x - 1;
        a.y1 = LV_MIN(dsc->p1->y, dsc->p2->y);
        a.y2 = obj->coords.y2;
        lv_draw_rect(dsc->draw_ctx, &draw_rect_dsc, &a);

        /*Remove the masks*/
        lv_draw_mask_free_param(&line_mask_param);
        lv_draw_mask_free_param(&fade_mask_param);
        lv_draw_mask_remove_id(line_mask_id);
        lv_draw_mask_remove_id(fade_mask_id);
    }
    /*Hook the division lines too*/
    else if(dsc->part == LV_PART_MAIN) {
        if(dsc->line_dsc == NULL || dsc->p1 == NULL || dsc->p2 == NULL) return;

        /*Vertical line*/
        if(dsc->p1->x == dsc->p2->x) {
            dsc->line_dsc->color  = lv_palette_lighten(LV_PALETTE_GREY, 1);
            if(dsc->id == 3) {
                dsc->line_dsc->width  = 2;
                dsc->line_dsc->dash_gap  = 0;
                dsc->line_dsc->dash_width  = 0;
            }
            else {
                dsc->line_dsc->width = 1;
                dsc->line_dsc->dash_gap  = 6;
                dsc->line_dsc->dash_width  = 6;
            }
        }
        /*Horizontal line*/
        else {
            if(dsc->id == 2) {
                dsc->line_dsc->width  = 2;
                dsc->line_dsc->dash_gap  = 0;
                dsc->line_dsc->dash_width  = 0;
            }
            else {
                dsc->line_dsc->width = 2;
                dsc->line_dsc->dash_gap  = 6;
                dsc->line_dsc->dash_width  = 6;
            }

            if(dsc->id == 1  || dsc->id == 3) {
                dsc->line_dsc->color  = lv_palette_main(LV_PALETTE_GREEN);
            }
            else {
                dsc->line_dsc->color  = lv_palette_lighten(LV_PALETTE_GREY, 1);
            }
        }
    }
}

static void add_data(lv_timer_t * timer)
{
    LV_UNUSED(timer);
    static uint32_t cnt = 0;
    lv_chart_set_next_value(chart1, ser1, lv_rand(20, 90));

    if(cnt % 4 == 0) lv_chart_set_next_value(chart1, ser2, lv_rand(40, 60));

    cnt++;
}

/**
 * Add a faded area effect to the line chart and make some division lines ticker
 */
void lv_example_chart_2(void)
{
    /*Create a chart1*/
    chart1 = lv_chart_create(lv_scr_act());
    lv_obj_set_size(chart1, 200, 150);
    lv_obj_center(chart1);
    lv_chart_set_type(chart1, LV_CHART_TYPE_LINE);   /*Show lines and points too*/

    lv_chart_set_div_line_count(chart1, 5, 7);

    lv_obj_add_event_cb(chart1, draw_event_cb, LV_EVENT_DRAW_PART_BEGIN, NULL);
    lv_chart_set_update_mode(chart1, LV_CHART_UPDATE_MODE_CIRCULAR);

    /*Add two data series*/
    ser1 = lv_chart_add_series(chart1, lv_palette_main(LV_PALETTE_RED), LV_CHART_AXIS_PRIMARY_Y);
    ser2 = lv_chart_add_series(chart1, lv_palette_main(LV_PALETTE_BLUE), LV_CHART_AXIS_SECONDARY_Y);

    uint32_t i;
    for(i = 0; i < 10; i++) {
        lv_chart_set_next_value(chart1, ser1, lv_rand(20, 90));
        lv_chart_set_next_value(chart1, ser2, lv_rand(30, 70));
    }

    lv_timer_create(add_data, 200, NULL);
}

#endif

MicroPython code  

 GitHub Simulator
def draw_event_cb(e):

    obj = e.get_target()

    # Add the faded area before the lines are drawn
    dsc = lv.obj_draw_part_dsc_t.__cast__(e.get_param())
    if dsc.part != lv.PART.ITEMS:
        return
    if not dsc.p1 or not dsc.p2:
        return

    # Add a line mask that keeps the area below the line
    line_mask_param = lv.draw_mask_line_param_t()
    line_mask_param.points_init(dsc.p1.x, dsc.p1.y, dsc.p2.x, dsc.p2.y, lv.DRAW_MASK_LINE_SIDE.BOTTOM)
    # line_mask_id = line_mask_param.draw_mask_add(None)
    line_mask_id = lv.draw_mask_add(line_mask_param, None)
    # Add a fade effect: transparent bottom covering top
    h = obj.get_height()
    fade_mask_param = lv.draw_mask_fade_param_t()
    coords = lv.area_t()
    obj.get_coords(coords)
    fade_mask_param.init(coords, lv.OPA.COVER, coords.y1 + h // 8, lv.OPA.TRANSP,coords.y2)
    fade_mask_id = lv.draw_mask_add(fade_mask_param,None)

    # Draw a rectangle that will be affected by the mask
    draw_rect_dsc = lv.draw_rect_dsc_t()
    draw_rect_dsc.init()
    draw_rect_dsc.bg_opa = lv.OPA._20
    draw_rect_dsc.bg_color = dsc.line_dsc.color

    a = lv.area_t()
    a.x1 = dsc.p1.x
    a.x2 = dsc.p2.x - 1
    a.y1 = min(dsc.p1.y, dsc.p2.y)
    coords = lv.area_t()
    obj.get_coords(coords)
    a.y2 = coords.y2
    dsc.draw_ctx.rect(draw_rect_dsc, a)

    # Remove the masks
    lv.draw_mask_remove_id(line_mask_id)
    lv.draw_mask_remove_id(fade_mask_id)


def add_data(timer):
    # LV_UNUSED(timer);
    cnt = 0
    chart1.set_next_value(ser1, lv.rand(20, 90))

    if cnt % 4 == 0:
        chart1.set_next_value(ser2, lv.rand(40, 60))

    cnt +=1

#
# Add a faded area effect to the line chart
#

# Create a chart1
chart1 = lv.chart(lv.scr_act())
chart1.set_size(200, 150)
chart1.center()
chart1.set_type(lv.chart.TYPE.LINE)    # Show lines and points too

chart1.add_event_cb(draw_event_cb, lv.EVENT.DRAW_PART_BEGIN, None)
chart1.set_update_mode(lv.chart.UPDATE_MODE.CIRCULAR)

# Add two data series
ser1 = chart1.add_series(lv.palette_main(lv.PALETTE.RED), lv.chart.AXIS.PRIMARY_Y)
ser2 = chart1.add_series(lv.palette_main(lv.PALETTE.BLUE), lv.chart.AXIS.SECONDARY_Y)

for i in range(10):
    chart1.set_next_value(ser1, lv.rand(20, 90))
    chart1.set_next_value(ser2, lv.rand(30, 70))

timer = lv.timer_create(add_data, 200, None)

Axis ticks and labels with scrolling

C code  

 GitHub
#include "../../lv_examples.h"
#if LV_USE_CHART && LV_BUILD_EXAMPLES

static void draw_event_cb(lv_event_t * e)
{
    lv_obj_draw_part_dsc_t * dsc = lv_event_get_draw_part_dsc(e);
    if(!lv_obj_draw_part_check_type(dsc, &lv_chart_class, LV_CHART_DRAW_PART_TICK_LABEL)) return;

    if(dsc->id == LV_CHART_AXIS_PRIMARY_X && dsc->text) {
        const char * month[] = {"Jan", "Febr", "March", "Apr", "May", "Jun", "July", "Aug", "Sept", "Oct", "Nov", "Dec"};
        lv_snprintf(dsc->text, dsc->text_length, "%s", month[dsc->value]);
    }
}

/**
 * Add ticks and labels to the axis and demonstrate scrolling
 */
void lv_example_chart_3(void)
{
    /*Create a chart*/
    lv_obj_t * chart;
    chart = lv_chart_create(lv_scr_act());
    lv_obj_set_size(chart, 200, 150);
    lv_obj_center(chart);
    lv_chart_set_type(chart, LV_CHART_TYPE_BAR);
    lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, 0, 100);
    lv_chart_set_range(chart, LV_CHART_AXIS_SECONDARY_Y, 0, 400);
    lv_chart_set_point_count(chart, 12);
    lv_obj_add_event_cb(chart, draw_event_cb, LV_EVENT_DRAW_PART_BEGIN, NULL);

    /*Add ticks and label to every axis*/
    lv_chart_set_axis_tick(chart, LV_CHART_AXIS_PRIMARY_X, 10, 5, 12, 3, true, 40);
    lv_chart_set_axis_tick(chart, LV_CHART_AXIS_PRIMARY_Y, 10, 5, 6, 2, true, 50);
    lv_chart_set_axis_tick(chart, LV_CHART_AXIS_SECONDARY_Y, 10, 5, 3, 4, true, 50);

    /*Zoom in a little in X*/
    lv_chart_set_zoom_x(chart, 800);

    /*Add two data series*/
    lv_chart_series_t * ser1 = lv_chart_add_series(chart, lv_palette_lighten(LV_PALETTE_GREEN, 2), LV_CHART_AXIS_PRIMARY_Y);
    lv_chart_series_t * ser2 = lv_chart_add_series(chart, lv_palette_darken(LV_PALETTE_GREEN, 2),
                                                   LV_CHART_AXIS_SECONDARY_Y);

    /*Set the next points on 'ser1'*/
    lv_chart_set_next_value(chart, ser1, 31);
    lv_chart_set_next_value(chart, ser1, 66);
    lv_chart_set_next_value(chart, ser1, 10);
    lv_chart_set_next_value(chart, ser1, 89);
    lv_chart_set_next_value(chart, ser1, 63);
    lv_chart_set_next_value(chart, ser1, 56);
    lv_chart_set_next_value(chart, ser1, 32);
    lv_chart_set_next_value(chart, ser1, 35);
    lv_chart_set_next_value(chart, ser1, 57);
    lv_chart_set_next_value(chart, ser1, 85);
    lv_chart_set_next_value(chart, ser1, 22);
    lv_chart_set_next_value(chart, ser1, 58);

    lv_coord_t * ser2_array = lv_chart_get_y_array(chart, ser2);
    /*Directly set points on 'ser2'*/
    ser2_array[0] = 92;
    ser2_array[1] = 71;
    ser2_array[2] = 61;
    ser2_array[3] = 15;
    ser2_array[4] = 21;
    ser2_array[5] = 35;
    ser2_array[6] = 35;
    ser2_array[7] = 58;
    ser2_array[8] = 31;
    ser2_array[9] = 53;
    ser2_array[10] = 33;
    ser2_array[11] = 73;

    lv_chart_refresh(chart); /*Required after direct set*/
}

#endif

MicroPython code  

 GitHub Simulator
def draw_event_cb(e):

    dsc = lv.obj_draw_part_dsc_t.__cast__(e.get_param())
    if dsc.part == lv.PART.TICKS and dsc.id == lv.chart.AXIS.PRIMARY_X:
        month = ["Jan", "Febr", "March", "Apr", "May", "Jun", "July", "Aug", "Sept", "Oct", "Nov", "Dec"]
        # dsc.text is defined char text[16], I must therefore convert the Python string to a byte_array
        dsc.text = bytes(month[dsc.value],"ascii")
#
# Add ticks and labels to the axis and demonstrate scrolling
#

# Create a chart
chart = lv.chart(lv.scr_act())
chart.set_size(200, 150)
chart.center()
chart.set_type(lv.chart.TYPE.BAR)
chart.set_range(lv.chart.AXIS.PRIMARY_Y, 0, 100)
chart.set_range(lv.chart.AXIS.SECONDARY_Y, 0, 400)
chart.set_point_count(12)
chart.add_event_cb(draw_event_cb, lv.EVENT.DRAW_PART_BEGIN, None)

# Add ticks and label to every axis
chart.set_axis_tick(lv.chart.AXIS.PRIMARY_X, 10, 5, 12, 3, True, 40)
chart.set_axis_tick(lv.chart.AXIS.PRIMARY_Y, 10, 5, 6, 2, True, 50)
chart.set_axis_tick(lv.chart.AXIS.SECONDARY_Y, 10, 5, 3, 4,True, 50)

# Zoom in a little in X
chart.set_zoom_x(800)

# Add two data series
ser1 = lv.chart.add_series(chart, lv.palette_lighten(lv.PALETTE.GREEN, 2), lv.chart.AXIS.PRIMARY_Y)
ser2 = lv.chart.add_series(chart, lv.palette_darken(lv.PALETTE.GREEN, 2), lv.chart.AXIS.SECONDARY_Y)

# Set the next points on 'ser1'
chart.set_next_value(ser1, 31)
chart.set_next_value(ser1, 66)
chart.set_next_value(ser1, 10)
chart.set_next_value(ser1, 89)
chart.set_next_value(ser1, 63)
chart.set_next_value(ser1, 56)
chart.set_next_value(ser1, 32)
chart.set_next_value(ser1, 35)
chart.set_next_value(ser1, 57)
chart.set_next_value(ser1, 85)
chart.set_next_value(ser1, 22)
chart.set_next_value(ser1, 58)

# Directly set points on 'ser2'
ser2.y_points = [92,71,61,15,21,35,35,58,31,53,33,73]

chart.refresh()  # Required after direct set


Show the value of the pressed points

C code  

 GitHub
#include "../../lv_examples.h"
#if LV_USE_CHART && LV_BUILD_EXAMPLES


static void event_cb(lv_event_t * e)
{
    lv_event_code_t code = lv_event_get_code(e);
    lv_obj_t * chart = lv_event_get_target(e);

    if(code == LV_EVENT_VALUE_CHANGED) {
        lv_obj_invalidate(chart);
    }
    if(code == LV_EVENT_REFR_EXT_DRAW_SIZE) {
        lv_coord_t * s = lv_event_get_param(e);
        *s = LV_MAX(*s, 20);
    }
    else if(code == LV_EVENT_DRAW_POST_END) {
        int32_t id = lv_chart_get_pressed_point(chart);
        if(id == LV_CHART_POINT_NONE) return;

        LV_LOG_USER("Selected point %d", (int)id);

        lv_chart_series_t * ser = lv_chart_get_series_next(chart, NULL);
        while(ser) {
            lv_point_t p;
            lv_chart_get_point_pos_by_id(chart, ser, id, &p);

            lv_coord_t * y_array = lv_chart_get_y_array(chart, ser);
            lv_coord_t value = y_array[id];

            char buf[16];
            lv_snprintf(buf, sizeof(buf), LV_SYMBOL_DUMMY"$%d", value);

            lv_draw_rect_dsc_t draw_rect_dsc;
            lv_draw_rect_dsc_init(&draw_rect_dsc);
            draw_rect_dsc.bg_color = lv_color_black();
            draw_rect_dsc.bg_opa = LV_OPA_50;
            draw_rect_dsc.radius = 3;
            draw_rect_dsc.bg_img_src = buf;
            draw_rect_dsc.bg_img_recolor = lv_color_white();

            lv_area_t a;
            a.x1 = chart->coords.x1 + p.x - 20;
            a.x2 = chart->coords.x1 + p.x + 20;
            a.y1 = chart->coords.y1 + p.y - 30;
            a.y2 = chart->coords.y1 + p.y - 10;

            lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e);
            lv_draw_rect(draw_ctx, &draw_rect_dsc, &a);

            ser = lv_chart_get_series_next(chart, ser);
        }
    }
    else if(code == LV_EVENT_RELEASED) {
        lv_obj_invalidate(chart);
    }
}

/**
 * Show the value of the pressed points
 */
void lv_example_chart_4(void)
{
    /*Create a chart*/
    lv_obj_t * chart;
    chart = lv_chart_create(lv_scr_act());
    lv_obj_set_size(chart, 200, 150);
    lv_obj_center(chart);

    lv_obj_add_event_cb(chart, event_cb, LV_EVENT_ALL, NULL);
    lv_obj_refresh_ext_draw_size(chart);

    /*Zoom in a little in X*/
    lv_chart_set_zoom_x(chart, 800);

    /*Add two data series*/
    lv_chart_series_t * ser1 = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_RED), LV_CHART_AXIS_PRIMARY_Y);
    lv_chart_series_t * ser2 = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_GREEN), LV_CHART_AXIS_PRIMARY_Y);
    uint32_t i;
    for(i = 0; i < 10; i++) {
        lv_chart_set_next_value(chart, ser1, lv_rand(60, 90));
        lv_chart_set_next_value(chart, ser2, lv_rand(10, 40));
    }
}

#endif

MicroPython code  

 GitHub Simulator
def event_cb(e):
    code = e.get_code()
    chart = e.get_target()

    if code == lv.EVENT.VALUE_CHANGED:
        chart.invalidate()

    if code == lv.EVENT.REFR_EXT_DRAW_SIZE:
        e.set_ext_draw_size(20)

    elif code == lv.EVENT.DRAW_POST_END:
        id = lv.chart.get_pressed_point(chart)
        if id == lv.CHART_POINT.NONE:
            return
        # print("Selected point ", id)
        for i in range(len(series)):
            p = lv.point_t()
            chart.get_point_pos_by_id(series[i], id, p)
            value = series_points[i][id]
            buf = lv.SYMBOL.DUMMY + "$" + str(value)

            draw_rect_dsc = lv.draw_rect_dsc_t()
            draw_rect_dsc.init()
            draw_rect_dsc.bg_color = lv.color_black()
            draw_rect_dsc.bg_opa = lv.OPA._50
            draw_rect_dsc.radius = 3
            draw_rect_dsc.bg_img_src = buf
            draw_rect_dsc.bg_img_recolor = lv.color_white()

            a = lv.area_t()
            coords = lv.area_t()
            chart.get_coords(coords)
            a.x1 = coords.x1 + p.x - 20
            a.x2 = coords.x1 + p.x + 20
            a.y1 = coords.y1 + p.y - 30
            a.y2 = coords.y1 + p.y - 10

            clip_area = lv.area_t.__cast__(e.get_param())
            lv.draw_rect(a, clip_area, draw_rect_dsc)

    elif code == lv.EVENT.RELEASED:
        chart.invalidate()

#
# Add ticks and labels to the axis and demonstrate scrolling
#

# Create a chart
chart = lv.chart(lv.scr_act())
chart.set_size(200, 150)
chart.center()

chart.add_event_cb(event_cb, lv.EVENT.ALL, None)
chart.refresh_ext_draw_size()

# Zoom in a little in X
chart.set_zoom_x(800)

# Add two data series
ser1 = chart.add_series(lv.palette_main(lv.PALETTE.RED), lv.chart.AXIS.PRIMARY_Y)
ser2 = chart.add_series(lv.palette_main(lv.PALETTE.GREEN), lv.chart.AXIS.PRIMARY_Y)

ser1_p = []
ser2_p = []
for i in range(10):
    ser1_p.append(lv.rand(60,90))
    ser2_p.append(lv.rand(10,40))
ser1.y_points = ser1_p
ser2.y_points = ser2_p

series = [ser1,ser2]
series_points=[ser1_p,ser2_p]


Display 1000 data points with zooming and scrolling

C code  

 GitHub
#include "../../lv_examples.h"
#if LV_USE_CHART && LV_USE_SLIDER && LV_BUILD_EXAMPLES

static lv_obj_t * chart;
/* Source: https://github.com/ankur219/ECG-Arrhythmia-classification/blob/642230149583adfae1e4bd26c6f0e1fd8af2be0e/sample.csv*/
static const lv_coord_t ecg_sample[] = {
    -2, 2, 0, -15, -39, -63, -71, -68, -67, -69, -84, -95, -104, -107, -108, -107, -107, -107, -107, -114, -118, -117,
        -112, -100, -89, -83, -71, -64, -58, -58, -62, -62, -58, -51, -46, -39, -27, -10, 4, 7, 1, -3, 0, 14, 24, 30, 25, 19,
        13, 7, 12, 15, 18, 21, 13, 6, 9, 8, 17, 19, 13, 11, 11, 11, 23, 30, 37, 34, 25, 14, 15, 19, 28, 31, 26, 23, 25, 31,
        39, 37, 37, 34, 30, 32, 22, 29, 31, 33, 37, 23, 13, 7, 2, 4, -2, 2, 11, 22, 33, 19, -1, -27, -55, -67, -72, -71, -63,
        -49, -18, 35, 113, 230, 369, 525, 651, 722, 730, 667, 563, 454, 357, 305, 288, 274, 255, 212, 173, 143, 117, 82, 39,
        -13, -53, -78, -91, -101, -113, -124, -131, -131, -131, -129, -128, -129, -125, -123, -123, -129, -139, -148, -153,
        -159, -166, -183, -205, -227, -243, -248, -246, -254, -280, -327, -381, -429, -473, -517, -556, -592, -612, -620,
        -620, -614, -604, -591, -574, -540, -497, -441, -389, -358, -336, -313, -284, -222, -167, -114, -70, -47, -28, -4, 12,
        38, 52, 58, 56, 56, 57, 68, 77, 86, 86, 80, 69, 67, 70, 82, 85, 89, 90, 89, 89, 88, 91, 96, 97, 91, 83, 78, 82, 88, 95,
        96, 105, 106, 110, 102, 100, 96, 98, 97, 101, 98, 99, 100, 107, 113, 119, 115, 110, 96, 85, 73, 64, 69, 76, 79,
        78, 75, 85, 100, 114, 113, 105, 96, 84, 74, 66, 60, 75, 85, 89, 83, 67, 61, 67, 73, 79, 74, 63, 57, 56, 58, 61, 55,
        48, 45, 46, 55, 62, 55, 49, 43, 50, 59, 63, 57, 40, 31, 23, 25, 27, 31, 35, 34, 30, 36, 34, 42, 38, 36, 40, 46, 50,
        47, 32, 30, 32, 52, 67, 73, 71, 63, 54, 53, 45, 41, 28, 13, 3, 1, 4, 4, -8, -23, -32, -31, -19, -5, 3, 9, 13, 19,
        24, 27, 29, 25, 22, 26, 32, 42, 51, 56, 60, 57, 55, 53, 53, 54, 59, 54, 49, 26, -3, -11, -20, -47, -100, -194, -236,
        -212, -123, 8, 103, 142, 147, 120, 105, 98, 93, 81, 61, 40, 26, 28, 30, 30, 27, 19, 17, 21, 20, 19, 19, 22, 36, 40,
        35, 20, 7, 1, 10, 18, 27, 22, 6, -4, -2, 3, 6, -2, -13, -14, -10, -2, 3, 2, -1, -5, -10, -19, -32, -42, -55, -60,
        -68, -77, -86, -101, -110, -117, -115, -104, -92, -84, -85, -84, -73, -65, -52, -50, -45, -35, -20, -3, 12, 20, 25,
        26, 28, 28, 30, 28, 25, 28, 33, 42, 42, 36, 23, 9, 0, 1, -4, 1, -4, -4, 1, 5, 9, 9, -3, -1, -18, -50, -108, -190,
        -272, -340, -408, -446, -537, -643, -777, -894, -920, -853, -697, -461, -251, -60, 58, 103, 129, 139, 155, 170, 173,
        178, 185, 190, 193, 200, 208, 215, 225, 224, 232, 234, 240, 240, 236, 229, 226, 224, 232, 233, 232, 224, 219, 219,
        223, 231, 226, 223, 219, 218, 223, 223, 223, 233, 245, 268, 286, 296, 295, 283, 271, 263, 252, 243, 226, 210, 197,
        186, 171, 152, 133, 117, 114, 110, 107, 96, 80, 63, 48, 40, 38, 34, 28, 15, 2, -7, -11, -14, -18, -29, -37, -44, -50,
        -58, -63, -61, -52, -50, -48, -61, -59, -58, -54, -47, -52, -62, -61, -64, -54, -52, -59, -69, -76, -76, -69, -67,
        -74, -78, -81, -80, -73, -65, -57, -53, -51, -47, -35, -27, -22, -22, -24, -21, -17, -13, -10, -11, -13, -20, -20,
        -12, -2, 7, -1, -12, -16, -13, -2, 2, -4, -5, -2, 9, 19, 19, 14, 11, 13, 19, 21, 20, 18, 19, 19, 19, 16, 15, 13, 14,
        9, 3, -5, -9, -5, -3, -2, -3, -3, 2, 8, 9, 9, 5, 6, 8, 8, 7, 4, 3, 4, 5, 3, 5, 5, 13, 13, 12, 10, 10, 15, 22, 17,
        14, 7, 10, 15, 16, 11, 12, 10, 13, 9, -2, -4, -2, 7, 16, 16, 17, 16, 7, -1, -16, -18, -16, -9, -4, -5, -10, -9, -8,
        -3, -4, -10, -19, -20, -16, -9, -9, -23, -40, -48, -43, -33, -19, -21, -26, -31, -33, -19, 0, 17, 24, 9, -17, -47,
        -63, -67, -59, -52, -51, -50, -49, -42, -26, -21, -15, -20, -23, -22, -19, -12, -8, 5, 18, 27, 32, 26, 25, 26, 22,
        23, 17, 14, 17, 21, 25, 2, -45, -121, -196, -226, -200, -118, -9, 73, 126, 131, 114, 87, 60, 42, 29, 26, 34, 35, 34,
        25, 12, 9, 7, 3, 2, -8, -11, 2, 23, 38, 41, 23, 9, 10, 13, 16, 8, -8, -17, -23, -26, -25, -21, -15, -10, -13, -13,
        -19, -22, -29, -40, -48, -48, -54, -55, -66, -82, -85, -90, -92, -98, -114, -119, -124, -129, -132, -146, -146, -138,
        -124, -99, -85, -72, -65, -65, -65, -66, -63, -64, -64, -58, -46, -26, -9, 2, 2, 4, 0, 1, 4, 3, 10, 11, 10, 2, -4,
        0, 10, 18, 20, 6, 2, -9, -7, -3, -3, -2, -7, -12, -5, 5, 24, 36, 31, 25, 6, 3, 7, 12, 17, 11, 0, -6, -9, -8, -7, -5,
        -6, -2, -2, -6, -2, 2, 14, 24, 22, 15, 8, 4, 6, 7, 12, 16, 25, 20, 7, -16, -41, -60, -67, -65, -54, -35, -11, 30,
        84, 175, 302, 455, 603, 707, 743, 714, 625, 519, 414, 337, 300, 281, 263, 239, 197, 163, 136, 109, 77, 34, -18, -50,
        -66, -74, -79, -92, -107, -117, -127, -129, -135, -139, -141, -155, -159, -167, -171, -169, -174, -175, -178, -191,
        -202, -223, -235, -243, -237, -240, -256, -298, -345, -393, -432, -475, -518, -565, -596, -619, -623, -623, -614,
        -599, -583, -559, -524, -477, -425, -383, -357, -331, -301, -252, -198, -143, -96, -57, -29, -8, 10, 31, 45, 60, 65,
        70, 74, 76, 79, 82, 79, 75, 62,
    };

static void slider_x_event_cb(lv_event_t * e)
{
    lv_obj_t * obj = lv_event_get_target(e);
    int32_t v = lv_slider_get_value(obj);
    lv_chart_set_zoom_x(chart, v);
}

static void slider_y_event_cb(lv_event_t * e)
{
    lv_obj_t * obj = lv_event_get_target(e);
    int32_t v = lv_slider_get_value(obj);
    lv_chart_set_zoom_y(chart, v);
}

/**
 * Display 1000 data points with zooming and scrolling.
 * See how the chart changes drawing mode (draw only vertical lines) when
 * the points get too crowded.
 */
void lv_example_chart_5(void)
{
    /*Create a chart*/
    chart = lv_chart_create(lv_scr_act());
    lv_obj_set_size(chart, 200, 150);
    lv_obj_align(chart, LV_ALIGN_CENTER, -30, -30);
    lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, -1000, 1000);

    /*Do not display points on the data*/
    lv_obj_set_style_size(chart, 0, LV_PART_INDICATOR);

    lv_chart_series_t * ser = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_RED), LV_CHART_AXIS_PRIMARY_Y);

    uint32_t pcnt = sizeof(ecg_sample) / sizeof(ecg_sample[0]);
    lv_chart_set_point_count(chart, pcnt);
    lv_chart_set_ext_y_array(chart, ser, (lv_coord_t *)ecg_sample);

    lv_obj_t * slider;
    slider = lv_slider_create(lv_scr_act());
    lv_slider_set_range(slider, LV_IMG_ZOOM_NONE, LV_IMG_ZOOM_NONE * 10);
    lv_obj_add_event_cb(slider, slider_x_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
    lv_obj_set_size(slider, 200, 10);
    lv_obj_align_to(slider, chart, LV_ALIGN_OUT_BOTTOM_MID, 0, 20);

    slider = lv_slider_create(lv_scr_act());
    lv_slider_set_range(slider, LV_IMG_ZOOM_NONE, LV_IMG_ZOOM_NONE * 10);
    lv_obj_add_event_cb(slider, slider_y_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
    lv_obj_set_size(slider, 10, 150);
    lv_obj_align_to(slider, chart, LV_ALIGN_OUT_RIGHT_MID, 20, 0);
}

#endif

MicroPython code  

 GitHub Simulator
# Source: https://github.com/ankur219/ECG-Arrhythmia-classification/blob/642230149583adfae1e4bd26c6f0e1fd8af2be0e/sample.csv
ecg_sample = [
    -2, 2, 0, -15, -39, -63, -71, -68, -67, -69, -84, -95, -104, -107, -108, -107, -107, -107, -107, -114, -118, -117,
    -112, -100, -89, -83, -71, -64, -58, -58, -62, -62, -58, -51, -46, -39, -27, -10, 4, 7, 1, -3, 0, 14, 24, 30, 25, 19,
    13, 7, 12, 15, 18, 21, 13, 6, 9, 8, 17, 19, 13, 11, 11, 11, 23, 30, 37, 34, 25, 14, 15, 19, 28, 31, 26, 23, 25, 31,
    39, 37, 37, 34, 30, 32, 22, 29, 31, 33, 37, 23, 13, 7, 2, 4, -2, 2, 11, 22, 33, 19, -1, -27, -55, -67, -72, -71, -63,
    -49, -18, 35, 113, 230, 369, 525, 651, 722, 730, 667, 563, 454, 357, 305, 288, 274, 255, 212, 173, 143, 117, 82, 39,
    -13, -53, -78, -91, -101, -113, -124, -131, -131, -131, -129, -128, -129, -125, -123, -123, -129, -139, -148, -153,
    -159, -166, -183, -205, -227, -243, -248, -246, -254, -280, -327, -381, -429, -473, -517, -556, -592, -612, -620,
    -620, -614, -604, -591, -574, -540, -497, -441, -389, -358, -336, -313, -284, -222, -167, -114, -70, -47, -28, -4, 12,
    38, 52, 58, 56, 56, 57, 68, 77, 86, 86, 80, 69, 67, 70, 82, 85, 89, 90, 89, 89, 88, 91, 96, 97, 91, 83, 78, 82, 88, 95,
    96, 105, 106, 110, 102, 100, 96, 98, 97, 101, 98, 99, 100, 107, 113, 119, 115, 110, 96, 85, 73, 64, 69, 76, 79,
    78, 75, 85, 100, 114, 113, 105, 96, 84, 74, 66, 60, 75, 85, 89, 83, 67, 61, 67, 73, 79, 74, 63, 57, 56, 58, 61, 55,
    48, 45, 46, 55, 62, 55, 49, 43, 50, 59, 63, 57, 40, 31, 23, 25, 27, 31, 35, 34, 30, 36, 34, 42, 38, 36, 40, 46, 50,
    47, 32, 30, 32, 52, 67, 73, 71, 63, 54, 53, 45, 41, 28, 13, 3, 1, 4, 4, -8, -23, -32, -31, -19, -5, 3, 9, 13, 19,
    24, 27, 29, 25, 22, 26, 32, 42, 51, 56, 60, 57, 55, 53, 53, 54, 59, 54, 49, 26, -3, -11, -20, -47, -100, -194, -236,
    -212, -123, 8, 103, 142, 147, 120, 105, 98, 93, 81, 61, 40, 26, 28, 30, 30, 27, 19, 17, 21, 20, 19, 19, 22, 36, 40,
    35, 20, 7, 1, 10, 18, 27, 22, 6, -4, -2, 3, 6, -2, -13, -14, -10, -2, 3, 2, -1, -5, -10, -19, -32, -42, -55, -60,
    -68, -77, -86, -101, -110, -117, -115, -104, -92, -84, -85, -84, -73, -65, -52, -50, -45, -35, -20, -3, 12, 20, 25,
    26, 28, 28, 30, 28, 25, 28, 33, 42, 42, 36, 23, 9, 0, 1, -4, 1, -4, -4, 1, 5, 9, 9, -3, -1, -18, -50, -108, -190,
    -272, -340, -408, -446, -537, -643, -777, -894, -920, -853, -697, -461, -251, -60, 58, 103, 129, 139, 155, 170, 173,
    178, 185, 190, 193, 200, 208, 215, 225, 224, 232, 234, 240, 240, 236, 229, 226, 224, 232, 233, 232, 224, 219, 219,
    223, 231, 226, 223, 219, 218, 223, 223, 223, 233, 245, 268, 286, 296, 295, 283, 271, 263, 252, 243, 226, 210, 197,
    186, 171, 152, 133, 117, 114, 110, 107, 96, 80, 63, 48, 40, 38, 34, 28, 15, 2, -7, -11, -14, -18, -29, -37, -44, -50,
    -58, -63, -61, -52, -50, -48, -61, -59, -58, -54, -47, -52, -62, -61, -64, -54, -52, -59, -69, -76, -76, -69, -67,
    -74, -78, -81, -80, -73, -65, -57, -53, -51, -47, -35, -27, -22, -22, -24, -21, -17, -13, -10, -11, -13, -20, -20,
    -12, -2, 7, -1, -12, -16, -13, -2, 2, -4, -5, -2, 9, 19, 19, 14, 11, 13, 19, 21, 20, 18, 19, 19, 19, 16, 15, 13, 14,
    9, 3, -5, -9, -5, -3, -2, -3, -3, 2, 8, 9, 9, 5, 6, 8, 8, 7, 4, 3, 4, 5, 3, 5, 5, 13, 13, 12, 10, 10, 15, 22, 17,
    14, 7, 10, 15, 16, 11, 12, 10, 13, 9, -2, -4, -2, 7, 16, 16, 17, 16, 7, -1, -16, -18, -16, -9, -4, -5, -10, -9, -8,
    -3, -4, -10, -19, -20, -16, -9, -9, -23, -40, -48, -43, -33, -19, -21, -26, -31, -33, -19, 0, 17, 24, 9, -17, -47,
    -63, -67, -59, -52, -51, -50, -49, -42, -26, -21, -15, -20, -23, -22, -19, -12, -8, 5, 18, 27, 32, 26, 25, 26, 22,
    23, 17, 14, 17, 21, 25, 2, -45, -121, -196, -226, -200, -118, -9, 73, 126, 131, 114, 87, 60, 42, 29, 26, 34, 35, 34,
    25, 12, 9, 7, 3, 2, -8, -11, 2, 23, 38, 41, 23, 9, 10, 13, 16, 8, -8, -17, -23, -26, -25, -21, -15, -10, -13, -13,
    -19, -22, -29, -40, -48, -48, -54, -55, -66, -82, -85, -90, -92, -98, -114, -119, -124, -129, -132, -146, -146, -138,
    -124, -99, -85, -72, -65, -65, -65, -66, -63, -64, -64, -58, -46, -26, -9, 2, 2, 4, 0, 1, 4, 3, 10, 11, 10, 2, -4,
    0, 10, 18, 20, 6, 2, -9, -7, -3, -3, -2, -7, -12, -5, 5, 24, 36, 31, 25, 6, 3, 7, 12, 17, 11, 0, -6, -9, -8, -7, -5,
    -6, -2, -2, -6, -2, 2, 14, 24, 22, 15, 8, 4, 6, 7, 12, 16, 25, 20, 7, -16, -41, -60, -67, -65, -54, -35, -11, 30,
    84, 175, 302, 455, 603, 707, 743, 714, 625, 519, 414, 337, 300, 281, 263, 239, 197, 163, 136, 109, 77, 34, -18, -50,
    -66, -74, -79, -92, -107, -117, -127, -129, -135, -139, -141, -155, -159, -167, -171, -169, -174, -175, -178, -191,
    -202, -223, -235, -243, -237, -240, -256, -298, -345, -393, -432, -475, -518, -565, -596, -619, -623, -623, -614,
    -599, -583, -559, -524, -477, -425, -383, -357, -331, -301, -252, -198, -143, -96, -57, -29, -8, 10, 31, 45, 60, 65,
    70, 74, 76, 79, 82, 79, 75, 62,
]

def slider_x_event_cb(e):

    slider = e.get_target()
    v = slider.get_value()
    chart.set_zoom_x(v)

def slider_y_event_cb(e):

    slider = e.get_target()
    v = slider.get_value()
    chart.set_zoom_y(v)


#
# Display 1000 data points with zooming and scrolling.
# See how the chart changes drawing mode (draw only vertical lines) when
# the points get too crowded.

# Create a chart
chart = lv.chart(lv.scr_act())
chart.set_size(200, 150)
chart.align(lv.ALIGN.CENTER, -30, -30)
chart.set_range(lv.chart.AXIS.PRIMARY_Y, -1000, 1000)

# Do not display points on the data
chart.set_style_size(0, lv.PART.INDICATOR)

ser = chart.add_series(lv.palette_main(lv.PALETTE.RED), lv.chart.AXIS.PRIMARY_Y)

pcnt = len(ecg_sample)
chart.set_point_count(pcnt)
chart.set_ext_y_array(ser, ecg_sample)

slider = lv.slider(lv.scr_act())
slider.set_range(lv.IMG_ZOOM.NONE, lv.IMG_ZOOM.NONE * 10)
slider.add_event_cb(slider_x_event_cb, lv.EVENT.VALUE_CHANGED, None)
slider.set_size(200,10)
slider.align_to(chart, lv.ALIGN.OUT_BOTTOM_MID, 0, 20)

slider = lv.slider(lv.scr_act())
slider.set_range(lv.IMG_ZOOM.NONE, lv.IMG_ZOOM.NONE * 10)
slider.add_event_cb(slider_y_event_cb, lv.EVENT.VALUE_CHANGED, None)
slider.set_size(10, 150)
slider.align_to(chart, lv.ALIGN.OUT_RIGHT_MID, 20, 0)


Show cursor on the clicked point

C code  

 GitHub
#include "../../lv_examples.h"
#if LV_USE_CHART && LV_BUILD_EXAMPLES

static lv_obj_t * chart;
static lv_chart_series_t * ser;
static lv_chart_cursor_t * cursor;

static void event_cb(lv_event_t * e)
{
    static int32_t last_id = -1;
    lv_event_code_t code = lv_event_get_code(e);
    lv_obj_t * obj = lv_event_get_target(e);

    if(code == LV_EVENT_VALUE_CHANGED) {
        last_id = lv_chart_get_pressed_point(obj);
        if(last_id != LV_CHART_POINT_NONE) {
            lv_chart_set_cursor_point(obj, cursor, NULL, last_id);
        }
    }
    else if(code == LV_EVENT_DRAW_PART_END) {
        lv_obj_draw_part_dsc_t * dsc = lv_event_get_draw_part_dsc(e);
        if(!lv_obj_draw_part_check_type(dsc, &lv_chart_class, LV_CHART_DRAW_PART_CURSOR)) return;
        if(dsc->p1 == NULL || dsc->p2 == NULL || dsc->p1->y != dsc->p2->y || last_id < 0) return;

        lv_coord_t * data_array = lv_chart_get_y_array(chart, ser);
        lv_coord_t v = data_array[last_id];
        char buf[16];
        lv_snprintf(buf, sizeof(buf), "%d", v);

        lv_point_t size;
        lv_txt_get_size(&size, buf, LV_FONT_DEFAULT, 0, 0, LV_COORD_MAX, LV_TEXT_FLAG_NONE);

        lv_area_t a;
        a.y2 = dsc->p1->y - 5;
        a.y1 = a.y2 - size.y - 10;
        a.x1 = dsc->p1->x + 10;
        a.x2 = a.x1 + size.x + 10;

        lv_draw_rect_dsc_t draw_rect_dsc;
        lv_draw_rect_dsc_init(&draw_rect_dsc);
        draw_rect_dsc.bg_color = lv_palette_main(LV_PALETTE_BLUE);
        draw_rect_dsc.radius = 3;

        lv_draw_rect(dsc->draw_ctx, &draw_rect_dsc, &a);

        lv_draw_label_dsc_t draw_label_dsc;
        lv_draw_label_dsc_init(&draw_label_dsc);
        draw_label_dsc.color = lv_color_white();
        a.x1 += 5;
        a.x2 -= 5;
        a.y1 += 5;
        a.y2 -= 5;
        lv_draw_label(dsc->draw_ctx, &draw_label_dsc, &a, buf, NULL);
    }
}

/**
 * Show cursor on the clicked point
 */
void lv_example_chart_6(void)
{
    chart = lv_chart_create(lv_scr_act());
    lv_obj_set_size(chart, 200, 150);
    lv_obj_align(chart, LV_ALIGN_CENTER, 0, -10);

    lv_chart_set_axis_tick(chart, LV_CHART_AXIS_PRIMARY_Y, 10, 5, 6, 5, true, 40);
    lv_chart_set_axis_tick(chart, LV_CHART_AXIS_PRIMARY_X, 10, 5, 10, 1, true, 30);

    lv_obj_add_event_cb(chart, event_cb, LV_EVENT_ALL, NULL);
    lv_obj_refresh_ext_draw_size(chart);

    cursor = lv_chart_add_cursor(chart, lv_palette_main(LV_PALETTE_BLUE), LV_DIR_LEFT | LV_DIR_BOTTOM);

    ser = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_RED), LV_CHART_AXIS_PRIMARY_Y);
    uint32_t i;
    for(i = 0; i < 10; i++) {
        lv_chart_set_next_value(chart, ser, lv_rand(10, 90));
    }

    lv_chart_set_zoom_x(chart, 500);

    lv_obj_t * label = lv_label_create(lv_scr_act());
    lv_label_set_text(label, "Click on a point");
    lv_obj_align_to(label, chart, LV_ALIGN_OUT_TOP_MID, 0, -5);
}

#endif

MicroPython code  

 GitHub Simulator
class ExampleChart_6():

    def __init__(self):
        self.last_id = -1
        #
        # Show cursor on the clicked point
        #

        chart = lv.chart(lv.scr_act())
        chart.set_size(200, 150)
        chart.align(lv.ALIGN.CENTER, 0, -10)

        chart.set_axis_tick(lv.chart.AXIS.PRIMARY_Y, 10, 5, 6, 5, True, 40)
        chart.set_axis_tick(lv.chart.AXIS.PRIMARY_X, 10, 5, 10, 1, True, 30)

        chart.add_event_cb(self.event_cb, lv.EVENT.ALL, None)
        chart.refresh_ext_draw_size()

        self.cursor = chart.add_cursor(lv.palette_main(lv.PALETTE.BLUE), lv.DIR.LEFT | lv.DIR.BOTTOM)

        self.ser = chart.add_series(lv.palette_main(lv.PALETTE.RED), lv.chart.AXIS.PRIMARY_Y)

        self.ser_p = []
        for i in range(10):
            self.ser_p.append(lv.rand(10,90))
        self.ser.y_points = self.ser_p

        newser = chart.get_series_next(None)
        # print("length of data points: ",len(newser.points))
        chart.set_zoom_x(500)

        label = lv.label(lv.scr_act())
        label.set_text("Click on a point")
        label.align_to(chart, lv.ALIGN.OUT_TOP_MID, 0, -5)


    def event_cb(self,e):

        code = e.get_code()
        chart = e.get_target()

        if code == lv.EVENT.VALUE_CHANGED:
            # print("last_id: ",self.last_id)
            self.last_id = chart.get_pressed_point()
            if self.last_id != lv.CHART_POINT.NONE:
                p = lv.point_t()
                chart.get_point_pos_by_id(self.ser, self.last_id, p)
                chart.set_cursor_point(self.cursor, None, self.last_id)

        elif code == lv.EVENT.DRAW_PART_END:
            # print("EVENT.DRAW_PART_END")
            dsc = lv.obj_draw_part_dsc_t.__cast__(e.get_param())
            # if dsc.p1 and dsc.p2:
                # print("p1, p2", dsc.p1,dsc.p2)
                # print("p1.y, p2.y", dsc.p1.y, dsc.p2.y)
                # print("last_id: ",self.last_id)
            if dsc.part == lv.PART.CURSOR and dsc.p1 and dsc.p2 and dsc.p1.y == dsc.p2.y and self.last_id >= 0:

                v = self.ser_p[self.last_id]

                # print("value: ",v)
                value_txt = str(v)
                size = lv.point_t()
                lv.txt_get_size(size, value_txt, lv.font_default(), 0, 0, lv.COORD.MAX, lv.TEXT_FLAG.NONE)

                a = lv.area_t()
                a.y2 = dsc.p1.y - 5
                a.y1 = a.y2 - size.y - 10
                a.x1 = dsc.p1.x + 10
                a.x2 = a.x1 + size.x + 10

                draw_rect_dsc = lv.draw_rect_dsc_t()
                draw_rect_dsc.init()
                draw_rect_dsc.bg_color = lv.palette_main(lv.PALETTE.BLUE)
                draw_rect_dsc.radius = 3

                lv.draw_rect(a, dsc.clip_area, draw_rect_dsc)

                draw_label_dsc = lv.draw_label_dsc_t()
                draw_label_dsc.init()
                draw_label_dsc.color = lv.color_white()
                a.x1 += 5
                a.x2 -= 5
                a.y1 += 5
                a.y2 -= 5
                lv.draw_label(a, dsc.clip_area, draw_label_dsc, value_txt, None)

example_chart_6 = ExampleChart_6()

Scatter chart

C code  

 GitHub
#include "../../lv_examples.h"
#if LV_USE_CHART && LV_BUILD_EXAMPLES

static void draw_event_cb(lv_event_t * e)
{
    lv_obj_draw_part_dsc_t * dsc = lv_event_get_draw_part_dsc(e);
    if(dsc->part == LV_PART_ITEMS) {
        lv_obj_t * obj = lv_event_get_target(e);
        lv_chart_series_t * ser = lv_chart_get_series_next(obj, NULL);
        uint32_t cnt = lv_chart_get_point_count(obj);
        /*Make older value more transparent*/
        dsc->rect_dsc->bg_opa = (LV_OPA_COVER *  dsc->id) / (cnt - 1);

        /*Make smaller values blue, higher values red*/
        lv_coord_t * x_array = lv_chart_get_x_array(obj, ser);
        lv_coord_t * y_array = lv_chart_get_y_array(obj, ser);
        /*dsc->id is the tells drawing order, but we need the ID of the point being drawn.*/
        uint32_t start_point = lv_chart_get_x_start_point(obj, ser);
        uint32_t p_act = (start_point + dsc->id) % cnt; /*Consider start point to get the index of the array*/
        lv_opa_t x_opa = (x_array[p_act] * LV_OPA_50) / 200;
        lv_opa_t y_opa = (y_array[p_act] * LV_OPA_50) / 1000;

        dsc->rect_dsc->bg_color = lv_color_mix(lv_palette_main(LV_PALETTE_RED),
                                               lv_palette_main(LV_PALETTE_BLUE),
                                               x_opa + y_opa);
    }
}

static void add_data(lv_timer_t * timer)
{
    LV_UNUSED(timer);
    lv_obj_t * chart = timer->user_data;
    lv_chart_set_next_value2(chart, lv_chart_get_series_next(chart, NULL), lv_rand(0, 200), lv_rand(0, 1000));
}

/**
 * A scatter chart
 */
void lv_example_chart_7(void)
{
    lv_obj_t * chart = lv_chart_create(lv_scr_act());
    lv_obj_set_size(chart, 200, 150);
    lv_obj_align(chart, LV_ALIGN_CENTER, 0, 0);
    lv_obj_add_event_cb(chart, draw_event_cb, LV_EVENT_DRAW_PART_BEGIN, NULL);
    lv_obj_set_style_line_width(chart, 0, LV_PART_ITEMS);   /*Remove the lines*/

    lv_chart_set_type(chart, LV_CHART_TYPE_SCATTER);

    lv_chart_set_axis_tick(chart, LV_CHART_AXIS_PRIMARY_X, 5, 5, 5, 1, true, 30);
    lv_chart_set_axis_tick(chart, LV_CHART_AXIS_PRIMARY_Y, 10, 5, 6, 5, true, 50);

    lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_X, 0, 200);
    lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, 0, 1000);

    lv_chart_set_point_count(chart, 50);

    lv_chart_series_t * ser = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_RED), LV_CHART_AXIS_PRIMARY_Y);
    uint32_t i;
    for(i = 0; i < 50; i++) {
        lv_chart_set_next_value2(chart, ser, lv_rand(0, 200), lv_rand(0, 1000));
    }

    lv_timer_create(add_data, 100, chart);
}

#endif

MicroPython code  

 GitHub Simulator
#!/opt/bin/lv_micropython -i
import utime as time
import lvgl as lv
import display_driver

def draw_event_cb(e):
    dsc = e.get_draw_part_dsc()
    if dsc.part == lv.PART.ITEMS:
        obj = e.get_target()
        ser = obj.get_series_next(None)
        cnt = obj.get_point_count()
        # print("cnt: ",cnt)
        # Make older value more transparent
        dsc.rect_dsc.bg_opa = (lv.OPA.COVER *  dsc.id) // (cnt - 1)

        # Make smaller values blue, higher values red
        # x_array = chart.get_x_array(ser)
        # y_array = chart.get_y_array(ser)
        # dsc->id is the tells drawing order, but we need the ID of the point being drawn.
        start_point = chart.get_x_start_point(ser)
        # print("start point: ",start_point)
        p_act = (start_point + dsc.id) % cnt # Consider start point to get the index of the array
        # print("p_act", p_act)
        x_opa = (x_array[p_act] * lv.OPA._50) // 200
        y_opa = (y_array[p_act] * lv.OPA._50) // 1000

        dsc.rect_dsc.bg_color = lv.palette_main(lv.PALETTE.RED).color_mix(
                                             lv.palette_main(lv.PALETTE.BLUE),
                                             x_opa + y_opa)

def add_data(timer,chart):
    # print("add_data")
    x = lv.rand(0,200)
    y = lv.rand(0,1000)
    chart.set_next_value2(ser, x, y)
    # chart.set_next_value2(chart.gx, y)
    x_array.pop(0)
    x_array.append(x)
    y_array.pop(0)
    y_array.append(y)

#
# A scatter chart
#

chart = lv.chart(lv.scr_act())
chart.set_size(200, 150)
chart.align(lv.ALIGN.CENTER, 0, 0)
chart.add_event_cb(draw_event_cb, lv.EVENT.DRAW_PART_BEGIN, None)
chart.set_style_line_width(0, lv.PART.ITEMS)   # Remove the lines

chart.set_type(lv.chart.TYPE.SCATTER)

chart.set_axis_tick(lv.chart.AXIS.PRIMARY_X, 5, 5, 5, 1, True, 30)
chart.set_axis_tick(lv.chart.AXIS.PRIMARY_Y, 10, 5, 6, 5, True, 50)

chart.set_range(lv.chart.AXIS.PRIMARY_X, 0, 200)
chart.set_range(lv.chart.AXIS.PRIMARY_Y, 0, 1000)

chart.set_point_count(50)

ser = chart.add_series(lv.palette_main(lv.PALETTE.RED), lv.chart.AXIS.PRIMARY_Y)

x_array = []
y_array = []
for i in range(50):
    x_array.append(lv.rand(0, 200))
    y_array.append(lv.rand(0, 1000))

ser.x_points = x_array
ser.y_points = y_array

# Create an `lv_timer` to update the chart.

timer = lv.timer_create_basic()
timer.set_period(100)
timer.set_cb(lambda src: add_data(timer,chart))

Stacked area chart

C code  

 GitHub
#include "../../lv_examples.h"
#if LV_USE_CHART && LV_DRAW_COMPLEX && LV_BUILD_EXAMPLES

/*  A struct is used to keep track of the series list because later we need to draw to the series in the reverse order to which they were initialised. */
typedef struct {
    lv_obj_t * obj;
    lv_chart_series_t * series_list[3];
} stacked_area_chart_t;

static stacked_area_chart_t stacked_area_chart;

/**
 * Callback which draws the blocks of colour under the lines
 **/
static void draw_event_cb(lv_event_t * e)
{
    lv_obj_t * obj = lv_event_get_target(e);

    /*Add the faded area before the lines are drawn*/
    lv_obj_draw_part_dsc_t * dsc = lv_event_get_draw_part_dsc(e);
    if(dsc->part == LV_PART_ITEMS) {
        if(!dsc->p1 || !dsc->p2)
            return;

        /*Add a line mask that keeps the area below the line*/
        lv_draw_mask_line_param_t line_mask_param;
        lv_draw_mask_line_points_init(&line_mask_param, dsc->p1->x, dsc->p1->y, dsc->p2->x, dsc->p2->y,
                                      LV_DRAW_MASK_LINE_SIDE_BOTTOM);
        int16_t line_mask_id = lv_draw_mask_add(&line_mask_param, NULL);

        /*Draw a rectangle that will be affected by the mask*/
        lv_draw_rect_dsc_t draw_rect_dsc;
        lv_draw_rect_dsc_init(&draw_rect_dsc);
        draw_rect_dsc.bg_opa = LV_OPA_COVER;
        draw_rect_dsc.bg_color = dsc->line_dsc->color;

        lv_area_t a;
        a.x1 = dsc->p1->x;
        a.x2 = dsc->p2->x;
        a.y1 = LV_MIN(dsc->p1->y, dsc->p2->y);
        a.y2 = obj->coords.y2 -
               13; /* -13 cuts off where the rectangle draws over the chart margin. Without this an area of 0 doesn't look like 0 */
        lv_draw_rect(dsc->draw_ctx, &draw_rect_dsc, &a);

        /*Remove the mask*/
        lv_draw_mask_free_param(&line_mask_param);
        lv_draw_mask_remove_id(line_mask_id);
    }
}

/**
 * Helper function to round a fixed point number
 **/
static int32_t round_fixed_point(int32_t n, int8_t shift)
{
    /* Create a bitmask to isolates the decimal part of the fixed point number */
    int32_t mask = 1;
    for(int32_t bit_pos = 0; bit_pos < shift; bit_pos++) {
        mask = (mask << 1) + 1;
    }

    int32_t decimal_part = n & mask;

    /* Get 0.5 as fixed point */
    int32_t rounding_boundary = 1 << (shift - 1);

    /* Return either the integer part of n or the integer part + 1 */
    return (decimal_part < rounding_boundary) ? (n & ~mask) : ((n >> shift) + 1) << shift;
}

/**
 * Stacked area chart
 */
void lv_example_chart_8(void)
{
    /*Create a stacked_area_chart.obj*/
    stacked_area_chart.obj = lv_chart_create(lv_scr_act());
    lv_obj_set_size(stacked_area_chart.obj, 200, 150);
    lv_obj_center(stacked_area_chart.obj);
    lv_chart_set_type(stacked_area_chart.obj, LV_CHART_TYPE_LINE);
    lv_chart_set_div_line_count(stacked_area_chart.obj, 5, 7);
    lv_obj_add_event_cb(stacked_area_chart.obj, draw_event_cb, LV_EVENT_DRAW_PART_BEGIN, NULL);

    /* Set range to 0 to 100 for percentages. Draw ticks */
    lv_chart_set_range(stacked_area_chart.obj, LV_CHART_AXIS_PRIMARY_Y, 0, 100);
    lv_chart_set_axis_tick(stacked_area_chart.obj, LV_CHART_AXIS_PRIMARY_Y, 3, 0, 5, 1, true, 30);

    /*Set point size to 0 so the lines are smooth */
    lv_obj_set_style_size(stacked_area_chart.obj, 0, LV_PART_INDICATOR);

    /*Add some data series*/
    stacked_area_chart.series_list[0] = lv_chart_add_series(stacked_area_chart.obj, lv_palette_main(LV_PALETTE_RED),
                                                            LV_CHART_AXIS_PRIMARY_Y);
    stacked_area_chart.series_list[1] = lv_chart_add_series(stacked_area_chart.obj, lv_palette_main(LV_PALETTE_BLUE),
                                                            LV_CHART_AXIS_PRIMARY_Y);
    stacked_area_chart.series_list[2] = lv_chart_add_series(stacked_area_chart.obj, lv_palette_main(LV_PALETTE_GREEN),
                                                            LV_CHART_AXIS_PRIMARY_Y);

    for(int point = 0; point < 10; point++) {
        /* Make some random data */
        uint32_t vals[3] = {lv_rand(10, 20), lv_rand(20, 30), lv_rand(20, 30)};

        int8_t fixed_point_shift = 5;
        uint32_t total = vals[0] + vals[1] + vals[2];
        uint32_t draw_heights[3];
        uint32_t int_sum = 0;
        uint32_t decimal_sum = 0;

        /* Fixed point cascade rounding ensures percentages add to 100 */
        for(int32_t series_index = 0; series_index < 3; series_index++) {
            decimal_sum += (((vals[series_index] * 100) << fixed_point_shift) / total);
            int_sum += (vals[series_index] * 100) / total;

            int32_t modifier = (round_fixed_point(decimal_sum, fixed_point_shift) >> fixed_point_shift) - int_sum;

            /*  The draw heights are equal to the percentage of the total each value is + the cumulative sum of the previous percentages.
                The accumulation is how the values get "stacked" */
            draw_heights[series_index] = int_sum + modifier;

            /*  Draw to the series in the reverse order to which they were initialised.
                Without this the higher values will draw on top of the lower ones.
                This is because the Z-height of a series matches the order it was initialised */
            lv_chart_set_next_value(stacked_area_chart.obj, stacked_area_chart.series_list[3 - series_index - 1],
                                    draw_heights[series_index]);
        }
    }

    lv_chart_refresh(stacked_area_chart.obj);
}

#endif

MicroPython code  

 GitHub Simulator
import display_driver
import lvgl as lv

# A class is used to keep track of the series list because later we
#  need to draw to the series in the reverse order to which they were initialised.
class StackedAreaChart:
    def __init__(self):
        self.obj = None
        self.series_list = [None, None, None]

stacked_area_chart = StackedAreaChart()

#
# Callback which draws the blocks of colour under the lines
#
def draw_event_cb(e):

    obj = e.get_target()
    cont_a = lv.area_t()
    obj.get_coords(cont_a)

    #Add the faded area before the lines are drawn
    dsc = e.get_draw_part_dsc()
    if dsc.part == lv.PART.ITEMS:
        if not dsc.p1 or not dsc.p2:
            return

        # Add a line mask that keeps the area below the line
        line_mask_param = lv.draw_mask_line_param_t()
        line_mask_param.points_init(dsc.p1.x, dsc.p1.y, dsc.p2.x, dsc.p2.y, lv.DRAW_MASK_LINE_SIDE.BOTTOM)
        line_mask_id = lv.draw_mask_add(line_mask_param, None)

        #Draw a rectangle that will be affected by the mask
        draw_rect_dsc = lv.draw_rect_dsc_t()
        draw_rect_dsc.init()
        draw_rect_dsc.bg_opa = lv.OPA.COVER
        draw_rect_dsc.bg_color = dsc.line_dsc.color

        a = lv.area_t()
        a.x1 = dsc.p1.x
        a.x2 = dsc.p2.x
        a.y1 = min(dsc.p1.y, dsc.p2.y)
        a.y2 = cont_a.y2 - 13 # -13 cuts off where the rectangle draws over the chart margin. Without this an area of 0 doesn't look like 0
        dsc.draw_ctx.rect(draw_rect_dsc, a)

        # Remove the mask
        lv.draw_mask_free_param(line_mask_param)
        lv.draw_mask_remove_id(line_mask_id)


#
# Helper function to round a fixed point number
#
def round_fixed_point(n, shift):
    # Create a bitmask to isolates the decimal part of the fixed point number
    mask = 1
    for bit_pos in range(shift):
        mask = (mask << 1) + 1

    decimal_part = n & mask

    # Get 0.5 as fixed point
    rounding_boundary = 1 << (shift - 1)

    # Return either the integer part of n or the integer part + 1
    if decimal_part < rounding_boundary:
        return (n & ~mask)
    return ((n >> shift) + 1) << shift


#
# Stacked area chart
#
def lv_example_chart_8():

    #Create a stacked_area_chart.obj
    stacked_area_chart.obj = lv.chart(lv.scr_act())
    stacked_area_chart.obj.set_size(200, 150)
    stacked_area_chart.obj.center()
    stacked_area_chart.obj.set_type( lv.chart.TYPE.LINE)
    stacked_area_chart.obj.set_div_line_count(5, 7)
    stacked_area_chart.obj.add_event_cb( draw_event_cb, lv.EVENT.DRAW_PART_BEGIN, None)

    # Set range to 0 to 100 for percentages. Draw ticks
    stacked_area_chart.obj.set_range(lv.chart.AXIS.PRIMARY_Y,0,100)
    stacked_area_chart.obj.set_axis_tick(lv.chart.AXIS.PRIMARY_Y, 3, 0, 5, 1, True, 30)

    #Set point size to 0 so the lines are smooth
    stacked_area_chart.obj.set_style_size(0, lv.PART.INDICATOR)

    # Add some data series
    stacked_area_chart.series_list[0] = stacked_area_chart.obj.add_series(lv.palette_main(lv.PALETTE.RED), lv.chart.AXIS.PRIMARY_Y)
    stacked_area_chart.series_list[1] = stacked_area_chart.obj.add_series(lv.palette_main(lv.PALETTE.BLUE), lv.chart.AXIS.PRIMARY_Y)
    stacked_area_chart.series_list[2] = stacked_area_chart.obj.add_series(lv.palette_main(lv.PALETTE.GREEN), lv.chart.AXIS.PRIMARY_Y)

    for point in range(10):
        # Make some random data
        vals = [lv.rand(10, 20), lv.rand(20, 30), lv.rand(20, 30)]

        fixed_point_shift = 5
        total = vals[0] + vals[1] + vals[2]
        draw_heights = [0, 0, 0]
        int_sum = 0
        decimal_sum = 0

        # Fixed point cascade rounding ensures percentages add to 100
        for series_index in range(3):
            decimal_sum += int(((vals[series_index] * 100) << fixed_point_shift) // total)
            int_sum += int((vals[series_index] * 100) / total)

            modifier = (round_fixed_point(decimal_sum, fixed_point_shift) >> fixed_point_shift) - int_sum

            #  The draw heights are equal to the percentage of the total each value is + the cumulative sum of the previous percentages.
            #   The accumulation is how the values get "stacked"
            draw_heights[series_index] = int(int_sum + modifier)

            #  Draw to the series in the reverse order to which they were initialised.
            #   Without this the higher values will draw on top of the lower ones.
            #   This is because the Z-height of a series matches the order it was initialised
            stacked_area_chart.obj.set_next_value( stacked_area_chart.series_list[3 - series_index - 1], draw_heights[series_index])

    stacked_area_chart.obj.refresh()

lv_example_chart_8()

API

Typedefs

typedef uint8_t lv_chart_type_t
typedef uint8_t lv_chart_update_mode_t
typedef uint8_t lv_chart_axis_t

Enums

enum [anonymous]

Chart types

Values:

enumerator LV_CHART_TYPE_NONE

Don't draw the series

enumerator LV_CHART_TYPE_LINE

Connect the points with lines

enumerator LV_CHART_TYPE_BAR

Draw columns

enumerator LV_CHART_TYPE_SCATTER

Draw points and lines in 2D (x,y coordinates)

enum [anonymous]

Chart update mode for lv_chart_set_next

Values:

enumerator LV_CHART_UPDATE_MODE_SHIFT

Shift old data to the left and add the new one the right

enumerator LV_CHART_UPDATE_MODE_CIRCULAR

Add the new data in a circular way

enum [anonymous]

Enumeration of the axis'

Values:

enumerator LV_CHART_AXIS_PRIMARY_Y
enumerator LV_CHART_AXIS_SECONDARY_Y
enumerator LV_CHART_AXIS_PRIMARY_X
enumerator LV_CHART_AXIS_SECONDARY_X
enumerator _LV_CHART_AXIS_LAST
enum lv_chart_draw_part_type_t

type field in lv_obj_draw_part_dsc_t if class_p = lv_chart_class Used in LV_EVENT_DRAW_PART_BEGIN and LV_EVENT_DRAW_PART_END

Values:

enumerator LV_CHART_DRAW_PART_DIV_LINE_INIT

Used before/after drawn the div lines

enumerator LV_CHART_DRAW_PART_DIV_LINE_HOR

Used for each horizontal division lines

enumerator LV_CHART_DRAW_PART_DIV_LINE_VER

Used for each vertical division lines

enumerator LV_CHART_DRAW_PART_LINE_AND_POINT

Used on line and scatter charts for lines and points

enumerator LV_CHART_DRAW_PART_BAR

Used on bar charts for the rectangles

enumerator LV_CHART_DRAW_PART_CURSOR

Used on cursor lines and points

enumerator LV_CHART_DRAW_PART_TICK_LABEL

Used on tick lines and labels

Functions

LV_EXPORT_CONST_INT(LV_CHART_POINT_NONE)
lv_obj_t *lv_chart_create(lv_obj_t *parent)

Create a chart object

Parameters

parent -- pointer to an object, it will be the parent of the new chart

Returns

pointer to the created chart

void lv_chart_set_type(lv_obj_t *obj, lv_chart_type_t type)

Set a new type for a chart

Parameters
  • obj -- pointer to a chart object

  • type -- new type of the chart (from 'lv_chart_type_t' enum)

void lv_chart_set_point_count(lv_obj_t *obj, uint16_t cnt)

Set the number of points on a data line on a chart

Parameters
  • obj -- pointer to a chart object

  • cnt -- new number of points on the data lines

void lv_chart_set_range(lv_obj_t *obj, lv_chart_axis_t axis, lv_coord_t min, lv_coord_t max)

Set the minimal and maximal y values on an axis

Parameters
  • obj -- pointer to a chart object

  • axis -- LV_CHART_AXIS_PRIMARY_Y or LV_CHART_AXIS_SECONDARY_Y

  • min -- minimum value of the y axis

  • max -- maximum value of the y axis

void lv_chart_set_update_mode(lv_obj_t *obj, lv_chart_update_mode_t update_mode)

Set update mode of the chart object. Affects

Parameters
  • obj -- pointer to a chart object

  • mode -- the update mode

void lv_chart_set_div_line_count(lv_obj_t *obj, uint8_t hdiv, uint8_t vdiv)

Set the number of horizontal and vertical division lines

Parameters
  • obj -- pointer to a chart object

  • hdiv -- number of horizontal division lines

  • vdiv -- number of vertical division lines

void lv_chart_set_zoom_x(lv_obj_t *obj, uint16_t zoom_x)

Zoom into the chart in X direction

Parameters
  • obj -- pointer to a chart object

  • zoom_x -- zoom in x direction. LV_ZOOM_NONE or 256 for no zoom, 512 double zoom

void lv_chart_set_zoom_y(lv_obj_t *obj, uint16_t zoom_y)

Zoom into the chart in Y direction

Parameters
  • obj -- pointer to a chart object

  • zoom_y -- zoom in y direction. LV_ZOOM_NONE or 256 for no zoom, 512 double zoom

uint16_t lv_chart_get_zoom_x(const lv_obj_t *obj)

Get X zoom of a chart

Parameters

obj -- pointer to a chart object

Returns

the X zoom value

uint16_t lv_chart_get_zoom_y(const lv_obj_t *obj)

Get Y zoom of a chart

Parameters

obj -- pointer to a chart object

Returns

the Y zoom value

void lv_chart_set_axis_tick(lv_obj_t *obj, lv_chart_axis_t axis, lv_coord_t major_len, lv_coord_t minor_len, lv_coord_t major_cnt, lv_coord_t minor_cnt, bool label_en, lv_coord_t draw_size)

Set the number of tick lines on an axis

Parameters
  • obj -- pointer to a chart object

  • axis -- an axis which ticks count should be set

  • major_len -- length of major ticks

  • minor_len -- length of minor ticks

  • major_cnt -- number of major ticks on the axis

  • minor_cnt -- number of minor ticks between two major ticks

  • label_en -- true: enable label drawing on major ticks

  • draw_size -- extra size required to draw the tick and labels (start with 20 px and increase if the ticks/labels are clipped)

lv_chart_type_t lv_chart_get_type(const lv_obj_t *obj)

Get the type of a chart

Parameters

obj -- pointer to chart object

Returns

type of the chart (from 'lv_chart_t' enum)

uint16_t lv_chart_get_point_count(const lv_obj_t *obj)

Get the data point number per data line on chart

Parameters

chart -- pointer to chart object

Returns

point number on each data line

uint16_t lv_chart_get_x_start_point(const lv_obj_t *obj, lv_chart_series_t *ser)

Get the current index of the x-axis start point in the data array

Parameters
  • chart -- pointer to a chart object

  • ser -- pointer to a data series on 'chart'

Returns

the index of the current x start point in the data array

void lv_chart_get_point_pos_by_id(lv_obj_t *obj, lv_chart_series_t *ser, uint16_t id, lv_point_t *p_out)

Get the position of a point to the chart.

Parameters
  • chart -- pointer to a chart object

  • ser -- pointer to series

  • id -- the index.

  • p_out -- store the result position here

void lv_chart_refresh(lv_obj_t *obj)

Refresh a chart if its data line has changed

Parameters

chart -- pointer to chart object

lv_chart_series_t *lv_chart_add_series(lv_obj_t *obj, lv_color_t color, lv_chart_axis_t axis)

Allocate and add a data series to the chart

Parameters
  • obj -- pointer to a chart object

  • color -- color of the data series

  • axis -- the y axis to which the series should be attached (::LV_CHART_AXIS_PRIMARY_Y or ::LV_CHART_AXIS_SECONDARY_Y)

Returns

pointer to the allocated data series

void lv_chart_remove_series(lv_obj_t *obj, lv_chart_series_t *series)

Deallocate and remove a data series from a chart

Parameters
  • chart -- pointer to a chart object

  • series -- pointer to a data series on 'chart'

void lv_chart_hide_series(lv_obj_t *chart, lv_chart_series_t *series, bool hide)

Hide/Unhide a single series of a chart.

Parameters
  • obj -- pointer to a chart object.

  • series -- pointer to a series object

  • hide -- true: hide the series

void lv_chart_set_series_color(lv_obj_t *chart, lv_chart_series_t *series, lv_color_t color)

Change the color of a series

Parameters
  • obj -- pointer to a chart object.

  • series -- pointer to a series object

  • color -- the new color of the series

void lv_chart_set_x_start_point(lv_obj_t *obj, lv_chart_series_t *ser, uint16_t id)

Set the index of the x-axis start point in the data array. This point will be considers the first (left) point and the other points will be drawn after it.

Parameters
  • obj -- pointer to a chart object

  • ser -- pointer to a data series on 'chart'

  • id -- the index of the x point in the data array

lv_chart_series_t *lv_chart_get_series_next(const lv_obj_t *chart, const lv_chart_series_t *ser)

Get the next series.

Parameters
  • chart -- pointer to a chart

  • ser -- the previous series or NULL to get the first

Returns

the next series or NULL if there is no more.

lv_chart_cursor_t *lv_chart_add_cursor(lv_obj_t *obj, lv_color_t color, lv_dir_t dir)

Add a cursor with a given color

Parameters
  • obj -- pointer to chart object

  • color -- color of the cursor

  • dir -- direction of the cursor. LV_DIR_RIGHT/LEFT/TOP/DOWN/HOR/VER/ALL. OR-ed values are possible

Returns

pointer to the created cursor

void lv_chart_set_cursor_pos(lv_obj_t *chart, lv_chart_cursor_t *cursor, lv_point_t *pos)

Set the coordinate of the cursor with respect to the paddings

Parameters
  • obj -- pointer to a chart object

  • cursor -- pointer to the cursor

  • pos -- the new coordinate of cursor relative to the chart

void lv_chart_set_cursor_point(lv_obj_t *chart, lv_chart_cursor_t *cursor, lv_chart_series_t *ser, uint16_t point_id)

Stick the cursor to a point

Parameters
  • obj -- pointer to a chart object

  • cursor -- pointer to the cursor

  • ser -- pointer to a series

  • point_id -- the point's index or LV_CHART_POINT_NONE to not assign to any points.

lv_point_t lv_chart_get_cursor_point(lv_obj_t *chart, lv_chart_cursor_t *cursor)

Get the coordinate of the cursor with respect to the paddings

Parameters
  • obj -- pointer to a chart object

  • cursor -- pointer to cursor

Returns

coordinate of the cursor as lv_point_t

void lv_chart_set_all_value(lv_obj_t *obj, lv_chart_series_t *ser, lv_coord_t value)

Initialize all data points of a series with a value

Parameters
  • obj -- pointer to chart object

  • ser -- pointer to a data series on 'chart'

  • value -- the new value for all points. LV_CHART_POINT_NONE can be used to hide the points.

void lv_chart_set_next_value(lv_obj_t *obj, lv_chart_series_t *ser, lv_coord_t value)

Set the next point's Y value according to the update mode policy.

Parameters
  • obj -- pointer to chart object

  • ser -- pointer to a data series on 'chart'

  • value -- the new value of the next data

void lv_chart_set_next_value2(lv_obj_t *obj, lv_chart_series_t *ser, lv_coord_t x_value, lv_coord_t y_value)

Set the next point's X and Y value according to the update mode policy.

Parameters
  • obj -- pointer to chart object

  • ser -- pointer to a data series on 'chart'

  • x_value -- the new X value of the next data

  • y_value -- the new Y value of the next data

void lv_chart_set_value_by_id(lv_obj_t *obj, lv_chart_series_t *ser, uint16_t id, lv_coord_t value)

Set an individual point's y value of a chart's series directly based on its index

Parameters
  • obj -- pointer to a chart object

  • ser -- pointer to a data series on 'chart'

  • id -- the index of the x point in the array

  • value -- value to assign to array point

void lv_chart_set_value_by_id2(lv_obj_t *obj, lv_chart_series_t *ser, uint16_t id, lv_coord_t x_value, lv_coord_t y_value)

Set an individual point's x and y value of a chart's series directly based on its index Can be used only with LV_CHART_TYPE_SCATTER.

Parameters
  • obj -- pointer to chart object

  • ser -- pointer to a data series on 'chart'

  • id -- the index of the x point in the array

  • x_value -- the new X value of the next data

  • y_value -- the new Y value of the next data

void lv_chart_set_ext_y_array(lv_obj_t *obj, lv_chart_series_t *ser, lv_coord_t array[])

Set an external array for the y data points to use for the chart NOTE: It is the users responsibility to make sure the point_cnt matches the external array size.

Parameters
  • obj -- pointer to a chart object

  • ser -- pointer to a data series on 'chart'

  • array -- external array of points for chart

void lv_chart_set_ext_x_array(lv_obj_t *obj, lv_chart_series_t *ser, lv_coord_t array[])

Set an external array for the x data points to use for the chart NOTE: It is the users responsibility to make sure the point_cnt matches the external array size.

Parameters
  • obj -- pointer to a chart object

  • ser -- pointer to a data series on 'chart'

  • array -- external array of points for chart

lv_coord_t *lv_chart_get_y_array(const lv_obj_t *obj, lv_chart_series_t *ser)

Get the array of y values of a series

Parameters
  • obj -- pointer to a chart object

  • ser -- pointer to a data series on 'chart'

Returns

the array of values with 'point_count' elements

lv_coord_t *lv_chart_get_x_array(const lv_obj_t *obj, lv_chart_series_t *ser)

Get the array of x values of a series

Parameters
  • obj -- pointer to a chart object

  • ser -- pointer to a data series on 'chart'

Returns

the array of values with 'point_count' elements

uint32_t lv_chart_get_pressed_point(const lv_obj_t *obj)

Get the index of the currently pressed point. It's the same for every series.

Parameters

obj -- pointer to a chart object

Returns

the index of the point [0 .. point count] or LV_CHART_POINT_ID_NONE if no point is being pressed

Variables

const lv_obj_class_t lv_chart_class
struct lv_chart_series_t
#include <lv_chart.h>

Descriptor a chart series

Public Members

lv_coord_t *x_points
lv_coord_t *y_points
lv_color_t color
uint16_t start_point
uint8_t hidden
uint8_t x_ext_buf_assigned
uint8_t y_ext_buf_assigned
uint8_t x_axis_sec
uint8_t y_axis_sec
struct lv_chart_cursor_t

Public Members

lv_point_t pos
lv_coord_t point_id
lv_color_t color
lv_chart_series_t *ser
lv_dir_t dir
uint8_t pos_set
struct lv_chart_tick_dsc_t

Public Members

lv_coord_t major_len
lv_coord_t minor_len
lv_coord_t draw_size
uint32_t minor_cnt
uint32_t major_cnt
uint32_t label_en
struct lv_chart_t

Public Members

lv_obj_t obj
lv_ll_t series_ll

Linked list for the series (stores lv_chart_series_t)

lv_ll_t cursor_ll

Linked list for the cursors (stores lv_chart_cursor_t)

lv_chart_tick_dsc_t tick[4]
lv_coord_t ymin[2]
lv_coord_t ymax[2]
lv_coord_t xmin[2]
lv_coord_t xmax[2]
lv_coord_t pressed_point_id
uint16_t hdiv_cnt

Number of horizontal division lines

uint16_t vdiv_cnt

Number of vertical division lines

uint16_t point_cnt

Point number in a data line

uint16_t zoom_x
uint16_t zoom_y
lv_chart_type_t type

Line or column chart

lv_chart_update_mode_t update_mode