diff --git a/.gitignore b/.gitignore index 0150388..99cdcdf 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,6 @@ layers/dot-cams/*/data/states.js layers/survey-markers/states.js layers/tjx/data/chains.js layers/crop-history/data/counties.js +layers/mn-sales-tax/data/history.js .direnv venv diff --git a/layers/index.js b/layers/index.js index e0c9727..2fa9ccd 100644 --- a/layers/index.js +++ b/layers/index.js @@ -24,6 +24,7 @@ import cropHistory from './crop-history/index.js'; import mnAmbulanceServiceAreas from './mn-ambulance-service-areas/layer.js'; import upsServiceAreas from './ups/index.js'; import fccTowersLayer from './fcc/towers/layer.js'; +import mnSalesTaxLayers from './mn-sales-tax/index.js'; const layerCategories = [ { // Base maps @@ -114,6 +115,7 @@ const layerCategories = [ light_pollution, tjx, cropHistory, + mnSalesTaxLayers, ]; export default layerCategories; diff --git a/layers/mn-sales-tax/get_data.py b/layers/mn-sales-tax/get_data.py new file mode 100755 index 0000000..455e3b5 --- /dev/null +++ b/layers/mn-sales-tax/get_data.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python3 +import os +import urllib.request +import urllib.parse + +# https://services9.arcgis.com/LLh6i97mwBitl1k5/ArcGIS/rest/services +# +# TODO: They have more historical data here but I'm not sure what the format is: +# +# locgnrl_sales_usetax_areas_2020Q2_History_2004Q1thru2020Q2_Transposed +layers = [ + ('2018Q3', 'locgnrl_sales_usetax_areas_2018Q3'), + ('2018Q4', 'locgnrl_sales_usetax_areas_2018Q4'), + ('2019Q1', 'locgnrl_sales_usetax_areas_2019Q1'), + ('2019Q2', 'locgnrl_sales_usetax_areas_2019Q2'), + ('2019Q3', 'locgnrl_sales_usetax_areas_2019Q3'), + ('2019Q4', 'locgnrl_sales_usetax_areas_2019Q4'), + ('2020Q1', 'locgnrl_sales_usetax_areas_2020Q1'), + ('2020Q2', 'locgnrl_sales_usetax_areas_2020Q2'), + ('2020Q3', 'local_general_salestax_areas_2020Q3'), + ('2020Q4', 'local_general_salestax_areas_2020Q4'), + ('2021Q1', 'local_general_salestax_areas_2021Q1'), + ('2021Q2', 'local_general_salestax_areas_2021Q2'), + ('2021Q3', 'locgnrl_sales_usetax_areas_2021Q3'), + ('2021Q4', 'local_general_salestax_areas_2021Q4'), + ('2022Q1', 'local_general_salestax_areas_2022_Q1'), + ('2022Q2', 'local_general_salestax_areas_2022Q2'), + ('2022Q3', 'local_general_salestax_areas_2022Q3'), + ('2022Q4', 'local_general_salestax_areas_2022Q4'), + ('2023Q1', 'local_general_salestax_areas_2023Q1'), + ('2023Q2', 'locgnrl_sales_usetax_areas_2023Q2'), + ('2023Q3', 'local_general_salestax_areas_2023Q3'), + ('2023Q4', 'local_general_salestax_areas_2023Q4'), + ('2024Q1', 'locgnrl_sales_usetax_areas_2024Q1'), + ('2024Q2', 'locgnrl_sales_usetax_areas_2024Q2'), + ('2024Q3', 'locgnrl_sales_usetax_areas_2024Q3'), + ('2025Q1', 'locgnrl_sales_usetax_areas_2025Q1'), + ('2025Q2', 'local_general_salestax_areas_2025Q2'), + # ('2025Q2', 'locgnrl_sales_usetax_areas_2025Q2'), # This one also exists? + # ('2025Q3', 'locgnrl_sales_usetax_areas_2025Q3'), # 2025Q3 and Q4 400 bad request back? Not sure why. + # ('2025Q4', 'locgnrl_sales_usetax_areas_2025Q4'), + ('2026Q1', 'locgnrl_sales_usetax_areas_2026Q1'), + # ('2026Q2-test', 'test_locgnrl_sales_usetax_areas_2026Q2'), +] + +BASE_URL = "https://services9.arcgis.com/LLh6i97mwBitl1k5/ArcGIS/rest/services" +PATH="FeatureServer/0/query" +QUERY_STRING = urllib.parse.urlencode({ + "where": "1=1", + "outFields": "*", + "returnGeometry": "true", + "f": "geojson", + "maxAllowableOffset": "0.001" +}) + +os.makedirs("data", exist_ok=True) +for layer in layers: + if os.path.exists(f'data/{layer[0]}.geojson'): + print(f"Already have {layer[0]}, skipping…") + continue + url = f"{BASE_URL}/{layer[1]}/{PATH}?{QUERY_STRING}" + print(f"Downloading {layer[0]}…") + with urllib.request.urlopen(url) as response, open(f'data/{layer[0]}.geojson', "wb") as out_file: + out_file.write(response.read()) + + +with open('data/history.js', 'w') as f: + for layer in layers: + f.write(f"import Y{layer[0]} from './{layer[0]}.geojson?url';\n") + f.write('\nexport default {\n') + for layer in layers: + f.write(f" '{layer[0]}': Y{layer[0]},\n") + f.write("};\n") diff --git a/layers/mn-sales-tax/index.js b/layers/mn-sales-tax/index.js new file mode 100644 index 0000000..30960a4 --- /dev/null +++ b/layers/mn-sales-tax/index.js @@ -0,0 +1,45 @@ +import GeoJSON from 'ol/format/GeoJSON.js'; +import VectorLayer from 'ol/layer/Vector.js'; +import VectorSource from 'ol/source/Vector.js'; + +import history from './data/history.js'; + +import { Fill, Stroke, Style, Text } from 'ol/style.js'; + + +function style(feature){ + return new Style({ + text: new Text({ + text: feature.get('NameLabel') + ': ' + feature.get('TotalFrmal'), + }), + fill: new Fill({ + color: 'rgba(255,255,255,0.4)', + }), + stroke: new Stroke({ + color: '#008800', + width: 1.25, + }), + }); +} + +const layers = { + name: "Minnesota Sales Tax", + layers: [], +}; + +for (let [name, url] of Object.entries(history)) { + const layer = new VectorLayer({ + source: new VectorSource({ + url, + format: new GeoJSON, + }), + style: style, + }); + + layers.layers.push({ + name, + layer, + }); +} + +export default layers;