Industry Power Shifts: A 3D Clustering Analysis of Union Decline, Dividends, and Taxes
James Burnard
CONTEXT AND MOTIVATION
In 2025, I took a class called Survey Design and Analysis with Professor Nathan Meyers, who I really bonded with. I would frequently talk to him after class about Economics and his dissertation that was in progress. Eventually he offered an opportunity to explore some of the data he was working with.
We met weekly over Zoom and shared conversations about the state of his work, any interesting articles he would recommend, as well as any updates on the exploratory analysis I was doing. Overall, this experience was fantastic. I was able to work with one of the largest datasets I’ve ever worked with and have frequent conversations with a very kind professor whom I learned a lot from.
The final output is an interactive HTML report that includes a WebGL-powered 3D animation, hoverable industry points, rotatable axes, playback controls, a year timeline, speed control, cluster legend, and a cluster membership table.
INTRODUCTION
Nathan Meyer’s study, The Effect of Privatization on U.S. Employment and Industry Earnings Distributions, 2000-2018, argues that privatization should be understood as a structural shift in employment from the public sector toward the private sector. This shift has consequences for worker earnings across industries and income levels. The project builds on this by visualizing how industries move through a related economic space defined by three key variables: union decline, shareholder dividends, and taxes paid. I used 3D clustering as my visualization to explore whether industries with different labor, capital, and tax profiles separate into distinct patterns over time.
Inspired by Meyers’s industry-level approach to employment privatization, this project asks how broader transformations in labor power and firm behavior can be made visible. While Meyers focuses on public-private employment composition and earnings effects, this visualization examines adjacent indicators of institutional change: declining union density, shareholder dividend distributions, and taxes paid. By animating industry clusters over time, the project turns a static clustering analysis into an interactive map of changing industry power.
THE DATA
This project starts with the numeric union decline dataset, which Meyers shared with me. I developed a Python script to load the dataset, filter it to the relevant year range, and keep the variables needed for clustering and visualization.
The following key variables were extracted for analysis: _________________________________________________________________________
Year:
The observation year for each industry row. In the visualization, this
is what drives the animation over time.
Uniondens:
Union density. This measures the share or proportion of workers in an
industry who are union members or covered by unions, depending on the
dataset definition. In your project, it is used to calculate union
decline.
Dividendsdom:
Domestic dividends. This represents shareholder dividend payments
associated with domestic activity. In the project, it acts as a proxy
for shareholder payouts / capital returns by industry.
Taxespaid:
Taxes paid by the industry. In the visualization, this is one of the
three standardized clustering dimensions and represents the tax-payment
side of the industry profile.
Indcat:
Industry category code. This is the numeric industry identifier used to
group observations by industry. The script maps these codes to readable
names like mining, utilities, construction, retail, health care,
etc.
____________________________________________________________________________
Industry codes are mapped to readable industry names using a custom lookup dictionary. Union decline is calculated by taking each industry’s baseline union density and subtracting its union density in each year. This produces a time-varying union decline measure for each industry.
The three clustering variables are then standardized: union decline domestic shareholder dividends taxes paid. Standardization was important because the variables operate on very different scales. Without scaling, larger numeric variables like dividends or taxes could dominate the clustering model.
The final visualization dataset contains 886 industry-year observations, covering 44 industries across 27 years (1982-2008) and grouped into 3 K-Means clusters.
CLUSTERING
I used K-Means clustering on the standardized variables. Rather than hard coding a cluster count immediately, the script tests multiple values of k, from 3 to 8, and evaluates each one using silhouette score. The best silhouette score selected k = 3. The resulting clusters were then described based on the strongest standardized features in each cluster center. This produced readable cluster labels such as:
High Taxes Paid / High Dividends
Low Union Decline / Low Taxes Paid
High Union Decline / Low Taxes Paid
Each industry-year observation was assigned to one of these clusters.
INITIAL PLOTLY VERSION
The first version of the visualization used Plotly’s Scatter3d and animation frames. This produced a working interactive 3D plot with:
colored cluster points
industry path lines
hover labels
a year slider
play/pause controls
basic camera rotation
However, Plotly’s 3D animation system still behaved like frame playback. Even with more frames, the motion felt slightly like stop-motion because Plotly was swapping between discrete animation frames.
SWITCH TO THREE.js
To make the animation genuinely smoother, I replaced the Plotly animation layer with a custom Three.js/WebGL visualization. This was the biggest architectural change in the project. Instead of pre-generating hundreds of Plotly frames, the Python script now exports compact structured data into the HTML page. Three.js then renders the 3D scene in the browser using a continuous requestAnimationFrame loop.
This means point positions are recalculated every rendered frame, producing much smoother animation.
Three.js Scene Construction
The Three.js version creates a full 3D scene with:
a WebGL renderer
perspective camera
orbit controls
lighting
3D point meshes
historical industry path lines
grid lines
colored axis lines
hover detection with recasting
Each industry is represented as a sphere. Each sphere moves through the standardized 3D feature space over time.
The axes represent:
X: Union Decline
Y: Shareholder Dividends
Z: Taxes Paid
The industry path lines show each industry’s trajectory through the clustering space across years.
Smooth Animation
The animation is driven by browser time rather than fixed pre-rendered
frames.
For each animation frame:
The current year advances based on elapsed time and playback speed.
The script finds the two real data years surrounding the current animated year.
It interpolates between those two observations.
It applies cubic easing for smoother movement.
It updates every industry sphere’s position.
It updates cluster color transitions.
It renders the scene.
This creates fluid, continuous movement instead of stepping from frame to frame.
FINDINGS
The resulting animated plot is very much telling of the economic space. Cluster two represents the high union decline/ low taxes paid category, any industry in this cluster is colored red. In the early years, there are hardly any industries that fall within this category. In the last year that is modeled however, multiple industries turn red, and if you rotate the plot to only pay attention to the union decline axis, you’ll notice there is a steady progression of dots moving left along that axis. The dots moving left means that union decline is increasing steadily as the years progress.
This all suggests that declining union density is not confined to a few sectors but is a broader structural trend. In this visualization, that movement represents a weakening or organized labor’s institutional presence across industries. By plotting union decline alongside shareholder dividends and taxes paid, the project situates labor decline within a much wider economic transformation.