Capital is Back: From Labor to Capital in the Modern Economy
economy
python
Wealth-Income Ratios in Advanced Economies 1980-2023
Published
Aug 14, 2025
Keywords
wealth-income
Summary
The chart illustration the evolution of thel wealth-income ratio from 1980 to 2023 highlights the interplay between wealth accumulation and income generation over last five decades. It reveals a clear upward trend, reflecting the disproportionate growth of wealth relative to income, particularly in recent decades. This relationship is largely determined by the growth of the economy relative to the growth of capital. When capital grows at a faster rate than the economy, wealth concentrates disproportionately, amplifying disparities and altering the balance of economic power.
Code
# Libraries# ===================================================import requestsimport pandas as pdimport numpy as npimport seaborn as snsimport matplotlib.pyplot as pltimport matplotlib.lines as mlinesimport matplotlib.patheffects as patheffectsimport matplotlib.font_manager as fmimport matplotlib.image as mpimgfrom io import BytesIO# Extract Data (Countries)# ===================================================# Extract JSON to dataframeurl ='https://raw.githubusercontent.com/guillemmaya92/world_map/main/Dim_Country.json'response = requests.get(url)data = response.json()df = pd.DataFrame(data)df = pd.DataFrame.from_dict(data, orient='index').reset_index()df_countries = df.rename(columns={'index': 'ISO3'})# Extract Data (WID)# ===================================================# Extract PARQUET to dataframeurl ="https://raw.githubusercontent.com/guillemmaya92/Analytics/master/Data/WID_Values.parquet"df = pd.read_parquet(url, engine="pyarrow")# Transform Data# ===================================================# Filter nulls and countriesdf = df[df['wiratio'].notna()]df = pd.merge(df, df_countries, left_on='country', right_on='ISO2', how='inner')# Rename columnsdf = df.rename( columns={'Country_Abr': 'country_name','wiratio': 'beta' } )# Filter countries have data post 1980dfx = df.loc[df['year'] ==1980, 'country']df = df[df['country'].isin(dfx)]df = df[df['year'] >=1980]df = df[df['Analytical'] =='Advanced Economies']# Dataframe countriesdfc = df[df['country'].isin(['CN', 'US', 'FR', 'DE', 'ES'])]# Select columns and orderdf = df[['year', 'country', 'country_name', 'beta']]print(df)# Visualization Data# ===================================================# Font Styleplt.rcParams.update({'font.family': 'sans-serif', 'font.sans-serif': ['Open Sans'], 'font.size': 10})# Create color dictionaire palette = {'CN': '#ffc2c2', 'US': '#c2d2ff', 'FR': '#c2ffcb', 'DE': '#e5c2ff', 'ES': '#fffac2'}# Create line plotsplt.figure(figsize=(12, 8))sns.lineplot(data=df, x='year', y='beta', hue='country', linewidth=0.3, alpha=0.5, palette=['gray'], legend=False)sns.lineplot(data=dfc, x='year', y='beta', hue='country', linewidth=2.25, palette=['black'], legend=False)sns.lineplot(data=dfc, x='year', y='beta', hue='country', linewidth=1.5, palette=palette, legend=False)# Custom plotplt.text(0, 1.08, 'Capital is back', fontsize=16, fontweight='bold', ha='left', transform=plt.gca().transAxes)plt.text(0, 1.045, 'Wealth-Income Ratios in Advanced Economies 1980-2023', fontsize=11, color='#262626', ha='left', transform=plt.gca().transAxes)plt.xlabel('Year', fontsize=10, fontweight='bold')plt.ylabel('Wealth-Income Ratio', fontsize=10, fontweight='bold')plt.grid(axis='x', alpha=0.7, linestyle=':')plt.ylim(0, 12)plt.xlim(1980, 2026)plt.xticks(range(1980, 2026, 10))plt.tight_layout()# Delete spinesfor spine in ["top", "right"]: plt.gca().spines[spine].set_visible(False)# Add Data Sourceplt.text(0, -0.08, 'Data Source: World Inequality Database (WID)', transform=plt.gca().transAxes, fontsize=8, fontweight='bold', color='gray')# Add Notesplt.text(0, -0.1, 'Notes: Wealth-Income Ratio is the division of national wealth by national income.', transform=plt.gca().transAxes, fontsize=7, fontstyle='italic', color='gray')# Add Year labelformatted_date =2023plt.text(1, 1.08, f'{formatted_date}', transform=plt.gca().transAxes, fontsize=20, ha='right', va='top', fontweight='bold', color='#D3D3D3')# Legend valuesbeta_cn =round(df[(df['country'] =='CN') & (df['year'] ==2023)]['beta'].values[0], 1)beta_de =round(df[(df['country'] =='DE') & (df['year'] ==2023)]['beta'].values[0], 1)beta_es =round(df[(df['country'] =='ES') & (df['year'] ==2023)]['beta'].values[0], 1)beta_fr =round(df[(df['country'] =='FR') & (df['year'] ==2023)]['beta'].values[0], 1)beta_us =round(df[(df['country'] =='US') & (df['year'] ==2023)]['beta'].values[0], 1)# Legend linesline1 = mlines.Line2D([], [], color=palette['CN'], label=f'China: {beta_cn}', linewidth=2)line2 = mlines.Line2D([], [], color=palette['DE'], label=f'Germany: {beta_de}', linewidth=2)line3 = mlines.Line2D([], [], color=palette['ES'], label=f'Spain: {beta_es}', linewidth=2)line4 = mlines.Line2D([], [], color=palette['FR'], label=f'France: {beta_fr}', linewidth=2)line5 = mlines.Line2D([], [], color=palette['US'], label=f'USA: {beta_us}', linewidth=2)line6 = mlines.Line2D([], [], color='grey', label=f'Advanced economies', linewidth=1)line1.set_path_effects([patheffects.withStroke(linewidth=4, foreground='black')])line2.set_path_effects([patheffects.withStroke(linewidth=4, foreground='black')])line3.set_path_effects([patheffects.withStroke(linewidth=4, foreground='black')])line4.set_path_effects([patheffects.withStroke(linewidth=4, foreground='black')])line5.set_path_effects([patheffects.withStroke(linewidth=4, foreground='black')])# Legend plotplt.legend(handles=[line1, line2, line3, line4, line5, line6], title='Countries', fontsize=9, title_fontproperties=fm.FontProperties(weight='bold'))# Define flagsflag_urls = {'CN': 'https://raw.githubusercontent.com/matahombres/CSS-Country-Flags-Rounded/master/flags/CN.png','US': 'https://raw.githubusercontent.com/matahombres/CSS-Country-Flags-Rounded/master/flags/US.png','FR': 'https://raw.githubusercontent.com/matahombres/CSS-Country-Flags-Rounded/master/flags/FR.png','ES': 'https://raw.githubusercontent.com/matahombres/CSS-Country-Flags-Rounded/master/flags/ES.png','DE': 'https://raw.githubusercontent.com/matahombres/CSS-Country-Flags-Rounded/master/flags/DE.png'}# Load flagsflags = {country: mpimg.imread(BytesIO(requests.get(url).content)) for country, url in flag_urls.items()}# Add flagsyear =2023# Adjust flags itemsfor country, flag in flags.items():# Find beta for each country beta_value = df[(df['country'] == country) & (df['year'] == year)]['beta'].values[0]if country =='CN': plt.imshow(flag, aspect='auto', extent=[year+1, year+2, beta_value -0.2, beta_value +0.2], alpha=0.7)elif country =='DE': plt.imshow(flag, aspect='auto', extent=[year+1, year+2, beta_value -0.2, beta_value +0.2], alpha=0.7)elif country =='ES': plt.imshow(flag, aspect='auto', extent=[year+1, year+2, beta_value -0.2, beta_value +0.2], alpha=0.7)elif country =='FR': plt.imshow(flag, aspect='auto', extent=[year+1, year+2, beta_value -0.4, beta_value +0], alpha=0.7)elif country =='US': plt.imshow(flag, aspect='auto', extent=[year+1, year+2, beta_value -0.4, beta_value +0], alpha=0.7)# Save the animation :)plt.savefig("C:/Users/guill/Downloads/FIG_WID_Beta_Evolution.png", dpi=300, bbox_inches='tight') # Show plotplt.show()