Public
Edited
Feb 24
Insert cell
Insert cell
Insert cell
import {vl} from "@vega/vega-lite-api-v5"
Insert cell
import {uniqueValid} from "@uwdata/data-utilities"
Insert cell
import {printTable} from "@uwdata/data-utilities"
Insert cell
data = FileAttachment("social-development.csv").csv()
Insert cell
printTable(data.slice(0,5))
Insert cell
Insert cell
Insert cell
dataWithDecade = data.map(d => ({...d, Decade: Math.floor(d.Year / 10) * 10 // Group years into decades
}))
Insert cell
printTable(dataWithDecade.slice(0,5))
Insert cell
vl.markArc({ innerRadius: 0, outerRadius: 130 })
.data(dataWithDecade)
.encode(
vl.theta().fieldQ('Count').title('Count'), // Count of entries per decade
vl.color().fieldN('Decade').title('Decade'), // Color by decade
vl.tooltip().fieldN('Decade').fieldQ('Percentage').format('.1%')
)
.transform(
vl.aggregate([{ op: 'count', as: 'Count' }]).groupby(['Decade']), // save counts
vl.joinaggregate([{op: 'sum', field: 'Count', as: 'TotalCount' }]), // Sum all rows
// find percentage for each decade:
vl.calculate('datum.Count / datum.TotalCount').as('Percentage')
)
.width(300)
.height(300)
.title('Distribution of Datapoints by Decade')
.render()
Insert cell
Insert cell
Math.max(...data.map(d => d.Year)) // seeing maximum value in year column
Insert cell
Math.min(...data.map(d => d.Year))
Insert cell
Insert cell
[...new Set(data.map(d => d['Country Name']))] // array of unique countries in dataset
Insert cell
Insert cell
vl.layer([
vl.markBar()
.data(data)
.encode(
vl.x().fieldQ('Count').title('Number of Data Points'), // Show count of data points
vl.y().fieldN('Country Name').sort('-x').title('Country')
)
.transform(
vl.aggregate([{ op: 'count', as: 'Count' }]).groupby(['Country Name']), // save counts
vl.filter(vl.fieldQ('Count').lt(50)) // Filter countries with count less than 50
),
vl.markRule({ color: 'green', strokeWidth: 2 })
.data(data)
.transform(
vl.aggregate([{ op: 'count', as: 'Count' }]).groupby(['Country Name']),
vl.joinaggregate([{ op: 'mean', field: 'Count', as: 'AverageCount' }]) // plot average count for context
)
.encode(
vl.x().fieldQ('AverageCount')
),
// make label for vertical line:
vl.markText({ align: 'left', baseline: 'bottom', dx: 80, dy: -5, color: 'green' }) // position the label
.data(data)
.encode(
vl.x(),
vl.text().datum('Average Count for all Countries') // define label
)
])
.width(500)
.height(300)
.title('Lesser Represented Countries in Dataset')
.render()

Insert cell
Insert cell
Insert cell
// Seeing structure of some of the data
data.map(row => row['average_value_Unemployment, male (% of male labor force) (modeled ILO estimate)'])
.filter(value => value !== "" && value !== undefined && value !== null) //drop NaNs
.filter((value, index, self) => self.indexOf(value) === index) // get unique values

Insert cell
// filter for one country
Singaporedata = data.filter(row => row['Country Name'] === 'Singapore')
Insert cell
// choose employment related columns to represent
singapore_employment = Singaporedata.flatMap(row => {
const time = row['Year'];
return [
{ time, value: +row['average_value_Unemployment, male (% of male labor force) (modeled ILO estimate)'], variable: 'Male Unemployment' }, //renaming columns for legend simplicity
{ time, value: +row['average_value_Unemployment, female (% of female labor force) (modeled ILO estimate)'], variable: 'Female Unemployment' },
{ time, value: +row['average_value_Children in employment, total (% of children ages 7-14)'], variable: 'Employment % of children ages 7-14' },
{ time, value: +row['average_value_Labor force participation rate for ages 15-24, total (%) (modeled ILO estimate)'], variable: 'Labor Force Participation ages 15-24' },
{ time, value: +row['average_value_Labor force participation rate, total (% of total population ages 15-64) (modeled ILO estimate)'], variable: 'Labor Force Participation ages 15-64' }
];

}).filter(d => d.value !== 0) // drop 0 values for cleaner graph
Insert cell
// Plot using point
vl.markPoint()
.data(singapore_employment)
.encode(
vl.x().fieldT("time").title("Year"),
vl.y().fieldQ("value").title("Average Value (%)"),
vl.color().fieldN("variable").title("Variable").scale({ scheme: "category10" }).legend({
labelLimit: 200}), //allow full legend labels to show
vl.tooltip(["time", "value", "variable"])
)
.width(500)
.height(300)
.title('Average Employment and Unemployment Rates in Singapore')
.render()
Insert cell
Insert cell
Denmarkdata = data.filter(row => row['Country Name'] === 'Denmark')
Insert cell
// choose employment related columns to represent
denmark_employment = Denmarkdata.flatMap(row => {
const time = row['Year'];
return [
{ time, value: +row['average_value_Unemployment, male (% of male labor force) (modeled ILO estimate)'], variable: 'Male Unemployment' }, //renaming columns for legend simplicity
{ time, value: +row['average_value_Unemployment, female (% of female labor force) (modeled ILO estimate)'], variable: 'Female Unemployment' },
{ time, value: +row['average_value_Children in employment, total (% of children ages 7-14)'], variable: 'Employment % of children ages 7-14' },
{ time, value: +row['average_value_Labor force participation rate for ages 15-24, total (%) (modeled ILO estimate)'], variable: 'Labor Force Participation ages 15-24' },
{ time, value: +row['average_value_Labor force participation rate, total (% of total population ages 15-64) (modeled ILO estimate)'], variable: 'Labor Force Participation ages 15-64' }
];

}).filter(d => d.value !== 0) // drop 0 values for cleaner graph
Insert cell
// Plot using point
vl.markPoint()
.data(denmark_employment)
.encode(
vl.x().fieldT("time").title("Year"),
vl.y().fieldQ("value").title("Average Value (%)"),
vl.color().fieldN("variable").title("Variable").scale({ scheme: "category10" }).legend({
labelLimit: 200}), //allow full legend labels to show
vl.tooltip(["time", "value", "variable"])
)
.width(500)
.height(300)
.title('Average Employment and Unemployment Rates in Denmark')
.render()
Insert cell
Insert cell
usadata = data.filter(row => row['Country Name'] === 'United States')
Insert cell
// choose employment related columns to represent
usa_employment = usadata.flatMap(row => {
const time = row['Year'];
return [
{ time, value: +row['average_value_Unemployment, male (% of male labor force) (modeled ILO estimate)'], variable: 'Male Unemployment' }, //renaming columns for legend simplicity
{ time, value: +row['average_value_Unemployment, female (% of female labor force) (modeled ILO estimate)'], variable: 'Female Unemployment' },
{ time, value: +row['average_value_Children in employment, total (% of children ages 7-14)'], variable: 'Employment % of children ages 7-14' },
{ time, value: +row['average_value_Labor force participation rate for ages 15-24, total (%) (modeled ILO estimate)'], variable: 'Labor Force Participation ages 15-24' },
{ time, value: +row['average_value_Labor force participation rate, total (% of total population ages 15-64) (modeled ILO estimate)'], variable: 'Labor Force Participation ages 15-64' }
];

}).filter(d => d.value !== 0) // drop 0 values for cleaner graph
Insert cell
// Plot using point
vl.markPoint()
.data(usa_employment)
.encode(
vl.x().fieldT("time").title("Year"),
vl.y().fieldQ("value").title("Average Value (%)"),
vl.color().fieldN("variable").title("Variable").scale({ scheme: "category10" }).legend({
labelLimit: 200}), //allow full legend labels to show
vl.tooltip(["time", "value", "variable"])
)
.width(500)
.height(300)
.title('Average Employment and Unemployment Rates in the United States')
.render()
Insert cell
Insert cell
egyptdata = data.filter(row => row['Country Name'] === 'Egypt, Arab Rep.')
Insert cell
// choose employment related columns to represent
egypt_employment = egyptdata.flatMap(row => {
const time = row['Year'];
return [
{ time, value: +row['average_value_Unemployment, male (% of male labor force) (modeled ILO estimate)'], variable: 'Male Unemployment' }, //renaming columns for legend simplicity
{ time, value: +row['average_value_Unemployment, female (% of female labor force) (modeled ILO estimate)'], variable: 'Female Unemployment' },
{ time, value: +row['average_value_Children in employment, total (% of children ages 7-14)'], variable: 'Employment of children ages 7-14' },
{ time, value: +row['average_value_Labor force participation rate for ages 15-24, total (%) (modeled ILO estimate)'], variable: 'Labor Force Participation ages 15-24' },
{ time, value: +row['average_value_Labor force participation rate, total (% of total population ages 15-64) (modeled ILO estimate)'], variable: 'Labor Force Participation ages 15-64' }
];

}).filter(d => d.value !== 0) // drop 0 values for cleaner graph
Insert cell
// Plot using point
vl.markPoint()
.data(egypt_employment)
.encode(
vl.x().fieldT("time").title("Year"),
vl.y().fieldQ("value").title("Average Value (%)"),
vl.color().fieldN("variable").title("Variable").scale({ scheme: "category10" }).legend({
labelLimit: 200}), //allow full legend labels to show
vl.tooltip(["time", "value", "variable"])
)
.width(500)
.height(300)
.title('Average Employment and Unemployment Rates in Egypt')
.render()
Insert cell
Insert cell
Insert cell
// defining data for countries with top

topMaleCountries = data.map(row => ({
country: row['Country Name'],
rate: +row['average_value_Unemployment, female (% of female labor force) (modeled ILO estimate)'],
gender: 'Male'
}))
.sort((a, b) => b.rate - a.rate) // Sort in order
.slice(0, 20) // limit to top 20
Insert cell
topFemaleCountries = data.map(row => ({
country: row['Country Name'],
rate: +row['average_value_Unemployment, female (% of female labor force) (modeled ILO estimate)'],
gender: 'Female'
}))
.sort((a, b) => b.rate - a.rate) // Sort in order
.slice(0, 20) // limit to top 20
Insert cell
// combine for male and female
MF_unemployment = [...topMaleCountries, ...topFemaleCountries]
Insert cell
vl.markBar()
.data(MF_unemployment)
.encode(
vl.x().fieldN("country").title("Country").axis({ labelAngle: -45 }),
vl.y().fieldQ("rate").title("Average Unemployment Rate (%)"),
vl.color().fieldN("gender").title("Gender"),
vl.column().fieldN("gender").title("Gender")
)
.render()
Insert cell
Insert cell
vl.markBar()
.data(data)
.transform(
vl.aggregate([ // take mean of unemployment metric
{ op: 'mean', field: 'average_value_Unemployment, male (% of male labor force) (modeled ILO estimate)', as: 'mean_male' }
]).groupby(['Country Name']),

vl.window({ op: 'rank', as: 'rank' }) // Rank to find highest unemployment
.sort([{ field: 'mean_male', order: 'descending' }]),
vl.filter('datum.rank <= 10') // limit to top 10 countries

)
.encode(
vl.y().fieldQ('mean_male').title('Average Male Unemployment Rate (%)'),
vl.x().fieldN('Country Name').title('Country').axis({ labelAngle: -40 }),
vl.color().fieldQ('mean_male').title('%').scale({ scheme: 'tealblues' })
)
.width(500)
.height(300)
.title('Countries with Highest Average Male Unemployment Rates')
.render()

Insert cell
vl.markBar()
.data(data)
.transform(
vl.aggregate([ // take mean of unemployment metric
{ op: 'mean', field: 'average_value_Unemployment, female (% of female labor force) (modeled ILO estimate)', as: 'mean_female' }
]).groupby(['Country Name']),

vl.window({ op: 'rank', as: 'rank' }) // Rank to find highest unemployment
.sort([{ field: 'mean_female', order: 'descending' }]),
vl.filter('datum.rank <= 10') // limit to top 10 countries
)
.encode(
vl.y().fieldQ('mean_female').title('Average Female Unemployment Rate (%)'),
vl.x().fieldN('Country Name').title('Country').axis({ labelAngle: -40 }),
vl.color().fieldQ('mean_female').title('%').scale({ scheme: 'tealblues' })
)
.width(500)
.height(300)
.title('Countries with Highest Average Female Unemployment Rates')
.render()

Insert cell
Insert cell
southafricadata = data.filter(row => row['Country Name'] === 'South Africa')
Insert cell
southafrica_employment = southafricadata.flatMap(row => {
const time = row['Year'];
return [
{ time, value: +row['average_value_Unemployment, male (% of male labor force) (modeled ILO estimate)'], variable: 'Male Unemployment (%)' }, //renaming columns for legend simplicity
{ time, value: +row['average_value_Unemployment, female (% of female labor force) (modeled ILO estimate)'], variable: 'Female Unemployment (%)' },
{ time, value: +row['average_value_Life expectancy at birth, female (years)'], variable: 'Female Life Expectancy (yrs)' },
{ time, value: +row['average_value_Life expectancy at birth, male (years)'], variable: 'Male Life Expectancy (yrs)' },
];

}).filter(d => d.value !== 0) // drop 0 values for cleaner graph
Insert cell
// Plot using markpoint
vl.markPoint()
.data(southafrica_employment)
.encode(
vl.x().fieldT("time").title("Year"),
vl.y().fieldQ("value").title("Average Value"),
vl.color().fieldN("variable").title("Variable").scale({ scheme: "paired" }).legend({
labelLimit: 200}), //allow full legend labels to show
vl.tooltip(["time", "value", "variable"])
)
.width(500)
.height(300)
.title('Unemployment and Livelihood Metrics in South Africa')
.render()
Insert cell
Insert cell
nmacedoniadata = data.filter(row => row['Country Name'] === 'North Macedonia')
Insert cell
nmacedonia_employment = nmacedoniadata.flatMap(row => {
const time = row['Year'];
return [
{ time, value: +row['average_value_Unemployment, male (% of male labor force) (modeled ILO estimate)'], variable: 'Male Unemployment (%)' }, //renaming columns for legend simplicity
{ time, value: +row['average_value_Unemployment, female (% of female labor force) (modeled ILO estimate)'], variable: 'Female Unemployment (%)' },
{ time, value: +row['average_value_Life expectancy at birth, female (years)'], variable: 'Female Life Expectancy (yrs)' },
{ time, value: +row['average_value_Life expectancy at birth, male (years)'], variable: 'Male Life Expectancy (yrs)' },
];

}).filter(d => d.value !== 0) // drop 0 values for cleaner graph
Insert cell
// Plot using point
vl.markPoint()
.data(nmacedonia_employment)
.encode(
vl.x().fieldT("time").title("Year"),
vl.y().fieldQ("value").title("Average Value"),
vl.color().fieldN("variable").title("Variable").scale({ scheme: "paired" }).legend({
labelLimit: 200}), //allow full legend labels to show
vl.tooltip(["time", "value", "variable"])
)
.width(500)
.height(300)
.title('Unemployment and Livelihood Metrics in North Macedonia')
.render()
Insert cell
Insert cell
vl.hconcat(
vl.markBar()
.data(data)
.transform(
vl.aggregate([ // take mean of unemployment metric
{ op: 'mean', field: 'average_value_Unemployment, male (% of male labor force) (modeled ILO estimate)', as: 'mean_male' }
]).groupby(['Country Name']),

vl.window({ op: 'rank', as: 'rank' }) // Rank to find highest unemployment
.sort([{ field: 'mean_male', order: 'descending' }]),
vl.filter('datum.rank <= 10')

)
.encode(
vl.y().fieldQ('mean_male').title('Average Male Unemployment Rate (%)'),
vl.x().fieldN('Country Name').title('Country').axis({ labelAngle: -40 }),
// vl.color().fieldQ('mean_male').title('%').scale({ scheme: 'tealblues' })
)
.width(500)
.height(300)
.title('Countries with Highest Average Male Unemployment Rates'),

vl.markBar()
.data(data)
.transform(
vl.aggregate([ // Calculate the mean for each country
{ op: 'mean', field: 'average_value_Life expectancy at birth, male (years)', as: 'life_expectancy_male' }
]).groupby(['Country Name']),
vl.window({ op: 'rank', as: 'rank' }) // Rank countries by mean_male unemployment
.sort([{ field: 'mean_male', order: 'descending' }]),
vl.filter('datum.rank <= 10')
)
.encode(
vl.y().fieldQ('life_expectancy_male').title('Life Expectancy (years)'),
vl.x().fieldN('Country Name').title('Country').axis({ labelAngle: -40 }),
// vl.color().fieldQ('life_expectancy_male').title('Years').scale({ scheme: 'reds' })
)
.width(500)
.height(300)
.title('Life Expectancy for Countries with Highest Male Unemployment')
).render()
Insert cell
vl.hconcat(
vl.markBar()
.data(data)
.transform(
vl.aggregate([ // take mean of unemployment metric
{ op: 'mean', field: 'average_value_Unemployment, female (% of female labor force) (modeled ILO estimate)', as: 'mean_female' }
]).groupby(['Country Name']),

vl.window({ op: 'rank', as: 'rank' }) // Rank to find highest unemployment
.sort([{ field: 'mean_female', order: 'descending' }]),
vl.filter('datum.rank <= 10')

)
.encode(
vl.y().fieldQ('mean_female').title('Average Female Unemployment Rate (%)'),
vl.x().fieldN('Country Name').title('Country').axis({ labelAngle: -40 }),
// vl.color().fieldQ('mean_male').title('%').scale({ scheme: 'tealblues' })
)
.width(500)
.height(300)
.title('Countries with Highest Average Female Unemployment Rates'),

vl.markBar()
.data(data)
.transform(
vl.aggregate([ // Calculate the mean for each country
{ op: 'mean', field: 'average_value_Life expectancy at birth, female (years)', as: 'life_expectancy_female' }
]).groupby(['Country Name']),
vl.window({ op: 'rank', as: 'rank' }) // Rank countries by mean_male unemployment
.sort([{ field: 'mean_female', order: 'descending' }]),
vl.filter('datum.rank <= 10')
)
.encode(
vl.y().fieldQ('life_expectancy_female').title('Life Expectancy (years)'),
vl.x().fieldN('Country Name').title('Country').axis({ labelAngle: -40 }),
)
.width(500)
.height(300)
.title('Life Expectancy for Countries with Highest Female Unemployment')
).render()
Insert cell
Insert cell
vl.hconcat(
vl.markPoint()
.data(data)
.transform(
vl.aggregate([
{ op: 'mean', field: 'average_value_Unemployment, male (% of male labor force) (modeled ILO estimate)', as: 'mean_male' },
{ op: 'mean', field: 'average_value_Life expectancy at birth, male (years)', as: 'life_expectancy_male' }
]).groupby(['Country Name']),
)
.encode(
vl.x().fieldQ('mean_male').title('Unemployment Rate (%)'),
vl.y().fieldQ('life_expectancy_male').title('Life Expectancy (years)'),
)
.width(500)
.height(300)
.title('Male Unemployment Rate vs Life Expectancy at Birth'),

vl.markPoint()
.data(data)
.transform(
vl.aggregate([
{ op: 'mean', field: 'average_value_Unemployment, female (% of female labor force) (modeled ILO estimate)', as: 'mean_female' },
{ op: 'mean', field: 'average_value_Life expectancy at birth, female (years)', as: 'life_expectancy_female' }
]).groupby(['Country Name']),

)
.encode(
vl.x().fieldQ('mean_female').title('Unemployment Rate (%)'),
vl.y().fieldQ('life_expectancy_female').title('Life Expectancy (years)'),
)
.width(500)
.height(300)
.title('Female Unemployment Rate vs Life Expectancy at Birth')

)
.render()
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more