fl_chart icon indicating copy to clipboard operation
fl_chart copied to clipboard

Line Chart SideTitles follow interval incorrectly

Open MatasRut opened this issue 2 years ago • 4 comments

The Max value of the axis titles does not follow the given interval by default which renders the built-in interval calculation useless in some cases.

For example with values [3.14, 5, 6.2, 8.2, 12, 12.2] on the Y axis and interval = 1 or default interval the middle titles will follow this interval but the baseline will be 3.14 and maxY value will be 12.2. I think it should be 3 and 13. I know as a workaround I could set the baseline and maxY value myself but if I'm using the default interval that is calculated under the hood there might be no way to know what should be the correct maxY value. Maybe there is currently a way to change this behavior that I don't know of?

I'm pretty sure this is due to the changes done to interval recently as I'm only facing this issue after upgrading FlChart from 0.40.6

Sample LineChart widget
 Chart();

 @override
 State<Chart> createState() => _ChartState();
}

class _ChartState extends State<Chart> {
 @override
 Widget build(BuildContext context) {
   return LineChart(
     LineChartData(
       borderData: FlBorderData(
         border: Border.all(
           color: Colors.white12,
           width: 1.0,
           style: BorderStyle.solid,
         ),
       ),
       titlesData: FlTitlesData(
         leftTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)),
         topTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)),
         rightTitles: AxisTitles(
           sideTitles: SideTitles(
               showTitles: true,
               reservedSize: 60,
               getTitlesWidget: (value, meta) {
                 return Container(
                   margin: const EdgeInsets.only(left: 10),
                   child: Text(value.toString()),
                 );
               }),
         ),
         bottomTitles: AxisTitles(
             sideTitles: SideTitles(
           showTitles: true,
           interval: 2,
           getTitlesWidget: (value, meta) {
             return Text(value.toString());
           },
         )),
       ),
       gridData: FlGridData(),
       lineBarsData: [
         LineChartBarData(
           barWidth: 2.5,
           isCurved: false,
           dotData: FlDotData(show: false),
           color: Colors.green,
           belowBarData: BarAreaData(
             show: true,
             gradient: LinearGradient(
               begin: Alignment.topCenter,
               end: Alignment.bottomCenter,
               colors: [
                 const Color(0xff19a629).withOpacity(0.5),
                 const Color(0xff19a629).withOpacity(0.05),
               ],
             ),
           ),
           spots: [
             FlSpot(1.0, 3.14),
             FlSpot(2.0, 5.28),
             FlSpot(3.0, 9.22),
             FlSpot(4.0, 12.3),
             FlSpot(5.0, 3.14),
           ],
         )
       ],
     ),
   );
 }
}

Screenshots image

Versions

  • Flutter: 2.10.3
  • FlChart: 0.50.1

MatasRut avatar May 04 '22 13:05 MatasRut

Is this related? https://github.com/imaNNeoFighT/fl_chart/issues/906

GitHelge avatar May 16 '22 14:05 GitHelge

It is related, however, no solution was provided. As a workaround, I could hide the min and max titles but the axis would look weird in my opinion. Would be nice if there was some way to get the titles to follow the interval completely (display nearest number in interval instead of min and max values).

MatasRut avatar May 16 '22 15:05 MatasRut

It is related, however, no solution was provided. As a workaround, I could hide the min and max titles but the axis would look weird in my opinion. Would be nice if there was some way to get the titles to follow the interval completely (display nearest number in interval instead of min and max values).

Here is a comment I posted in #906 that addresses this issue. Hiding the min and max titles would result to an undesired behavior because it could be that the max value aligns with the interval and therefore should be rendered. However, if you are hiding it then it will not be rendered.

Dnathan33 avatar May 20 '22 18:05 Dnathan33

Hi, guys. It's my first post, so please be patient. I have the same question.

I have some array of DateTime: FlSpot(1640988000000, 1), //2022/01/01 00:00 FlSpot(1640991600000, 2), //2022/01/01 01:00 FlSpot(1640995200000, 1), //2022/01/01 02:00 FlSpot(1640998800000, 2), //2022/01/01 03:00 FlSpot(1641002400000, 1), //2022/01/01 04:00 FlSpot(1641006000000, 2), //2022/01/01 05:00

And Interval: 3000000; // 50 minutes

Expected values and fact values is correct.

Expected values: 1640988000000.0 : 00:00 1640991000000.0 : 00:50 1640994000000.0 : 01:40 1640997000000.0 : 02:30 1641000000000.0 : 03:20 1641003000000.0 : 04:10 1641006000000.0 : 05:00

Fact values: [log] 1640988000000.0 : 00:00 [log] 1640991000000.0 : 00:50 [log] 1640994000000.0 : 01:40 [log] 1640997000000.0 : 02:30 [log] 1641000000000.0 : 03:20 [log] 1641003000000.0 : 04:10 [log] 1641006000000.0 : 05:00

But when array of DateTime is: FlSpot(1640995200000, 1), //2022/01/01 02:00 FlSpot(1640998800000, 2), //2022/01/01 03:00 FlSpot(1641002400000, 1), //2022/01/01 04:00 FlSpot(1641006000000, 2), //2022/01/01 05:00 FlSpot(1641009600000, 1), //2022/01/01 06:00 FlSpot(1641013200000, 2), //2022/01/01 07:00

And the same interval: 3000000; // 50 minutes

Expected values and fact values is not identical.

Expected values: 1640995200000.0 : 02:00 1640998200000.0 : 02:50 1641001200000.0 : 03:40 1641004200000.0 : 04:30 1641007200000.0 : 05:20 1641010200000.0 : 06:10 1641013200000.0 : 07:00

Fact values: [log] 1640995200000.0 : 02:00 [log] 1640997000000.0 : 02:30 <-- 30 minutes difference [log] 1641000000000.0 : 03:20 [log] 1641003000000.0 : 04:10 [log] 1641006000000.0 : 05:00 [log] 1641009000000.0 : 05:50 [log] 1641012000000.0 : 06:40 [log] 1641013200000.0 : 07:00 <-- 20 minutes difference

Could you please explain why value have incorrect interval?

Thank you so much.

Versions:

  • Flutter version 2.10.4
  • Dart version 2.16.2
  • fl_chart: 0.50.6
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:fl_chart/fl_chart.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'FL Chart Test',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: AppBar(),
      body: Column(
        children: [
          SizedBox(
            height: 300,
            child: Padding(
              padding: const EdgeInsets.all(24),
              child: LineChart(
                LineChartData(
                  lineBarsData: [
                    LineChartBarData(
                      spots: const [
                        // FlSpot(1640988000000, 1), //2022/01/01 00:00
                        // FlSpot(1640991600000, 2), //2022/01/01 01:00
                        FlSpot(1640995200000, 1), //2022/01/01 02:00
                        FlSpot(1640998800000, 2), //2022/01/01 03:00
                        FlSpot(1641002400000, 1), //2022/01/01 04:00
                        FlSpot(1641006000000, 2), //2022/01/01 05:00
                        FlSpot(1641009600000, 1), //2022/01/01 06:00
                        FlSpot(1641013200000, 2), //2022/01/01 07:00
                      ],
                    ),
                  ],
                  gridData: FlGridData(
                    show: false,
                  ),
                  titlesData: FlTitlesData(
                    leftTitles: AxisTitles(
                      sideTitles: SideTitles(
                        showTitles: false,
                      ),
                    ),
                    topTitles: AxisTitles(
                      sideTitles: SideTitles(
                        showTitles: false,
                      ),
                    ),
                    rightTitles: AxisTitles(
                      sideTitles: SideTitles(
                        showTitles: false,
                      ),
                    ),
                    bottomTitles: AxisTitles(
                      sideTitles: SideTitles(
                        showTitles: true,
                        interval: 3000000, // 50 minutes
                        getTitlesWidget: (double value, TitleMeta meta) {

                          String dateTimeString = DateFormat('HH:mm').format(DateTime.fromMillisecondsSinceEpoch(value.toInt()));
                          log('$value : $dateTimeString');

                          return Padding(
                            padding: const EdgeInsets.only(top: 8.0),
                            child: Text(dateTimeString),
                          );
                        },
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

ShBr2k avatar May 26 '22 18:05 ShBr2k

Can you please confirm that this issue still exists or not?

imaNNeo avatar Jan 30 '23 13:01 imaNNeo

I remember we solved this issue a while ago.

imaNNeo avatar Jan 30 '23 13:01 imaNNeo

I believe it is still not solved yet. The auto-defined maxY is still the highest value in the dataset instead of the next auto-defined interval just like the example from @MatasRut. More examples are below:

The appropriate maxY would be just the next interval 25%. The max value here is 20.6. Screenshot 2023-03-01 at 23 05 40

The next interval should be 250 instead of the max value 218. Screenshot 2023-03-01 at 23 05 49

I'm using the latest version 0.61.0.

tsungweihsu avatar Mar 01 '23 22:03 tsungweihsu

I believe it is still not solved yet. The auto-defined maxY is still the highest value in the dataset instead of the next auto-defined interval just like the example from @MatasRut. More examples are below:

What if you disable showing the max value?

BTW we have a duplicate issue here: #906. Please follow it. I am going to close this issue

imaNNeo avatar Mar 02 '23 06:03 imaNNeo