A look at residental real estate listing and sales, according to monthly reports from Zillow.
import pandas as pd
import numpy as np
import altair as alt
from datetime import datetime
today = datetime.today()
#
urls = {
"Listings_PriceCut": "https://files.zillowstatic.com/research/public_csvs/perc_listings_price_cut/Metro_perc_listings_price_cut_uc_sfrcondo_week.csv",
"SalesCount": "https://files.zillowstatic.com/research/public_csvs/sales_count_now/Metro_sales_count_now_uc_sfrcondo_month.csv",
"NewListings": "https://files.zillowstatic.com/research/public_csvs/new_listings/Metro_new_listings_uc_sfrcondo_week.csv",
"MedianAgeToPending": "https://files.zillowstatic.com/research/public_csvs/med_doz_pending/Metro_med_doz_pending_uc_sfrcondo_week.csv",
"RentIndex": "https://files.zillowstatic.com/research/public_csvs/zori/Metro_ZORI_AllHomesPlusMultifamily_Smoothed.csv",
}
def doChart(metric='Listings_PriceCut', location='United States', unit='%', zero=True, yoy=False, color='navy', size=3):
url = urls.get(metric)
df_raw = pd.read_csv(url, encoding = "ISO-8859-1")
months = df_raw.columns.to_list()[3:]
df_tmp = df_raw.set_index('RegionName')[months].T.reset_index()
print('Most recent data: {}'.format(months[-1]))
if yoy:
df_yoy = df_tmp[['index', location]].sort_values('index').copy()
df_yoy = df_yoy.set_index('index')
df_yoy['Change'] = df_yoy[location].apply(lambda v: v if isinstance(v, float) else np.nan).pct_change(12).apply(lambda v: 100 * v)
df_yoy = df_yoy.dropna()
#print(df_yoy.tail(20))
return alt.Chart(df_yoy.reset_index()).mark_bar(size=size, color=color).encode(
alt.X('index:T', axis=alt.Axis(title='', format="%b-%y")),
alt.Y('Change:Q', axis=alt.Axis(title=metric.replace('_', ' ') + " [{}]".format(unit))),
color=alt.condition(f"datum['Change'] < 0",
alt.value('tomato'),
alt.value(color)
),
tooltip=[alt.Tooltip('Change:Q', format=',.02f'), alt.Tooltip('index:T', format='%B %Y')]
).properties(
title="Zillow {} ({}) YoY Growth over time".format(metric.replace('_', ' '), location),
width=750,
height=450,
background='white'
)
else:
theFormat = unit if '%' in unit else '$,d' if '$' in unit else ',d'
return alt.Chart(df_tmp).mark_line(color=color).encode(
alt.X('index:T', axis=alt.Axis(title='', format="%b-%y")),
alt.Y('{}:Q'.format(location),
scale=alt.Scale(zero=zero),
axis=alt.Axis(title=metric.replace('_', ' ') + f" [{unit}]", format=theFormat)),
tooltip=[alt.Tooltip('{}:Q'.format(location), format=',.02f'),
alt.Tooltip('index:T', format='%B %Y')]
).properties(
title="Zillow {} ({}) over time".format(metric.replace('_', ' '), location),
width=750,
height=450,
background='white'
)
doChart(metric='Listings_PriceCut', location='United States')
c = doChart(metric='SalesCount', location='United States', unit='YoY % Growth', yoy=True, color='teal')
c.save('residential-realestate-zillow.png')
c.display()
doChart(metric='SalesCount', location='Chicago, IL', unit='YoY % Growth', yoy=True)
doChart(metric='SalesCount', location='Denver, CO', unit='YoY % Growth', yoy=True)
doChart(metric='SalesCount', location='Des Moines, IA', unit='YoY % Growth', yoy=True)
doChart(metric='Listings_PriceCut', location='Denver, CO')
doChart(metric='NewListings', location='Chicago, IL', unit='# of homes')
doChart(metric='MedianAgeToPending', location='United States', unit='days')
doChart(metric='MedianAgeToPending', location='Dallas-Fort Worth, TX', unit='days')
doChart(metric='MedianAgeToPending', location='Denver, CO', unit='days')
doChart(metric='MedianAgeToPending', location='Phoenix, AZ', unit='days')
doChart(metric='NewListings', location='United States', unit='# of homes')
doChart(metric='SalesCount', location='Denver, CO', unit='# of homes')
doChart(metric='RentIndex', location='United States', unit='$ / month', zero=True)
doChart(metric='RentIndex', location='Denver, CO', unit='$ / month')