This guide explains how to use @buildcanada/charts as a client library with your own CSV or JSON data.
npm install @buildcanada/charts
# or
bun add @buildcanada/chartsYour application must also have these dependencies:
npm install react react-dom mobx mobx-reactimport { ChartsProvider, Grapher, GrapherState } from "@buildcanada/charts"
import "@buildcanada/charts/styles.css"
function App() {
const grapherState = createYourChart()
return (
<ChartsProvider>
<div style={{ width: "800px", height: "600px" }}>
<Grapher grapherState={grapherState} />
</div>
</ChartsProvider>
)
}All charts require data with these mandatory columns:
- Entity Name (or "entity"): The name of the data series (e.g., country, category)
- Year (or time column): The time dimension
- Value column(s): Your numeric data
The simplest approach uses the createTestDataset helper with a structured array:
import {
Grapher,
GrapherState,
createTestDataset,
fakeEntities,
legacyToChartsTableAndDimensionsWithMandatorySlug,
GRAPHER_CHART_TYPES,
DimensionProperty,
} from "@buildcanada/charts"
import type { TestData, TestMetadata } from "@buildcanada/charts"
// Step 1: Define your data as TestData array
const myData: TestData = [
{ year: 2020, entity: { id: 1, name: "Canada", code: "CAN" }, value: 100 },
{ year: 2021, entity: { id: 1, name: "Canada", code: "CAN" }, value: 120 },
{ year: 2020, entity: { id: 2, name: "USA", code: "USA" }, value: 200 },
{ year: 2021, entity: { id: 2, name: "USA", code: "USA" }, value: 220 },
]
// Step 2: Define metadata for your indicator
const myMetadata: TestMetadata = {
id: 1, // unique identifier for this variable
display: {
name: "GDP Growth",
unit: "%",
shortUnit: "%",
numDecimalPlaces: 1,
},
}
// Step 3: Create the dataset and table
const variableId = myMetadata.id
const dimensions = [
{ variableId, property: DimensionProperty.y },
]
const dataset = createTestDataset([
{ data: myData, metadata: myMetadata },
])
const table = legacyToChartsTableAndDimensionsWithMandatorySlug(
dataset,
dimensions,
{} // optional: color mapping for entities
)
// Step 4: Create GrapherState
const grapherState = new GrapherState({
title: "GDP Growth by Country",
dimensions,
chartTypes: [GRAPHER_CHART_TYPES.LineChart],
})
grapherState.inputTable = tableIf you have JSON data from an API or file:
import {
Grapher,
GrapherState,
createTestDataset,
legacyToChartsTableAndDimensionsWithMandatorySlug,
GRAPHER_CHART_TYPES,
DimensionProperty,
} from "@buildcanada/charts"
// Your JSON data
const jsonData = [
{ country: "Canada", year: 2020, gdp: 1.8 },
{ country: "Canada", year: 2021, gdp: 5.0 },
{ country: "USA", year: 2020, gdp: -3.4 },
{ country: "USA", year: 2021, gdp: 5.7 },
]
// Create entity mapping (id must be unique per entity)
const entityMap = new Map<string, { id: number; name: string }>()
let entityId = 1
jsonData.forEach((row) => {
if (!entityMap.has(row.country)) {
entityMap.set(row.country, { id: entityId++, name: row.country })
}
})
// Transform to TestData format
const testData = jsonData.map((row) => ({
year: row.year,
entity: entityMap.get(row.country)!,
value: row.gdp,
}))
// Create metadata
const metadata = {
id: 1,
display: {
name: "GDP Growth Rate",
unit: "%",
numDecimalPlaces: 1,
},
}
// Build chart
const dimensions = [{ variableId: 1, property: DimensionProperty.y }]
const dataset = createTestDataset([{ data: testData, metadata }])
const table = legacyToChartsTableAndDimensionsWithMandatorySlug(dataset, dimensions, {})
const grapherState = new GrapherState({
title: "GDP Growth Rate",
dimensions,
chartTypes: [GRAPHER_CHART_TYPES.LineChart],
})
grapherState.inputTable = tableFor CSV data, parse it first then convert to the TestData format:
import { parseDelimited } from "@buildcanada/charts"
// CSV string (could be from file or fetch)
const csvString = `country,year,value
Canada,2020,100
Canada,2021,120
USA,2020,200
USA,2021,220`
// Parse CSV to rows
const rows = parseDelimited(csvString) as Array<{
country: string
year: string
value: string
}>
// Create entity mapping
const entityMap = new Map<string, { id: number; name: string }>()
let entityId = 1
rows.forEach((row) => {
if (!entityMap.has(row.country)) {
entityMap.set(row.country, { id: entityId++, name: row.country })
}
})
// Convert to TestData format
const testData = rows.map((row) => ({
year: parseInt(row.year, 10),
entity: entityMap.get(row.country)!,
value: parseFloat(row.value),
}))
// Then create the chart as in Method 2...async function loadCSVFile(file: File) {
const text = await file.text()
const rows = parseDelimited(text)
// Transform to TestData format...
}
// Usage with file input
<input type="file" accept=".csv" onChange={(e) => {
if (e.target.files?.[0]) {
loadCSVFile(e.target.files[0])
}
}} />async function loadCSVFromUrl(url: string) {
const response = await fetch(url)
const text = await response.text()
const rows = parseDelimited(text)
// Transform to TestData format...
}Configure the chart type using chartTypes:
import { GRAPHER_CHART_TYPES } from "@buildcanada/charts"
// Available chart types:
GRAPHER_CHART_TYPES.LineChart // Time series line chart
GRAPHER_CHART_TYPES.DiscreteBar // Bar chart (single time point)
GRAPHER_CHART_TYPES.StackedArea // Stacked area chart
GRAPHER_CHART_TYPES.StackedBar // Stacked bar chart
GRAPHER_CHART_TYPES.SlopeChart // Slope chart (two time points)
GRAPHER_CHART_TYPES.ScatterPlot // Scatter plot (requires x and y)
GRAPHER_CHART_TYPES.Marimekko // Marimekko chart
// Example: Line chart
const grapherState = new GrapherState({
chartTypes: [GRAPHER_CHART_TYPES.LineChart],
// ...
})
// Example: Bar chart
const grapherState = new GrapherState({
chartTypes: [GRAPHER_CHART_TYPES.DiscreteBar],
// ...
})For map visualizations, set hasMapTab: true and tab: "map":
import { MapRegionName, ColorSchemeName } from "@buildcanada/charts"
const grapherState = new GrapherState({
dimensions,
hasMapTab: true,
tab: "map",
map: {
region: MapRegionName.World, // or MapRegionName.Canada for provincial maps
colorScale: {
baseColorScheme: ColorSchemeName.Blues,
},
},
})
grapherState.inputTable = tableImportant for maps: Entity names must match the geographic regions in the map data. For world maps, use standard country names. For Canada maps, use province/territory names.
Scatter plots require both X and Y variables:
// Define two variables
const xData: TestData = [/* x-axis values */]
const yData: TestData = [/* y-axis values */]
const xMetadata = { id: 1, display: { name: "GDP per capita" } }
const yMetadata = { id: 2, display: { name: "Life expectancy" } }
const dimensions = [
{ variableId: 1, property: DimensionProperty.x },
{ variableId: 2, property: DimensionProperty.y },
]
const dataset = createTestDataset([
{ data: xData, metadata: xMetadata },
{ data: yData, metadata: yMetadata },
])
const table = legacyToChartsTableAndDimensionsWithMandatorySlug(dataset, dimensions, {})
const grapherState = new GrapherState({
chartTypes: [GRAPHER_CHART_TYPES.ScatterPlot],
dimensions,
})
grapherState.inputTable = tableTo show specific entities by default:
const grapherState = new GrapherState({
// ...
selectedEntityNames: ["Canada", "USA", "Germany"],
})Assign custom colors to entities:
const entityColors = {
"Canada": "#ff0000",
"USA": "#0000ff",
"Germany": "#ffcc00",
}
const table = legacyToChartsTableAndDimensionsWithMandatorySlug(
dataset,
dimensions,
entityColors // Pass colors here
)import {
ChartsProvider,
Grapher,
GrapherState,
createTestDataset,
legacyToChartsTableAndDimensionsWithMandatorySlug,
parseDelimited,
GRAPHER_CHART_TYPES,
DimensionProperty,
Bounds,
} from "@buildcanada/charts"
import "@buildcanada/charts/styles.css"
function CSVChart({ csvData }: { csvData: string }) {
// Parse CSV
const rows = parseDelimited(csvData) as Array<{
entity: string
year: string
value: string
}>
// Build entity map
const entityMap = new Map<string, { id: number; name: string }>()
let entityId = 1
rows.forEach((row) => {
if (!entityMap.has(row.entity)) {
entityMap.set(row.entity, { id: entityId++, name: row.entity })
}
})
// Convert to TestData
const testData = rows.map((row) => ({
year: parseInt(row.year, 10),
entity: entityMap.get(row.entity)!,
value: parseFloat(row.value),
}))
// Build chart
const variableId = 1
const dimensions = [{ variableId, property: DimensionProperty.y }]
const dataset = createTestDataset([{
data: testData,
metadata: {
id: variableId,
display: { name: "Value", numDecimalPlaces: 0 },
},
}])
const table = legacyToChartsTableAndDimensionsWithMandatorySlug(
dataset,
dimensions,
{}
)
const grapherState = new GrapherState({
title: "My Chart",
chartTypes: [GRAPHER_CHART_TYPES.LineChart],
dimensions,
bounds: new Bounds(0, 0, 800, 600),
})
grapherState.inputTable = table
return (
<ChartsProvider>
<div style={{ width: "800px", height: "600px" }}>
<Grapher grapherState={grapherState} />
</div>
</ChartsProvider>
)
}
// Usage
const csv = `entity,year,value
Canada,2020,100
Canada,2021,110
Canada,2022,105
USA,2020,200
USA,2021,210
USA,2022,215`
function App() {
return <CSVChart csvData={csv} />
}The library provides pre-defined entity mappings for countries and regions:
import { fakeEntities } from "@buildcanada/charts"
// fakeEntities contains ~200 countries and regions with pre-assigned IDs
const canadaEntity = fakeEntities["Canada"] // { id: X, name: "Canada", code: "CAN" }
const usaEntity = fakeEntities["United States"] // { id: Y, name: "United States", code: "USA" }
// Use in your data
const testData = [
{ year: 2020, entity: fakeEntities["Canada"], value: 100 },
{ year: 2020, entity: fakeEntities["United States"], value: 200 },
]Customize the charts with global configuration:
import { ChartsProvider } from "@buildcanada/charts"
const config = {
branding: {
poweredByText: "My Organization",
logo: {
type: "none", // or "buildCanada", "canadaSpends", "custom"
},
},
dataApi: {
baseUrl: "https://api.example.com/v1/indicators/",
},
}
function App() {
return (
<ChartsProvider config={config}>
{/* Your charts */}
</ChartsProvider>
)
}Key types for working with data:
import type {
TestData, // Array of { year, entity, value }
TestMetadata, // Variable metadata with display options
EntityName, // string
EntityId, // number
EntityCode, // string
} from "@buildcanada/charts"
// TestData structure
type TestData = Array<{
year: number
entity: { id: EntityId; code?: EntityCode; name?: EntityName }
value: string | number
}>
// TestMetadata structure
type TestMetadata = {
id: number
display?: {
name?: string
unit?: string
shortUnit?: string
numDecimalPlaces?: number
}
}- Ensure entity names match between your data and the chart
- Verify the year values are numbers, not strings
- Check that
dimensionsincludes the correctvariableId
- Entity names must exactly match geographic region names
- For world maps, use standard country names (e.g., "United States", not "USA")
- For Canada maps, use full province names (e.g., "British Columbia", not "BC")
- Pass the color map to
legacyToChartsTableAndDimensionsWithMandatorySlug - Entity names in the color map must exactly match data entity names