¿Para qué sirve un gráfico de líneas?
Los gráficos de líneas son ideales para visualizar tendencias continuas o evoluciones en el tiempo. Permiten seguir datos que cambian progresivamente, como temperaturas diarias, ventas mensuales o rendimientos deportivos durante una temporada. Son fáciles de entender, lo que los convierte en herramientas perfectas para:
- Mostrar progresiones o regresiones (por ejemplo: ingresos anuales).
- Comparar varias series de datos en un mismo eje (por ejemplo: temperaturas de varias ciudades).
- Identificar picos o caídas en datos continuos (por ejemplo: tráfico de red).
Crear un Line Chart básico
Aquí tienes un ejemplo simple para mostrar datos de ventas anuales.
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_charts/charts.dart'; // Importa el paquete Syncfusion para los gráficos
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Gráfico de líneas básico')),
body: Center(
// SfCartesianChart es el widget principal de Syncfusion para los gráficos cartesianos
// Es INDISPENSABLE para crear un gráfico (líneas, columnas, etc.)
child: SfCartesianChart(
// primaryXAxis define el eje horizontal (X). Es INDISPENSABLE para indicar el tipo de datos en este eje
// NumericAxis se usa aquí porque los datos del eje X (años) son numéricos
primaryXAxis: NumericAxis(),
// series es una lista de series de datos a mostrar. INDISPENSABLE para cualquier gráfico
// Aquí usamos LineSeries para un gráfico de líneas
series: <LineSeries<SalesData, double>>[
// LineSeries es el tipo de serie específico para un gráfico de líneas
LineSeries<SalesData, double>(
// dataSource contiene los datos brutos a mostrar. INDISPENSABLE para proporcionar los puntos del gráfico
dataSource: [
SalesData(2020, 35), // Cada objeto representa un punto (x, y)
SalesData(2021, 28),
SalesData(2022, 34),
SalesData(2023, 32),
SalesData(2024, 40),
],
// xValueMapper mapea cada punto de datos a un valor en el eje X
// INDISPENSABLE para decirle al gráfico qué poner en el eje horizontal
// Aquí tomamos el atributo 'year' de SalesData
xValueMapper: (SalesData sales, _) => sales.year,
// yValueMapper mapea cada punto de datos a un valor en el eje Y
// INDISPENSABLE para decirle al gráfico qué poner en el eje vertical
// Aquí tomamos el atributo 'sales' de SalesData
yValueMapper: (SalesData sales, _) => sales.sales,
),
],
),
),
),
);
}
}
// Clase para estructurar los datos del gráfico
// No es un widget, pero es INDISPENSABLE para organizar los datos pasados a dataSource
class SalesData {
// Constructor que inicializa las propiedades year y sales
SalesData(this.year, this.sales);
// 'year' representa el valor en el eje X (aquí, un año)
final double year;
// 'sales' representa el valor en el eje Y (aquí, una cantidad de ventas)
final double sales;
}
Estos son los elementos indispensables para hacer un gráfico de líneas simple en Flutter:
- SfCartesianChart: El contenedor principal para cualquier gráfico cartesiano (líneas, barras, etc.).
- primaryXAxis: Define el eje horizontal. Sin esto, el gráfico no sabe cómo interpretar los datos X.
- series: La lista de series a mostrar. Sin series, no hay nada que dibujar.
- LineSeries: Especifica que queremos un gráfico de líneas.
- dataSource: Los datos brutos (lista de objetos).
- xValueMapper y yValueMapper: Conectan los datos a los ejes X e Y.
¿Cómo agregar varias líneas al gráfico?
Un gráfico de líneas se vuelve aún más potente cuando muestra varias series de datos para comparar tendencias. Con syncfusion_flutter_charts, basta con agregar varias LineSeries a la lista series de SfCartesianChart. Cada serie puede tener sus propios datos, colores, marcadores y leyendas. Aquí te explico cómo hacerlo.
A continuación, un ejemplo donde mi clase SalesData contiene dos listas de datos a presentar:
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
final TooltipBehavior _tooltip = TooltipBehavior(enable: true);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Gráfico de líneas con varias líneas')),
body: SfCartesianChart(
title: ChartTitle(text: 'Ventas por región (2025)'),
legend: Legend(
isVisible: true), // Activa la leyenda para identificar las líneas
tooltipBehavior: _tooltip,
primaryXAxis: CategoryAxis(
title: AxisTitle(text: 'Mes'),
),
primaryYAxis: NumericAxis(
title: AxisTitle(text: 'Ventas (k€)'),
minimum: 20,
maximum: 50,
),
series: <LineSeries<SalesData, String>>[
// Primera línea: Región A
LineSeries<SalesData, String>(
name: 'Región A', // Nombre para la leyenda
dataSource: [
SalesData('Ene', 35),
SalesData('Feb', 28),
SalesData('Mar', 34),
SalesData('Abr', 32),
SalesData('May', 40),
],
xValueMapper: (SalesData sales, _) => sales.month,
yValueMapper: (SalesData sales, _) => sales.sales,
color: Colors.blue, // Color de la línea
markerSettings: MarkerSettings(
isVisible: true,
shape: DataMarkerType.circle,
width: 6,
height: 6,
color: Colors.blue,
),
),
// Segunda línea: Región B
LineSeries<SalesData, String>(
name: 'Región B', // Nombre para la leyenda
dataSource: [
SalesData('Ene', 25),
SalesData('Feb', 30),
SalesData('Mar', 27),
SalesData('Abr', 35),
SalesData('May', 38),
],
xValueMapper: (SalesData sales, _) => sales.month,
yValueMapper: (SalesData sales, _) => sales.sales,
color: Colors.red, // Color diferente para distinguir
markerSettings: MarkerSettings(
isVisible: true,
shape: DataMarkerType.triangle,
width: 6,
height: 6,
color: Colors.red,
),
),
],
),
),
);
}
}
class SalesData {
SalesData(this.month, this.sales);
final String month;
final double sales;
}
¿Cómo personalizar tu gráfico de líneas?
Saber cómo hacer un gráfico de líneas en Flutter ya es un buen comienzo, pero ahora veamos cómo personalizarlo según tus necesidades.
Cambiar la apariencia de la línea
Puedes modificar el color, el grosor y la transparencia de la línea ajustando las siguientes propiedades:
- color: Define el color de la línea.
- width: Ajusta el grosor.
- opacity: Controla la transparencia de la línea (valor entre 0 y 1).
LineSeries<SalesData, String>(
dataSource: /* ... */,
xValueMapper: (SalesData sales, _) => sales.month,
yValueMapper: (SalesData sales, _) => sales.sales,
color: Colors.blueAccent, // Línea de color azul
width: 3.0, // Grosor de 3 píxeles
opacity: 0.8, // Ligeramente transparente
),
Hacer una línea de puntos (Dashed line)
Utiliza dashArray para crear una línea de puntos. Los valores alternan entre la longitud de los segmentos y los espacios (por ejemplo: [5, 5] = 5 unidades llenas, 5 unidades vacías).
LineSeries<SalesData, String>(
dataSource: /* ... */,
xValueMapper: (SalesData sales, _) => sales.month,
yValueMapper: (SalesData sales, _) => sales.sales,
dashArray: [5, 5], // Puntos regulares
),
Hacer una línea multicolor
Con pointColorMapper, cada segmento puede tener un color diferente basado en tus datos.
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Gráfico Syncfusion')),
body: Center(
child: SfCartesianChart(
primaryXAxis: CategoryAxis(),
title: ChartTitle(text: 'Ventas mensuales 2025'),
series: <CartesianSeries>[
LineSeries<SalesData, String>(
dataSource: [
SalesData('Ene', 35, Colors.red),
SalesData('Feb', 28, Colors.green),
SalesData('Mar', 34, Colors.blue),
SalesData('Abr', 32, Colors.yellow),
SalesData('May', 40, Colors.black)
],
pointColorMapper: (SalesData data, _) => data.color,
xValueMapper: (SalesData data, _) => data.year,
yValueMapper: (SalesData data, _) => data.sales)
],
),
),
),
);
}
}
class SalesData {
SalesData(this.year, this.sales, this.color);
final String year;
final double sales;
final Color color;
}
Agregar marcadores en los puntos
Las markerSettings permiten mostrar marcadores (círculos, cuadrados, etc.) en cada punto de datos:
- isVisible: Activa los marcadores.
- shape: Forma (círculo, rectángulo, diamante, etc.).
- size: Tamaño del marcador.
- color: Color.
LineSeries<SalesData, String>(
dataSource: /* ... */,
markerSettings: MarkerSettings(
isVisible: true,
shape: DataMarkerType.circle,
width: 6,
height: 6,
color: Colors.red,
),
xValueMapper: (SalesData data, _) => data.year,
yValueMapper: (SalesData data, _) => data.sales)
Aquí está la lista de los diferentes marcadores disponibles:
- DataMarkerType.circle: Un marcador redondo clásico.
- DataMarkerType.rectangle: Un marcador cuadrado o rectangular según los valores de width y height.
- DataMarkerType.triangle: Un marcador en forma de triángulo apuntando hacia arriba.
- DataMarkerType.invertedTriangle: Un triángulo apuntando hacia abajo.
- DataMarkerType.diamond: Un marcador en forma de rombo.
- DataMarkerType.pentagon: Un marcador de cinco lados.
- DataMarkerType.verticalLine: Una pequeña línea vertical centrada en el punto.
- DataMarkerType.horizontalLine: Una pequeña línea horizontal centrada en el punto.
Mostrar etiquetas de datos
Con dataLabelSettings, agrega valores directamente en el gráfico:
- isVisible: Activa las etiquetas.
- labelAlignment: Posición (arriba, abajo, etc.).
- textStyle: Estilo del texto.
LineSeries<SalesData, String>(
dataSource: [
SalesData('Ene', 35, Colors.red),
SalesData('Feb', 28, Colors.green),
SalesData('Mar', 34, Colors.blue),
SalesData('Abr', 32, Colors.yellow),
SalesData('May', 40, Colors.black)
],
dataLabelSettings: DataLabelSettings(
isVisible: true,
labelAlignment: ChartDataLabelAlignment.top,
textStyle: TextStyle(fontSize: 12, color: Colors.black),
),
pointColorMapper: (SalesData data, _) => data.color,
xValueMapper: (SalesData data, _) => data.year,
yValueMapper: (SalesData data, _) => data.sales)
Personalizar tus ejes
Los ejes pueden ajustarse para mejorar la legibilidad:
- primaryXAxis: Eje X (por ejemplo: NumericAxis, CategoryAxis).
- primaryYAxis: Eje Y.
- Opciones: título, intervalos, formato.
SfCartesianChart(
primaryXAxis: NumericAxis(
title: AxisTitle(text: 'Años'), // Título mostrado bajo el eje X
interval: 1, // Una marca cada 1 año (2020, 2021, etc.)
),
primaryYAxis: NumericAxis(
title: AxisTitle(
text: 'Ventas'), // Título mostrado a la izquierda del eje Y
minimum: 20, // Valor mínimo de las ventas
maximum: 50, // Valor máximo de las ventas
interval: 5, // Una marca cada 5 unidades (20, 25, 30, etc.)
),
title: ChartTitle(text: 'Ventas mensuales 2025'),
series: /* ... */,
)
Cuidado, las posibilidades de personalización no son las mismas según el tipo de eje. Aquí están las diferentes variantes que puedes usar:
Tipo | Datos adaptados | Ejemplo de uso |
---|---|---|
NumericAxis | Números continuos | Años, cantidades |
CategoryAxis | Categorías textuales | Meses, nombres de productos |
DateTimeAxis | Fechas/horas continuas | Ventas por día |
DateTimeCategoryAxis | Fechas discretas | Primeros días de los meses |
LogarithmicAxis | Datos exponenciales | Crecimiento logarítmico |
Agregar un eje Y adicional
Cuando tus líneas representan datos con unidades o escalas diferentes (por ejemplo: ventas en k€ y tasa de crecimiento en %), un solo eje Y puede hacer que el gráfico sea ilegible. Con la propiedad axes de SfCartesianChart, puedes agregar un segundo eje de ordenadas (o más), y luego asociarlo a una serie mediante yAxisName.
Aquí tienes un ejemplo donde una línea muestra las ventas (k€) y otra la tasa de crecimiento (%):
SfCartesianChart(
primaryXAxis: CategoryAxis(
title: AxisTitle(text: 'Mes'),
),
primaryYAxis: NumericAxis(
title: AxisTitle(text: 'Ventas (k€)'),
minimum: 20,
maximum: 50,
),
axes: <ChartAxis>[
// Agrega los ejes adicionales
NumericAxis(
name: 'secondYAxis', // Nombre único para este eje
title: AxisTitle(text: 'Tasa de crecimiento (%)'),
minimum: 0,
maximum: 10,
opposedPosition: true, // Coloca el eje a la derecha
),
],
legend: Legend(isVisible: true),
series: <LineSeries<SalesData, String>>[
LineSeries<SalesData, String>(
name: 'Ventas',
dataSource: [
SalesData('Ene', 35, Colors.blue),
SalesData('Feb', 28, Colors.blue),
SalesData('Mar', 34, Colors.blue),
],
xValueMapper: (SalesData sales, _) => sales.month,
yValueMapper: (SalesData sales, _) => sales.sales,
color: Colors.blue,
),
LineSeries<SalesData, String>(
name: 'Crecimiento',
yAxisName: 'secondYAxis', // Asocia esta serie al segundo eje
dataSource: [
SalesData('Ene', 5.2, Colors.red),
SalesData('Feb', 3.8, Colors.red),
SalesData('Mar', 6.1, Colors.red),
],
xValueMapper: (SalesData sales, _) => sales.month,
yValueMapper: (SalesData sales, _) => sales.sales,
color: Colors.red,
),
],
)
Agregar un título y una leyenda
También es posible añadir un título y una leyenda a tu gráfico de líneas para mejorar su comprensión.
- title: Título del gráfico.
- legend: Leyenda para identificar las series.
SfCartesianChart(
title: ChartTitle(text: 'Evolución de las ventas anuales'),
legend: Legend(isVisible: true),
series: /* ... */,
),
Permitir interacciones con el gráfico
Añade funcionalidades interactivas:
- tooltipBehavior: Muestra información emergente al pasar el cursor.
- trackballBehavior: Línea vertical que sigue el cursor.
Modificar la duración de la animación
Por último, puedes gestionar la duración de la animación de entrada con animationDuration (en milisegundos):
LineSeries<SalesData, double>(
dataSource: /* ... */,
xValueMapper: (SalesData sales, _) => sales.year,
yValueMapper: (SalesData sales, _) => sales.sales,
(
),