Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Line Chart Overlap and Repeat Points by Loading Data from Future #986

Open
MALLORY8K opened this issue May 1, 2022 · 11 comments
Open

Line Chart Overlap and Repeat Points by Loading Data from Future #986

MALLORY8K opened this issue May 1, 2022 · 11 comments

Comments

@MALLORY8K
Copy link

Hello, I have a problem the chart repeats itself and overlaps random by Hot Reload my App

here you can see what i mean
https://imgur.com/a/xGct2NN

I load Data from Sqflite and add to my list, here is my Code

 builder() {
    return FutureBuilder<List<Note>>(
        future: myFuture,
        builder: (context, snapshot) {
          return snapshot.hasData
              ? ListView.builder(
                  shrinkWrap: true,
                  itemCount: snapshot.data!.length,
                  itemBuilder: (BuildContext context, int i) {
                    return adder(
                      snapshot.data![i],
                      snapshot.data!.length,
                    );
                  },
                )
              : const SizedBox.shrink();
        });
  }
adder(Note note, int index) {
    double steps = 12 / (index - 1);
  
      mySpots.add(FlSpot(points, note.value));
      points = points + steps;

    return const SizedBox.shrink();
  }
════════ Exception caught by rendering library ═════════════════════════════════
LateInitializationError: Field 'mostLeftSpot' has not been initialized.
The relevant error-causing widget was
LineChart
@imaNNeo
Copy link
Owner

imaNNeo commented May 18, 2022

Please provide me a reproducible code in a main.dart file.

@aqoong
Copy link

aqoong commented Jun 7, 2022

I have the same issue.
I think it's an issue that emerges when try to draw real-time.
I want to change the mostLeftSpot to an option.

@imaNNeo
Copy link
Owner

imaNNeo commented Jun 10, 2022

@aqoong Any reproducible code?

@aqoong
Copy link

aqoong commented Jun 11, 2022

This is my draw widget.
I'm drawing signals in real time using Bluetooth.
The signal is a List<double?> type.
In 0.50.0 and above, the data must be full to be visible.

import 'dart:async';
import 'dart:collection';
import 'dart:math';

import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';

class SignalDrawWidget extends StatefulWidget {
  final double height;


  SignalDrawWidget(
      {Key? key,
      required this.height})
      : super(key: key) {
  }

  @override
  State<SignalDrawWidget> createState() => _SignalDrawWidgetState();
}

class _SignalDrawWidgetState extends State<SignalDrawWidget>
    with TickerProviderStateMixin {
  final int maxLength = 250 * 5;
  
  Queue<double?> dataContainer = Queue();

  late List<FlSpot> chartSpots = List.generate(maxLength, (_) => FlSpot.nullSpot);

  int curDrawIndex = 0;

  late AnimationController animationController;

  @override
  void initState() {
    super.initState();
    animationController = AnimationController(
      vsync: this,
      upperBound: maxLength.toDouble(),
      lowerBound: 0,
      duration: Duration(
          milliseconds:
              ((maxLength / 250) * 1000)
                  .toInt()),
    );
    Timer.periodic(const Duration(milliseconds: 1), (_) {
      final random = Random();

      dataContainer.add(random.nextDouble() * 6);
    });


    _setAnimation();

    startDraw();
  }

  @override
  void dispose() {
    try {
      stopDraw();
    } catch (e) {}
    super.dispose();
  }

  void _setAnimation() => animationController.addListener(() {
        final curAnimationValue = animationController.value.toInt();

        if (curAnimationValue < maxLength) {
            _createSpots(curAnimationValue);
        } else {
          //Data full. animation restart
          chartSpots = List.generate(maxLength, (_) => FlSpot.nullSpot);
          curDrawIndex = 0;

          if (animationController != null) {
            animationController.reset();
            startDraw();
          } else {
            stopDraw();
          }
        }
      });

  void _createSpots(int currentAnimationValue) {
    final queue = dataContainer;
    for (int i = curDrawIndex; i < currentAnimationValue; i++) {
      if (queue.isEmpty) {
        chartSpots[i] = FlSpot.nullSpot;
      } else {
        double? value = queue.removeFirst();

        chartSpots[i] =
            (value != null) ? FlSpot(i.toDouble(), value) : FlSpot.nullSpot;
      }
    }
    curDrawIndex = currentAnimationValue;
  }

  void startDraw() {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      animationController.forward(from: 0.0);
      setState(() {});
    });
  }

  void stopDraw() => animationController.stop(canceled: true);

  @override
  Widget build(BuildContext context) => Container(
    width: double.infinity.w,
    height: double.infinity.h,
    child: _buildCenterSignalChart(maxX: maxLength.toDouble()),
  );

  Widget _buildCenterSignalChart(
          {
          required double maxX}) =>
      Center(
        child: _chart(maxX, maxY: 6, minY: -6),
      );

  Widget _chart(double maxX, {double? maxY, double? minY}) => LineChart(LineChartData(
          titlesData: FlTitlesData(show: false),
          lineTouchData: LineTouchData(enabled: false),
          gridData: FlGridData(show: false),
          borderData: FlBorderData(show: false),
          maxY: maxY ?? 1.5,
          minY: minY ?? -0.5,
          maxX: maxX,
          minX: 0,
          lineBarsData: [
            LineChartBarData(
              dotData: FlDotData(show: false),
              color: Colors.black,
              barWidth: 1,
              spots: chartSpots,
            )
          ]));
}

@Carl-CWX
Copy link

Carl-CWX commented Jun 23, 2022

Live update a LineChart by adding data to the spot list worked fine pre 0.50.0 but I now get an exception repeatedly, Once I stop updating it the chart appears..

════════ Exception caught by rendering library ═════════════════════════════════
The following LateError was thrown during paint():
LateInitializationError: Field 'mostLeftSpot' has not been initialized.

The relevant error-causing widget was
LineChart
lib\…\record\record_page.dart:174
When the exception was thrown, this was the stack
#0 LineChartBarData.mostLeftSpot (package:fl_chart/src/chart/line_chart/line_chart_data.dart)
package:fl_chart/…/line_chart/line_chart_data.dart:1
#1 LineChartPainter.drawBar
package:fl_chart/…/line_chart/line_chart_painter.dart:842
#2 LineChartPainter.drawBarLine
package:fl_chart/…/line_chart/line_chart_painter.dart:231
#3 LineChartPainter.paint
package:fl_chart/…/line_chart/line_chart_painter.dart:106
#4 RenderLineChart.paint

@AmanMasipeddi
Copy link

I am also seeing this issue now.

@cw-JihunCha
Copy link

cw-JihunCha commented Jul 27, 2022

Is there any solution??

@jimmyhappy19920308
Copy link

jimmyhappy19920308 commented Aug 21, 2022

I find if no initialization LineChartBarData's spots will get this error.

but some times data source is dynamic.

@mzakharo
Copy link

Please see a reproducible example below. The mostLeftSpot issue occurs when spots array is initially empty, and then one more value is added to the spots list (during live plotting). One way to workaround the error is by toggling show field in LineChartBarData after the first valid sample is received.

import 'package:flutter/material.dart';
import 'package:fl_chart/fl_chart.dart';
import 'dart:async';

void main() {
  runApp(const MyApp());
}
class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: const MyHomePage(),
    );
  }
}
class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
  List<FlSpot> points = [];
  bool show_me = true; //initialize to false to  workaround mostLeftSpot error
  @override
  void initState() {
    super.initState();
    Timer(const Duration(milliseconds: 1000), () {
      setState(() {
        points.add(FlSpot(5, 5));
        show_me = true;
      });
    });   
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: LineChart(
        swapAnimationDuration: const Duration(milliseconds: 0),
        LineChartData(
          minY: 0,
          minX: 0,
          maxY: 10,
          maxX: 10,
          lineBarsData: [
            LineChartBarData(
              spots: points,
              show : show_me,
              dotData: FlDotData(
                show: true,
              ),
            ),         
          ],
        ),
      ),
    );
  }
}

@Shunt22
Copy link

Shunt22 commented Oct 18, 2022

Another workaround which works for me. Set your points list to new one in setState
My goal was to replace all points entierly.

class MyChart extends StatefulWidget {
  List<FlSpot> points = [];

  MyChart({super.key});

  @override
  State<MyChart> createState() => MyChartState();
}

class MyChartState extends State<MyChart> {
  @override
  Widget build(BuildContext context) {
    return LineChart(
      LineChartData(
          minX: 0,
          maxX: 10,
          minY: 0,
          maxY: 100,
          lineBarsData: [LineChartBarData(spots: widget.points)]),
    );
  }

  void changePoints(List<FlSpot> newPoints) {
    setState(() {
      widget.points = newPoints;
    });
  }
}

I have my MyChartState without _ so I can access changePoints from another widget by key.

@PrinceGoyal
Copy link

PrinceGoyal commented Jun 22, 2023

Just add show property at LineChartBarData, this will remove your exception

LineChartBarData(
          show: spotsList.isNotEmpty, // do not show LineChartBarData when spotsList his empty, make sure spotsList is not null
          spots: spotsList
   )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

10 participants