Last active
May 20, 2025 18:51
-
-
Save dgketchum/3c9e3d7bb1db5be9a09a3a6d6d26ebee to your computer and use it in GitHub Desktop.
Montana Range High Points Shapefile
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
import csv | |
import requests | |
import time | |
import geopandas | |
from shapely.geometry import Point | |
""" | |
Montana State Library: Montana's Tallest Peaks by Mountain Range | |
https://msl.mt.gov/geoinfo/geography/geography_facts/montanaxs_tallest_peaks_by_mountain_range | |
Pulling most of these by GNIS name lookup and filling in the missing values under MISSING | |
by finding the peak with the MSL link and getting coordinates from Google Earth. | |
""" | |
WATERDATA_API_URL = "https://dashboard.waterdata.usgs.gov/service/geocoder/get/location/1.0" | |
STATE_ABBREVIATION = "MT" | |
REQUEST_TIMEOUT = 15 | |
DELAY_BETWEEN_REQUESTS = 2.0 | |
MISSING = {'Bears Paw Mountains': (48.148593, -109.65075), | |
# Beartooth Mountains GNIS lookup gets first result from Tobacco Root | |
'Beartooth Mountains': (45.1841, -109.79129), | |
# exact point of Beaverhead Mtns HP is in Idaho | |
'Beaverhead Mountains': (44.447227, -112.996476), | |
# Bighorn's Montana HP is drive-up | |
# 'Bighorn Mountains': (45.00098, -107.91139), | |
# Bighorn Overall HP is Cloud Peak | |
'Bighorn Mountains': (44.382147, -107.173951), | |
'Big Sheep Mountains': (47.044020, -105.730260), | |
# not sure why this one finds a bad coordinate pair | |
'Bitteroot Range': (45.88965, -114.2981), | |
'Blacktail Mountains': (44.987672, -112.578531), | |
'Castle Mountains': (46.452622, -110.753254), | |
# not sure why this one finds a bad coordinate pair | |
'Chalk Buttes': (45.708559, -104.734215), | |
'Gravelly Range': (44.90425, -111.85563), | |
'Henrys Lake Mountains': (44.7633, -111.3906), | |
'Highland Mountains': (45.742484, -112.461789), | |
'John Long Mountains': (46.479171, -113.680506), | |
'Little Snowy Mountains': (46.752222, -109.173333), | |
'Lewis and Clark Range': (47.11654, -112.738643), | |
'Long Pines': (45.639974, -104.184526), | |
'North Moccasin Mountains': (47.31448, -109.46758), | |
'Ruby Range': (45.312778, -112.228056), | |
'South Moccasin Mountains': (47.1725, -109.523889), | |
'Sweet Grass Hills': (48.931379, -111.532198), | |
'Wolf Mountains': (45.03603, -107.19281)} | |
def get_coordinates_from_gnis(mountain_name): | |
params = { | |
"term": mountain_name, | |
"include": "gnis", | |
"states": STATE_ABBREVIATION, | |
"maxSuggestions": 1 | |
} | |
headers = {} | |
response = requests.get(WATERDATA_API_URL, params=params, headers=headers, timeout=REQUEST_TIMEOUT) | |
response.raise_for_status() | |
data = response.json() | |
if data and len(data) > 0: | |
location = data[0] | |
if location.get("Source") == "gnis" and "Latitude" in location and "Longitude" in location: | |
print(f'{mountain_name}: {location["Latitude"]:.2f}, {location["Longitude"]:.2f}') | |
return location["Latitude"], location["Longitude"] | |
else: | |
raise ValueError | |
def process_mountains_csv(input_csv_filepath, output_csv_filepath, output_shapefile_filepath): | |
processed_mountains_for_csv = [] | |
mountains_for_geodataframe = [] | |
with open(input_csv_filepath, mode='r', encoding='utf-8-sig') as infile: | |
reader = csv.DictReader(infile) | |
for row_number, row_dict in enumerate(reader, 1): | |
name_from_csv = row_dict.get('Name') | |
climbed = row_dict.get('done') | |
range = row_dict.get('range') | |
elev_ft = row_dict.get('elev_ft') | |
status_msg = "" | |
lat, lon = None, None | |
current_attributes = dict(row_dict) | |
if name_from_csv and name_from_csv.strip(): | |
stripped_name = name_from_csv.strip() | |
current_attributes['Name'] = stripped_name | |
if range in MISSING: | |
loc = MISSING[range] | |
print(f'{stripped_name}: {loc[0]:.2f}, {loc[1]:.2f}') | |
else: | |
loc = get_coordinates_from_gnis(stripped_name) | |
lat, lon = loc[0], loc[1] | |
time.sleep(DELAY_BETWEEN_REQUESTS) | |
status_msg = "Success" | |
point_data = current_attributes.copy() | |
point_data['geometry'] = Point(float(lon), float(lat)) | |
point_data['latitude'] = float(lat) | |
point_data['longitude'] = float(lon) | |
point_data['status'] = status_msg | |
mountains_for_geodataframe.append(point_data) | |
else: | |
status_msg = "Skipped - Empty name in CSV" | |
current_attributes['Name'] = name_from_csv if name_from_csv else '' | |
csv_entry = { | |
'name': current_attributes['Name'], | |
'latitude': lat if lat is not None else 'N/A', | |
'longitude': lon if lon is not None else 'N/A', | |
'range': range, | |
'elev_ft': elev_ft, | |
'done': climbed | |
} | |
processed_mountains_for_csv.append(csv_entry) | |
if processed_mountains_for_csv: | |
with open(output_csv_filepath, mode='w', newline='', encoding='utf-8') as outfile: | |
fieldnames = list(csv_entry.keys()) | |
writer = csv.DictWriter(outfile, fieldnames=fieldnames) | |
writer.writeheader() | |
writer.writerows(processed_mountains_for_csv) | |
if mountains_for_geodataframe: | |
gdf = geopandas.GeoDataFrame(mountains_for_geodataframe, crs="EPSG:4326") | |
sanitized_columns = {} | |
for col_name in gdf.columns: | |
if col_name == 'geometry': | |
sanitized_columns[col_name] = 'geometry' | |
continue | |
s_name = str(col_name).replace(' ', '_').replace('.', '_').replace('-', '_') | |
s_name = s_name[:10] | |
original_s_name = s_name | |
count = 1 | |
while s_name in sanitized_columns.values(): | |
s_name = original_s_name[:10 - len(str(count))] + str(count) | |
count += 1 | |
sanitized_columns[col_name] = s_name | |
gdf.rename(columns=sanitized_columns, inplace=True) | |
gdf.to_file(output_shapefile_filepath, driver='ESRI Shapefile') | |
if __name__ == "__main__": | |
d = os.path.expanduser('~') | |
input_file = os.path.join(d, 'mt_highpoints_noCoords.csv') | |
output_csv = os.path.join(d, 'mt_highpoints.csv') | |
output_shp = os.path.join(d, 'mt_highpoints.shp') | |
process_mountains_csv(input_file, output_csv, output_shp) | |
# ========================= EOF ==================================================================== |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Name | elev_ft | range | done | |
---|---|---|---|---|
Granite Peak | 12799 | Beartooth Mountains | 0 | |
Hilgard Peak | 11316 | Madison Range | 0 | |
Mount Cowen | 11212 | Absaroka Range | 0 | |
Crazy Peak | 11209 | Crazy Mountains | 1 | |
Tweedy Mountain | 11154 | Pioneer Mountains | 0 | |
Eighteenmile Peak | 11125 | Beaverhead Mountains | 1 | |
Electric Peak | 10969 | Gallatin Range | 0 | |
West Goat Peak | 10793 | Anaconda Range | 1 | |
Un-named Peak | 10606 | Henrys Lake Mountains | 0 | |
Hollowtop Mountain | 10604 | Tobacco Root Mountains | 1 | |
Sunset Peak | 10581 | Snowcrest Range | 1 | |
Black Butte | 10542 | Gravelly Range | 1 | |
Mount Cleveland | 10466 | Lewis Range | 0 | |
Table Mountain | 10223 | Highland Mountains | 0 | |
Mount Jefferson | 10203 | Centennial Mountains | 1 | |
Mount Powell | 10168 | Flint Creek Range | 1 | |
Trapper Peak | 10157 | Bitteroot Range | 1 | |
Kintla Peak | 10101 | Livingston Range | 0 | |
McDonald Peak | 9820 | Mission Range | 1 | |
Ellis Peak | 9699 | Tendoy Mountains | 0 | |
Sacagawea Peak | 9650 | Bridger Range | 0 | |
Mount Edith | 9480 | Big Belt Mountains | 0 | |
Un-named Peak | 9477 | Blacktail Mountains | 0 | |
Crow Peak | 9414 | Elkhorn Mountains | 0 | |
Red Mountain | 9411 | Lewis and Clark Range | 0 | |
Rocky Mountain | 9392 | Sawtooth Range | 1 | |
Un-named Peak | 9391 | Ruby Range | 0 | |
Holland Peak | 9356 | Swan Range | 1 | |
Un-named Peak | 9257 | Bighorn Mountains | 0 | |
Big Baldy Mountain | 9177 | Little Belt Mountains | 0 | |
Kent Peak | 9010 | Sapphire Mountains | 0 | |
Haystack Mountain | 8819 | Boulder Mountains | 0 | |
Big Pryor Mountain | 8786 | Pryor Mountains | 0 | |
Snowshoe Peak | 8738 | Cabinet Mountains | 1 | |
Great Northern Mountain | 8705 | Flathead Range | 1 | |
Greathouse Peak | 8681 | Big Snowy Mountains | 1 | |
McLeod Peak | 8620 | Rattlesnake Mountains | 1 | |
Elk Peak | 8566 | Castle Mountains | 0 | |
Butte Cabin Ridge | 8468 | John Long Mountains | 0 | |
Nasukoin Mountain | 8086 | Whitefish Range | 1 | |
Ch-paa-qn Peak | 7996 | Reservation Divide | 0 | |
Poorman Mountain | 7832 | Galton Range | 0 | |
Northwest Peak | 7705 | Purcell Mountains | 1 | |
Highwood Baldy | 7670 | Highwood Mountains | 0 | |
Old Baldy Mountain | 7511 | Garnet Range | 0 | |
Cherry Peak | 7352 | Couer d'Alene Mountains | 0 | |
Stark Mountain | 7352 | Ninemile Divide | 1 | |
McGuire Mountain | 6991 | Salish Mountains | 0 | |
West Butte | 6983 | Sweet Grass Hills | 0 | |
Bearpaw Baldy | 6916 | Bears Paw Mountains | 0 | |
Judith Peak | 6428 | Judith Mountains | 0 | |
Un-named Peak | 6260 | Little Snowy Mountains | 0 | |
Un-named Peak | 5798 | South Moccasin Mountains | 0 | |
Antoine Butte | 5720 | Little Rocky Mountains | 0 | |
Un-named Peak | 5602 | North Moccasin Mountains | 0 | |
Un-named Peak | 5450 | Wolf Mountains | 0 | |
Dunn Mountain | 4744 | Bull Mountains | 0 | |
West Chalk Butte | 4200 | Chalk Buttes | 0 | |
Tri-Point Lookout | 4120 | Long Pines | 0 | |
Big Sheep Mountain | 3590 | Big Sheep Mountains | 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment