Scatter Chart for Price Against Conversion
You are a pricing analyst, and you have a list price and a conversion rate for every SKU in the catalogue. The question is not which SKU converts best. It is where, as the price climbs, buyers stop buying: is there a band where conversion collapses, and where does it start? A sorted table gives you thirty numbers to compare by eye. A scatter chart gives you the shape, and the cliff is the first thing you see.
The example below plots one point per SKU, list price along the bottom and conversion up the side. The chart is bound to the grid, so it draws exactly the rows the grid is showing. Put a SKU in the box, or open the filter on the Price column and keep only the products above fifty, and the points you do not want leave the chart on the next frame. Clear the filter and they come back.
Why a scatter and not a line
A line chart joins its points in order, and that implies a trend from one price to the next that you have not measured. Your SKUs are separate products, not consecutive readings of one thing. A scatter draws each SKU as itself and leaves the space between them empty, so a gap in the prices stays a gap and a single odd product stays visible as a single odd point. The collapse shows up as the place where the cloud drops away.
The chart is a view of the grid
There is no second data set to keep in step. createChart takes the grid itself, reads its filtered rows, and redraws whenever they change. x names the column along the bottom and y the one up the side. Because every SKU has its own price, each row keeps its own point. Sort, filter or edit the grid and the chart follows, because a chart of rows you cannot see would be describing a different data set.
The code, in plain JavaScript
import { createGrid } from '@toclocoinc/lattice-grid';
import { createChart } from '@toclocoinc/lattice-grid/modules/charts';
import '@toclocoinc/lattice-grid/css';
const prices = [9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51,
54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 93, 96];
const conversion = [5.8, 5.9, 5.6, 5.7, 5.4, 5.5, 5.2, 5.3, 5.0, 5.1, 4.8, 4.9,
4.6, 4.4, 4.5, 3.1, 2.6, 2.2, 1.8, 1.9, 1.5, 1.2, 1.4, 1.0, 0.9, 1.1, 0.8,
0.7, 0.8, 0.6];
const rows = prices.map((price, i) => ({
id: i + 1, sku: `SKU-${101 + i}`, price, conversion: conversion[i],
}));
const grid = createGrid(document.querySelector('#grid'), {
rowKey: 'id',
columns: [
{ field: 'sku', title: 'SKU' },
{ field: 'price', title: 'List price', type: 'number', filter: { type: 'number' } },
{ field: 'conversion', title: 'Conversion (%)', type: 'number', filter: { type: 'number' } },
],
rows,
});
createChart({
grid, container: '#chart', type: 'scatter',
x: 'price', y: 'conversion',
title: 'Conversion rate against list price',
});
Give #chart and #grid a height in your page and that is the whole screen.
The same thing in React
The React adapter is a factory: you pass it React and createGrid, and it returns the component. The component forwards a ref whose .grid is the real grid, which is what the chart binds to.
import React, { useEffect, useRef } from 'react';
import { createGrid } from '@toclocoinc/lattice-grid';
import { createChart } from '@toclocoinc/lattice-grid/modules/charts';
import { createLatticeGrid } from '@toclocoinc/lattice-grid/modules/react';
import '@toclocoinc/lattice-grid/css';
const LatticeGrid = createLatticeGrid({ React, createGrid });
const columns = [
{ field: 'sku', title: 'SKU' },
{ field: 'price', title: 'List price', type: 'number', filter: { type: 'number' } },
{ field: 'conversion', title: 'Conversion (%)', type: 'number', filter: { type: 'number' } },
];
export function PriceBands({ rows }) {
const gridRef = useRef(null);
const chartEl = useRef(null);
useEffect(() => {
const chart = createChart({
grid: gridRef.current.grid, container: chartEl.current, type: 'scatter',
x: 'price', y: 'conversion',
title: 'Conversion rate against list price',
});
return () => chart.destroy();
}, []);
return (
<>
<div ref={chartEl} style={{ height: 300 }} />
<LatticeGrid ref={gridRef} rowKey="id" columns={columns} rows={rows} style={{ height: 300 }} />
</>
);
}
Pass it the same thirty rows as the first listing, with sku, price and conversion on each.
The options used
| Option | Type | What it does |
|---|---|---|
grid |
Grid | Required. The grid to read. |
container |
Element or string | Required. Where to draw. |
type |
string | 'scatter' here. 'bubble' adds a third column as the size of each point. |
x / y |
string | The two columns to plot against each other. |
title |
string | Drawn above the plot. |
Go further
The charts page lists every chart type the same grid can feed, and the bar, line and pie family demo draws the scatter and its bubble neighbour beside the rest of the Cartesian types. To see how a chart keeps following the grid when you filter by clicking, read how to draw a chart that follows the grid.