Hacer un gráfico de líneas (Line Chart) en Flutter


Avatar de Pedro Cortez

Ahora que hemos implementado syncfusion_flutter_charts, veamos cómo hacer nuestro primer gráfico, con un Line Chart, o Gráfico de líneas en francés.


¿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.

Asegúrate previamente de haber configurado correctamente syncfusion_flutter_charts añadiendo su dependencia en tu archivo pubspec.yaml.

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.

¿Por qué crear una clase SalesData?

Esta clase no es un widget, pero estructura los datos. Podrías usar una simple lista de mapas (por ejemplo: {‘year’: 2020, ‘sales’: 35}), pero una clase hace que el código sea más claro.

¿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;
}

Si tus series tienen escalas muy diferentes (por ejemplo: una en miles, la otra en unidades), puedes agregar un segundo eje Y adicional.

¿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;
}

El color se aplica al enlace entre el punto que has definido y el siguiente. Por ejemplo, si pones tu primer punto en rojo, será la línea entre este y el segundo punto la que aparecerá en rojo.

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)

El valor mostrado es el de tu eje de abscisas. En el ejemplo que muestro aquí, hablamos entonces de las ventas.

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:

TipoDatos adaptadosEjemplo de uso
NumericAxisNúmeros continuosAños, cantidades
CategoryAxisCategorías textualesMeses, nombres de productos
DateTimeAxisFechas/horas continuasVentas por día
DateTimeCategoryAxisFechas discretasPrimeros días de los meses
LogarithmicAxisDatos exponencialesCrecimiento 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,
(
),

Avatar de Pedro Cortez