or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

api

features

charts

charts.mdconditional-formatting.mdvisualizations.md
authorization.mdchangesets.mdcharts-as-code.mdcompiler.mddashboards.mddbt.mdee-features.mdformatting.mdparameters.mdpivot.mdprojects-spaces.mdsql-runner.mdtemplating.mdwarehouse.md
index.md
tile.json

visualization.mddocs/guides/

Visualization Guide

This guide shows you how to create charts and visualizations from query results using Lightdash data models. For detailed API documentation, see Charts API.

Overview

Lightdash provides data models that transform query results into ECharts configurations for visualization:

  • CartesianChartDataModel - Bar, line, area, scatter charts
  • PieChartDataModel - Pie and donut charts
  • TableDataModel - Data tables

Cartesian Charts

Cartesian charts display data on X and Y axes (bar, line, area, scatter).

Basic Bar Chart

import {
  CartesianChartDataModel,
  ChartKind,
  type MetricQuery,
  type Explore,
} from "@lightdash/common";

// Create data model
const dataModel = new CartesianChartDataModel({
  resultsRunner,
  fieldConfig: {
    x: {
      reference: "orders_created_month",
      type: "category",
    },
    y: [{
      reference: "orders_total_revenue",
      aggregation: "sum",
    }],
  },
  type: ChartKind.VERTICAL_BAR,
});

// Get ECharts options
const echartsOptions = dataModel.getChartOptions();

// Use with ECharts library (in frontend code)
// const chart = echarts.init(document.getElementById('chart'));
// chart.setOption(echartsOptions);

Line Chart with Multiple Series

const dataModel = new CartesianChartDataModel({
  resultsRunner,
  fieldConfig: {
    x: {
      reference: "orders_created_date",
      type: "time",
    },
    y: [
      {
        reference: "orders_total_revenue",
        aggregation: "sum",
      },
      {
        reference: "orders_count",
        aggregation: "count",
      },
    ],
  },
  type: ChartKind.LINE,
});

Grouped Bar Chart

Display data grouped by a dimension:

const dataModel = new CartesianChartDataModel({
  resultsRunner,
  fieldConfig: {
    x: {
      reference: "orders_created_month",
      type: "category",
    },
    y: [{
      reference: "orders_total_amount",
      aggregation: "sum",
    }],
    groupBy: {
      reference: "orders_status",
      type: "category",
    },
  },
  type: ChartKind.VERTICAL_BAR,
});

Scatter Plot

const dataModel = new CartesianChartDataModel({
  resultsRunner,
  fieldConfig: {
    x: {
      reference: "orders_total_amount",
      type: "linear",
    },
    y: [{
      reference: "orders_item_count",
      aggregation: "sum",
    }],
  },
  type: ChartKind.SCATTER,
});

Area Chart

const dataModel = new CartesianChartDataModel({
  resultsRunner,
  fieldConfig: {
    x: {
      reference: "orders_created_date",
      type: "time",
    },
    y: [{
      reference: "orders_total_revenue",
      aggregation: "sum",
    }],
  },
  type: ChartKind.AREA,
  config: {
    layout: {
      showGridX: true,
      showGridY: true,
    },
    eChartsConfig: {
      series: [{
        areaStyle: { opacity: 0.3 },
      }],
    },
  },
});

Pie Charts

Display proportional data as circular charts.

Basic Pie Chart

import { PieChartDataModel, ChartKind } from "@lightdash/common";

const dataModel = new PieChartDataModel({
  resultsRunner,
  fieldConfig: {
    dimension: "orders_status",
    metric: "orders_count",
  },
  type: ChartKind.PIE,
});

const echartsOptions = dataModel.getChartOptions();

Donut Chart

const dataModel = new PieChartDataModel({
  resultsRunner,
  fieldConfig: {
    dimension: "orders_region",
    metric: "orders_total_revenue",
  },
  type: ChartKind.PIE,
  config: {
    layout: {
      isDonut: true,
    },
  },
});

Table Visualization

Display data in tabular format.

Basic Table

import { TableDataModel } from "@lightdash/common";

const dataModel = new TableDataModel({
  resultsRunner,
  columnConfig: [
    { fieldId: "customers_name", visible: true },
    { fieldId: "orders_count", visible: true },
    { fieldId: "orders_total_revenue", visible: true },
  ],
  conditionalFormatting: [],
});

const tableData = dataModel.getTransformedData();

Table with Conditional Formatting

import {
  TableDataModel,
  type ConditionalFormattingConfig,
} from "@lightdash/common";

const conditionalFormatting: ConditionalFormattingConfig[] = [{
  target: { fieldId: "orders_total_revenue" },
  rule: {
    type: "greater_than",
    value: 10000,
  },
  color: "#4CAF50",
}];

const dataModel = new TableDataModel({
  resultsRunner,
  columnConfig: columns,
  conditionalFormatting,
});

Chart Configuration

Customize Chart Layout

const dataModel = new CartesianChartDataModel({
  resultsRunner,
  fieldConfig,
  type: ChartKind.VERTICAL_BAR,
  config: {
    layout: {
      xLabel: "Month",
      yLabel: ["Revenue ($)"],
      showGridX: false,
      showGridY: true,
      showLegend: true,
    },
  },
});

Custom Colors

const dataModel = new CartesianChartDataModel({
  resultsRunner,
  fieldConfig,
  type: ChartKind.LINE,
  config: {
    eChartsConfig: {
      color: ["#FF6B6B", "#4ECDC4", "#45B7D1"],
    },
  },
});

Axis Configuration

const dataModel = new CartesianChartDataModel({
  resultsRunner,
  fieldConfig,
  type: ChartKind.VERTICAL_BAR,
  config: {
    eChartsConfig: {
      xAxis: {
        axisLabel: {
          rotate: 45,
        },
      },
      yAxis: {
        scale: true,
        min: 0,
      },
    },
  },
});

Advanced Features

Pivot Transformations

Transform data before charting:

import { derivePivotConfigurationFromChart, type PivotConfig } from "@lightdash/common";

// Derive pivot configuration from chart
const pivotConfig: PivotConfig | undefined = derivePivotConfigurationFromChart(
  chart,
  query,
  itemsMap
);

if (pivotConfig) {
  // Apply pivot transformation
  const pivotedData = pivotQueryResults({
    rows,
    ...pivotConfig,
    itemsMap,
  });
}

Chart Data Transformation

Get transformed data for custom rendering:

const dataModel = new CartesianChartDataModel({
  resultsRunner,
  fieldConfig,
  type: ChartKind.LINE,
});

// Get pivoted data
const pivotedData = dataModel.getPivotedChartData();

// Get fully transformed data
const transformedData = dataModel.getTransformedData();

Conditional Formatting

Apply color rules to chart data:

import {
  createConditionalFormattingConfigWithColorRange,
  type ConditionalFormattingColorRange,
} from "@lightdash/common";

const colorRange: ConditionalFormattingColorRange = {
  min: { value: 0, color: "#FF0000" },
  max: { value: 100, color: "#00FF00" },
};

const config = createConditionalFormattingConfigWithColorRange(
  colorRange,
  { fieldId: "orders_total_revenue" }
);

Chart Types Reference

Cartesian Chart Types

  • VERTICAL_BAR - Vertical bar chart
  • HORIZONTAL_BAR - Horizontal bar chart
  • LINE - Line chart
  • AREA - Area chart
  • SCATTER - Scatter plot
  • MIXED - Mixed chart (multiple series with different types)

Other Chart Types

  • PIE - Pie or donut chart
  • TABLE - Data table
  • BIG_NUMBER - Single metric display
  • FUNNEL - Funnel chart

Complete Example

End-to-end chart creation:

import {
  CartesianChartDataModel,
  ChartKind,
  getItemMap,
  formatRows,
  type MetricQuery,
  type MetricQueryResponse,
} from "@lightdash/common";

async function createRevenueChart(
  query: MetricQuery,
  response: MetricQueryResponse,
  explore: Explore
) {
  // 1. Create item map
  const itemsMap = getItemMap(
    explore,
    query.additionalMetrics,
    query.tableCalculations,
    query.customDimensions
  );

  // 2. Format results
  const formattedRows = formatRows(response.rows, itemsMap);

  // 3. Create results runner
  const resultsRunner = {
    rows: formattedRows,
    columns: query.dimensions.concat(query.metrics),
  };

  // 4. Create data model
  const dataModel = new CartesianChartDataModel({
    resultsRunner,
    fieldConfig: {
      x: {
        reference: "orders_created_month",
        type: "category",
      },
      y: [{
        reference: "orders_total_revenue",
        aggregation: "sum",
      }],
    },
    type: ChartKind.VERTICAL_BAR,
    config: {
      layout: {
        xLabel: "Month",
        yLabel: ["Total Revenue"],
        showLegend: false,
      },
      eChartsConfig: {
        color: ["#4ECDC4"],
      },
    },
  });

  // 5. Get ECharts options
  const chartOptions = dataModel.getChartOptions();

  return chartOptions;
}

Tips and Best Practices

1. Choose the Right Chart Type

  • Bar charts - Compare categories
  • Line charts - Show trends over time
  • Pie charts - Show proportions (use sparingly)
  • Scatter plots - Show correlations
  • Tables - Show detailed data

2. Limit Series

Keep charts readable by limiting the number of series:

// Good: 2-3 series
y: [
  { reference: "revenue" },
  { reference: "cost" },
]

// Avoid: Too many series
y: metrics.map(m => ({ reference: m })) // Could be 10+ series

3. Handle Time Series

Use appropriate time granularity:

// For trends: daily or weekly
x: { reference: "orders_created_date", type: "time" }

// For overview: monthly or quarterly
x: { reference: "orders_created_month", type: "category" }

4. Format Axis Labels

Make labels readable:

config: {
  layout: {
    xLabel: "Order Date",
    yLabel: ["Revenue (USD)"],
  },
  eChartsConfig: {
    xAxis: {
      axisLabel: {
        rotate: 45,  // Prevent label overlap
      },
    },
  },
}

Next Steps