The United States is a vast place with a diverse economic landscape. One way to characterize an economy is by looking at the distribution of employment across industries. To get a sense of how the mix of industries differs across states, I decided to look at data from the Bureau of Labor Statistic's Quarterly Census of Employment and Wages.
In the interactive plot above, each row represents an industry, and each bar represents a state. The position of the bars on the x-axis represents the industry's share of that state's total workforce. Click on the buttons above the charts to highlight regions and to see data for different years. Hover over the bars to see state names.
Focusing on one year's data at a time, we can spot some interesting regional patterns by examining where bars of the same color tend to concentrate in the distribution. For example, looking at 2016's data, we can clearly see how much more predominant Manufacturing is in the Midwest than in the West, since there are more blue bars to the right and more green bars to the left, with little overlap in between.
This is perhaps not too surprising. What is more surprising, to me at least, is the relative predominance of Construction and Real estate in the West -- perhaps a sign of the region's robust population growth and economic development -- and of Finance and insurance and Management of Companies and enterprises in the Midwest -- perhaps a result of the regions lower cost of operations compared to large coastal cities.
Switching between the years, we can see how employment distribution has changed over time. The most dramatic shift is probably the rise of employment in Health care and social assistance along with the decline in Manufacturing.
The combination of regional patterns and changes over time reveals some interesting insights. For example, looking at 2016's data, I noticed that Health care and social assistance, and Educational services, appear to be more predominant in the Northeast than elsewhere in the country. However, back in 1990, this wasn't the case. The Midwest was almost on par with the Northeast in terms of percent of people employed in Health care and social assistance, and the West was ahead of the Northeast in terms of Educational services. The rise of Healthcare and Educational services in the Northeast appears to a trend that has developed in the last thirty years.
Another interesting pattern I noticed is the increased predominance of Accomodation and food services in many states. Back in 1990, a few Western states stand out as having more employement in Accomodation and food services. In the last three decades, however, employment in Accomondation and food services have increased in other states, so that in 2016, there is no longer a clear division between the regions.
The data comes from the Bureau of Labor Statistic's Quarterly Census of Employment and Wages. Percentages are calculated from annual averages of monthly employment levels, by dividing employment for a given industry by total employment for that state. Employment includes all ownership types (public and private sectors). Industries represent NAICS Supersectors and the "Unclassified" category is not shown. Raw data and R script used to process the data can be found on my github.
forked from kathyxiong's block: Distribution of employment by industry, by state
xxxxxxxxxx
<html>
<head>
<meta charset="utf-8" />
<title>Industry Employment Visualization</title>
<script type="text/javascript" src="https://d3js.org/d3.v5.min.js"></script>
<style type="text/css">
body {
font-family: Helvetica, Arial, sans-serif;
font-size: 12px;
}
.grid line {
stroke: lightgrey;
shape-rendering: crispEdges;
}
.grid path,
.x-axis path,
.y-axis path {
stroke-width: 0;
}
.y-axis {
font-weight: bold;
font-size: 14px;
text-transform: initial;
}
.region-button,
.year-button,
.button-caption {
text-transform: uppercase;
}
#tooltip {
position: absolute;
width: auto;
height: auto;
padding: 2px;
background-color: white;
border-color: black;
border-style: solid;
border-width: 1px;
pointer-events: none;
}
#tooltip.hidden {
display: none;
}
#tooltip p {
margin: 0;
line-height: 12px;
text-transform: initial;
}
</style>
</head>
<body>
<script>
var margin = {top: 100, right: 20, bottom: 40, left: 350},
width = 1200 - margin.right - margin.left,
height = 800 - margin.top - margin.bottom;
var formatPercent = d3.format(".0%");
var x = d3.scaleLinear()
.range([0, width]);
var y = d3.scaleBand()
.rangeRound([0, height])
.padding(0.1);
var col = d3.scaleOrdinal()
.range(["#e41a1c",
"#377eb8",
"#4daf4a",
"#984ea3"]);
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin.right + margin.left)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var rowConverter = function(d) {
return {
id: d.id,
year: +d.year,
area_title: d.area_title,
industry_title: d.industry_title,
industry_emplvl: +d.industry_emplvl,
total_emplvl: +d.total_emplvl,
industry_emp_pct: +d.industry_emp_pct,
industry_emp_pct_us: +d.industry_emp_pct_us,
region: d.region
};
}
d3.csv("viz_data.csv", rowConverter).then(function(data) {
//console.log(data[0]);
var data_sub = [];
// default to showing 2016 data
for (var i = 0; i < data.length; i++) {
if (data[i].year == 2016) {
data_sub.push(data[i]);
}
}
var sort_y = function(a, b) {
return d3.descending(a.industry_emp_pct_us, b.industry_emp_pct_us);
}
x.domain([0, d3.max(data, function(d) { return d.industry_emp_pct; })]);
y.domain(data_sub.sort(sort_y).map(function(d) { return d.industry_title; }));
svg.append("g")
.attr("class", "x-axis")
.call(
d3.axisTop(x)
.tickFormat(formatPercent)
.tickSize(0)
);
svg.append("g")
.attr("class", "x-axis")
.attr("transform", "translate(0," + height + ")")
.call(
d3.axisBottom(x)
.tickFormat(formatPercent)
.tickSize(0)
);
svg.append("g")
.attr("class", "y-axis")
.call(
d3.axisLeft(y)
.tickSize(0)
.tickPadding(10)
);
svg.append("g")
.attr("class", "grid")
.call(
d3.axisTop(x)
.tickSize(-height)
.tickFormat("")
);
svg.append("text")
.attr("class", "x-axis-title")
.attr("transform", "translate(" + width / 2 + "," + height + ")")
.attr("dy", "30px")
.attr("text-anchor", "middle")
.text("Percent of workforce employed in industry")
/************************************** draw bars **************************************/
// first draw a set of grey bars that will be in the background
svg.selectAll(".bar-background")
.data(data_sub, function(d) { return d.id; })
.enter()
.append("rect")
.attr("class", "bar-background")
.attr("x", function(d) { return x(d.industry_emp_pct) - 2; })
.attr("y", function(d) { return y(d.industry_title); })
.attr("height", y.bandwidth())
.attr("width", 4)
// fill background bars with grey
.attr("fill", "#d3d3d3");
// then draw a set that will be in the foreground, and will be toggled on/off by region
svg.selectAll(".bar-foreground")
.data(data_sub, function(d) { return d.id; })
.enter()
.append("rect")
.attr("class", "bar-foreground")
.attr("x", function(d) { return x(d.industry_emp_pct) - 2; })
.attr("y", function(d) { return y(d.industry_title); })
.attr("height", y.bandwidth())
.attr("width", 4)
// fill foreground bars according to region, default to showing all regions
.attr("fill", function(d) { return col(d.region); })
.attr("visibility", "visible")
.on("mouseover", function(d){
//Get bar position
var xPos = parseFloat(d3.select(this).attr("x")) + margin.left + 8;
var yPos = parseFloat(d3.select(this).attr("y")) + margin.top - 12;
//Update tooltip position & value
d3.select("#tooltip")
.style("left", xPos + "px")
.style("top", yPos + "px")
.select("#value")
.text(d.area_title + ": " + formatPercent(d.industry_emp_pct));
//Show tooltip
d3.select("#tooltip").classed("hidden", false);
})
.on("mouseout", function(d) {
//Hide tooltip
d3.select("#tooltip").classed("hidden", true);
});
/********************************** draw region buttons **********************************/
var regionList = [ {region: "All Regions", id: "region-all"},
{region: "West", id: "region-west"},
{region: "Midwest", id: "region-midwest"},
{region: "South", id: "region-south"},
{region: "Northeast", id: "region-northeast"}];
svg.append("text")
.attr("class", "button-caption")
.attr("transform", function(d, i) {
return "translate(0, -70)";
})
.attr("text-anchor", "start")
.attr("fill", "black")
.text("Select region");
var regionButton = svg.selectAll(".region-button")
.data(regionList)
.enter()
.append("g")
.attr("class", "region-button")
.attr("id", function(d) { return d.id; })
.attr("transform", function(d, i) {
return "translate(" + i * 100 + ", -60)";
})
.on("mouseover", function() {
var rect = d3.select(this).select("rect");
if (rect.attr("fill-opacity") == 0) {
rect.attr("fill-opacity", 0.25);
}
})
.on("mouseout", function() {
var rect = d3.select(this).select("rect");
if (rect.attr("fill-opacity") == 0.25) {
rect.attr("fill-opacity", 0);
}
});
regionButton.append("rect")
.attr("width", 90)
.attr("height", 30)
.attr("stroke-width", 2)
.attr("stroke", function(d) {
if(d.region == "All Regions") {
return "black";
} else {
return col(d.region);
}
})
// default to "on" position for "All Regions" (opaque fill, white font),
// "off" position for all others
.attr("fill", function(d) {
if(d.region == "All Regions") {
return "black";
} else {
return col(d.region);
}
})
.attr("fill-opacity", function(d) {
if(d.region == "All Regions") {
return 1;
} else {
return 0;
}
});
regionButton.append("text")
.attr("dx", 45)
.attr("dy", 19)
.attr("text-anchor", "middle")
.text(function(d) { return d.region; })
// default to "on" position for "All Regions" (opaque fill, white font),
// "off" position for all others
.attr("fill", function(d) {
if(d.region == "All Regions") {
return "white";
} else {
return col(d.region);
}
});
/*********************************** draw year buttons ************************************/
var yearList = [ {year: 2016, id: "year-2016"},
{year: 2010, id: "year-2010"},
{year: 2000, id: "year-2000"},
{year: 1990, id: "year-1990"}];
svg.append("text")
.attr("class", "button-caption")
.attr("transform", function(d, i) {
return "translate(" + (width - 70 - 3 * 80) + ", -70)";
})
.attr("text-anchor", "start")
.attr("fill", "black")
.text("Select year");
var yearButton = svg.selectAll(".year-button")
.data(yearList)
.enter()
.append("g")
.attr("class", "year-button")
.attr("id", function(d) { return d.id; })
.attr("transform", function(d, i) {
return "translate(" + (width - 70 - i * 80) + ", -60)";
})
.on("mouseover", function() {
var rect = d3.select(this).select("rect");
if (rect.attr("fill") == "white") {
rect.attr("fill", "lightgrey");
}
})
.on("mouseout", function() {
var rect = d3.select(this).select("rect");
if (rect.attr("fill") == "lightgrey") {
rect.attr("fill", "white");
}
});
yearButton.append("rect")
.attr("width", 70)
.attr("height", 30)
.attr("stroke-width", 2)
.attr("stroke", "black")
// default to "on" position for 2016 (black fill, white font),
// "off" position for all others (white fill, black font)
.attr("fill", function(d) {
if(d.year == 2016) {
return "black";
} else {
return "white";
}
});
yearButton.append("text")
.attr("dx", 35)
.attr("dy", 19)
.attr("text-anchor", "middle")
.text(function(d) { return d.year; })
// default to "on" position for 2016 (black fill, white font),
// "off" position for all others (white fill, black font)
.attr("fill", function(d) {
if(d.year == 2016) {
return "white";
} else {
return "black";
}
});
/********************************** add action to region buttons **********************************/
function toggleRegion(obj, region) {
// set all region buttons to "off"
var regionButton = svg.selectAll(".region-button");
regionButton.selectAll("rect")
.attr("fill-opacity", 0);
regionButton.selectAll("text")
.attr("fill", function(d) {
if(d.region == "All Regions") {
return "black";
} else {
return col(d.region);
}
});
// set current region button to "on"
obj.select("rect")
.attr("fill-opacity", 1);
obj.select("text")
.attr("fill", "white");
// highlight selected region in chart
svg.selectAll(".bar-foreground")
.attr("visibility", function(d) {
if(d.region == region) {
return "visible";
} else {
return "hidden";
}
});
}
// bind toggle action to region buttons
svg.select("#region-midwest")
.on("click", function() {
toggleRegion(d3.select(this), "Midwest")
});
svg.select("#region-west")
.on("click", function() {
toggleRegion(d3.select(this), "West")
});
svg.select("#region-northeast")
.on("click", function() {
toggleRegion(d3.select(this), "Northeast")
});
svg.select("#region-south")
.on("click", function() {
toggleRegion(d3.select(this), "South")
});
// special case for the "All Regions" button
svg.select("#region-all")
.on("mouseover", function() {
var rect = d3.select(this).select("rect");
if (rect.attr("fill-opacity") == 0) {
rect.attr("fill-opacity", 0.25);
}
})
.on("mouseout", function() {
var rect = d3.select(this).select("rect");
if (rect.attr("fill-opacity") == 0.25) {
rect.attr("fill-opacity", 0);
}
})
.on("click", function() {
// set all region buttons to "off"
var regionButton = svg.selectAll(".region-button");
regionButton.selectAll("rect")
.attr("fill-opacity", 0);
regionButton.selectAll("text")
.attr("fill", function(d) {
if(d.region == "All Regions") {
return "black";
} else {
return col(d.region);
}
});
// set current region button to "on"
var obj = d3.select(this);
obj.select("rect")
.attr("fill-opacity", 1);
obj.select("text")
.attr("fill", "white");
// show all regions in chart
svg.selectAll(".bar-foreground")
.attr("visibility", "visible");
});
/********************************** add action to year buttons **********************************/
function toggleYear(obj, year) {
// set all year buttons to "off"
var regionButton = svg.selectAll(".year-button");
regionButton.selectAll("rect")
.attr("fill", "white");
regionButton.selectAll("text")
.attr("fill", "black");
// set current year button to "on"
obj.select("rect")
.attr("fill", "black");
obj.select("text")
.attr("fill", "white");
// change data selection and update bars
var data_sub = [];
for (var i = 0; i < data.length; i++) {
if (data[i].year == year) {
data_sub.push(data[i]);
}
}
// first update background bars
svg.selectAll(".bar-background")
.data(data_sub, function(d) { return d.id; })
.transition()
.duration(1000)
.attr("x", function(d) { return x(d.industry_emp_pct) - 2; });
// then update foreground bars
svg.selectAll(".bar-foreground")
.data(data_sub, function(d) { return d.id; })
.transition()
.duration(1000)
.attr("x", function(d) { return x(d.industry_emp_pct) - 2; });
}
// bind toggle action to region buttons
svg.select("#year-2016").on("click", function() { toggleYear(d3.select(this), 2016)} );
svg.select("#year-2010").on("click", function() { toggleYear(d3.select(this), 2010)} );
svg.select("#year-2000").on("click", function() { toggleYear(d3.select(this), 2000)} );
svg.select("#year-1990").on("click", function() { toggleYear(d3.select(this), 1990)} );
});
</script>
<div>
<div id="tooltip" class="hidden">
<p id="value"></p>
</div>
</div>
</body>
</html>
https://d3js.org/d3.v5.min.js