Skip to content

Commit

Permalink
Move PTAXSIM DB file to runner temp dir (#36)
Browse files Browse the repository at this point in the history
* Move PTAXSIM db file to runner temp dir

* Reformat RUNNER_TEMP context ref

* Set PTAXSIM_DB_PATH explicitly

* Set the DB file path, not dir path

* Switch back to temp dir

* Fix working dir issues

* Make sure temp dir exists

* Fix bash syntax

* Revert to not explicitly making temp dir

* Set PTAXSIM_DB_PATH in vignettes

* Fix NaN values produced by 0.00 agency rates
  • Loading branch information
dfsnow authored May 3, 2024
1 parent 9971e4e commit f0b4b82
Show file tree
Hide file tree
Showing 12 changed files with 100 additions and 20 deletions.
23 changes: 19 additions & 4 deletions .github/actions/prepare-ptaxsim/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ inputs:
ASSUMED_ROLE:
description: AWS role used for S3 actions
outputs:
PTAXSIM_DB_DIR:
description: "PTAXSIM database directory on runner"
value: ${{ steps.set_db_dir.outputs.PTAXSIM_DB_DIR }}
PTAXSIM_VERSION:
description: "PTAXSIM database version"
value: ${{ steps.version_db.outputs.PTAXSIM_VERSION }}
Expand All @@ -18,6 +21,14 @@ runs:
- name: Checkout
uses: actions/checkout@v4

- name: Set database directory
id: set_db_dir
run: |
PDIR=$RUNNER_TEMP
echo "PTAXSIM_DB_DIR=$PDIR" >> $GITHUB_ENV
echo "PTAXSIM_DB_DIR=$PDIR" >> $GITHUB_OUTPUT
shell: bash

- name: Get database version
id: version_db
run: |
Expand All @@ -30,7 +41,7 @@ runs:
uses: actions/cache@v3.3.2
id: cache_db
with:
path: ptaxsim.db.bz2
path: ${{ env.PTAXSIM_DB_DIR }}/ptaxsim.db.bz2
key: ${{ format('{0}-{1}', env.PTAXSIM_VERSION, hashFiles('DESCRIPTION')) }}
enableCrossOsArchive: true

Expand All @@ -47,23 +58,27 @@ runs:
run: |
aws s3 cp ${{ inputs.PTAXSIM_DB_BASE_URI }}/ptaxsim-${{ env.PTAXSIM_VERSION }}.db.bz2 ptaxsim.db.bz2 --quiet
shell: bash
working-directory: ${{ env.PTAXSIM_DB_DIR }}

- name: Unpack database (Linux)
if: runner.os == 'Linux'
run: |
sudo apt-get install -y pbzip2
pbzip2 -dk ${{ github.workspace }}/ptaxsim.db.bz2
pbzip2 -dk ptaxsim.db.bz2
shell: bash
working-directory: ${{ env.PTAXSIM_DB_DIR }}

- name: Unpack database (macOS)
if: runner.os == 'macOS'
run: |
brew install pbzip2
pbzip2 -dk ${{ github.workspace }}/ptaxsim.db.bz2
pbzip2 -dk ptaxsim.db.bz2
shell: bash
working-directory: ${{ env.PTAXSIM_DB_DIR }}

- name: Unpack database (Windows)
if: runner.os == 'Windows'
run: |
7z x ${{ github.workspace }}\ptaxsim.db.bz2
7z x ptaxsim.db.bz2
shell: cmd
working-directory: ${{ env.PTAXSIM_DB_DIR }}
6 changes: 5 additions & 1 deletion .github/workflows/R-CMD-check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ jobs:
- {os: ubuntu-latest, r: 'release'}
- {os: ubuntu-latest, r: 'oldrel-1'}
env:
PTAXSIM_DB_PATH: ${{ github.workspace }}/ptaxsim.db
R_KEEP_PKG_SOURCE: yes

# Required for OIDC access to S3
Expand Down Expand Up @@ -48,10 +47,15 @@ jobs:
needs: check

- name: Prepare PTAXSIM database
id: prep_ptaxsim_db
uses: ./.github/actions/prepare-ptaxsim
with:
ASSUMED_ROLE: ${{ secrets.AWS_IAM_ROLE_TO_ASSUME_ARN }}

- name: Set PTAXSIM database path
run: echo "PTAXSIM_DB_PATH=${{ steps.prep_ptaxsim_db.outputs.PTAXSIM_DB_DIR }}/ptaxsim.db" >> $GITHUB_ENV
shell: bash

- name: Check R package
uses: r-lib/actions/check-r-package@v2
with:
Expand Down
7 changes: 5 additions & 2 deletions .github/workflows/pkgdown.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ name: pkgdown
jobs:
build-pkgdown-site:
runs-on: ubuntu-latest
env:
PTAXSIM_DB_PATH: ${{ github.workspace }}/ptaxsim.db

# Required for OIDC access to S3
permissions:
Expand All @@ -37,10 +35,15 @@ jobs:
needs: website

- name: Prepare PTAXSIM database
id: prep_ptaxsim_db
uses: ./.github/actions/prepare-ptaxsim
with:
ASSUMED_ROLE: ${{ secrets.AWS_IAM_ROLE_TO_ASSUME_ARN }}

- name: Set PTAXSIM database path
run: echo "PTAXSIM_DB_PATH=${{ steps.prep_ptaxsim_db.outputs.PTAXSIM_DB_DIR }}/ptaxsim.db" >> $GITHUB_ENV
shell: bash

- name: Build pkgdown site
run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE)
shell: Rscript {0}
Expand Down
7 changes: 5 additions & 2 deletions .github/workflows/test-coverage.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ name: test-coverage
jobs:
test-coverage:
runs-on: ubuntu-latest
env:
PTAXSIM_DB_PATH: ${{ github.workspace }}/ptaxsim.db

# Required for OIDC access to S3
permissions:
Expand All @@ -32,10 +30,15 @@ jobs:
needs: coverage

- name: Prepare PTAXSIM database
id: prep_ptaxsim_db
uses: ./.github/actions/prepare-ptaxsim
with:
ASSUMED_ROLE: ${{ secrets.AWS_IAM_ROLE_TO_ASSUME_ARN }}

- name: Set PTAXSIM database path
run: echo "PTAXSIM_DB_PATH=${{ steps.prep_ptaxsim_db.outputs.PTAXSIM_DB_DIR }}/ptaxsim.db" >> $GITHUB_ENV
shell: bash

- name: Test coverage
run: |
covr::codecov(
Expand Down
1 change: 1 addition & 0 deletions R/tax_bill.R
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ tax_bill <- function(year_vec,
# Calculate the exemption effect by subtracting the exempt amount from
# the total taxable EAV
dt[, agency_tax_rate := agency_total_ext / as.numeric(agency_total_eav)]
dt[, agency_tax_rate := replace(agency_tax_rate, is.nan(agency_tax_rate), 0)]
dt[, tax_amt_exe := exe_total * agency_tax_rate]
dt[, tax_amt_pre_exe := round(eav * agency_tax_rate, 2)]
dt[, tax_amt_post_exe := round(tax_amt_pre_exe - tax_amt_exe, 2)]
Expand Down
6 changes: 6 additions & 0 deletions tests/testthat/test-tax_bill.R
Original file line number Diff line number Diff line change
Expand Up @@ -244,4 +244,10 @@ test_that("agnostic to input data.table row order", {
)
})

test_that("Returns 0 for agency with base/levy of 0", {
expect_false(
any(is.nan(tax_bill(2022, c("12283000140000", "12284120030000"))$final_tax))
)
})

DBI::dbDisconnect(ptaxsim_db_conn)
10 changes: 9 additions & 1 deletion vignettes/appeals.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ library(sf)
ptaxsim_db_conn <- DBI::dbConnect(RSQLite::SQLite(), here("./ptaxsim.db"))
```

```{r, echo=FALSE}
# This is needed to build the vignette using GitHub Actions
ptaxsim_db_conn <- DBI::dbConnect(
RSQLite::SQLite(),
Sys.getenv("PTAXSIM_DB_PATH")
)
```

## Gathering PINs of interest

To determine the impact of appeals, we first need a way to gather all the properties (PINs) in Schaumburg. Fortunately, PTAXSIM's database has all the data required to accomplish this task.
Expand Down Expand Up @@ -228,7 +236,7 @@ sb_pins_summ <- sb_pins_all %>%
),
idx = (med_av / med_av[stage == "2018\nboard"]) * 100
)
```
```

Finally, we can plot the index over time to see how reassessment and the subsequent appeals at each stage impacted assessed values.

Expand Down
18 changes: 13 additions & 5 deletions vignettes/exemptions.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ knitr::opts_chunk$set(

# Introduction

Property tax exemptions are savings that lower a homeowner’s property tax bill. They work by reducing or freezing the taxable value (Equalized Assessed Value, or EAV) of a home. For example, the most common exemption, the Homeowner Exemption, reduces EAV by \$10,000.
Property tax exemptions are savings that lower a homeowner’s property tax bill. They work by reducing or freezing the taxable value (Equalized Assessed Value, or EAV) of a home. For example, the most common exemption, the Homeowner Exemption, reduces EAV by \$10,000.

Once the exemption EAV has been subtracted from the property's EAV, the final EAV is multiplied by the local tax rate to get the final property tax bill. Since local tax rates can vary significantly by area, the actual effective value of each exemption likewise varies geographically.

Expand Down Expand Up @@ -41,6 +41,14 @@ library(ptaxsim)
ptaxsim_db_conn <- DBI::dbConnect(RSQLite::SQLite(), here("./ptaxsim.db"))
```

```{r, echo=FALSE}
# This is needed to build the vignette using GitHub Actions
ptaxsim_db_conn <- DBI::dbConnect(
RSQLite::SQLite(),
Sys.getenv("PTAXSIM_DB_PATH")
)
```

The PIN we'll use is **25-32-114-005-0000**, the same PIN whose bill is shown above. This is a small, single-family property in Calumet with a very typical exemption situation, just a Homeowner Exemption.

We can use the `tax_bill()` function to get every bill for this PIN from the last 15 years. These bills will _include_ any reduction from exemptions the PIN received.
Expand Down Expand Up @@ -183,7 +191,7 @@ The exemption amount for this PIN has increased in tandem with increases in the

We can also use PTAXSIM to answer hypotheticals. For example, how would this PIN's bill history change if the Homeowner Exemption increased from \$10,000 to \$15,000 in 2018?

To find out, we again create a modified PIN input to pass to `tax_bill()`. This time, we increase the Homeowner Exemption to $15,000 for all years after 2018.
To find out, we again create a modified PIN input to pass to `tax_bill()`. This time, we increase the Homeowner Exemption to $15,000 for all years after 2018.

```{r}
exe_dt_2 <- lookup_pin(2006:2020, "25321140050000") %>%
Expand Down Expand Up @@ -293,7 +301,7 @@ We're using `data.table` syntax here because it's much faster than `dplyr` when
t_bills_w_exe <- tax_bill(t_years, t_pins)[, stage := "With exemptions"]
```

Unlike a single PIN, removing exemptions from many PINs means that the base (the amount of total taxable value available) will change substantially. In order to accurately model the effect of removing exemptions, we need to fully recalculate the base of each district by adding the sum of taxable value recovered from each PIN.
Unlike a single PIN, removing exemptions from many PINs means that the base (the amount of total taxable value available) will change substantially. In order to accurately model the effect of removing exemptions, we need to fully recalculate the base of each district by adding the sum of taxable value recovered from each PIN.

To start, we use the `lookup_pin()` function to recover the total EAV of exemptions for each PIN.

Expand Down Expand Up @@ -367,7 +375,7 @@ t_no_exe_summ <- rbind(t_bills_w_exe, t_bills_no_exe)[
]
```

Finally, we can plot the average bill with and without exemptions by property type.
Finally, we can plot the average bill with and without exemptions by property type.

<details>

Expand Down Expand Up @@ -427,7 +435,7 @@ Exemptions in Calumet have significantly increased in both volume and amount (vi

Conversely, Calumet's commercial property owners have picked up an increasingly large share of the overall tax burden since 2006. In 2019, the average commercial property paid about $1,100 more than they would have if exemptions did not exist.

## Changing exemptions
## Changing exemptions

PTAXSIM can also answer hypotheticals about large areas. For example, how would the average residential tax bill in Calumet change if the Senior Exemption increased by $5,000 and the Senior Freeze Exemption was removed?

Expand Down
8 changes: 8 additions & 0 deletions vignettes/introduction.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ library(ptaxsim)
ptaxsim_db_conn <- DBI::dbConnect(RSQLite::SQLite(), here("ptaxsim.db"))
```

```{r, echo=FALSE}
# This is needed to build the vignette using GitHub Actions
ptaxsim_db_conn <- DBI::dbConnect(
RSQLite::SQLite(),
Sys.getenv("PTAXSIM_DB_PATH")
)
```

## The main function - `tax_bill()` {#main-arguments}

PTAXSIM has a single primary function - `tax_bill()` - with two *required* arguments:
Expand Down
10 changes: 9 additions & 1 deletion vignettes/mapping.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ library(tidyr)
ptaxsim_db_conn <- DBI::dbConnect(RSQLite::SQLite(), here("./ptaxsim.db"))
```

```{r, echo=FALSE}
# This is needed to build the vignette using GitHub Actions
ptaxsim_db_conn <- DBI::dbConnect(
RSQLite::SQLite(),
Sys.getenv("PTAXSIM_DB_PATH")
)
```

## Single taxing district

We're going to use the the Village of Ford Heights as our example taxing district, since it's relatively small and uncomplicated.
Expand Down Expand Up @@ -362,7 +370,7 @@ fhm_pins <- DBI::dbGetQuery(
)
```

This gives us about 2,300 PINs, roughly 300 more than the Village of Ford Heights has alone. We can fetch and prepare the geometries the same way we did for the single district case.
This gives us about 2,300 PINs, roughly 300 more than the Village of Ford Heights has alone. We can fetch and prepare the geometries the same way we did for the single district case.

```{r}
fhm_pins_geo <- lookup_pin10_geometry(
Expand Down
14 changes: 11 additions & 3 deletions vignettes/reassessment.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,15 @@ library(tidyr)
ptaxsim_db_conn <- DBI::dbConnect(RSQLite::SQLite(), here("./ptaxsim.db"))
```

The example PIN we’ll use is **16-26-406-015-0000**. This is a small, single-family property in West Chicago without any exemptions. We can use the `tax_bill()` function to get every bill for this PIN from 2006 to 2021.
```{r, echo=FALSE}
# This is needed to build the vignette using GitHub Actions
ptaxsim_db_conn <- DBI::dbConnect(
RSQLite::SQLite(),
Sys.getenv("PTAXSIM_DB_PATH")
)
```

The example PIN we’ll use is **16-26-406-015-0000**. This is a small, single-family property in West Chicago without any exemptions. We can use the `tax_bill()` function to get every bill for this PIN from 2006 to 2021.

```{r}
p <- tax_bill(2006:2021, "16264060150000")
Expand Down Expand Up @@ -744,7 +752,7 @@ cw_fut_agency_tots <- DBI::dbGetQuery(

## Levies

We also need to recalculate levies for the whole county based on our assumption:
We also need to recalculate levies for the whole county based on our assumption:

- All levies will change by their average change of the last 3 years

Expand All @@ -768,7 +776,7 @@ cw_fut_levies <- lookup_agency(

## Preparing inputs

Now that we've calculated our hypothetical future values, we need to transform the data into the format excepted by `tax_bill()`. We do this by replicating the input format provided by each `lookup_` function from PTAXSIM.
Now that we've calculated our hypothetical future values, we need to transform the data into the format excepted by `tax_bill()`. We do this by replicating the input format provided by each `lookup_` function from PTAXSIM.

```{r}
# Prep pin_dt. Keep only Ward 22 pins
Expand Down
10 changes: 9 additions & 1 deletion vignettes/tifs.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ library(sf)
ptaxsim_db_conn <- DBI::dbConnect(RSQLite::SQLite(), here("./ptaxsim.db"))
```

```{r, echo=FALSE}
# This is needed to build the vignette using GitHub Actions
ptaxsim_db_conn <- DBI::dbConnect(
RSQLite::SQLite(),
Sys.getenv("PTAXSIM_DB_PATH")
)
```

## Gathering PINs of interest

To determine the TIF's impact, we first need a way to gather all the properties (PINs) in Wheeling. Fortunately, PTAXSIM's database has all the data required to accomplish this task.
Expand Down Expand Up @@ -188,7 +196,7 @@ wh_pins_map

The map shows the TIF district highlighted in <span style="color:#7d26cd"><strong>purple</strong></span>. It covers mostly commercial buildings and a small park. The primary development is called the [Wheeling Town Center](https://thewheelingtowncenter.com/).

### A quick aside: tax codes
### A quick aside: tax codes

The Wheeling Town Center II TIF was created by layering an additional taxing district boundary onto existing districts. When this happened, a new ***tax code*** was created. A tax code is a 5-digit number that identifies the unique combination of overlapping tax districts for a given area.

Expand Down

0 comments on commit f0b4b82

Please sign in to comment.