# default_exp cityfinance
This colab and more can be found at https://github.com/BNIA/VitalSigns.
Whats Inside?:
https://bniajfi.org/indicators/Housing%20And%20Community%20Development/homtax
https://bniajfi.org/indicators/Housing%20And%20Community%20Development/histax
Indicators Used
- ✔️ 46 - histax - (MdProp, BCDF) Number of Historic Tax Credits per 1,000 Residential Units
The number of residential properties that received the Historic Tax Credit per 1,000 residential properties within an area. The credit is granted on the increased assessment directly resulting from qualified improvements. The duration of the credit is for 10 years, and is applicable to properties located in designated areas of significant historical value.
- ✔️ 47 - homtax - (MdProp, BCDF) Number of Homestead Tax Credits per 1,000 Residential Units
The number of residential properties that received the homestead tax credit per 1,000 residential properties within an area. The Homestead Credit limits the increase in taxable assessments each year to a fixed percentage. Every county and municipality in Maryland is required to limit taxable assessment increases to 10% or less each year, with the Baltimore City rate capped at 4%.
❌
Datasets Used
- ✔️ housing.TaxCredits_201X (46-homtax, 47-owntax) From BidBaltimore
year = "20"
Import Modules
! pip install -U -q PyDrive
! pip install geopy
! pip install geopandas
! pip install geoplot
! pip install dataplay
! pip install matplotlib
! pip install psycopg2-binary! apt-get install build-dep python-psycopg2
! apt-get install libpq-dev
! apt-get install libspatialindex-dev!pip install rtree
!pip install dexplotfrom dataplay.geoms import workWithGeometryData%%capture
# These imports will handle everything
import os
import sys
import csv
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import geopandas as gpd
from geopandas import GeoDataFrame
import psycopg2
import pyproj
from pyproj import Proj, transform
# conda install -c conda-forge proj4
from shapely.geometry import Point
from shapely import wkb
from shapely.wkt import loads
# https://pypi.org/project/geopy/
from geopy.geocoders import Nominatim
# In case file is KML, enable support
import fiona
fiona.drvsupport.supported_drivers['kml'] = 'rw'
fiona.drvsupport.supported_drivers['KML'] = 'rw'from IPython.display import clear_output
clear_output(wait=True)import ipywidgets as widgets
from ipywidgets import interact, interact_manual
Configure Enviornment
# This will just beautify the output
pd.set_option('display.expand_frame_repr', False)
pd.set_option('display.precision', 2)
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"
# pd.set_option('display.expand_frame_repr', False)
# pd.set_option('display.precision', 2)
# pd.reset_option('max_colwidth')
pd.set_option('max_colwidth', 20)
# pd.reset_option('max_colwidth')totalres = pd.read_csv("37-totalres-19.csv")
# totalres.set_index('CSA2010', inplace=True)
totalres.tail(1)
HomesteadTax_FY20 - BidBaltimore - NEW
lsoriginal = gpd.read_file("HomesteadTax_FY20"+year+"_CSACity.shp");original.rename(columns={ 'CSA':'CSA2010', 'BaltCity':'InBaltimore'}, inplace=True)
df = original[ original['CSA2010'].notnull() | original['InBaltimore'].notnull() ]print('After filtering records where a CSA or Baltimore geo-code match Exists')
print( 'All rows Before Filter: ', original.shape[0] ) # rows, columns
print( '# w BCity.isnull: ', df.InBaltimore.isnull().sum() ); bmorow = df[ df.CSA2010.isnull() ].shape[0]
print( '# w CSA2010.isnull: ', bmorow ); csarow = df[ df.CSA2010.notnull() ].shape[0]
print( '# w CSA2010.notnull: ', csarow );
print( '# rows After Filter: ', df.shape[0],'==',csarow,'+',bmorow,'==', csarow + bmorow); # add baltimore city
df.CSA2010 = df.CSA2010.fillna('Baltimore City')homesteadTax = df.copy()
homesteadTax.head(1)
HistoricTax_FY20xx - BidBaltimore - NEW
lsoriginal = gpd.read_file("HistoricTax_FY20"+year+"_CSACity.shp");original.rename(columns={ 'CSA':'CSA2010', 'BaltCity':'InBaltimore'}, inplace=True)
df = original[ original['CSA2010'].notnull() | original['InBaltimore'].notnull() ]print('After filtering records where a CSA or Baltimore geo-code match Exists')
print( 'All rows Before Filter: ', original.shape[0] ) # rows, columns
print( '# w BCity.isnull: ', df.InBaltimore.isnull().sum() ); bmorow = df[ df.CSA2010.isnull() ].shape[0]
print( '# w CSA2010.isnull: ', bmorow ); csarow = df[ df.CSA2010.notnull() ].shape[0]
print( '# w CSA2010.notnull: ', csarow );
print( '# rows After Filter: ', df.shape[0],'==',csarow,'+',bmorow,'==', csarow + bmorow); # add baltimore city
df.CSA2010 = df.CSA2010.fillna('Baltimore City')historicTax = df.copy()
historicTax.head(1)
HistoricTax 46 - (MdProp, TaxSale)
https://bniajfi.org/indicators/Housing%20And%20Community%20Development/histax
Above:2016Query. Beloew:2017Query
with numerator AS (
select (sum(
case
when csa_present
then 1
else NULL
end)::numeric) as result, csa
from vital_signs.match_csas_and_bc_by_geom('housing.historictax_fy2018', 'gid', 'the_geom') a
left join housing.historictax_fy2018 b on a.gid = b.gid
group by csa
),
denominator AS (
select (sum(
case
when (address != $$NULL$$) AND (desclu = $$Apartments$$ OR desclu = $$Residential$$ OR desclu = $$Residential Commercial$$ OR desclu = $$Residential Condominium$$)
then 1
else NULL
end)::numeric
) as result, csa
from vital_signs.match_csas_and_bc_by_geom('housing.mdprop_2017v2', 'gid', 'the_geom') a
left join housing.mdprop_2017v2 b on a.gid = b.gid
group by csa, the_pop
),
tbl AS (
select denominator.csa,(numerator.result / denominator.result)*(1000::numeric) as result
from numerator left join denominator on numerator.csa = denominator.csa
)
select * from tbl where 1 = 1 ORDER BY csa ASC;
t = """
with numerator AS (
select (sum(
case
when csa_present
then 1
else NULL
end)::numeric) as result, csa
from vital_signs.match_csas_and_bc_by_geom('housing.historictax_fy2017', 'gid', 'the_geom') a
left join housing.historictax_fy2017 b on a.gid = b.gid
group by csa
),
denominator AS (
select (sum(
case
when (address != $$NULL$$) AND (desclu = $$Apartments$$ OR desclu = $$Residential$$ OR desclu = $$Residential Commercial$$ OR desclu = $$Residential Condominium$$)
then 1
else NULL
end)::numeric
) as result, csa
from vital_signs.match_csas_and_bc_by_geom('housing.mdprop_2017', 'gid', 'the_geom') a
left join housing.mdprop_2017 b on a.gid = b.gid
group by csa, the_pop
),
tbl AS (
select denominator.csa,(numerator.result / denominator.result)*(1000::numeric) as result
from numerator left join denominator on numerator.csa = denominator.csa
)
update vital_signs.data
set histax = result from tbl where data.csa = tbl.csa and data_year = '2016';
"""historicTax.columnstotalres = pd.read_csv("37-totalres-"+year+".csv"def histax(df, totalres, year):
histax = df.copy()
# Aggregate Numeric Values by Sum
histax['histaxCount'] = 1
histax = histax.groupby('CSA2010').sum(numeric_only=True)
# Make sure ALL csas and BaltimoreCity are included. among other things
histax = totalres[ ['CSA2010','totalres'+year] ].merge( histax, left_on='CSA2010', right_on='CSA2010', how='outer' )
# Update the baltimore CSA.
histax.at[55,'histaxCount'] = histax['histaxCount'].sum()
# Create the Indicator
histax['46-histax'+year] = histax['histaxCount'] * 1000 / totalres['totalres'+year]
histax = histax[['CSA2010', 'histaxCount', '46-histax'+year, 'totalres'+year ]]
compareYears = gpd.read_file("https://services1.arcgis.com/mVFRs7NF4iFitgbY/ArcGIS/rest/services/Histax/FeatureServer/0/query?where=1%3D1&outFields=*&returnGeometry=true&f=pgeojson");
prevYear = 'histax'+ str( int(year) - 1 )
if prevYear in compareYears.columns:
histax = histax.merge( compareYears[['CSA2010', prevYear]], left_on='CSA2010', right_on='CSA2010', how='outer' )
histax['change'] = histax['46-histax'+year] - histax[ prevYear ]
histax['percentChange'] = histax['change'] / histax[ prevYear ] * 1000
histax['change'] = histax['change'].apply(lambda x: "{:.2f}".format(x) )
histax = histax[['CSA2010', 'histaxCount', 'totalres19', 'histax18', '40-histax19', 'percentChange', 'change']]
return histaxhistax = histax( historicTax, totalres, year)
histax.head(60)
histax.to_csv('46-histax'+year+'.csv', index=False)
HomesteadTax 47 - (MdProp, TaxSale)
t = """
with numerator AS (
select (sum(
case
when csa_present
then 1
else NULL
end)::numeric) as result, csa
from vital_signs.match_csas_and_bc_by_geom('housing.homesteadtax_fy2017', 'gid', 'the_geom') a
left join housing.homesteadtax_fy2017 b on a.gid = b.gid
group by csa
),
denominator AS (
select (sum(
case
when (address != $$NULL$$) AND (desclu = $$Apartments$$ OR desclu = $$Residential$$ OR desclu = $$Residential Commercial$$ OR desclu = $$Residential Condominium$$)
then 1
else NULL
end)::numeric
) as result, csa
from vital_signs.match_csas_and_bc_by_geom('housing.mdprop_2017', 'gid', 'the_geom') a
left join housing.mdprop_2017 b on a.gid = b.gid
group by csa, the_pop
),
tbl AS (
select denominator.csa,(numerator.result / denominator.result)*(1000::numeric) as result
from numerator left join denominator on numerator.csa = denominator.csa
)
update vital_signs.data
set homtax = result from tbl where data.csa = tbl.csa and data_year = '2016';
Above:2016Query. Beloew:2017Query
with numerator AS (
select (sum(
case
when csa_present
then 1
else NULL
end)::numeric) as result, csa
from vital_signs.match_csas_and_bc_by_geom('housing.homesteadtax_fy2018', 'gid', 'the_geom') a
left join housing.homesteadtax_fy2018 b on a.gid = b.gid
group by csa
),
denominator AS (
select (sum(
case
when (address != $$NULL$$) AND (desclu = $$Apartments$$ OR desclu = $$Residential$$ OR desclu = $$Residential Commercial$$ OR desclu = $$Residential Condominium$$)
then 1
else NULL
end)::numeric
) as result, csa
from vital_signs.match_csas_and_bc_by_geom('housing.mdprop_2017v2', 'gid', 'the_geom') a
left join housing.mdprop_2017v2 b on a.gid = b.gid
group by csa, the_pop
),
tbl AS (
select denominator.csa,(numerator.result / denominator.result)*(1000::numeric) as result
from numerator left join denominator on numerator.csa = denominator.csa
)
select * from tbl where 1 = 1 ORDER BY csa ASC;
"""totalres = pd.read_csv("37-totalres-"+year+".csv")totalres.columns#export
def homtax(df, totalres, year):
homtax = df.copy()
# Aggregate Numeric Values by Sum
homtax['homtaxCount'] = 1
homtax = homtax.groupby('CSA2010').sum(numeric_only=True)
# Make sure ALL csas and BaltimoreCity are included. among other things
homtax = totalres[ ['CSA2010','totalres'+year] ].merge( homtax, left_on='CSA2010', right_on='CSA2010', how='outer' )
# Update the baltimore CSA.
homtax.at[55,'homtaxCount'] = homtax['homtaxCount'].sum()
# Create the Indicator
homtax['47-homtax'+year] = homtax['homtaxCount'] * 1000 / totalres['totalres'+year]
homtax = homtax[['CSA2010', 'homtaxCount', '47-homtax'+year, 'totalres'+year ]]
compareYears = gpd.read_file("https://services1.arcgis.com/mVFRs7NF4iFitgbY/ArcGIS/rest/services/Histax/FeatureServer/0/query?where=1%3D1&outFields=*&returnGeometry=true&f=pgeojson");
prevYear = 'histax'+ str( int(year) - 1 )
if prevYear in compareYears.columns:
homtax = homtax.merge( compareYears[['CSA2010', prevYear]], left_on='CSA2010', right_on='CSA2010', how='outer' )
homtax['change'] = homtax['47-homtax'+year] - homtax[ prevYear ]
homtax['percentChange'] = homtax['change'] / homtax[ prevYear ] * 1000
homtax['change'] = homtax['change'].apply(lambda x: "{:.2f}".format(x) )
homtax = homtax[['CSA2010', 'homtaxCount', 'totalres19', 'homtax18', '47-homtax19', 'percentChange', 'change']]
return homtaxhomtax = homtax( homesteadTax, totalres, year)
homtax.head(60)
homtax.to_csv('47-homtax'+year+'.csv', index=False)
owntax 48
Seema did it most recently
select (sum(
case
when csa_present
then 1
else 0
end)::numeric) as result, csa
from vital_signs.match_csas_and_bc_by_geom('housing.homeownertax_2016', 'gid', 'the_geom') a
left join housing.homeownertax_2016 b on a.gid = b.gid
group by csa order by csa
WE ARE NOT USING THE QUERY OR THE DATA FROM THE QUERY
DATA WAS PROVIDED IN AN ALREADY AGGREGATED FORM
STARTING FROM 2016; WE Used to get it raw.
We do not get it raw for data confidentiality reasons (you would know how much people earn.)
we don't have 2020 so i know it's 19. but just something to keep in our notes, that for dept of finance data the fiscal year is +1 on what we call it for VS