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).
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.)
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,
});
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),
),
),
);
}
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,
),
);
}
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
);
}
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],
)
];
}
- 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);
}
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,
),
),
));
}
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.
Top comments (0)