DEV Community

Cover image for Creating a Line Chart with Secondary Y-Axis in Flutter
Nithin
Nithin

Posted on

Creating a Line Chart with Secondary Y-Axis in Flutter

In this guide, we’ll explore how to create a line chart in Flutter with a secondary Y-axis for datasets that have different scales. By using fl_chart, we’ll develop a flexible charting solution that works for any generic data.

Why a Secondary Y-Axis?

Sometimes, two datasets that share an X-axis (e.g., timestamps) but have different Y-axis scales need to be visualized together. For example:

  • Primary Y-Axis: Represents Dataset A.

  • Secondary Y-Axis: Represents Dataset B (on a different scale).

Sample 1 represents single y axis. Sample 2 represents dual y-axis with scaling

Above image displays the need for secondary y-axis in certain scenarios. Sample 1 represents single y axis. Sample 2 represents dual y-axis with scaling

Step 1: Define the Data for the Chart

First, define two datasets that will be plotted on the chart. In our example, these datasets will represent different measurements that we wish to compare over time.

List<double> primaryData = [10, 20, 15, 30, 25];  // Dataset A
List<double> secondaryData = [50, 100, 75, 200, 150];  // Dataset B
List<String> xAxisLabels = ["Jan", "Feb", "Mar", "Apr", "May"];  // X-Axis labels (time, categories, etc.)
Enter fullscreen mode Exit fullscreen mode

Step 2: Create the Widget for the Chart

Now, create a new Flutter widget that will display the chart. We will use the LineChart widget from fl_chart.

2.1 Define the Widget Class

class DualAxisLineChart extends StatelessWidget {
  const DualAxisLineChart({
    super.key,
    required this.primaryData,
    required this.secondaryData,
    required this.xAxisLabels,
    required this.primaryColor,
    required this.secondaryColor,
    required this.scaleSecondaryData,
  });
Enter fullscreen mode Exit fullscreen mode

2.2 Define Chart Properties

primaryData and secondaryData: Lists of values for the primary and secondary data lines.
xAxisLabels: A list of X-axis labels (e.g., months or categories).
primaryColor and secondaryColor: Colors for the primary and secondary data lines.
scaleSecondaryData: A function to scale the secondary data to fit within the primary Y-axis.

2.3 Build the LineChart Widget

@override
Widget build(BuildContext context) {
  return Padding(
    padding: const EdgeInsets.all(16.0),
    child: LineChart(
      LineChartData(
        gridData: _buildGridData(),
        titlesData: _buildTitlesData(),
        lineBarsData: _buildLineBarsData(),
        borderData: FlBorderData(show: true),
      ),
    ),
  );
}
Enter fullscreen mode Exit fullscreen mode

2.4 Define Grid Data

Configure the grid lines using FlGridData. This section will make the chart's background grid visible. Modify as per requirement.

FlGridData _buildGridData() {
  return FlGridData(
    drawVerticalLine: false,
    getDrawingHorizontalLine: (_) => FlLine(
      color: Colors.grey[300]!,
      strokeWidth: 0.5,
    ),
  );
}
Enter fullscreen mode Exit fullscreen mode

2.5 Define Titles Data

Use FlTitlesData to configure the axis titles. You will define both left (primary Y-axis), right (secondary Y-axis), and bottom (X-axis) titles.

FlTitlesData _buildTitlesData() {
  return FlTitlesData(
    /// display underlying price on right side. utilise scaling to emulate second y-axis.
      rightTitles: AxisTitles(
          sideTitles: SideTitles(
              showTitles: true,
              getTitlesWidget: (double value, TitleMeta meta) {
                final int tentativeIndex =
                    ((meta.axisPosition / meta.parentAxisSize) * secondaryData.length)
                        .toInt();
                final int index = tentativeIndex.clamp(0, secondaryData.length - 1);
                return Text(
                  text: // TODO: format text and set,
                );
              })),
    /// empty top axis
    topTitles: const AxisTitles(),
    // TODO: define other title here similarly
  );
}
Enter fullscreen mode Exit fullscreen mode

2.6 Define Line Data for Both Axes

The lineBarsData section defines the lines for both datasets. We will use LineChartBarData to create a line for each dataset. Utilise FlDotData to specify points on the graph to draw the line through.

List<LineChartBarData> _buildLineBarsData() {
  return [
      LineChartBarData(
        color: primaryColor,
        barWidth: barWidth.r,
        dotData: const FlDotData(show: false),
        spots: primaryData.mapIndexed((int index, double value) {
          return FlSpot(index.toDouble(), value);
        }).toList(),
      ),
      LineChartBarData(
        color: secondaryColor,
        barWidth: barWidth.r,
        dotData: const FlDotData(show: false),
        spots: secondaryData.mapIndexed((int index, double value) {
          return FlSpot(index.toDouble(), scaleSecondaryData(value));
        }).toList(),
        dashArray: <int>[5, 5],
      )
  ];
}
Enter fullscreen mode Exit fullscreen mode
  • For each dataset, the LineChartBarData defines how the line is drawn.
  • scaleSecondaryData: A function that scales the data to fit the chart’s axis.
  • dashArray: this will render the secondary line as dashed specifying width and gap.

Step 3: Define a Scaling Function for the Secondary Data

To ensure the secondary dataset fits within the scale of the primary Y-axis, we need to create a scaling function. This function will adjust the secondary data to match the range of the primary data.

double scaleSecondaryData(double value) {
  double primaryMin = 10;
  double primaryMax = 30;
  double secondaryMin = 50;
  double secondaryMax = 200;

  double primaryRange = primaryMax - primaryMin;
  double secondaryRange = secondaryMax - secondaryMin;

  return primaryMin + (value - secondaryMin) * (primaryRange / secondaryRange);
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Create the Widget to Display the Chart

Now, we will create a MaterialApp widget and add the chart widget to the screen.

void main() {
  runApp(MaterialApp(
    home: Scaffold(
      appBar: AppBar(title: Text("Dual Axis Line Chart")),
      body: DualAxisLineChart(
        primaryData: [10, 20, 15, 30, 25], // Example Dataset A
        secondaryData: [50, 100, 75, 200, 150], // Example Dataset B
        xAxisLabels: ["Jan", "Feb", "Mar", "Apr", "May"], // Example X-axis
        primaryColor: Colors.blue,
        secondaryColor: Colors.red,
        scaleSecondaryData: scaleSecondaryData,
      ),
    ),
  ));
}
Enter fullscreen mode Exit fullscreen mode

Step 5: Run the Application

After implementing the above code, run your Flutter app, and you should see a line chart with two Y-axes. The primary data will be on the left Y-axis, while the secondary data will be scaled to fit the primary Y-axis and shown on the right.

Conclusion

You have now successfully created a line chart in Flutter with a secondary Y-axis! This approach can be used to compare two datasets with different ranges, such as temperatures and rainfall, stock prices and trading volume, or any other comparable metrics.

Feel free to adjust the styling, scaling, and data to suit your specific use case. The fl_chart package provides a lot of flexibility to customize your chart to your needs.

Links

fl_chart widgets
Pub Package

Top comments (0)