图表 (lv_chart)

概述

图表是用于可视化数据点的基本对象。目前支持折线图(用线连接点并/或在点上绘制点)和柱状图

图表可以具有:

  • 分割线

  • 两个 y 轴

  • 轴刻度和刻度上的文本

  • 光标

  • 滚动和缩放功能

部件和样式

  • LV_PART_MAIN 图表的背景。使用所有典型的背景和线条(用于分割线)相关的样式属性。填充使系列区域变小。对于柱状图,pad_column 设置相邻索引列之间的间距。

  • LV_PART_SCROLLBAR 如果图表被缩放,则使用的滚动条。有关详细信息,请参阅 基础对象 的文档。

  • LV_PART_ITEMS 指代折线或柱状系列。

    • 折线图:线条属性用于线条。widthheightbg_colorradius 用于设置点的外观。

    • 柱状图:典型的背景属性用于样式化柱状图。pad_column 设置同一索引列之间的间距。

  • LV_PART_INDICATOR 指代折线图和散点图上的点(小圆圈或方块)。

  • LV_PART_CURSOR 线条属性用于样式化光标。widthheightbg_colorradius 用于设置点的外观。

  • LV_PART_TICKS 线条文本样式属性用于样式化刻度。

用法

图表类型

以下是数据展示类型:

  • LV_CHART_TYPE_NONE 不显示任何数据。可用于隐藏系列。

  • LV_CHART_TYPE_LINE 在数据点之间绘制线条,并/或在数据点上绘制点(矩形或圆形)。

  • LV_CHART_TYPE_BAR 绘制柱状图。

  • LV_CHART_TYPE_SCATTER 绘制 X/Y 图表,显示点和点之间的线条。

可以使用 lv_chart_set_type(chart, LV_CHART_TYPE_...) 指定展示类型。

数据系列

可以通过 lv_chart_add_series(chart, color, axis) 向图表添加任意数量的系列。这会分配一个 lv_chart_series_t 结构,其中包含所选的 color 和一个用于数据点的数组。 axis 可以具有以下值:

  • LV_CHART_AXIS_PRIMARY_Y 左轴

  • LV_CHART_AXIS_SECONDARY_Y 右轴

  • LV_CHART_AXIS_PRIMARY_X 底部轴

  • LV_CHART_AXIS_SECONDARY_X 顶部轴

axis 指定应使用哪个轴的范围来缩放值。

lv_chart_set_ext_y_array(chart, ser, value_array) 使图表对给定系列使用外部数组。 value_array 应如下所示:lv_coord_t * value_array[num_points]。数组大小需要足够大以容纳该系列的所有点。 数组的指针将保存在图表中,因此它需要是全局、静态或动态分配的。 注意:在更新外部数据源后,应调用 lv_chart_refresh(chart) 来更新图表。

可以使用 lv_chart_get_y_array(chart, ser) 获取系列的值数组,该数组可与 ext_array普通数组一起使用。

对于 LV_CHART_TYPE_SCATTER 类型,也可以使用 lv_chart_set_ext_x_array(chart, ser, value_array)lv_chart_get_x_array(chart, ser)

修改数据

有多种方法可以设置系列的数据:

  1. 在数组中手动设置值,例如 ser1->points[3] = 7,然后使用 lv_chart_refresh(chart) 刷新图表。

  2. 使用 lv_chart_set_value_by_id(chart, ser, id, value),其中 id 是要更新的点的索引。

  3. 使用 lv_chart_set_next_value(chart, ser, value)

  4. 使用 lv_chart_set_all_value(chart, ser, value) 将所有点初始化为给定值。

使用 LV_CHART_POINT_NONE 作为值可以使库跳过绘制该点、列或线段。

对于 LV_CHART_TYPE_SCATTER 类型,也可以使用 lv_chart_set_value_by_id2(chart, ser, id, value)lv_chart_set_next_value2(chart, ser, x_value, y_value)

更新模式

lv_chart_set_next_value 的行为取决于更新模式

  • LV_CHART_UPDATE_MODE_SHIFT 将旧数据向左移动,并将新数据添加到右侧。

  • LV_CHART_UPDATE_MODE_CIRCULAR 以循环方式添加新数据,例如心电图。

可以使用 lv_chart_set_update_mode(chart, LV_CHART_UPDATE_MODE_...) 更改更新模式。

点的数量

可以通过 lv_chart_set_point_count(chart, point_num) 修改系列中的点数。默认值为 10。 注意:这也会影响为系列分配外部缓冲区时处理的点数,因此需要确保外部数组足够大。

处理大量点

在折线图中,如果点的数量大于水平像素数,图表将仅绘制垂直线,以提高大量数据的绘制效率。 例如,如果每像素有 10 个点,LVGL 会搜索最小值和最大值,并在它们之间绘制垂直线,以确保不会遗漏峰值。

垂直范围

可以使用 lv_chart_set_range(chart, axis, min, max) 指定 y 方向的最小值和最大值。 axis 可以是 LV_CHART_AXIS_PRIMARY(左轴)或 LV_CHART_AXIS_SECONDARY(右轴)。

点的值将按比例缩放。默认范围为:0..100。

分割线

可以通过 lv_chart_set_div_line_count(chart, hdiv_num, vdiv_num) 修改水平和垂直分割线的数量。 默认设置为 3 条水平分割线和 5 条垂直分割线。 如果某一侧有可见边框且没有填充,则分割线会绘制在边框上,因此不会显示。

为系列设置默认起点

如果希望绘图从系列的默认起点 point[0] 以外的点开始,可以使用 lv_chart_set_x_start_point(chart, ser, id) 设置新的起点索引。

注意:LV_CHART_UPDATE_MODE_SHIFT 也会更改 start_point

刻度线和标签

可以使用 lv_chart_set_axis_tick(chart, axis, major_len, minor_len, major_cnt, minor_cnt, label_en, draw_size) 为轴添加刻度线和标签。

  • axis 可以是 LV_CHART_AXIS_X/PRIMARY_Y/SECONDARY_Y

  • major_len 是主刻度线的长度

  • minor_len 是次刻度线的长度

  • major_cnt 是轴上的主刻度线数量

  • minor_cnt 是两个主刻度线之间的次刻度线数量

  • label_entrue 时启用主刻度线上的标签绘制

  • draw_size 绘制刻度线和标签所需的额外大小(从 20 像素开始,如果刻度线/标签被裁剪则增加)

缩放

可以使用 lv_chart_set_zoom_x(chart, factor)lv_chart_set_zoom_y(chart, factor) 分别在 x 和 y 方向上缩放图表。 如果 factor 为 256,则没有缩放。512 表示双倍缩放,依此类推。不允许小于 256 的值。

光标

可以使用 lv_chart_cursor_t * c1 = lv_chart_add_cursor(chart, color, dir); 添加光标。 dir 的可能值为 LV_DIR_NONE/RIGHT/UP/LEFT/DOWN/HOR/VER/ALL 或它们的 OR 值,用于指定光标应绘制的方向。

lv_chart_set_cursor_pos(chart, cursor, &point) 设置光标的位置。 pos 是一个指向 lv_point_t 变量的指针。例如:lv_point_t point = {10, 20};。如果图表被滚动,光标将保持在同一位置。

lv_chart_get_point_pos_by_id(chart, series, id, &point_out) 获取给定点的坐标。这对于将光标放置在给定点非常有用。

lv_chart_set_cursor_point(chart, cursor, series, point_id) 将光标固定在某个点上。如果点的位置发生变化(新值或滚动),光标将随点移动。

事件

  • LV_EVENT_VALUE_CHANGED 当点击新点时发送。lv_chart_get_pressed_point(chart) 返回被点击点的从零开始的索引。

  • LV_EVENT_DRAW_PART_BEGINLV_EVENT_DRAW_PART_END 会针对以下类型发送:

    • LV_CHART_DRAW_PART_DIV_LINE_INIT 在绘制分割线之前/之后使用,用于为任何额外绘图添加遮罩。以下字段已设置:

      • part: LV_PART_MAIN

      • line_dsc

    • LV_CHART_DRAW_PART_DIV_LINE_HOR, LV_CHART_DRAW_PART_DIV_LINE_VER 用于每条水平和垂直分割线。

      • part: LV_PART_MAIN

      • id: 线的索引

      • p1, p2: 线的点

      • line_dsc

    • LV_CHART_DRAW_PART_LINE_AND_POINT 用于折线图和散点图的线条和点。

      • part: LV_PART_ITEMS

      • id: 点的索引

      • value: 第 id 个点的值

      • p1, p2: 线的点

      • draw_area: 点的区域

      • line_dsc

      • rect_dsc

      • sub_part_ptr: 指向系列的指针

    • LV_CHART_DRAW_PART_BAR 用于柱状图的矩形。

      • part: LV_PART_ITEMS

      • id: 点的索引

      • value: 第 id 个点的值

      • draw_area: 点的区域

      • rect_dsc

      • sub_part_ptr: 指向系列的指针

    • LV_CHART_DRAW_PART_CURSOR 用于光标线条和点。

      • part: LV_PART_CURSOR

      • p1, p2: 线的点

      • line_dsc

      • rect_dsc

      • draw_area: 点的区域

    • LV_CHART_DRAW_PART_TICK_LABEL 用于刻度线和标签。

      • part: LV_PART_TICKS

      • id: 轴

      • value: 刻度线的值

      • text: value 转换为十进制或次刻度线上的 NULL

      • line_dsc

      • label_dsc

也可以查看 基础对象 的事件。

了解更多关于事件的信息。

按键

图表对象不处理任何按键。

了解更多关于按键的信息。

示例

折线图

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


带有自定义分割线的渐变区域折线图

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)

带滚动的轴刻度和标签

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


显示按下点的值

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]


显示 1000 个数据点并支持缩放和滚动

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)


在点击点上显示光标

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()

散点图

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))

堆叠区域图

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

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)

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

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