How to fix an error and memory leak with dynamic LineChart

35 Views Asked by At

I'm trying to create a dynamically changing graph that reflects the latest values. However, I am getting an error message and a memory leaks, and I don't know the cause. Could you please let me know if you know the cause?

Error Message:

[ERROR:flutter/flow/layers/transform_layer.cc(23)] TransformLayer is constructed with an invalid matrix.

Memory leaks
Memory leaks were confirmed using the top command. flet memory increased over time.

My code is below:

import flet as ft
import schedule
import time
import random

vx_val = [0]*1000 # 10ms*100*1000=1000s
vx_time = [round(i*0.1,1) for i in range(-1000+1, 0+1, 1)] # 10ms*100*1000=1000s

time_start = time.perf_counter()
elapsed_time = time.perf_counter() - time_start

class GuiViewer_graph(ft.UserControl):

    ref_vx_linechartdata = ft.Ref[ft.LineChartData]()

    def __init__(self):
        super().__init__()

    def build(self):
        
        chart_vx = ft.LineChartData(
            data_points=[],
            stroke_width=5,
            color=ft.colors.BLUE,
            curved=False,
            stroke_cap_round=True,
            ref=self.ref_vx_linechartdata,
        )
        
        for i in range(0, len(vx_val)):
            chart_vx.data_points.append(
                ft.LineChartDataPoint(x=vx_time[i], y=vx_val[i])
            )
        
        vx_graph=ft.LineChart(
            data_series=[
                chart_vx,
            ],
            border=ft.border.all(3, ft.colors.with_opacity(0.2, ft.colors.ON_SURFACE)),
            horizontal_grid_lines=ft.ChartGridLines(
                interval=20, color=ft.colors.with_opacity(0.2, ft.colors.ON_SURFACE), width=1
            ),
            # vertical_grid_lines=ft.ChartGridLines(
            #     interval=10, color=ft.colors.with_opacity(0.2, ft.colors.ON_SURFACE), width=1
            # ),
            left_axis=ft.ChartAxis(
                title=ft.Text('velocity[km/h]', weight=ft.FontWeight.BOLD),
                labels_size=40,
                labels_interval=20,
            ),
            bottom_axis = ft.ChartAxis(
                title=ft.Text('time[sec]', weight=ft.FontWeight.BOLD),
                labels_size=40,
                labels_interval=10,
            ),
            min_y=0,
            max_y=180,
            interactive=True,
            animate=True,
            #expand=True,
        )

        table = ft.Container(
            content=ft.Column(
                scroll=True,
                controls=[
                    # speed graph,
                    ft.Container(
                        content=ft.Column(
                            horizontal_alignment = ft.CrossAxisAlignment.CENTER,
                            controls=[
                                ft.Text('Speed', size=20, weight=ft.FontWeight.BOLD),
                                vx_graph,
                            ],
                        ),
                        margin=30,
                        expand=True,
                    ),
                ],
                #expand=True,
            ),
        )
        
        return table
    
    def update(self):
        self.control.update()

def gui(page: ft.Page):
    page.title = "Viewer"
    page.horizontal_alignment = ft.CrossAxisAlignment.CENTER

    main_window = ft.Container(
        content=GuiViewer_graph()
    )

    page.add(main_window)
    page.update()

    def gui_update(page):
            
            global time_start, elapsed_time, vx_val, vx_time

            # Elapsed Time calc
            elapsed_time = time.perf_counter() - time_start

            # graph data update
            vx_current = random.uniform(0, 160)
            vx_val[0:-1] = vx_val[1:]
            vx_val[-1] = vx_current
            vx_time[0:-1] = vx_time[1:]
            vx_time[-1] = elapsed_time

            for i in range(0,len(vx_val)):
                # Memory leak point !!
                GuiViewer_graph.ref_vx_linechartdata.current.data_points[i] = ft.LineChartDataPoint(x=vx_time[i], y=vx_val[i])
            
            GuiViewer_graph.ref_vx_linechartdata.current.update()

 

    # Sceduler
    every_second=0.1
    schedule.every(every_second).seconds.do(gui_update,page=page)

    while True:
        schedule.run_pending()
        time.sleep(0.1)

if __name__ == '__main__':
    ft.app(target=gui)
1

There are 1 best solutions below

1
ADITYA On

Instead of updating each data point individually in the loop, you can clear and update the entire data list at once. Make sure to properly manage references to avoid memory leaks.

def gui_update(page):
    global time_start, elapsed_time, vx_val, vx_time

    # Elapsed Time calc
    elapsed_time = time.perf_counter() - time_start

    # graph data update
    vx_current = random.uniform(0, 160)
    vx_val = vx_val[1:] + [vx_current]
    vx_time = vx_time[1:] + [elapsed_time]

    # Update chart data
    chart_data = GuiViewer_graph.ref_vx_linechartdata.current
    chart_data.data_points = [ft.LineChartDataPoint(x=x, y=y) for x, y in zip(vx_time, vx_val)]
    chart_data.update()