This tool transforms a list of values at latitude and longitude points into an interactive map in the style of a traditional "value-per-acre" analysis.The map is colour graded in a heat-map style from red to blue, red indicating high value and blue indicating a low value.
Each block by default is 100m².
Parcel Data is used to assign colours to each individual parcel found.
This tool was used to compile the map at https://strongtownslangley.org/maps?revenue-map
You can download the tool from the releases page: https://github.com/StrongTownsLangley/ValuePerAcre/releases/
This tool was designed to work with Township of Langley data specifically, but should be flexible enough to work for other places.
The tool has two modes, one where it will calculate the values from input tax rates and assessed property values, and another where it will take pre-calculated values.
(1) Usage from Property Assessments (Have to Calculate Tax using Tax Rates File): vpa.exe -from-tax-rates="tax-rates.json" -from-assessments="assessment-file.geojson" [-assessment-pid-field="PID"] [-parcels="parcel-file.geojson"]
(2) Usage from Values (Tax or Value already calculated): vpa.exe -from-values="value-file.geojson" [-parcels="parcel-file.geojson"]
Optional Flags: [output-folder="json"] [-tax-rate-divider=1000] [-levels=50] [-block-size=100]"
Viewable maps are generated in the output folder:
- website.static.html can be opened as a local file in a brower but is a larger file as it contains all the layers data.
- website.dynamic.html will not work as a local file and must run on a local or remote webserver, but is smaller as it loads the level_*.json files generated by the tool dynamically. This is the preferred method for deployment on the internet and allows you to customize the page and simply update the level files seperately in future.
Looking at a map with properties grouped into blocks colourized based on their taxable value is allows us to see what areas are the most and least productive and contribute the most and least revenue to city finances.
Value per Acre analysis is advocated by Strong Towns to evaluate the efficiency of land use by focusing on both its productivity and desirability relative to infrastructure investment.
While higher density development typically corresponds with a higher taxable value, more desirable areas can also attract higher home prices and as such, higher taxable value. This effect can compensate for areas of low taxable value like parks that increase desirability.
- Langley Township offers comprehensive assessed property values on its open data portal at https://data-tol.opendata.arcgis.com/search?tags=Land%20and%20Parcel%20Information
- The tool calculates taxable values by multiplying them with corresponding tax rates which are released in PDF format every year e.g. https://www.tol.ca/en/services/resources/property-taxes/document-feed/2024-Tax-Rates.pdf
- Point Mode:
- The total area is partitioned into 100m² blocks (which is adjustable using the -block-size flag)
- Each property value is added to its respective block based on it's coordinates.
- Parcel Mode:
- The taxable value is mapped to it's respective parcels in the parcel geojson file using the PID field.
- The value is divided by the total area of the property in acres.
- The tool searches for which block value to use as the highest value cap, the blocks are then grouped into 50 levels from highest to lowest (number of levels adjustable with -levels flag) according to the most even distribution.
- The tool then outputs a webpage map, json files with the blocks grouped by level, as well as other information in json files.
If using method (1), then the tax rates and assessment file must be in the following format:
tax-rates.json:
{
"Residential": 3.80248,
"Utilities": 42.53820,
"SupportiveHousing": 2.37008,
"MajorIndustry": 8.34595,
"LightIndustry": 10.24375,
"Business": 12.02044,
"ManagedForest": 0,
"Rec_NonProfit": 6.73828,
"Farm": 15.97448
}
These rates are then used in combination with the *_Land and *_Buildings values in the assessment file. Below is a version with just the required/used structure and fields:
assessment-file.geojson:
{
"type": "FeatureCollection",
"name": "Assessments",
"crs": { "type": "name", "properties": { "name": "" } },
"features": [
{ "type": "Feature", "properties": { "Residential_Buildings": 113700, "Residential_Land": 0, "Utilities_Improvements": 0, "Utilities_Land": 0, "SupportiveHousing_Buildings": 0, "SupportiveHousing_Land": 0, "MajorIndustry_Buildings": 0, "MajorIndustry_Land": 0, "LightIndustry_Buildings": 0, "LightIndustry_Land": 0, "Business_Buildings": 0, "Business_Land": 0, "ManagedForest_Improvements": 0, "ManagedForest_Land": 0, "Rec_NonProfit_Buildings": 0, "Rec_NonProfit_Land": 0, "Farm_Buildings": 0, "Farm_Land": 9098, "Latitude": 49.004443779630002, "Longitude": -122.64299023049 } },
{ "type": "Feature", "properties": { "Residential_Buildings": 191000, "Residential_Land": 1954000, "Utilities_Improvements": 0, "Utilities_Land": 0, "SupportiveHousing_Buildings": 0, "SupportiveHousing_Land": 0, "MajorIndustry_Buildings": 0, "MajorIndustry_Land": 0, "LightIndustry_Buildings": 0, "LightIndustry_Land": 0, "Business_Buildings": 0, "Business_Land": 0, "ManagedForest_Improvements": 0, "ManagedForest_Land": 0, "Rec_NonProfit_Buildings": 0, "Rec_NonProfit_Land": 0, "Farm_Buildings": 0, "Farm_Land": 0, "Latitude": 49.004450579390003, "Longitude": -122.63949034914999 } },
...
]
}
parcel-file.geojson: This is a pretty standard GeoJSON file, however points are expected in EPSG:4326 format but are converted to WGS84 for Leaflet.
{
"type": "FeatureCollection",
"crs": {
"type": "name",
"properties": {
"name": "EPSG:26910"
}
},
"features": [
{
"type": "Feature",
"id": 797972,
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
525199.054600001,
5432031.84979953
],
[
525101.0592,
5432031.52039953
],
[
525100.3221,
5432129.37989953
],
[
525198.567,
5432129.78269953
],
[
525198.712899999,
5432106.36829953
],
[
525198.997799999,
5432048.33409953
],
[
525199.054600001,
5432031.84979953
]
]
]
},
"properties": {
"PID": "000-561-123",
}
},
{
"type": "Feature",
"id": 797973,
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
534499.5739,
5445708.15879954
],
[
534499.590099999,
5445712.92899954
],
[
534509.826899999,
5445712.89819954
],
[
534509.8108,
5445708.12819954
],
[
534499.5739,
5445708.15879954
]
]
]
},
"properties": {
"PID": "000-561-456",
}
}
]
}
A simplifified version might look like this:
tax-rates.json:
{
"Residential": 5
}
assessment-file.geojson:
{
"type": "FeatureCollection",
"name": "Assessments",
"crs": { "type": "name", "properties": { "name": "" } },
"features": [
{ "type": "Feature", "properties": { "Residential_Buildings": 113700, "Residential_Land": 0, "Latitude": 49.004443779630002, "Longitude": -122.64299023049 } },
{ "type": "Feature", "properties": { "Residential_Buildings": 191000, "Residential_Land": 1954000, "Latitude": 49.004450579390003, "Longitude": -122.63949034914999 } },
...
]
}
parcel-file.geojson:
{
"type": "FeatureCollection",
},
"features": [
{
"type": "Feature",
"id": 797972,
"geometry": {
"type": "Polygon",
"coordinates": [ ]
]
},
"properties": {
"PID": "000-561-123",
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [ ]
},
"properties": {
"PID": "000-561-456",
}
}
]
}
If using method (2), the values file should be in this format. This is likely the method you will want to use if your data is from another city or source. PID Field only required if parcel file is specified.
value-file.geojson:
[
{
"Latitude": 49.00444377963,
"Longitude": -122.64299023049,
"Value": 577.68
"PID": "008-401-123"
},
{
"Latitude": 49.00445057939,
"Longitude": -122.63949034915,
"Value": 8156.32
"PID": "008-401-456"
},
...
]
- A commercial firm producing this kind of analysis is Urban3, who produce 3D renderings in addition to factoring in not just the Value but also the Cost-per-Acre.
- Fellow Strong Towns Local Conversation group A Better Cobb created their own set of Value per Acre tools, available at https://github.com/ABetterCobb/ValuePerAcre/
This tool was programmed by James Hansen (james@strongtownslangley.org)
Leaflet is used to display the map.
Newtonsoft.Json is used to read and write JSON files and data.
The project is a Visual Studio 2010 project in C# .NET 4.0. It's an old platform, but I like to use older platforms for simple tools like this.
If you encounter any issues while using it or have suggestions for improvement, please open an issue on the GitHub repository. Pull requests are also welcome.
I can be found on Strong Towns Local Conversation discord, you can also get help in the #🧮do-the-math channel on the Strong Towns Langley discord: https://discord.gg/MuAn3cFd8J
This program is released under the Apache 2.0 License. If you use it for your website or project, please provide credit to Strong Towns Langley and preferably link to this GitHub.