Author: Martin Wong @ Autonomous Econ This is a demo site built using Quarto and Python. Check out the full Substack post here.
Average home ownership has been dropping in each successive generation at every given age group, see Figure 1.
Code
import pandas as pdimport plotly.express as px# Load the demographic share datasetdf_ownership = pd.read_csv("home_ownership_generation.csv", sep=",")# Function to plot home ownership rates by age and generation using Plotlydef plot_ownership_by_age_and_generation_plotly(df):# Define the custom color palette colors = {"Gen X": "#636EFA", # blue"Baby Boomer": "#B6E880", # light green"Gen Z": "#FFA15A", # orange"Millennial": "#EF553B", # red"Silent": "#FF97FF", # pink }# Create the plot fig = px.line( df, x="Age group", y="Home Ownership Rate", color="Generation", title="", labels={"Age group": "Age Group","Home Ownership Rate": "Home Ownership Rate (%)", }, line_shape="linear", color_discrete_map=colors, # Apply the custom color palette ) fig.update_layout( xaxis_title="Age Group", yaxis_title="", legend_title_text="", template="plotly_dark", xaxis=dict(tickangle=45), plot_bgcolor="#282a36", paper_bgcolor="#282a36", font=dict(size=14, family="Consolas"), # Set the font to Consolas title_font=dict(size=18, family="Consolas"), width=500, # Adjust based on your needs height=450, # Adjust based on your needs margin=dict(l=20, r=20, t=40, b=20), ) fig.update_yaxes(title_text="", range=[40, 90]) fig.show()# Plot the data using Plotlydf_ownership_grouped = ( df_ownership[ (df_ownership["Generation"] !="Other")& (df_ownership["Generation"] !="Total")& (~df_ownership["Age group"].isin(["0-4", "5-9", "10-14"])) ] .groupby(["Age group", "Generation"])["Home Ownership Rate"] .mean() .reset_index())plot_ownership_by_age_and_generation_plotly(df_ownership_grouped)
Average home ownership since 1986 has declined the most for those aged 25-34, see Figure 2.
Code
import pandas as pdimport plotly.graph_objects as go# Load the demographic share datasetdf_filtered = pd.read_csv("home_ownership_generation.csv", sep=",")# Filter the data for the age ranges 25 to 74age_ranges = ["25-29","30-34","35-39","40-44","45-49","50-54","55-59","60-64","65-69","70-74",]df_filtered = df_filtered[df_filtered["Age group"].isin(age_ranges)]# Define a function to map age ranges to the new intervalsdef map_age(age):if age in ["25-29", "30-34"]:return"25-34"elif age in ["35-39", "40-44"]:return"35-44"elif age in ["45-49", "50-54"]:return"45-54"elif age in ["55-59", "60-64"]:return"55-64"elif age in ["65-69", "70-74"]:return"65-74"else:returnNone# Apply the function to create a new age columndf_filtered.loc[:, "Age_Group"] = df_filtered["Age group"].apply(map_age)# Group the data by the new age column and calculate the mean Home Ownership Rate for each groupdf_grouped = ( df_filtered.groupby(["Year", "Age_Group"])["Home Ownership Rate"] .mean() .reset_index())# Create a line plot using Plotlyfig = go.Figure()# Define colors for each age groupcolors = {"25-34": "#636EFA", # blue"35-44": "#B6E880", # light green"45-54": "#FFA15A", # orange"55-64": "#EF553B", # red"65-74": "#FF97FF", # pink}# Add traces for each age groupfor age_group in df_grouped["Age_Group"].unique(): age_group_data = df_grouped[df_grouped["Age_Group"] == age_group] fig.add_trace( go.Scatter( x=age_group_data["Year"], y=age_group_data["Home Ownership Rate"], mode="lines+markers", name=age_group, line=dict(color=colors[age_group]), showlegend=False, ) )# Add annotation for the last data point of each age group fig.add_annotation( x=age_group_data["Year"].values[-1] +1, y=age_group_data["Home Ownership Rate"].values[-1], text=age_group, font=dict(color=colors[age_group], family="Consolas"), showarrow=False, xanchor="left", yanchor="middle", )# Update layout for dark modefig.update_layout( title="Home Ownership Rate (mean) by Age Group", template="plotly_dark", plot_bgcolor="#282a36", paper_bgcolor="#282a36", title_font=dict(size=18, family="Consolas"), xaxis_title="Year", yaxis_title="Home Ownership Rate", font=dict(size=14, family="Consolas"), width=500, # Adjust based on your needs height=450, # Adjust based on your needs margin=dict(l=20, r=50, t=40, b=20),)fig.update_yaxes(title_text="", range=[40, 90])fig.update_xaxes(title_text="", range=[1985, 2020])fig.show()
Baby boomers have been the driving home ownership growth but their influence will begin to wane in the coming decade, see Figure 3.
Code
import pandas as pdfrom plotly.subplots import make_subplotsimport plotly.graph_objects as go# Load the datasetdf = pd.read_csv("pop_estimate_processed_nz.csv", sep=",")df_2030 = pd.read_csv("pop_estimate_processed_2030.csv", sep=",")# Concatenate df_2030 to dfdf_combined = pd.concat([df, df_2030], ignore_index=True)# Apply the relabeling function to the 'Age' columndf_combined["Age"] = df_combined["Age"].apply(lambda age: "90+"if age =="90 Years and over"else age)# Define the years of interest for plotting (excluding 2018)years = [1996, 2006, 2023, 2030]# Create a subplot figure with 2 rows and 2 columnsfig = make_subplots( rows=2, cols=2, shared_yaxes=True, subplot_titles=[f"{year}"for year in years])row_col_pairs = [(1, 1), (1, 2), (2, 1), (2, 2)]for (row, col), year inzip(row_col_pairs, years):# Filter data for the specific year year_data = df_combined[df_combined["Year"] == year]# Determine bar colors based on 'Generation' colors = ["orange"if gen =="Baby Boomer"else"skyblue"for gen in year_data["Generation"] ]# Create bar traces for each age group fig.add_trace( go.Bar( x=year_data["Age"], y=year_data["Population"], marker_color=colors, showlegend=False, ), row=row, col=col, )# Add annotation pointing to the 'Baby Boomer' bar for 1996fig.add_annotation( x="65-69 Years", y=270000, # Adjust the y-coordinate to move the annotation down xref="x1", yref="y1", text="Baby Boomers", showarrow=False, font=dict( color="orange", size=16, family="Consolas" ), # Increase the font size and set font family)# Update layout for dark modefig.update_layout( template="plotly_dark", width=700, height=700, margin=dict(l=20, r=20, t=40, b=20), title_text="", plot_bgcolor="#282a36", paper_bgcolor="#282a36", font=dict(size=14, family="Consolas"), # Set the font family for the entire plot)# Update axis labels and rotate x-axis tick labelsfig.update_xaxes(title_text="", tickangle=45, tickfont=dict(family="Consolas"))fig.update_yaxes(title_text="", showticklabels=True, tickfont=dict(family="Consolas"))fig.update_yaxes(title_text="", range=[0, 400000])fig.show()