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)
136
total_williamson_value = williamson_df.williamson_assessment.sum()
printmoney(total_williamson_value)
$182,204,442
total_prop13_value = williamson_df.prop13_assessment.sum()
printmoney(total_prop13_value)
$371,160,842
printmoney(total_prop13_value - total_williamson_value)
$188,956,400
printpctchange(total_williamson_value, total_prop13_value)
-50.91%
total_williamson_tax = williamson_df.williamson_tax.sum()
printmoney(total_williamson_tax)
$2,016,049
estimated_prop13_tax = total_prop13_value * 0.011
printmoney(estimated_prop13_tax)
$4,082,769
printmoney(estimated_prop13_tax - total_williamson_tax)
$2,066,720
printpctchange(total_williamson_tax, estimated_prop13_tax)
-50.62%
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()
index | assessment_break | |
---|---|---|
0 | count | $136 |
1 | mean | $-1,389,385 |
2 | std | $1,668,667 |
3 | min | $-15,048,700 |
4 | 25% | $-1,797,666 |
5 | 50% | $-924,590 |
6 | 75% | $-419,249 |
7 | max | $-8,246 |
williamson_df.sort_values("assessment_break").head()[[
'apn',
'primary_owner',
'williamson_assessment',
'prop13_assessment',
'assessment_break'
]]
apn | primary_owner | williamson_assessment | prop13_assessment | assessment_break | |
---|---|---|---|---|---|
107 | 83680025 | HOLLISTER RANCH TRUST 1/5/16 | $6,799,698 | $21,848,398 | $-15,048,700 |
85 | 83680005 | HOLLISTER RANCH 54 GP CA | $1,823,680 | $8,147,960 | $-6,324,280 |
106 | 83680024 | DASH HOLDINGS III, LLC | $4,401,121 | $10,092,512 | $-5,691,391 |
3 | 83700002 | HAYDEN PROPERTIES, LLC | $2,315,560 | $6,746,081 | $-4,430,521 |
104 | 83680022 | HOWARD RANCH LLC | $2,409,530 | $6,788,460 | $-4,378,930 |
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()
index | tax_break_estimate | |
---|---|---|
0 | count | $136 |
1 | mean | $-15,196 |
2 | std | $18,302 |
3 | min | $-165,064 |
4 | 25% | $-19,551 |
5 | 50% | $-10,162 |
6 | 75% | $-4,610 |
7 | max | $-83 |
williamson_df.sort_values("tax_break_estimate").head()[[
'apn',
'primary_owner',
'williamson_tax',
'prop13_tax_estimate',
'tax_break_estimate'
]]
apn | primary_owner | williamson_tax | prop13_tax_estimate | tax_break_estimate | |
---|---|---|---|---|---|
107 | 83680025 | HOLLISTER RANCH TRUST 1/5/16 | $75,269 | $240,332 | $-165,064 |
85 | 83680005 | HOLLISTER RANCH 54 GP CA | $20,187 | $89,628 | $-69,441 |
106 | 83680024 | DASH HOLDINGS III, LLC | $48,718 | $111,018 | $-62,300 |
3 | 83700002 | HAYDEN PROPERTIES, LLC | $25,632 | $74,207 | $-48,575 |
104 | 83680022 | HOWARD RANCH LLC | $26,672 | $74,673 | $-48,001 |
williamson_df.to_csv(f"{settings.output_dir}/analyzed.csv", index=False, encoding="utf-8")