Scatter chart Since 0.7.0
Multiple series shown as a scatter plot. Similar to a line chart.
Usage
To use this component in a Nunjucks template you would add the following (assumes you've loaded OI Lume Viz into componentNamespace: 'oi'
):
{% comp 'oi.chart.scatter', { "config": config } %}{% endcomp %}
where config
is replaced by an object that contains some or all of these variables:
data
- Either a reference to a CSV file in the Lume site or an array of rows with named attributescolumns
- As with many of the visualisation types you can optionally add virtual columns.colours
- Define some visualisation-specific named colours.width
- Set a specific width for the visualisation.height
- Set a specific height for the visualisation.axis
- Define thex
(horizontal) axis.legend
- Define the legend.series
- An ordered array of series. Each one is of the form:title
- The display name of the series.x
- The title of the column to use for the horizontal axis value.y
- The title of the column to use for the vertical axis value.colour
- The hex code to use to colour this series.tooltip
- Either a string, template string, or the column heading to use to build a tooltip.points
- Properties of the points:size
- The size of the point.marker
- One ofcircle
,triangle
,square
,diamond
,pentagon
,hexagon
,octagon
,line
, orcross
.rotate
- How much to rotate the marker around its centre by, in degrees.
where
- Limit the rows to include
attribution
- Add a line of attribution text under the visualisation.
Examples
- Basic
- Auto-generated grid
- Explicitly defined grid
- Category-based data
- Custom icons
- Gaps in series
- Limiting a series to specific rows
1. Basic§
This is a basic scatter chart with one data series showing unemployment over time for 16-17 year olds (data from the ONS's A01: Summary of labour market statistics). The graph is auto-scaled to the data using axis → x → tick → spacing
and axis → y → tick → spacing
. The tick marks for each axis
are defined using those same properties and styled with axis → x → grid
.
This example was made with config
:
data: test.data.unemploymentByAge
series:
- title: 16-17
x: Year
y: 16-17→rate (%)1
colour: '#e52e36'
{
"data": "test.data.unemploymentByAge",
"series": [{
"title": "16-17",
"x": "Year",
"y": "16-17→rate (%)1",
"colour": "#e52e36"
}]
}
2. Auto-generated grid§
This is a basic scatter chart showing the same data as above. In this example we have auto-scaled each axis to the data using axis → x → tick → spacing
and axis → y → tick → spacing
. The tick → spacing
values are used to auto generate tick marks which are styled with axis → x → grid
and axis → y → grid
.
This example was made with config
:
data: test.data.unemploymentByAge
axis:
x:
grid:
show: true
tick:
spacing: 5
'y':
grid:
show: true
tick:
spacing: 5
series:
- title: 16-17
x: Year
y: 16-17→rate (%)1
colour: '#e52e36'
{
"data": "test.data.unemploymentByAge",
"axis": {
"x": {
"grid": {
"show": true
},
"tick": {
"spacing": 5
}
},
"y": {
"grid": {
"show": true
},
"tick": {
"spacing": 5
}
}
},
"series": [{
"title": "16-17",
"x": "Year",
"y": "16-17→rate (%)1",
"colour": "#e52e36"
}]
}
3. Explicitly defined grid§
This more complicated chart shows four different age groups from A01: Summary of labour market statistics. In this case they all share a common x-value column in the data but they don't have to. We define titles for each axis. The x-axis range is explicitly limited to the years 2000
to 2022.5
with tick marks set every 2 years but only showing labels on the decades. The tickSize
is defined per tick
. The vertical lines (associated with ticks on the x-axis) have stroke-dasharray
set to make them dashed and a tick → size
set for the axis
rather than for each tick. We can customise the tooltip
for each series
by providing a column/virtual column in the data or a string template. We also create an interactive legend.
This example was made with config
:
data: test.data.unemploymentByAge
legend:
show: true
axis:
x:
title:
label: Year
grid:
stroke-dasharray: 6 2
stroke-width: 1
ticks:
- value: 2000
grid: true
label: '2000'
tickSize: 5
- value: 2002
grid: true
label: ''
- value: 2004
grid: true
label: ''
- value: 2006
grid: true
label: ''
- value: 2008
grid: true
label: ''
- value: 2010
grid: true
label: '2010'
tickSize: 5
- value: 2012
grid: true
label: ''
- value: 2014
grid: true
label: ''
- value: 2016
grid: true
label: ''
- value: 2018
grid: true
label: ''
- value: 2020
grid: true
label: '2020'
tickSize: 5
min: 2000
max: 2022.5
'y':
min: 0
max: 45
title:
label: Unemployment
grid:
stroke-width: 0.5
ticks:
- value: 0
grid: true
label: 0%
- value: 5
grid: true
label: ''
- value: 10
grid: true
label: 10%
- value: 15
grid: true
label: ''
- value: 20
grid: true
label: 20%
- value: 25
grid: true
label: ''
- value: 30
grid: true
label: 30%
- value: 35
grid: true
label: ''
- value: 40
grid: true
label: 40%
- value: 45
grid: true
label: ''
tick:
size: 5
series:
- title: 16-17
x: Year
y: 16-17→rate (%)1
colour: '#e52e36'
tooltip: '16-17<br />{{ Date }}: {{ 16-17→rate (%)1 | toFixed(1) }}%'
- title: 18-24
x: Year
y: 18-24→rate (%)1
colour: '#f7ab3d'
tooltip: '18-24<br />{{ Date }}: {{ 18-24→rate (%)1 | toFixed(1) }}%'
- title: 25-49
x: Year
y: 25-49→rate (%)1
colour: '#c7b200'
tooltip: '25-49<br />{{ Date }}: {{ 25-49→rate (%)1 | toFixed(1) }}%'
- title: 50-64
x: Year
y: 50 and over→rate (%)1
colour: '#005776'
tooltip: '50 and over<br />{{ Date }}: {{ 50 and over→rate (%)1 | toFixed(1) }}%'
{
"data": "test.data.unemploymentByAge",
"legend": {
"show": true
},
"axis": {
"x": {
"title": {
"label": "Year"
},
"grid": {
"stroke-dasharray": "6 2",
"stroke-width": 1
},
"ticks": [{
"value": 2000,
"grid": true,
"label": "2000",
"tickSize": 5
},{
"value": 2002,
"grid": true,
"label": ""
},{
"value": 2004,
"grid": true,
"label": ""
},{
"value": 2006,
"grid": true,
"label": ""
},{
"value": 2008,
"grid": true,
"label": ""
},{
"value": 2010,
"grid": true,
"label": "2010",
"tickSize": 5
},{
"value": 2012,
"grid": true,
"label": ""
},{
"value": 2014,
"grid": true,
"label": ""
},{
"value": 2016,
"grid": true,
"label": ""
},{
"value": 2018,
"grid": true,
"label": ""
},{
"value": 2020,
"grid": true,
"label": "2020",
"tickSize": 5
}],
"min": 2000,
"max": 2022.5
},
"y": {
"min": 0,
"max": 45,
"title": {
"label": "Unemployment"
},
"grid": {
"stroke-width": 0.5
},
"ticks": [{
"value": 0,
"grid": true,
"label": "0%"
},{
"value": 5,
"grid": true,
"label": ""
},{
"value": 10,
"grid": true,
"label": "10%"
},{
"value": 15,
"grid": true,
"label": ""
},{
"value": 20,
"grid": true,
"label": "20%"
},{
"value": 25,
"grid": true,
"label": ""
},{
"value": 30,
"grid": true,
"label": "30%"
},{
"value": 35,
"grid": true,
"label": ""
},{
"value": 40,
"grid": true,
"label": "40%"
},{
"value": 45,
"grid": true,
"label": ""
}],
"tick": {
"size": 5
}
}
},
"series": [{
"title": "16-17",
"x": "Year",
"y": "16-17→rate (%)1",
"colour": "#e52e36",
"tooltip": "16-17<br />{{ Date }}: {{ 16-17→rate (%)1 | toFixed(1) }}%"
},{
"title": "18-24",
"x": "Year",
"y": "18-24→rate (%)1",
"colour": "#f7ab3d",
"tooltip": "18-24<br />{{ Date }}: {{ 18-24→rate (%)1 | toFixed(1) }}%"
},{
"title": "25-49",
"x": "Year",
"y": "25-49→rate (%)1",
"colour": "#c7b200",
"tooltip": "25-49<br />{{ Date }}: {{ 25-49→rate (%)1 | toFixed(1) }}%"
},{
"title": "50-64",
"x": "Year",
"y": "50 and over→rate (%)1",
"colour": "#005776",
"tooltip": "50 and over<br />{{ Date }}: {{ 50 and over→rate (%)1 | toFixed(1) }}%"
}]
}
4. Category-based data§
Sometimes you have data that is in categories.
This example was made with config
:
legend:
show: true
data: test.data.example_data
axis:
x:
grid:
show: true
min: -0.5
max: 9.5
ticks:
- value: 0
label: A
- value: 1
label: B
- value: 2
label: C
- value: 3
label: D
- value: 4
label: E
- value: 5
label: F
- value: 6
label: G
- value: 7
label: H
- value: 8
label: I
- value: 9
label: J
'y':
grid:
show: true
tick:
spacing: 25
max: 100
series:
- title: Series 1
colour: red
x: category
y: series1
- title: Series 2
colour: blue
x: category
y: series2
- title: Series 3
colour: green
x: category
y: series3
{
"legend": {
"show": true
},
"data": "test.data.example_data",
"axis": {
"x": {
"grid": {
"show": true
},
"min": -0.5,
"max": 9.5,
"ticks": [{
"value": 0,
"label": "A"
},{
"value": 1,
"label": "B"
},{
"value": 2,
"label": "C"
},{
"value": 3,
"label": "D"
},{
"value": 4,
"label": "E"
},{
"value": 5,
"label": "F"
},{
"value": 6,
"label": "G"
},{
"value": 7,
"label": "H"
},{
"value": 8,
"label": "I"
},{
"value": 9,
"label": "J"
}]
},
"y": {
"grid": {
"show": true
},
"tick": {
"spacing": 25
},
"max": 100
}
},
"series": [{
"title": "Series 1",
"colour": "red",
"x": "category",
"y": "series1"
},{
"title": "Series 2",
"colour": "blue",
"x": "category",
"y": "series2"
},{
"title": "Series 3",
"colour": "green",
"x": "category",
"y": "series3"
}]
}
5. Custom icons§
Line markers can be defined using the points
object on a series
. Points can have a marker
(one of circle
, triangle
, square
, diamond
, pentagon
, hexagon
, octagon
, line
, or cross
), a size
, and a rotation given by rotate
(in degrees).
This example was made with config
:
legend:
show: true
data:
- series1-y: 10
series2-y: 12
series3-y: 15
series1-x: 0.09
series2-x: 0.1
series3-x: 0.1
- series1-y: 20
series2-y: 22
series3-y: 32
series1-x: 0.19
series2-x: 0.2
series3-x: 0.19
- series1-y: 23
series2-y: 21
series3-y: 24
series1-x: 0.28
series2-x: 0.3
series3-x: 0.31
- series1-y: 47
series2-y: 45
series3-y: 35
series1-x: 0.41
series2-x: 0.4
series3-x: 0.39
- series1-y: 34
series2-y: 37
series3-y: 31
series1-x: 0.52
series2-x: 0.5
series3-x: 0.49
- series1-y: 55
series2-y: 57
series3-y: 52
series1-x: 0.61
series2-x: 0.6
series3-x: 0.61
- series1-y: 49
series2-y: 59
series3-y: 19
series1-x: 0.69
series2-x: 0.7
series3-x: 0.68
- series1-y: 20
series2-y: 30
series3-y: 10
series1-x: 0.83
series2-x: 0.8
series3-x: 0.81
- series1-y: 10
series2-y: 12
series3-y: 1
series1-x: 0.91
series2-x: 0.9
series3-x: 0.89
- series1-y: 5
series2-y: 2
series3-y: 30
series1-x: 1.05
series2-x: 1
series3-x: 1.01
axis:
x:
grid:
show: true
tick:
spacing: 0.2
'y':
grid:
show: true
tick:
spacing: 25
max: 100
series:
- title: Series 1
x: series1-x
y: series1-y
points:
size: 8
- title: Series 2
x: series2-x
y: series2-y
points:
marker: square
size: 16
- title: Series 3
x: series3-x
y: series3-y
points:
marker: triangle
rotate: 180
size: 32
{
"legend": {
"show": true
},
"data": [{
"series1-y": 10,
"series2-y": 12,
"series3-y": 15,
"series1-x": 0.09,
"series2-x": 0.1,
"series3-x": 0.1
},{
"series1-y": 20,
"series2-y": 22,
"series3-y": 32,
"series1-x": 0.19,
"series2-x": 0.2,
"series3-x": 0.19
},{
"series1-y": 23,
"series2-y": 21,
"series3-y": 24,
"series1-x": 0.28,
"series2-x": 0.3,
"series3-x": 0.31
},{
"series1-y": 47,
"series2-y": 45,
"series3-y": 35,
"series1-x": 0.41,
"series2-x": 0.4,
"series3-x": 0.39
},{
"series1-y": 34,
"series2-y": 37,
"series3-y": 31,
"series1-x": 0.52,
"series2-x": 0.5,
"series3-x": 0.49
},{
"series1-y": 55,
"series2-y": 57,
"series3-y": 52,
"series1-x": 0.61,
"series2-x": 0.6,
"series3-x": 0.61
},{
"series1-y": 49,
"series2-y": 59,
"series3-y": 19,
"series1-x": 0.69,
"series2-x": 0.7,
"series3-x": 0.68
},{
"series1-y": 20,
"series2-y": 30,
"series3-y": 10,
"series1-x": 0.83,
"series2-x": 0.8,
"series3-x": 0.81
},{
"series1-y": 10,
"series2-y": 12,
"series3-y": 1,
"series1-x": 0.91,
"series2-x": 0.9,
"series3-x": 0.89
},{
"series1-y": 5,
"series2-y": 2,
"series3-y": 30,
"series1-x": 1.05,
"series2-x": 1,
"series3-x": 1.01
}],
"axis": {
"x": {
"grid": {
"show": true
},
"tick": {
"spacing": 0.2
}
},
"y": {
"grid": {
"show": true
},
"tick": {
"spacing": 25
},
"max": 100
}
},
"series": [{
"title": "Series 1",
"x": "series1-x",
"y": "series1-y",
"points": {
"size": 8
}
},{
"title": "Series 2",
"x": "series2-x",
"y": "series2-y",
"points": {
"marker": "square",
"size": 16
}
},{
"title": "Series 3",
"x": "series3-x",
"y": "series3-y",
"points": {
"marker": "triangle",
"rotate": 180,
"size": 32
}
}]
}
6. Gaps in series Since 0.15.1§
This is a test to show what happens if data is missing in a series. In this case series 1 has no value at x=0.52
and series 2 is missing values for x=0.7
and x=0.8
.
This example was made with config
:
legend:
show: true
data: test.data.scatter-chart-data
axis:
x:
grid:
show: true
tick:
spacing: 0.2
'y':
grid:
show: true
tick:
spacing: 25
max: 100
series:
- title: Series 1
x: value 1
y: Series 1
points:
size: 8
- title: Series 2
x: value 2
y: Series 2
points:
marker: square
size: 16
- title: Series 3
x: value 3
y: Series 3
points:
marker: triangle
rotate: 180
size: 32
{
"legend": {
"show": true
},
"data": "test.data.scatter-chart-data",
"axis": {
"x": {
"grid": {
"show": true
},
"tick": {
"spacing": 0.2
}
},
"y": {
"grid": {
"show": true
},
"tick": {
"spacing": 25
},
"max": 100
}
},
"series": [{
"title": "Series 1",
"x": "value 1",
"y": "Series 1",
"points": {
"size": 8
}
},{
"title": "Series 2",
"x": "value 2",
"y": "Series 2",
"points": {
"marker": "square",
"size": 16
}
},{
"title": "Series 3",
"x": "value 3",
"y": "Series 3",
"points": {
"marker": "triangle",
"rotate": 180,
"size": 32
}
}]
}
7. Limiting a series to specific rows Since 0.16.0§
Sometimes you may have a big, stacked, file where you may want to use some rows for one series and other rows for another. We can limit a particular series
to only use certain rows by using the option where
. In the example below we have a dataset relating to housing that has a column London borough
that can take the values isLondon
and notLondon
. We could limit a particular series to rows that contain the value notLondon
by setting where
to "London borough"="notLondon"
.
This example was made with config
:
legend:
show: true
data: test.data.house-prices
axis:
x:
grid:
show: true
tick:
spacing: 5
'y':
grid:
show: true
tick:
spacing: 25
series:
- title: Outside London
x: wage_ratio
y: vacants_per_thousand_dwellings
where: '"London borough"="notLondon" AND "vacants_per_thousand_dwellings"<50'
- title: London
x: wage_ratio
y: vacants_per_thousand_dwellings
where: '"London borough"="isLondon" AND "vacants_per_thousand_dwellings"<50'
- title: Empties outside London
x: wage_ratio
y: vacants_per_thousand_dwellings
where: '"London borough"="notLondon" AND "vacants_per_thousand_dwellings">=50'
- title: Empties in London
x: wage_ratio
y: vacants_per_thousand_dwellings
where: '"London borough"="isLondon" AND "vacants_per_thousand_dwellings">=50'
{
"legend": {
"show": true
},
"data": "test.data.house-prices",
"axis": {
"x": {
"grid": {
"show": true
},
"tick": {
"spacing": 5
}
},
"y": {
"grid": {
"show": true
},
"tick": {
"spacing": 25
}
}
},
"series": [{
"title": "Outside London",
"x": "wage_ratio",
"y": "vacants_per_thousand_dwellings",
"where": "\"London borough\"=\"notLondon\" AND \"vacants_per_thousand_dwellings\"<50"
},{
"title": "London",
"x": "wage_ratio",
"y": "vacants_per_thousand_dwellings",
"where": "\"London borough\"=\"isLondon\" AND \"vacants_per_thousand_dwellings\"<50"
},{
"title": "Empties outside London",
"x": "wage_ratio",
"y": "vacants_per_thousand_dwellings",
"where": "\"London borough\"=\"notLondon\" AND \"vacants_per_thousand_dwellings\">=50"
},{
"title": "Empties in London",
"x": "wage_ratio",
"y": "vacants_per_thousand_dwellings",
"where": "\"London borough\"=\"isLondon\" AND \"vacants_per_thousand_dwellings\">=50"
}]
}