By Ben Welsh
The Los Angeles Times conducted an analysis of agricultural property tax breaks issued by Santa Barbara County for Steve Lopez's Oct. 20, 2018, column "At Hollister Ranch, homeowners enjoy private beaches — and hefty tax breaks, too."
It found that Hollister Ranch owners — including celebrities and wealthy business moguls — had their property tax trimmed by roughly 50% this year, reducing the county's revenue by about $2 million.
A map of all parcels in Santa Barbara County was filtered down to only those in Hollister Ranch using two publically available map files. They were then filtered again to include only parcels that received a property-tax break given to agricultural lands under California's Williamson Act. The names of parcel owners were acquired via a California Public Records Act request with the Santa Barbara County Assessor and merged with the maps.
This was done in consultation with Santa Barbara County officials as well as a lawyer for Hollister Ranch.
%run ./src/parcels.ipynb
The list of Hollister Ranch parcels was used to scrape property tax records published by the county assessor. They include the property tax each owner was billed in the most recent year. Also harvested was a "value notice" detailing each property's reduced assessment under the Williamson Act, as well as what it would have been assessed at without the break under Proposition 13, the state's reigning property tax law. Comparing these two values is the core of the analysis that follows. The data were gathered in consultation with Santa Barbara County officials.
Here is an example of a value notice with the two key values highlighted:
%run ./src/download.ipynb
%run ./src/parse.ipynb
import pandas as pd
import altair as alt
from src import settings
A little configuration
pd.options.display.float_format = '${:,.0f}'.format
A few helpers
printmoney = lambda s: print(f'${s:,.0f}')
printpctchange = lambda new, old: print(f'{((new - old) / old)*100:0.2f}%')
The scraped data is read in.
williamson_df = pd.read_csv(f"{settings.output_dir}/parsed.csv")
len(williamson_df)
total_williamson_value = williamson_df.williamson_assessment.sum()
printmoney(total_williamson_value)
total_prop13_value = williamson_df.prop13_assessment.sum()
printmoney(total_prop13_value)
printmoney(total_prop13_value - total_williamson_value)
printpctchange(total_williamson_value, total_prop13_value)
total_williamson_tax = williamson_df.williamson_tax.sum()
printmoney(total_williamson_tax)
estimated_prop13_tax = total_prop13_value * 0.011
printmoney(estimated_prop13_tax)
printmoney(estimated_prop13_tax - total_williamson_tax)
printpctchange(total_williamson_tax, estimated_prop13_tax)
williamson_df['assessment_break'] = williamson_df.williamson_assessment - williamson_df.prop13_assessment
alt.Chart(williamson_df).mark_bar().encode(
alt.X("assessment_break:Q", bin=True),
y='count()',
)
williamson_df.assessment_break.describe().reset_index()
williamson_df.sort_values("assessment_break").head()[[
'apn',
'primary_owner',
'williamson_assessment',
'prop13_assessment',
'assessment_break'
]]
williamson_df['prop13_tax_estimate'] = williamson_df.prop13_assessment * 0.011
williamson_df['tax_break_estimate'] = williamson_df.williamson_tax - williamson_df.prop13_tax_estimate
alt.Chart(williamson_df).mark_bar().encode(
alt.X("tax_break_estimate:Q", bin=True),
y='count()',
)
williamson_df['tax_break_estimate'].describe().reset_index()
williamson_df.sort_values("tax_break_estimate").head()[[
'apn',
'primary_owner',
'williamson_tax',
'prop13_tax_estimate',
'tax_break_estimate'
]]
williamson_df.to_csv(f"{settings.output_dir}/analyzed.csv", index=False, encoding="utf-8")