Published
Edited
Sep 10, 2021
1 star
Insert cell
Insert cell
numberOfGroups = 1465

Insert cell
chart = {
let root = pack(dataPure);
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("font-size", 10)
.attr("font-family", "sans-serif")
.attr("text-anchor", "middle");

const leaf = svg.selectAll("g")
//.data(root.leaves())
.data(root.descendants())
.join("g")
.attr("transform", d => `translate(${d.x + 1},${d.y + 1})`);


leaf.append("circle")
.attr("r", d => d.r)
//.attr("stroke", d => d.children ? "gray" : "none") //add color for group circles
.attr("stroke", "none")
.attr("stroke-width", "0.2px")
.attr("fill-opacity", 1.0)
.attr("fill", d => {
let fill
if (d.children) {
fill = "none"
} else {
//fill = color(d.data)
if (d.data.incomePerCapMon > highIncome) {
fill = d3.hsl(160, 0.25, 0.7)
} else if (d.data.incomePerCapMon > middleIncome) {
fill = d3.hsl(47, 1.0, 0.6)
} else {
fill = d3.hsl(10, 0.98, 0.8)
}
}
return fill
});

leaf.append("circle")
.attr("r", d => {
return Math.sqrt(lowIncome/d.data.incomePerCapMon)*d.r;
})
.attr("stroke", "white")
.attr("stroke-width", d => {
let width = 0.0
if (d.data.incomePerCapMon>lowIncome) {
width = 0.5
}
return width
})
.attr("fill-opacity", 0.0)
.attr("fill", "none");

leaf.append("circle")
.attr("r", d => {
return Math.sqrt(middleIncome/d.data.incomePerCapMon)*d.r;
})
.attr("stroke", "white")
.attr("stroke-width", d => {
let width = 0.0
if (d.data.incomePerCapMon>middleIncome) {
width = 0.5
}
return width
})
.attr("fill-opacity", 0.0)
.attr("fill", "none");

leaf.append("circle")
.attr("r", d => {
return Math.sqrt(highIncome/d.data.incomePerCapMon)*d.r;
})
.attr("stroke", "white")
.attr("stroke-width", d => {
let width = 0.0
if (d.data.incomePerCapMon>highIncome) {
width = 0.5
}
return width
})
.attr("fill-opacity", 0.0)
.attr("fill", "none");

leaf.append("circle")
.attr("r", d => {
return Math.sqrt(veryHighIncome/d.data.incomePerCapMon)*d.r;
})
.attr("stroke", "white")
.attr("stroke-width", d => {
let width = 0.0
if (d.data.incomePerCapMon>veryHighIncome) {
width = 0.5
}
return width
})
.attr("fill-opacity", 0.0)
.attr("fill", "none");

leaf.append("circle")
.attr("r", d => {
let scale = d3.scaleSqrt()
.domain([0, 146000000])
.range([0, 50]);
return scale(d.data.population)
})
.attr("fill", d3.hsl(360, 0, 0.3));

/*svg.selectAll(".categories")
.data(root.children)
.enter()
.append("g")
.attr("transform", d => `translate(${d.x + 1},${d.y + d.r + 1})`)
.append("text")
.text(d => d.data.name)
.attr("font-size", 12)
.attr("font-family", "sans-serif")
.attr("text-anchor", "middle");*/
return svg.node();
}
Insert cell
Insert cell
dataSocialGroups = {
let dataTmp = []
let lowIncomeClass = []
let middleClass = []
let upperMiddleClass = []
let highIncomeClass = []
let veryHighIncomeClass = []

for (let i in data.children) {
if (data.children[i].incomePerCapMon < lowIncome) {
lowIncomeClass.push(data.children[i])
} else if (data.children[i].incomePerCapMon < middleIncome) {
middleClass.push(data.children[i])
} else if (data.children[i].incomePerCapMon < highIncome) {
upperMiddleClass.push(data.children[i])
} else if (data.children[i].incomePerCapMon < veryHighIncome) {
highIncomeClass.push(data.children[i])
} else {
veryHighIncomeClass.push(data.children[i])
}
}
return {name: "Income Distribution",
children: [{name: "Low Income", children: lowIncomeClass},
{name: "Middle Income", children: middleClass},
{name: "Upper Middle Income", children: upperMiddleClass},
{name: "High Income", children: highIncomeClass},
{name: "Very High Income", children: veryHighIncomeClass}]
};
}
Insert cell
dataPure = {
let child = []

for (let i in data.children) {
child.push(data.children[i])
}
return {name: "Income Distribution",
children: [{name: "Entire Population", children: child}]
};
}
Insert cell
dataPure.children[0].children
Insert cell
pack = data => d3.pack()
.size([width - 2, height - 2])
.padding(1)
(d3.hierarchy(data)
.sum(d => d.incomePerCapMon)
//.sum(d => d.population)
.sort((a, b) => d3.descending(a.value, b.value)))
Insert cell
pack(dataSocialGroups)
Insert cell
Insert cell
Insert cell
Insert cell
format = d3.format(",d")
Insert cell
color = d => {return d3.hsl(160, 0.26, 0.9-d.incomePerCapMon/200000*0.4)}
Insert cell
d3 = require("d3@7")
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
incomePerCapMed = 27036.4
Insert cell
incomeModal = 15527.4
Insert cell
incomeMean = 35675.8
Insert cell
Insert cell
lowIncome = 16000
Insert cell
middleIncome = 40000
Insert cell
highIncome = 70000
Insert cell
veryHighIncome = 100000
Insert cell
Insert cell
freqLogNorm = function(x, mu, sigma) {
return 1/(x*Math.sqrt(2*Math.PI*sigma*sigma))*Math.exp(-Math.pow((Math.log(x)-mu),2)/(2*sigma*sigma));
}
Insert cell
mu = Math.log(incomePerCapMed)

Insert cell

sigma = Math.sqrt(2*(-mu + Math.log(incomeMean)))
Insert cell
sigma2 = Math.sqrt(mu - Math.log(incomeModal))
Insert cell
incomeMax = 500e3
Insert cell
nPoints = 1000
Insert cell
Insert cell
Insert cell
Insert cell
incomePopulationCDF = {
let data = []
let xTemp = 0
let yTemp = 0
let input = incomePopulationDensityData
for (let i = 0; i<=nPoints; i++) {
xTemp = input[i][0]
if (i>0) yTemp += 0.5*(input[i][1] + input[i-1][1])*(input[i][0]-input[i-1][0]);
data.push([xTemp, yTemp]);
}
return data
}
Insert cell
Insert cell
Insert cell
lorenzData = {
let data = []
let xTemp = 0
let yTemp = 0
data.push([0, 0])
for (let i = 1; i<=nPoints; i++) {
let populationSize = (incomePopulationCDF[i][1]-incomePopulationCDF[i-1][1])*populationTotal
let incomeMeanPerYear = 0.5*(incomePopulationCDF[i][0]+incomePopulationCDF[i-1][0])*12*populationSize
xTemp += populationSize/populationTotal;
yTemp += incomeMeanPerYear/incomeTotal;
data.push([xTemp, yTemp]);
}
data.push([1, 1])
return data
}
Insert cell
lorenzDataRosstat={
let dataRosstat = [{population: 0.2, income: 0.055},{population: 0.2, income: 0.103}, {population: 0.2, income: 0.153},{population: 0.2, income: 0.227}, {population: 0.2, income: 0.462}]

let dataRosstatPlot=[
{x: dataRosstat[0].population,
y: dataRosstat[0].income}
];
for (let i = 1; i<5; i++) {
dataRosstatPlot.push({x: dataRosstatPlot[i-1].x+dataRosstat[i].population,
y: dataRosstatPlot[i-1].y+dataRosstat[i].income
});
}
return dataRosstatPlot
}
Insert cell
lorenzCurve(1)-lorenzCurve(0.8)
Insert cell
Insert cell
lorenzCurve ={
let data = lorenzData;
let dataX = []
let dataY = []
for (let i=0; i<data.length; i++) {
dataX[i] = data[i][0]
dataY[i] = data[i][1]
}
function interpolate(x) {
let y
if (x > 0 && x < 1) {
let index = dataX.findIndex(element => element>=x)
y = dataY[index-1] + (dataY[index]-dataY[index-1])*(x-dataX[index-1])/(dataX[index]-dataX[index-1])
} else if (x<=0) {
y = 0
} else {
y = 1
}
return y
}
return interpolate
}
Insert cell
incomeDistr = {
function incomeDistribution(nGroups, lorenzCurve) {
let income = []
let groupSize = 1/nGroups

let x1 = 0.0, x2
let incomeTemp = 0
let populationTemp
let incomePerCapMonTemp
for (let i = 0; i < nGroups; i++) {
x2 = x1 + groupSize;
populationTemp = (x2 - x1)*populationTotal
incomeTemp = (lorenzCurve(x2) - lorenzCurve(x1))*incomeTotal
incomePerCapMonTemp = incomeTemp/12/populationTemp
income.push({population: populationTemp, income: incomeTemp, incomePerCapMon: incomePerCapMonTemp, betterThen: x1})

x1 = x2;
}
return income;
}
return incomeDistribution
}
Insert cell
test = incomeDistr(5, lorenzCurve)
Insert cell
dataTest
Insert cell
Insert cell
Insert cell
innerWidth = base - margin.left - margin.right;
Insert cell
innerHeight = base - margin.top - margin.bottom;
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more