├── AestheticMin.tif ├── TestZipCodes.zip ├── ClimbingWeatherApp-QGIS ├── temp.csv ├── ClimbingWeatherAppBasemap.qgz ├── QGISweather_app_main.py ├── QGIS-MakeMap.py ├── QGISdaily_forecast_functions.py └── ClimbingAreasInfo.csv ├── README.md ├── SagaNearestNeighbour.py ├── EuclideanDistance3D.py ├── RasterCalculator.py ├── Sandbox.py ├── IDWInterpolation.py ├── BREcheckmissingvaluesCSV.py ├── GRASSvIDWsurf.py ├── ClipRasterByMaskLayer.py ├── geomorph.py ├── reproject_crs_of_map_layers.py ├── AccessRasterPixelValues.py ├── Zone_Column_BRE.py ├── GoldenEagleDatashort.csv ├── MergeVectorLayers - BRE.py ├── convert_geographic_to_projected_coordinates.py ├── UVAOncologyPatientData.py ├── qgis_basemaps.py └── CreateLayoutManagerAndExport.py /AestheticMin.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epurpur/PyQGIS-Scripts/HEAD/AestheticMin.tif -------------------------------------------------------------------------------- /TestZipCodes.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epurpur/PyQGIS-Scripts/HEAD/TestZipCodes.zip -------------------------------------------------------------------------------- /ClimbingWeatherApp-QGIS/temp.csv: -------------------------------------------------------------------------------- 1 | Climbing_Areas,Conditions_Score,Zip_codes,Rank 2 | Pickens,2913.1200000000003,29671,best 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PyQGIS-Scripts 2 | Python Scripts written for various tasks in QGIS. FOSS GIS (Geographic Information Systems) software 3 | 4 | 5 | -------------------------------------------------------------------------------- /ClimbingWeatherApp-QGIS/ClimbingWeatherAppBasemap.qgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epurpur/PyQGIS-Scripts/HEAD/ClimbingWeatherApp-QGIS/ClimbingWeatherAppBasemap.qgz -------------------------------------------------------------------------------- /SagaNearestNeighbour.py: -------------------------------------------------------------------------------- 1 | """Template for SAGA: Nearest Neighbour tool""" 2 | 3 | import processing 4 | 5 | 6 | #print(help(processing.algorithmHelp('saga:nearestneighbour'))) 7 | 8 | parameters = {'SHAPES': '/Users/ep9k/Desktop/RandomPoints.gpkg', 9 | 'FIELD': 'OBJECTID', 10 | 'TARGET_USER_FITS': 0, 11 | 'TARGET_OUT_GRID': '/Users/ep9k/Desktop/Output.sdat'} 12 | 13 | processing.runAndLoadResults('saga:nearestneighbour', parameters) -------------------------------------------------------------------------------- /EuclideanDistance3D.py: -------------------------------------------------------------------------------- 1 | """Measures Euclidean Distance in 3 Dimensions (straight line distance). 2 | Takes x, y, z values for 2 points and calculates distance between them via Euclidean distance formula. 3 | 4 | Example: 5 | a = (2321.4 (latitude), -4747.62 (longitude), 750.5 (altitude)) 6 | """ 7 | 8 | from math import sqrt 9 | 10 | a = (2321.4, -4747.62, 750.5) 11 | b = (2321.4, -4747.62, 737.3) 12 | c = (2321.4, -4747.62, 732.9) 13 | 14 | distance1 = (sqrt(sum( (a-b)**2 for a, b in zip(a, b)))) 15 | distance2 = (sqrt(sum( (b-c)**2 for b, c in zip(b, c)))) 16 | 17 | print(distance1) 18 | print(distance2) 19 | 20 | -------------------------------------------------------------------------------- /RasterCalculator.py: -------------------------------------------------------------------------------- 1 | # In raster calculator, expression is: ( "AestheticMax@1" != 255) * "AestheticMax@1" 2 | import processing 3 | 4 | #processing.algorithmHelp('gdal:rastercalculator') #for help docs 5 | 6 | input_raster = QgsRasterLayer('/Users/ep9k/Desktop/Key-LogEcovaluator/Rasters/AestheticMax.tif', 'raster') 7 | output_raster = '/Users/ep9k/Desktop/reclassoutput.tif' 8 | 9 | 10 | parameters = {'INPUT_A' : input_raster, 11 | 'BAND_A' : 1, 12 | 'FORMULA' : '(A != 255) * A', 13 | 'OUTPUT' : output_raster} 14 | 15 | processing.runAndLoadResults('gdal:rastercalculator', parameters) 16 | -------------------------------------------------------------------------------- /Sandbox.py: -------------------------------------------------------------------------------- 1 | 2 | #This creates a new print layout 3 | project = QgsProject.instance() 4 | manager = project.layoutManager() 5 | layout = QgsPrintLayout(project) 6 | layout.initializeDefaults() 7 | layout.setName('My Layout6') 8 | manager.addLayout(layout) 9 | 10 | map = QgsLayoutItemMap(layout) 11 | 12 | #sets initial position on the page 13 | map.attemptSetSceneRect(QRectF(0, 0, 100, 100)) 14 | 15 | #sets size for the image 16 | map.attemptResize(QgsLayoutSize(6, 5, QgsUnitTypes.LayoutInches)) 17 | 18 | #set extent of map 19 | rectangle = QgsRectangle(-1350312, -21811, 1741463, 116086) 20 | map.setExtent(rectangle) 21 | 22 | layout.addLayoutItem(map) -------------------------------------------------------------------------------- /IDWInterpolation.py: -------------------------------------------------------------------------------- 1 | """script for running GRASS v.surf.idw tool""" 2 | 3 | import processing 4 | 5 | parameters = { 6 | 'input' : '/Users/ep9k/Desktop/qgis_data-master/area3_testdata_clipped.shp', 7 | 'npoints' : 12, 8 | 'power' : 2, 9 | 'column' : 'PDOP', 10 | 'GRASS_REGION_PARAMETER' : '-116.04415744105579,-116.0047567429083,37.029018114312905,37.054281406967974 [EPSG:4326]', 11 | 'GRASS_REGION_CELLSIZE_PARAMETER' : 0, 12 | 'GRASS_RASTER_FORMAT_OPT' : '', 13 | 'GRASS_RASTER_FORMAT_META' : '', 14 | 'GRASS_SNAP_TOLERANCE_PARAMETER' : -1, 15 | 'GRASS_MIN_AREA_PARAMETER' : 0.0001, 16 | 'output' : '/Users/ep9k/Desktop/GRASS_OUTPUT.tif'} 17 | 18 | processing.runAndLoadResults('grass7:v.surf.idw', parameters) 19 | -------------------------------------------------------------------------------- /BREcheckmissingvaluesCSV.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Tue Apr 30 15:09:13 2019 5 | 6 | @author: ep9k 7 | """ 8 | 9 | #template of how to combine columns (pandas DataFrames) 10 | #if column1 is empty, use value from column2. 11 | #if column2 is empty, use value from column3, and so on 12 | #using combine_first function from pandas library 13 | 14 | 15 | import pandas 16 | 17 | df = pandas.read_csv('/Users/ep9k/Desktop/NewCSV.csv') 18 | 19 | print(df) 20 | 21 | df.mapping = df.col1.combine_first(df.col2) 22 | 23 | print() 24 | print(df) 25 | 26 | df.mapping = df.col1.combine_first(df.col3) 27 | 28 | print() 29 | print(df) 30 | 31 | #df.to_csv('/Users/ep9k/Desktop/New2CSV.csv') 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /GRASSvIDWsurf.py: -------------------------------------------------------------------------------- 1 | """Code for GRASS v.idw.surf tool. Must use QGIS v3.6 for this to work""" 2 | 3 | import processing 4 | 5 | parameters = { 6 | 'input' : '/Users/ep9k/Desktop/qgis_data-master/area3_testdata_clipped.shp', 7 | 'npoints' : 12, 8 | 'power' : 2, 9 | 'column' : 'PDOP', 10 | 'GRASS_REGION_PARAMETER' : '-116.04415744105579,-116.0047567429083,37.029018114312905,37.054281406967974 [EPSG:4326]', 11 | 'GRASS_REGION_CELLSIZE_PARAMETER' : 0, 12 | 'GRASS_RASTER_FORMAT_OPT' : '', 13 | 'GRASS_RASTER_FORMAT_META' : '', 14 | 'GRASS_SNAP_TOLERANCE_PARAMETER' : -1, 15 | 'GRASS_MIN_AREA_PARAMETER' : 0.0001, 16 | 'output' : '/Users/ep9k/Desktop/GRASS_OUTPUT.tif'} 17 | 18 | processing.runAndLoadResults('grass7:v.surf.idw', parameters) -------------------------------------------------------------------------------- /ClipRasterByMaskLayer.py: -------------------------------------------------------------------------------- 1 | import processing 2 | from qgis.core import * 3 | 4 | raster_layer = QgsRasterLayer('/Users/ep9k/Desktop/Key-LogEcovaluator/Rasters/AestheticMax.tif', 'raster') 5 | mask_layer = QgsVectorLayer('/Users/ep9k/Desktop/Key-LogEcovaluator/TestVectorExtent.shp', 'mask', 'ogr') 6 | 7 | parameters = {'INPUT': raster_layer, 8 | 'MASK': mask_layer, 9 | 'NODATA': -9999, 10 | 'ALPHA_BAND': False, 11 | 'CROP_TO_CUTLINE': True, 12 | 'KEEP_RESOLUTION': True, 13 | 'OPTIONS': None, 14 | 'DATA_TYPE': 0, 15 | 'OUTPUT': '/Users/ep9k/Desktop/output_clip.tif'} 16 | 17 | processing.runAndLoadResults('gdal:cliprasterbymasklayer', parameters) 18 | 19 | #print(processing.algorithmHelp('gdal:cliprasterbymasklayer')) #prints info about parameters 20 | -------------------------------------------------------------------------------- /geomorph.py: -------------------------------------------------------------------------------- 1 | # run r.param.scale 2 | input_elevation_layer = '/Users/ep9k/Desktop/GRASS_TEST/elevation_export.tif' 3 | processing.run("grass7:r.param.scale", {'input': input_elevation_layer,'slope_tolerance':1,'curvature_tolerance':0.0001,'size':33,'method':0,'exponent':0,'zscale':1,'-c':False,'output':'/Users/ep9k/Desktop/GRASS_TEST/geomorphic_parameters.tif','GRASS_REGION_PARAMETER':None,'GRASS_REGION_CELLSIZE_PARAMETER':0,'GRASS_RASTER_FORMAT_OPT':'','GRASS_RASTER_FORMAT_META':''}) 4 | 5 | # run r.geomorphon 6 | geomorphic_parameters = '/Users/ep9k/Desktop/GRASS_TEST/geomorphic_parameters.tif' 7 | processing.run("grass7:r.geomorphon", {'elevation': geomorphic_parameters,'search':3,'skip':0,'flat':1,'dist':0,'forms':'/Users/ep9k/Desktop/GRASS_TEST/geomorphic_output.tif','-m':False,'-e':False,'GRASS_REGION_PARAMETER':None,'GRASS_REGION_CELLSIZE_PARAMETER':0,'GRASS_RASTER_FORMAT_OPT':'','GRASS_RASTER_FORMAT_META':''}) 8 | -------------------------------------------------------------------------------- /reproject_crs_of_map_layers.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | 4 | #checked_layers = [layer.name() for layer in QgsProject().instance().layerTreeRoot().children()] 5 | 6 | wrong_crs = [] 7 | 8 | for layer in QgsProject().instance().mapLayers().values(): 9 | # print(layer.name(), "=",layer.crs().authid()) 10 | if layer.crs().authid() != 'EPSG:4326': 11 | wrong_crs.append(layer) 12 | 13 | print("Layers with wrong CRS...") 14 | for layer in wrong_crs: 15 | print(layer.name(), '=', layer.crs().authid()) 16 | 17 | 18 | #print(qgis.utils.iface.activeLayer().crs().authid()) 19 | 20 | 21 | #processing.algorithmHelp('native:reprojectlayer') 22 | 23 | myfilepath = iface.activeLayer().dataProvider().dataSourceUri() 24 | #print(type(iface.activeLayer())) 25 | 26 | for layer in wrong_crs: 27 | # print(layer.dataProvider().dataSourceUri()) 28 | parameters = { 'INPUT' : '/Users/ep9k/Desktop/Oyster Reefs/Hog Island/HG2.shp', 29 | 'OUTPUT' : 'memory:', 30 | 'TARGET_CRS' : QgsCoordinateReferenceSystem('EPSG:4326') } 31 | 32 | processing.runAndLoadResults('native:reprojectlayer', parameters) 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /AccessRasterPixelValues.py: -------------------------------------------------------------------------------- 1 | layer = iface.activeLayer() 2 | print("Active Layer: ", layer.name()) 3 | provider = layer.dataProvider() 4 | extent = layer.extent() 5 | stats = provider.bandStatistics(1, QgsRasterBandStats.All) 6 | 7 | rows = layer.height() 8 | columns = layer.width() 9 | 10 | block = provider.block(1, extent, columns, rows) 11 | 12 | values= [] 13 | for row in range(rows): 14 | values.append([]) 15 | print("Values: ", values) 16 | 17 | for row in range(rows): #iterates through each row 18 | for column in range(columns): #iterates through each column 19 | values[row].append(block.value(row, column)) #appends the block.value to each position in values lists 20 | print(f"Values: {values}") 21 | 22 | flattened_list = [] #flattens values lists into one list 23 | for list in values: 24 | for element in list: 25 | flattened_list.append(element) 26 | 27 | 28 | unique_values = [] 29 | for item in flattened_list: 30 | if item not in unique_values: 31 | unique_values.append(item) 32 | print("Unique Values:", unique_values) 33 | 34 | 35 | for item in unique_values: 36 | count = 0 37 | 38 | for element in flattened_list: 39 | if element == item: 40 | count += 1 41 | 42 | print ("value: ", item, "count: ", count) -------------------------------------------------------------------------------- /ClimbingWeatherApp-QGIS/QGISweather_app_main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Fri Nov 2 11:11:02 2018 5 | 6 | @author: ep9k 7 | """ 8 | 9 | #This is the main module for my weather app 10 | #I'm submitting an API request to Open Weather Map's API (https://openweathermap.org/api) 11 | 12 | import QGISdaily_forecast_functions as dff 13 | 14 | 15 | def main(): 16 | """Weather app main module 17 | daily_forecast_functions and extended_forecast_functions contain individual descriptions of what each function does""" 18 | 19 | print("~~~~~~Erich's Weather~~~~~~~~") 20 | print("We will check the weather at various climbing destinations by state") 21 | 22 | user_state_choice = dff.state_choice(input("Enter state abbreviation (in caps) : ")) #gets user input for state abbreviation 23 | 24 | city_id_list = user_state_choice[0] #list of city ids returned from state_choice 25 | climbing_area_alias = user_state_choice[1] #list of climbing area aliases returned from state_choice 26 | zip_codes = user_state_choice[2] #list of zip codes for each location returned from state_choice 27 | 28 | json_data = dff.single_dynamic_api_request(city_id_list) #returns JSON data for each API request (city) in chosen state 29 | 30 | conditions = dff.display_conditions_today(json_data, climbing_area_alias, zip_codes) #returns dictionary of cities with conditions score as a dictionary 31 | 32 | dff.output_for_QGIS(conditions, zip_codes) #processes final output for QGIS in temp.csv file 33 | 34 | #Here is where the QGIS specific functions begin 35 | 36 | main() 37 | 38 | -------------------------------------------------------------------------------- /Zone_Column_BRE.py: -------------------------------------------------------------------------------- 1 | import processing 2 | 3 | def select_by_location(zone_name): 4 | """ Selects parcels from all_2019_parcels which are within the spatial boundary of a given zone """ 5 | 6 | parameters = { 'INPUT' : 'dbname=\'BRE_2019_Test\' host=localhost port=5432 sslmode=disable key=\'id_1\' srid=2264 type=MultiPolygon checkPrimaryKeyUnicity=\'1\' table=\"public\".\"All_Parcels_2019\" (geom)', 7 | 'INTERSECT' : f'postgres://dbname=\'BRE_2019_Test\' host=localhost port=5432 sslmode=disable key=\'id_2\' srid=2264 type=MultiPolygon checkPrimaryKeyUnicity=\'1\' table=\"public\".\"{zone_name}\" (geom)', 8 | 'METHOD' : 0, 9 | 'PREDICATE' : [6] } 10 | 11 | processing.runAndLoadResults('native:selectbylocation', parameters) 12 | 13 | select_by_location('Zone1b') 14 | 15 | 16 | #{ 'INPUT' : 'dbname=\'BRE_2019_Test\' host=localhost port=5432 sslmode=disable key=\'id_1\' srid=2264 type=MultiPolygon checkPrimaryKeyUnicity=\'1\' table=\"public\".\"All_Parcels_2019\" (geom)', 17 | #'INTERSECT' : 'postgres://dbname=\'BRE_2019_Test\' host=localhost port=5432 sslmode=disable key=\'id_2\' srid=2264 type=MultiPolygon checkPrimaryKeyUnicity=\'1\' table=\"public\".\"Zone1b\" (geom)', 18 | #'METHOD' : 0, 19 | #'PREDICATE' : [6] } 20 | 21 | 22 | 23 | #Zone (capital Z) 24 | def calculate_attributes(): 25 | """Calculates values for 'Zone' column after using 'Select By Location' 26 | to select all parcels from All_2019_parcels that are within each zone area. 27 | The zone column will label the corresponding columns for each zone as 28 | ex: 'Zone1a', 'Zone1b', and so on """ 29 | 30 | pass 31 | 32 | 33 | #'native:selectbylocation' -------------------------------------------------------------------------------- /GoldenEagleDatashort.csv: -------------------------------------------------------------------------------- 1 | Name,HDOP,Speed,COG,Alt,Latitude,Longitude 2 | 2016-03-24 15:57:46 UTC,"1.2","0","0 3 | ",750.500,-79.127,38.690 4 | 2016-03-24 15:57:47 UTC,"0.9","8.7","266",737.300,-79.127,38.690 5 | 2016-03-24 15:57:48 UTC,"0.9","15.8","266",732.900,-79.127,38.690 6 | 2016-03-24 15:57:49 UTC,"0.9","19.7","278",732.500,-79.127,38.690 7 | 2016-03-24 15:57:50 UTC,"1.2","19.8","285",731.900,-79.127,38.690 8 | 2016-03-24 15:57:52 UTC,"1.2","22","278",726.400,-79.127,38.690 9 | 2016-03-24 15:57:53 UTC,"0.9","22.1","281",726.100,-79.128,38.690 10 | 2016-03-24 15:57:54 UTC,"0.9","19.2","282",727.300,-79.128,38.690 11 | 2016-03-24 15:57:55 UTC,"0.9","15","277",727.300,-79.128,38.690 12 | 2016-03-24 15:57:56 UTC,"0.9","11.4","265",727.400,-79.128,38.690 13 | 2016-03-24 15:57:57 UTC,"0.9","16.7","234",724.700,-79.128,38.690 14 | 2016-03-24 15:57:58 UTC,"0.9","22.5","215",723.300,-79.128,38.690 15 | 2016-03-24 15:58:00 UTC,"0.9","21.9","213",722.300,-79.128,38.690 16 | 2016-03-24 15:58:01 UTC,"1.2","17.1","213",720.500,-79.128,38.690 17 | 2016-03-24 15:58:02 UTC,"0.9","16.3","217",718.300,-79.128,38.690 18 | 2016-03-24 15:58:03 UTC,"0.9","17.4","210",718.600,-79.128,38.689 19 | 2016-03-24 15:58:04 UTC,"0.9","17.3","209",718.500,-79.128,38.689 20 | 2016-03-24 15:58:05 UTC,"0.9","17.2","214",717.900,-79.128,38.689 21 | 2016-03-24 15:58:06 UTC,"0.9","16.5","219",717.500,-79.128,38.689 22 | 2016-03-24 15:58:07 UTC,"0.9","16.2","221",717.300,-79.128,38.689 23 | 2016-03-24 15:58:08 UTC,"0.9","17.5","229",716.500,-79.128,38.689 24 | 2016-03-24 15:58:10 UTC,"0.9","18.7","251",715.400,-79.129,38.689 25 | 2016-03-24 15:58:11 UTC,"0.9","18.3","257",712.100,-79.129,38.689 26 | 2016-03-24 15:58:12 UTC,"0.9","18.9","255",710.200,-79.129,38.689 27 | -------------------------------------------------------------------------------- /MergeVectorLayers - BRE.py: -------------------------------------------------------------------------------- 1 | 2 | import processing 3 | 4 | 5 | layer_paths = ['/Users/ep9k/Desktop/BRE/Zone1aKeepers.shp', 6 | '/Users/ep9k/Desktop/BRE/Zone1bKeepers.shp', 7 | '/Users/ep9k/Desktop/BRE/Zone1cKeepers.shp', 8 | '/Users/ep9k/Desktop/BRE/Zone1dKeepers.shp', 9 | '/Users/ep9k/Desktop/BRE/Zone1eKeepers.shp', 10 | '/Users/ep9k/Desktop/BRE/Zone1fKeepers.shp', 11 | '/Users/ep9k/Desktop/BRE/Zone1gKeepers.shp', 12 | '/Users/ep9k/Desktop/BRE/Zone2aKeepers.shp', 13 | '/Users/ep9k/Desktop/BRE/Zone2bKeepers.shp', 14 | '/Users/ep9k/Desktop/BRE/Zone2cKeepers.shp', 15 | '/Users/ep9k/Desktop/BRE/Zone2dKeepers.shp', 16 | '/Users/ep9k/Desktop/BRE/Zone2eKeepers.shp', 17 | '/Users/ep9k/Desktop/BRE/Zone2fKeepers.shp', 18 | '/Users/ep9k/Desktop/BRE/Zone3aKeepers.shp', 19 | '/Users/ep9k/Desktop/BRE/Zone3bKeepers.shp', 20 | '/Users/ep9k/Desktop/BRE/Zone3cKeepers.shp', 21 | '/Users/ep9k/Desktop/BRE/Zone3dKeepers.shp', 22 | '/Users/ep9k/Desktop/BRE/Zone3eKeepers.shp', 23 | '/Users/ep9k/Desktop/BRE/Zone3fKeepers.shp', 24 | '/Users/ep9k/Desktop/BRE/Zone4aKeepers.shp', 25 | '/Users/ep9k/Desktop/BRE/Zone4bKeepers.shp', 26 | '/Users/ep9k/Desktop/BRE/Zone4cKeepers.shp', 27 | '/Users/ep9k/Desktop/BRE/Zone4dKeepers.shp', 28 | '/Users/ep9k/Desktop/BRE/Zone4eKeepers.shp', 29 | '/Users/ep9k/Desktop/BRE/Zone4fKeepers.shp', 30 | '/Users/ep9k/Desktop/BRE/Zone5aKeepers.shp', 31 | '/Users/ep9k/Desktop/BRE/Zone5bKeepers.shp', 32 | '/Users/ep9k/Desktop/BRE/Zone5cKeepers.shp', 33 | '/Users/ep9k/Desktop/BRE/Zone5dKeepers.shp', 34 | '/Users/ep9k/Desktop/BRE/Zone5eKeepers.shp', 35 | '/Users/ep9k/Desktop/BRE/Zone5fKeepers.shp', 36 | '/Users/ep9k/Desktop/BRE/Zone5gKeepers.shp', 37 | '/Users/ep9k/Desktop/BRE/Zone5hKeepers.shp', 38 | '/Users/ep9k/Desktop/BRE/Zone5iKeepers.shp'] 39 | 40 | parameters = {'LAYERS': layer_paths, 41 | 'CRS': None, 42 | 'OUTPUT': '/Users/ep9k/Desktop/BRE/AllKeepers2018.shp'} 43 | 44 | processing.runAndLoadResults('qgis:mergevectorlayers', parameters) 45 | 46 | 47 | -------------------------------------------------------------------------------- /convert_geographic_to_projected_coordinates.py: -------------------------------------------------------------------------------- 1 | import utm 2 | import csv 3 | from math import sqrt 4 | 5 | 6 | file_path = '/Users/ep9k/Desktop/Distance calculation for track (corrected).csv' #change this to where your input file is 7 | 8 | 9 | with open(file_path) as csv_file: 10 | # headers = ['Nam', 'Altitud', 'Lon', 'Lat'] 11 | reader = csv.DictReader(csv_file) 12 | 13 | lat_coords = [] 14 | lon_coords = [] 15 | alt_coords = [] #altitude coordinates 16 | 17 | for row in reader: 18 | lat_coords.append(float(row['Lat'])) #need to make these floats for utm.from_latlon 19 | lon_coords.append(float(row['Lon'])) 20 | alt_coords.append(float(row['Altitud'])) 21 | 22 | 23 | coordinate_pairs = zip(lat_coords, lon_coords) 24 | #for coordinate in coordinate_pairs: 25 | # print(coordinate) #run this print statement to make sure coordinate pairs look right 26 | 27 | 28 | converted_coordinates = [] #this is a list of coordinate pairs 29 | 30 | 31 | for lon, lat in coordinate_pairs: 32 | conversion = utm.from_latlon(lat, lon) 33 | converted_coordinates.append(conversion) #does the math to convert coordinates from decimal degrees to meters using utm.from_latlon and then append them to converted_coordinates list 34 | 35 | 36 | eastings = [] #easier to write to .csv if I separated the eastings and northings 37 | northings = [] 38 | 39 | for lon, lat, zone_number, zone_letter in converted_coordinates: 40 | eastings.append(str(lon)) #need to convert back to string to write to csv file 41 | northings.append(str(lat)) 42 | # print(lon, lat) #use this to verify output looks right 43 | 44 | 45 | output_path = '/Users/ep9k/Desktop/csvexample.csv' #change this to where you want to write the file to on your computer 46 | output_file = open(output_path, 'w') 47 | with output_file: 48 | writer = csv.writer(output_file) 49 | writer.writerows(zip(eastings, northings)) #writes eastings in one column, northings in next 50 | 51 | 52 | #code for getting final answer? 53 | 54 | #from math import sqrt 55 | # 56 | #a = [696263.035, 4381837.828, 1420.7] 57 | #b = [696276.2649, 4381858.49, 1417.5] 58 | #c = [696288.6723, 4381877.687, 1414.2] 59 | # 60 | # 61 | # 62 | #distance1 = (sqrt(sum( (a-b)**2 for a, b in zip(a, b)))) 63 | #distance2 = (sqrt(sum( (b-c)**2 for b, c in zip(b, c)))) 64 | # 65 | #print(distance1) 66 | #print(distance2) 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | #print(utm.from_latlon(39.078891, -79.018371)) 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /ClimbingWeatherApp-QGIS/QGIS-MakeMap.py: -------------------------------------------------------------------------------- 1 | """This script takes data from QGISweather_app_main (which is stored in temp.csv) and applies a categorized color symbology to the map. 2 | Basically, it reads the zip codes from temp.csv and joins them to the ZipCodesWithClimbing shapefile. Then represents the 3 | 'Climbing Area Conditions Data_Rank' column of the attribute table to show either the 'best' conditions or 'other' conditions today. 4 | 5 | ***Note - State must have zip codes in ClimbingAreasInfo csv file or will not be represented in the final output""" 6 | 7 | 8 | from PyQt5.QtGui import QColor 9 | from PyQt5.QtCore import QVariant 10 | from qgis.PyQt.QtCore import QVariant 11 | 12 | #sets uri, join_layer and target_field as global variables 13 | uri = '/Users/ep9k/Desktop/ClimbingWeatherApp-QGIS/Shapefiles/ZipCodesWithClimbing.shp' 14 | 15 | join_layer = iface.addVectorLayer(uri, 'US Zip Codes', 'ogr') 16 | 17 | 18 | def read_temp_csv(): 19 | """Reads temp.csv, which contains weather info by zip code for chosen state. Adds it to map""" 20 | uri = "file:///Users/ep9k/Desktop/ClimbingWeatherApp-QGIS/temp.csv?delimiter=,'" 21 | 22 | info_layer = QgsVectorLayer(uri, 'Climbing Area Conditions Data', 'delimitedtext') 23 | if info_layer.isValid(): 24 | print("info_layer is valid. Adding csv to map") 25 | QgsProject.instance().addMapLayer(info_layer) 26 | else: 27 | print("Invalid csv file. please check your file path (uri variable)") 28 | 29 | return info_layer 30 | 31 | 32 | def join_tables(info_layer): 33 | """joins temp.csv to zip codes layer based on zip code column in attribute table 34 | join_layer is US zip codes layer, which is a global variable. 35 | info_layer is csv file with conditions data for each climbing location""" 36 | QgsProject.instance().addMapLayer(join_layer) 37 | 38 | csvField = 'Zip_codes' #this is zip codes column in attribute table of info_layer 39 | shpField = 'GEOID10' #this is zip codes column in attribute table of join_layer 40 | joinObject = QgsVectorLayerJoinInfo() 41 | joinObject.setJoinFieldName(csvField) #sets name of column for csvField, which is 'Zip Codes' column from attribute table of csv file 42 | joinObject.setTargetFieldName(shpField) #sets name of column for shpField, which is 'GEOID10' column from attribute table of zip code layer 43 | joinObject.setJoinLayerId(info_layer.id()) 44 | joinObject.setUsingMemoryCache(True) 45 | joinObject.setJoinLayer(info_layer) 46 | join_layer.addJoin(joinObject) 47 | 48 | print("Tables joined") 49 | 50 | 51 | def apply_categorized_symbology(): 52 | """this will take zip codes layer afer temp_csv is joined and creates a categorized symbology based on the 'Climbing Area Conditions Data_Rank' field in the attribute table 53 | Because there is only one "best conditions" for the day, the rank for each location are either "best" or "other". I hard coded these.""" 54 | 55 | categories_list = [] 56 | target_field = 'Climbing Area Conditions Data_Rank' 57 | 58 | symbol = QgsSymbol.defaultSymbol(join_layer.geometryType()) 59 | symbol.setColor(QColor("#f28500")) 60 | my_category = QgsRendererCategory('best', symbol, 'Best Conditions') 61 | categories_list.append(my_category) 62 | 63 | symbol = QgsSymbol.defaultSymbol(join_layer.geometryType()) 64 | symbol.setColor(QColor("#8a0000")) 65 | my_category = QgsRendererCategory('other', symbol, 'Suboptimal Conditions') 66 | categories_list.append(my_category) 67 | 68 | my_renderer = QgsCategorizedSymbolRenderer(target_field, categories_list) 69 | 70 | join_layer.setRenderer(my_renderer) 71 | 72 | print("Categorized color scheme applied") 73 | 74 | 75 | def main(): 76 | """this main module runs other functions in script""" 77 | info_layer = read_temp_csv() 78 | join_tables(info_layer) 79 | apply_categorized_symbology() 80 | 81 | 82 | main() -------------------------------------------------------------------------------- /ClimbingWeatherApp-QGIS/QGISdaily_forecast_functions.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Fri Nov 2 13:56:48 2018 5 | 6 | @author: ep9k 7 | """ 8 | import json 9 | import csv 10 | from pprint import pprint 11 | import requests 12 | 13 | 14 | def state_choice(state): 15 | """Asks for user_state_choice and imports csv('ClimbingAreasCityID.csv') of climbing areas by state. Looks for state in list, then returns list 16 | of city_ids and their climbing_area_alias for each location""" 17 | 18 | city_id_list = [] 19 | climbing_area_alias = [] 20 | zip_codes = [] 21 | 22 | with open('ClimbingAreasInfo.csv') as file: 23 | reader = csv.reader(file) 24 | my_list = list(reader) 25 | 26 | for i in my_list: 27 | if i[0] == state: 28 | climbing_area_alias.append(i[2]) 29 | city_id_list.append(i[3]) 30 | zip_codes.append(i[4]) 31 | 32 | return city_id_list, climbing_area_alias, zip_codes 33 | 34 | 35 | def single_dynamic_api_request(city_id_list): 36 | """city_id_list is returned from state_choice and uses them to create api request to return weather for city.""" 37 | 38 | city_id_string = ','.join([str(city) for city in city_id_list]) #String comprehension to make one string from list of strings in city_id_list ex:"763942,539671,334596". API request can take up to 20 cities at at time 39 | 40 | request = requests.get(f'http://api.openweathermap.org/data/2.5/group?APPID=333de4e909a5ffe9bfa46f0f89cad105&id={city_id_string}&units=imperial') 41 | 42 | json_data = json.loads(request.text) 43 | 44 | # pprint(json_data) #including this in case you want to see pprint json data for each city in list 45 | return json_data 46 | 47 | 48 | def display_conditions_today(json_data, climbing_area_alias, zip_codes): 49 | """gets json data from create_dynamic_api_request (after API request is made) 50 | and climbing_area_alias is list of climbing areas near towns (not necessarily town names themselves). 51 | Then, this function parses the JSON data returned for each location and prints it in a human readable format. 52 | Lastly, creates a conditions score for each location in the conditions dict (temp x humidity for each location) 53 | and prints the lowest conditions score for today. However, this logic is flawed because at some point it gets too cold or too hot and 54 | conditions worsen again. 55 | 56 | In the future I need to build in stops for temps that are too cold or too hot.""" 57 | 58 | print("Today's climbing weather forecast... \n") 59 | 60 | 61 | climbing_area_alias_count = 0 62 | zip_code_count = 0 63 | #I create these counts because climbing_alias_for_city is a list of climbing areas and I need to step through them each time I print info for a city 64 | #EX: Birmingham is the city but Moss Rock Preserve is the climbing area. Each time I run the 'for city in data['list']' loop, I need the corresponding climbing area name for each time I loop through 65 | #same reason applies to zip_code_count. I need to print the proper zip code to the proper location 66 | 67 | try: #try/except block here to handle KeyError 68 | for city in json_data['list']: 69 | if city['sys']['country'] != 'US': 70 | print(f"City: {city['name']}, {city['sys']['country']}") 71 | print(f"Climbing area: {climbing_area_alias[climbing_area_alias_count]}") 72 | print(f"Temp today: {city['main']['temp']}") 73 | print(f"Humidity: {city['main']['humidity']}") 74 | print(f"Weather: {city['weather'][0]['description']}\n") #need ['weather'][0]['description']. The description is item 0 in a list inside 'weather' 75 | climbing_area_alias_count += 1 76 | zip_code_count += 1 77 | else: 78 | print(f"City: {city['name']}") 79 | print(f"Climbing area: {climbing_area_alias[climbing_area_alias_count]}") 80 | print(f"Temp today: {city['main']['temp']}") 81 | print(f"Humidity: {city['main']['humidity']}") 82 | print(f"Weather: {city['weather'][0]['description']}") #need ['weather'][0]['description']. The description is item 0 in a list inside 'weather' 83 | print(f"Zip Code: {zip_codes[zip_code_count]}\n") 84 | climbing_area_alias_count += 1 85 | zip_code_count += 1 86 | 87 | conditions_dict = {} #Making a dict to store 'Name': 'Conditions_score' as key,value pair 88 | 89 | for city in json_data['list']: 90 | conditions_dict[city['name']] = (city['main']['temp']*city['main']['humidity']) 91 | 92 | print(f"Currently, the best conditions are in {min(conditions_dict, key=conditions_dict.get)}.") 93 | 94 | return conditions_dict 95 | 96 | except KeyError: 97 | print("**Key Error** Either the state you entered is not in the database...") 98 | print("Or there is a problem in the with/open block in the state_choice() function") 99 | 100 | 101 | def output_for_QGIS(conditions, zip_codes): 102 | """takes conditions_dict from display_conditions_today() and zip_codes for chosen state from ClimbingAreasInfo.csv. 103 | Starts by making list items out of all 3, then feeding them into temp.csv which will be processed by QGIS. 104 | 4th column is either 'best' for the minimum conditions score, or 'other' for all other values """ 105 | 106 | cities = list(conditions.keys()) 107 | conditions_scores = list(conditions.values()) 108 | rank = [] 109 | 110 | for i in conditions_scores: #this populates the rank list with 'best' for lowest score or 'other' 111 | if i == min(conditions_scores): 112 | rank.append('best') 113 | else: 114 | rank.append('other') 115 | 116 | together = zip(cities, conditions_scores, zip_codes, rank) #zips the 4 lists together 117 | 118 | 119 | with open('temp.csv', mode='w') as write_file: 120 | employee_writer = csv.writer(write_file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL) 121 | 122 | employee_writer.writerow(['Climbing_Areas', 'Conditions_Score', 'Zip_codes', 'Rank']) 123 | 124 | for i in together: 125 | employee_writer.writerow([i[0], i[1], i[2], i[3]]) 126 | 127 | -------------------------------------------------------------------------------- /UVAOncologyPatientData.py: -------------------------------------------------------------------------------- 1 | from PyQt5.QtGui import QColor 2 | from PyQt5.QtCore import QVariant 3 | from qgis.PyQt.QtCore import QVariant 4 | 5 | #sets uri, join_layer and target_field as global variables 6 | uri = '/Users/ep9k/Desktop/SandraMonson/cb_2017_us_zcta510_500k/cb_2017_us_zcta510_500k.shp' 7 | 8 | join_layer = iface.addVectorLayer(uri, 'Patients by Zip Code', 'ogr') 9 | target_field = 'PatCNT' 10 | 11 | 12 | def add_csv(): 13 | """Adds csv file of patient data to map. Pop-up dialog box prompts user to input file path 14 | QInputDialog prompts user for file name. User must input path to a CSV file""" 15 | 16 | file_name = QInputDialog.getText(None, 'Enter input filepath to csv file', 'Please save patient data as csv and paste full pathname here. (Example: /Users/ep9k/Desktop/SandraMonson/TestZips.csv)') 17 | file_name = file_name[0] #QInputDialog returns a tuple, this is first object of tuple, which is a string of the file name 18 | 19 | uri = f"file://{file_name}?delimiter=,'" #needs file:// before path to csv. I don't know why. 20 | 21 | info_layer = QgsVectorLayer(uri, 'Patient_Data', 'delimitedtext') 22 | if info_layer.isValid(): 23 | print("info_layer is valid. Adding csv to map") 24 | QgsProject.instance().addMapLayer(info_layer) #adds csv table to layer panel 25 | else: 26 | print("Invalid csv file. Please check your file path. (uri variable)") 27 | 28 | return info_layer #returns info layer, which is the csv file 29 | 30 | 31 | def join_tables(join_layer, info_layer): 32 | """Joins attributes tables of join_layer and info_layer 33 | join_layer is US zip codes layer 34 | info_layer is csv file with patient data""" 35 | QgsProject.instance().addMapLayer(join_layer) 36 | 37 | csvField = 'ZipCode' 38 | shpField = 'GEOID10' 39 | joinObject = QgsVectorLayerJoinInfo() 40 | joinObject.setJoinFieldName(csvField) #sets name of column for csvField, which is 'ZipCode' column from attribute table of csv file 41 | joinObject.setTargetFieldName(shpField) #sets name of column for shpField, which is 'GEOID10' column from attribute table of zipcode layer 42 | joinObject.setJoinLayerId(info_layer.id()) 43 | joinObject.setUsingMemoryCache(True) 44 | joinObject.setJoinLayer(info_layer) 45 | join_layer.addJoin(joinObject) 46 | 47 | print("Tables joined") 48 | 49 | 50 | def add_column_to_attribute_table(): 51 | """Adds new column to attribute table of join_layer. 52 | Then computes column (copies PatientCount field as numeric value)""" 53 | 54 | caps = join_layer.dataProvider().capabilities() #checks capabilities of join_layer. Can also print all capabilities 55 | if caps & QgsVectorDataProvider.AddAttributes: #if AddAttributes is a capability 56 | join_layer.dataProvider().addAttributes([QgsField('PatCNT', QVariant.Int)]) #Adds PatCNT as new column to attribute table of join_layer QVariant.Int is type for new column 57 | print("New Column added to attribute table") 58 | 59 | 60 | def calculate_attributes(): 61 | """Calculates values for 'PatCNT' by copying attributes from Patient_Data_PatientCount 62 | and adds them to 'PatCNT' column in US Zip Codes table""" 63 | 64 | with edit(join_layer): 65 | for feature in join_layer.getFeatures(): 66 | feature.setAttribute(feature.fieldNameIndex('PatCNT'), feature['Patient_Data_PatientCount']) 67 | join_layer.updateFeature(feature) 68 | print(f"Attribute calculated for {target_field} field") 69 | 70 | 71 | def apply_graduated_symbology(): 72 | """Creates Symbology for each value in range of values. 73 | Values are # of patients per zip code. 74 | Hard codes min value, max value, symbol (color), and label for each range of values. 75 | Then QgsSymbolRenderer takes field from attribute table and item from myRangeList and applies them to join_layer. 76 | Color values are hex codes, in a graduated fashion from light pink to black depending on intensity""" 77 | myRangeList = [] 78 | 79 | symbol = QgsSymbol.defaultSymbol(join_layer.geometryType()) #symbol stores a symbol for the geometry type of this layer, which is a polygon 80 | symbol.setColor(QColor("#f5c9c9")) #sets Color for this symbol 81 | myRange = QgsRendererRange(0, 2, symbol, '2 or fewer') #QgsRendererRange is used to define values for a range of values. Arguments are (min value, max value, color, label) 82 | myRangeList.append(myRange) #appends this range of values to myRangeList 83 | 84 | symbol = QgsSymbol.defaultSymbol(join_layer.geometryType()) 85 | symbol.setColor(QColor("#f97a7a")) 86 | myRange = QgsRendererRange(2.1, 4, symbol, '3-4') 87 | myRangeList.append(myRange) 88 | 89 | symbol = QgsSymbol.defaultSymbol(join_layer.geometryType()) 90 | symbol.setColor(QColor("#ff0000")) 91 | myRange = QgsRendererRange(4.1, 6, symbol, '5-6') 92 | myRangeList.append(myRange) 93 | 94 | symbol = QgsSymbol.defaultSymbol(join_layer.geometryType()) 95 | symbol.setColor(QColor("#8a0000")) 96 | myRange = QgsRendererRange(5.1, 7, symbol, '6-7') 97 | myRangeList.append(myRange) 98 | 99 | symbol = QgsSymbol.defaultSymbol(join_layer.geometryType()) 100 | symbol.setColor(QColor("#4a0000")) 101 | myRange = QgsRendererRange(7.1, 9, symbol, '8-9') 102 | myRangeList.append(myRange) 103 | 104 | symbol = QgsSymbol.defaultSymbol(join_layer.geometryType()) 105 | symbol.setColor(QColor("#000000")) 106 | myRange = QgsRendererRange(9.1, 100, symbol, '10 or more') 107 | myRangeList.append(myRange) 108 | 109 | myRenderer = QgsGraduatedSymbolRenderer(target_field, myRangeList) #reads target_field and uses values from myRangeList to populate those values in myRenderer 110 | myRenderer.setMode(QgsGraduatedSymbolRenderer.Custom) #sets this mode to Custom, because I have defined custom values 111 | 112 | join_layer.setRenderer(myRenderer) #applies the rendering to join_layer 113 | 114 | print(f"Graduated color scheme applied") 115 | 116 | 117 | def main_module(): 118 | """main module which runs all steps in script""" 119 | info_layer = add_csv() 120 | join_tables(join_layer, info_layer) #join_layer is global variable 121 | add_column_to_attribute_table() 122 | calculate_attributes() 123 | apply_graduated_symbology() 124 | print("All operations finished") 125 | 126 | main_module() 127 | -------------------------------------------------------------------------------- /qgis_basemaps.py: -------------------------------------------------------------------------------- 1 | """ 2 | This script should be run from the Python consol inside QGIS. 3 | 4 | It adds online sources to the QGIS Browser. 5 | Each source should contain a list with the folowing items (string type): 6 | [sourcetype, title, authconfig, password, referer, url, username, zmax, zmin] 7 | 8 | You can add or remove sources from the sources section of the code. 9 | 10 | Script by Klas Karlsson 11 | Sources from https://qms.nextgis.com/ 12 | 13 | Licence GPL-3 14 | """ 15 | 16 | 17 | # Sources 18 | sources = [] 19 | sources.append(["connections-xyz","Google Maps","","","","https://mt1.google.com/vt/lyrs=m&x=%7Bx%7D&y=%7By%7D&z=%7Bz%7D","","19","0"]) 20 | sources.append(["connections-xyz","Google Satellite", "", "", "", "https://mt1.google.com/vt/lyrs=s&x=%7Bx%7D&y=%7By%7D&z=%7Bz%7D", "", "19", "0"]) 21 | sources.append(["connections-xyz","Google Terrain", "", "", "", "https://mt1.google.com/vt/lyrs=t&x=%7Bx%7D&y=%7By%7D&z=%7Bz%7D", "", "19", "0"]) 22 | sources.append(["connections-xyz","Google Terrain Hybrid", "", "", "", "https://mt1.google.com/vt/lyrs=p&x=%7Bx%7D&y=%7By%7D&z=%7Bz%7D", "", "19", "0"]) 23 | sources.append(["connections-xyz","Google Satellite Hybrid", "", "", "", "https://mt1.google.com/vt/lyrs=y&x=%7Bx%7D&y=%7By%7D&z=%7Bz%7D", "", "19", "0"]) 24 | sources.append(["connections-xyz","Stamen Terrain", "", "", "Map tiles by Stamen Design, under CC BY 3.0. Data by OpenStreetMap, under ODbL", "http://tile.stamen.com/terrain/%7Bz%7D/%7Bx%7D/%7By%7D.png", "", "20", "0"]) 25 | sources.append(["connections-xyz","Stamen Toner", "", "", "Map tiles by Stamen Design, under CC BY 3.0. Data by OpenStreetMap, under ODbL", "http://tile.stamen.com/toner/%7Bz%7D/%7Bx%7D/%7By%7D.png", "", "20", "0"]) 26 | sources.append(["connections-xyz","Stamen Toner Light", "", "", "Map tiles by Stamen Design, under CC BY 3.0. Data by OpenStreetMap, under ODbL", "http://tile.stamen.com/toner-lite/%7Bz%7D/%7Bx%7D/%7By%7D.png", "", "20", "0"]) 27 | sources.append(["connections-xyz","Stamen Watercolor", "", "", "Map tiles by Stamen Design, under CC BY 3.0. Data by OpenStreetMap, under ODbL", "http://tile.stamen.com/watercolor/%7Bz%7D/%7Bx%7D/%7By%7D.jpg", "", "18", "0"]) 28 | sources.append(["connections-xyz","Wikimedia Map", "", "", "OpenStreetMap contributors, under ODbL", "https://maps.wikimedia.org/osm-intl/%7Bz%7D/%7Bx%7D/%7By%7D.png", "", "20", "1"]) 29 | sources.append(["connections-xyz","Wikimedia Hike Bike Map", "", "", "OpenStreetMap contributors, under ODbL", "http://tiles.wmflabs.org/hikebike/%7Bz%7D/%7Bx%7D/%7By%7D.png", "", "17", "1"]) 30 | sources.append(["connections-xyz","Esri Boundaries Places", "", "", "", "https://server.arcgisonline.com/ArcGIS/rest/services/Reference/World_Boundaries_and_Places/MapServer/tile/%7Bz%7D/%7By%7D/%7Bx%7D", "", "20", "0"]) 31 | sources.append(["connections-xyz","Esri Gray (dark)", "", "", "", "http://services.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Dark_Gray_Base/MapServer/tile/%7Bz%7D/%7By%7D/%7Bx%7D", "", "16", "0"]) 32 | sources.append(["connections-xyz","Esri Gray (light)", "", "", "", "http://services.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/%7Bz%7D/%7By%7D/%7Bx%7D", "", "16", "0"]) 33 | sources.append(["connections-xyz","Esri National Geographic", "", "", "", "http://services.arcgisonline.com/ArcGIS/rest/services/NatGeo_World_Map/MapServer/tile/%7Bz%7D/%7By%7D/%7Bx%7D", "", "12", "0"]) 34 | sources.append(["connections-xyz","Esri Ocean", "", "", "", "https://services.arcgisonline.com/ArcGIS/rest/services/Ocean/World_Ocean_Base/MapServer/tile/%7Bz%7D/%7By%7D/%7Bx%7D", "", "10", "0"]) 35 | sources.append(["connections-xyz","Esri Satellite", "", "", "", "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/%7Bz%7D/%7By%7D/%7Bx%7D", "", "17", "0"]) 36 | sources.append(["connections-xyz","Esri Standard", "", "", "", "https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/%7Bz%7D/%7By%7D/%7Bx%7D", "", "17", "0"]) 37 | sources.append(["connections-xyz","Esri Terrain", "", "", "", "https://server.arcgisonline.com/ArcGIS/rest/services/World_Terrain_Base/MapServer/tile/%7Bz%7D/%7By%7D/%7Bx%7D", "", "13", "0"]) 38 | sources.append(["connections-xyz","Esri Transportation", "", "", "", "https://server.arcgisonline.com/ArcGIS/rest/services/Reference/World_Transportation/MapServer/tile/%7Bz%7D/%7By%7D/%7Bx%7D", "", "20", "0"]) 39 | sources.append(["connections-xyz","Esri Topo World", "", "", "", "http://services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/%7Bz%7D/%7By%7D/%7Bx%7D", "", "20", "0"]) 40 | sources.append(["connections-xyz","OpenStreetMap Standard", "", "", "OpenStreetMap contributors, CC-BY-SA", "http://tile.openstreetmap.org/%7Bz%7D/%7Bx%7D/%7By%7D.png", "", "19", "0"]) 41 | sources.append(["connections-xyz","OpenStreetMap H.O.T.", "", "", "OpenStreetMap contributors, CC-BY-SA", "http://tile.openstreetmap.fr/hot/%7Bz%7D/%7Bx%7D/%7By%7D.png", "", "19", "0"]) 42 | sources.append(["connections-xyz","OpenStreetMap Monochrome", "", "", "OpenStreetMap contributors, CC-BY-SA", "http://tiles.wmflabs.org/bw-mapnik/%7Bz%7D/%7Bx%7D/%7By%7D.png", "", "19", "0"]) 43 | sources.append(["connections-xyz","Strava All", "", "", "OpenStreetMap contributors, CC-BY-SA", "https://heatmap-external-b.strava.com/tiles/all/bluered/%7Bz%7D/%7Bx%7D/%7By%7D.png", "", "15", "0"]) 44 | sources.append(["connections-xyz","Strava Run", "", "", "OpenStreetMap contributors, CC-BY-SA", "https://heatmap-external-b.strava.com/tiles/run/bluered/%7Bz%7D/%7Bx%7D/%7By%7D.png?v=19", "", "15", "0"]) 45 | sources.append(["connections-xyz","Open Weather Map Temperature", "", "", "Map tiles by OpenWeatherMap, under CC BY-SA 4.0", "http://tile.openweathermap.org/map/temp_new/%7Bz%7D/%7Bx%7D/%7By%7D.png?APPID=1c3e4ef8e25596946ee1f3846b53218a", "", "19", "0"]) 46 | sources.append(["connections-xyz","Open Weather Map Clouds", "", "", "Map tiles by OpenWeatherMap, under CC BY-SA 4.0", "http://tile.openweathermap.org/map/clouds_new/%7Bz%7D/%7Bx%7D/%7By%7D.png?APPID=ef3c5137f6c31db50c4c6f1ce4e7e9dd", "", "19", "0"]) 47 | sources.append(["connections-xyz","Open Weather Map Wind Speed", "", "", "Map tiles by OpenWeatherMap, under CC BY-SA 4.0", "http://tile.openweathermap.org/map/wind_new/%7Bz%7D/%7Bx%7D/%7By%7D.png?APPID=f9d0069aa69438d52276ae25c1ee9893", "", "19", "0"]) 48 | sources.append(["connections-xyz","CartoDb Dark Matter", "", "", "Map tiles by CartoDB, under CC BY 3.0. Data by OpenStreetMap, under ODbL.", "http://basemaps.cartocdn.com/dark_all/%7Bz%7D/%7Bx%7D/%7By%7D.png", "", "20", "0"]) 49 | sources.append(["connections-xyz","CartoDb Positron", "", "", "Map tiles by CartoDB, under CC BY 3.0. Data by OpenStreetMap, under ODbL.", "http://basemaps.cartocdn.com/light_all/%7Bz%7D/%7Bx%7D/%7By%7D.png", "", "20", "0"]) 50 | sources.append(["connections-xyz","Bing VirtualEarth", "", "", "", "http://ecn.t3.tiles.virtualearth.net/tiles/a{q}.jpeg?g=1", "", "19", "1"]) 51 | 52 | 53 | # Add sources to browser 54 | for source in sources: 55 | connectionType = source[0] 56 | connectionName = source[1] 57 | QSettings().setValue("qgis/%s/%s/authcfg" % (connectionType, connectionName), source[2]) 58 | QSettings().setValue("qgis/%s/%s/password" % (connectionType, connectionName), source[3]) 59 | QSettings().setValue("qgis/%s/%s/referer" % (connectionType, connectionName), source[4]) 60 | QSettings().setValue("qgis/%s/%s/url" % (connectionType, connectionName), source[5]) 61 | QSettings().setValue("qgis/%s/%s/username" % (connectionType, connectionName), source[6]) 62 | QSettings().setValue("qgis/%s/%s/zmax" % (connectionType, connectionName), source[7]) 63 | QSettings().setValue("qgis/%s/%s/zmin" % (connectionType, connectionName), source[8]) 64 | 65 | # Update GUI 66 | iface.reloadConnections() 67 | -------------------------------------------------------------------------------- /CreateLayoutManagerAndExport.py: -------------------------------------------------------------------------------- 1 | import numpy #using percentile function when calculating raster pixel value range 2 | #add import statements for qgis.core class functions, etc### 3 | 4 | 5 | #add function to clip output raster from step 2 to vector input used in step 1 (vector of the study area) 6 | """This clips output raster from step 2 to extent of vector input of study area""" 7 | ###Uses Clip Raster by mask layer tool from Raster>Extraction>... 8 | 9 | 10 | """This creates a new print layout""" 11 | project = QgsProject.instance() #gets a reference to the project instance 12 | manager = project.layoutManager() #gets a reference to the layout manager 13 | layout = QgsPrintLayout(project) #makes a new print layout object, takes a QgsProject as argument 14 | layoutName = "PrintLayout" 15 | 16 | layouts_list = manager.printLayouts() 17 | for layout in layouts_list: 18 | if layout.name() == layoutName: 19 | manager.removeLayout(layout) 20 | 21 | layout = QgsPrintLayout(project) 22 | layout.initializeDefaults() #create default map canvas 23 | layout.setName(layoutName) 24 | manager.addLayout(layout) 25 | 26 | 27 | 28 | """This adds a map item to the Print Layout""" 29 | map = QgsLayoutItemMap(layout) 30 | map.setRect(20, 20, 20, 20) 31 | #Set Extent 32 | #rectangle = QgsRectangle(1355502, -46398, 1734534, 137094) #an example of how to set map extent with coordinates 33 | #map.setExtent(rectangle) 34 | canvas = iface.mapCanvas() 35 | map.setExtent(canvas.extent()) #sets map extent to current map canvas 36 | layout.addLayoutItem(map) 37 | #Move & Resize 38 | map.attemptMove(QgsLayoutPoint(5, 27, QgsUnitTypes.LayoutMillimeters)) 39 | map.attemptResize(QgsLayoutSize(239, 178, QgsUnitTypes.LayoutMillimeters)) 40 | 41 | 42 | """Gathers active layers to add to legend""" 43 | #Checks layer tree objects and stores them in a list. This includes csv tables 44 | checked_layers = [layer.name() for layer in QgsProject().instance().layerTreeRoot().children() if layer.isVisible()] 45 | print(f"Adding {checked_layers} to legend." ) 46 | #get map layer objects of checked layers by matching their names and store those in a list 47 | layersToAdd = [layer for layer in QgsProject().instance().mapLayers().values() if layer.name() in checked_layers] 48 | root = QgsLayerTree() 49 | for layer in layersToAdd: 50 | #add layer objects to the layer tree 51 | root.addLayer(layer) 52 | 53 | 54 | """This adds a legend item to the Print Layout""" 55 | legend = QgsLayoutItemLegend(layout) 56 | legend.model().setRootGroup(root) 57 | layout.addLayoutItem(legend) 58 | legend.attemptMove(QgsLayoutPoint(246, 5, QgsUnitTypes.LayoutMillimeters)) 59 | 60 | 61 | 62 | """This symbolizes raster layer in legend""" 63 | #defining raster layer to work with (active layer in layer panel) 64 | layer = iface.activeLayer() 65 | print("Active Layer: ", layer.name()) 66 | provider = layer.dataProvider() 67 | extent = layer.extent() 68 | #Using RasterBandStats to find range of values in raster layer 69 | stats = provider.bandStatistics(1, QgsRasterBandStats.All) 70 | min_val = stats.minimumValue #minimum pixel value in layer 71 | max_val = stats.maximumValue #maximum pixel value in layer 72 | print("min value =", min_val) 73 | print("max value =", max_val) 74 | 75 | value_range = list(range(int(min_val), int(max_val+1))) #Range of values in raster layer. Without +1 doesn't capture highest value 76 | value_range.sort() 77 | for value in value_range: #deletes 0 value from value range so as not to skew shading in results 78 | if value < stats.minimumValue: 79 | del value 80 | 81 | 82 | #we will categorize pixel values into 5 quintiles, based on value_range of raster layer 83 | #defining min and max values for each quintile. 84 | #Also, values are rounded to 2 decimal places 85 | first_quintile_max = round(numpy.percentile(value_range, 20), 2) 86 | first_quintile_min = round(min_val, 2) 87 | second_quintile_max = round(numpy.percentile(value_range, 40), 2) 88 | second_quintile_min = round((first_quintile_max + .01), 2) 89 | third_quintile_max = round(numpy.percentile(value_range, 60), 2) 90 | third_quintile_min = round((second_quintile_max + .01), 2) 91 | fourth_quintile_max = round(numpy.percentile(value_range, 80), 2) 92 | fourth_quintile_min = round((third_quintile_max + .01), 2) 93 | fifth_quintile_max = round(numpy.percentile(value_range, 100), 2) 94 | fifth_quintile_min = round((fourth_quintile_max + .01), 2) 95 | 96 | 97 | ###maybe add function here to create index of color values based on ESV service### 98 | 99 | #builds raster shader with colors_list. 100 | raster_shader = QgsColorRampShader() 101 | raster_shader.setColorRampType(QgsColorRampShader.Discrete) #Shading raster layer with QgsColorRampShader.Discrete 102 | colors_list = [ QgsColorRampShader.ColorRampItem(0, QColor(255, 255, 255), 'No Data'), \ 103 | QgsColorRampShader.ColorRampItem(first_quintile_max, QColor(204, 219, 255), f"{first_quintile_min} - {first_quintile_max}"), \ 104 | QgsColorRampShader.ColorRampItem(second_quintile_max, QColor(153, 184, 255), f"{second_quintile_min} - {second_quintile_max}"), \ 105 | QgsColorRampShader.ColorRampItem(third_quintile_max, QColor(102, 148, 255), f"{third_quintile_min} - {third_quintile_max}"), \ 106 | QgsColorRampShader.ColorRampItem(fourth_quintile_max, QColor(51, 113, 255), f"{fourth_quintile_min} - {fourth_quintile_max}"), \ 107 | QgsColorRampShader.ColorRampItem(fifth_quintile_max, QColor(0, 77, 255), f"{fifth_quintile_min} - {fifth_quintile_max}")] 108 | raster_shader.setColorRampItemList(colors_list) #applies colors_list to raster_shader 109 | shader = QgsRasterShader() 110 | shader.setRasterShaderFunction(raster_shader) 111 | 112 | renderer = QgsSingleBandPseudoColorRenderer(layer.dataProvider(), 1, shader) #renders selected raster layer 113 | layer.setRenderer(renderer) 114 | layer.triggerRepaint() 115 | 116 | 117 | 118 | """This adds labels to the map""" 119 | title = QgsLayoutItemLabel(layout) 120 | title.setText("Title Here") 121 | title.setFont(QFont("Arial", 28)) 122 | title.adjustSizeToText() 123 | layout.addLayoutItem(title) 124 | title.attemptMove(QgsLayoutPoint(10, 4, QgsUnitTypes.LayoutMillimeters)) 125 | 126 | subtitle = QgsLayoutItemLabel(layout) 127 | subtitle.setText("Subtitle Here") 128 | subtitle.setFont(QFont("Arial", 17)) 129 | subtitle.adjustSizeToText() 130 | layout.addLayoutItem(subtitle) 131 | subtitle.attemptMove(QgsLayoutPoint(11, 20, QgsUnitTypes.LayoutMillimeters)) #allows moving text box 132 | 133 | credit_text = QgsLayoutItemLabel(layout) 134 | credit_text.setText("Credit Text Here") 135 | credit_text.setFont(QFont("Arial", 10)) 136 | credit_text.adjustSizeToText() 137 | layout.addLayoutItem(credit_text) 138 | credit_text.attemptMove(QgsLayoutPoint(246, 190, QgsUnitTypes.LayoutMillimeters)) 139 | 140 | 141 | """This exports a Print Layout as an image""" 142 | manager = QgsProject.instance().layoutManager() #this is a reference to the layout Manager, which contains a list of print layouts 143 | #for layout in manager.printLayouts(): #this prints all existing print layouts in a list 144 | # print(layout.name()) 145 | 146 | layout = manager.layoutByName(layoutName) #this accesses a specific layout, by name (which is a string) 147 | 148 | exporter = QgsLayoutExporter(layout) #this creates a QgsLayoutExporter object 149 | exporter.exportToPdf('/Users/ep9k/Desktop/TestLayout.pdf', QgsLayoutExporter.PdfExportSettings()) #this exports a pdf of the layout object 150 | #exporter.exportToImage('/Users/ep9k/Desktop/TestLayout.png', QgsLayoutExporter.ImageExportSettings()) #this exports an image of the layout object 151 | 152 | 153 | -------------------------------------------------------------------------------- /ClimbingWeatherApp-QGIS/ClimbingAreasInfo.csv: -------------------------------------------------------------------------------- 1 | State,City,Alias,City_ID,ZipCode 2 | NC,Blowing Rock,Boone vicinity,4456376,28605 3 | NC,Morganton,Linville Gorge,4480219,28655 4 | NC,Lake Lure,Rumbling Bald,4474803,28720 5 | NC,Brevard,Looking Glass,4457040,28712 6 | NC,Danbury,Moore's Wall,4462940,27016 7 | NC,Elkin,Stone Mountain,4465155,28621 8 | NC,Asheboro,Asheboro,4453035,27203 9 | WV,Fayetteville,New River Gorge,4798308,25840 10 | WV,Franklin,Franklin/Seneca Rocks,4806504,26807 11 | WV,Pearisburg,Bozoo,4778312,24739 12 | WV,Morgantown,Coopers Rock,4815352,26501 13 | TN,Chattanooga,Chattanooga vicinity,4612862,37341 14 | TN,Wartburg,Obed,4665933,37887 15 | TN,Nashville,King's Bluff,4644585,37011 16 | TN,Dayton,Dayton Pocket/Laurel Snow,4617536,37321 17 | VA,Madison,Old Rag,4771235,22727 18 | VA,Waynesboro,Charlottesvile vicinity,4792522,22980 19 | VA,Harrisonburg,Hidden Rocks/2nd Mountain,4763237,22801 20 | VA,Roanoke,McAfee's Knob,4782167,24001 21 | VA,McLean,Great Falls,4772354,22103 22 | VA,Abingdon,Hidden Valley,4743815,24210 23 | VA,Independence,Grayson Highlands,4829280,24348 24 | VA,Grundy,Breaks Interstate Park,4762512,24614 25 | VA,Richmond,Manchester Wall,4781708,23222 26 | AL,Fort Payne,Citadel/Little River Canyon,4062861,35967 27 | AL,Birmingham,Moss Rock Preserve,4049979,35005 28 | AL,Oneonta,Horse Pens 40,4081671,35121 29 | GA,LaFayette,Rocktown,4204241,30728 30 | GA,Atlanta,Boat Rock,4180439,30306 31 | GA,Clarkesville,Mount Yonah/Tallulah Gorge,4188197,30523 32 | KY,Campton,Red River Gorge,4286728,41301 33 | AR,Jasper,Horseshoe Canyon Ranch,4116400,72641 34 | AR,Ben Hur,Cowell,4105879,72856 35 | AR,Fayetteville,Fayetteville vicinity,4110486,72702 36 | MD,Bethesda,Carderock,4348599,20810 37 | MD,Hagerstown,Annapolis Rock,4357141,21740 38 | MD,Harper's Ferry,Harper's Ferry,4801850,25425 39 | SC,Pickens,Big Rock/Table Rock,4590946,29671 40 | PA,Harrisburg,Mt. Gretna/Governor's Stable,5192726,17101 41 | PA,Birdsboro,Birdsboro Quarry,5180620,19508 42 | PA,Pittsburgh,SW Pennsylvania vicinity,5206379,15204 43 | NY,New Paltz,Shawangunks,5128539, 44 | NY,New York,Central Park,5128581, 45 | NY,Tupper Lake,Adirondacks,5141580, 46 | IL,Carbondale,So-Ill vicinity,4235193, 47 | IL,Davenport,Mississippi Palisades,4853423, 48 | WI,Baraboo,Devil's Lake,5244638, 49 | MI,Lansing,Grand Ledge,4998830, 50 | MI,Marquette,Marquette vicinity,5000947, 51 | TX,Dripping Springs,Reimer's Ranch,4686903, 52 | TX,Belton,Roger's Park,4673425, 53 | TX,Waco,Tonkawa Falls,4739526, 54 | TX,Del Rio,Pecos River,5520076, 55 | TX,Fredericksburg,Enchanted Rock,4692279, 56 | TX,Amarillo,Palo Duro Canyon,5516233, 57 | TX,El Paso,Hueco Tanks,5520993, 58 | OH,Akron,Cleveland vicinity,5145476, 59 | OH,Youngstown,Youngstown vicinity,5177568, 60 | OH,Athens,Athens vicinity,4505542, 61 | IN,North Vernon,Muscatatuck State Park,4262318, 62 | IA,Cedar Rapids,Pictured Rocks State Park,4850751, 63 | IA,Dubuque,Backbone State Park,4854529, 64 | MO,Columbia,Columbia vicinity,4381982, 65 | MO,Ironton,Elephant Rocks,4392057, 66 | MO,Kansas City,Kansas City vicinity,4393217, 67 | AZ,Mesquite,Virgin River Gorge,5508180, 68 | AZ,Flagstaff,Flagstaff vicinity,5294810, 69 | AZ,Sedona,Sedona vicinity,5313667, 70 | AZ,Winslow,Jack's Canyon,5321473, 71 | AZ,Phoenix,Queen Creek Canyon,5308655, 72 | AZ,Tucson,Mt. Lemmon,5318313, 73 | AZ,Tombstone,Cochise Stronghold,5317714, 74 | NM,Taos,Taos Vicinity,5493811, 75 | NM,Santa Fe,Los Alamos,5490263, 76 | NM,Albuquerque,Sandias,5454711, 77 | NM,Socorro,Enchanted Tower,5491999, 78 | NM,Truth or Consequences,Truth or Consequences vicinity,5495292, 79 | NM,Las Cruces,Organ Mountains,5475352, 80 | VT,Burlington,Smuggler's Notch,5234372, 81 | VT,Montpelier,Marshfield Ledge,5238685, 82 | VT,Rutland,Killington,5240509, 83 | NH,Durham,Pawtuckaway,5085618, 84 | NH,Rumney,Rumney,5091981, 85 | NH,North Conway,Cathedral Ledge/Whitehorse Ledge/Cannon Cliff,5090347, 86 | CT,Wallingford,Central Connecticut,4845056, 87 | CT,Waterbury,West Rock,5242565, 88 | CT ,Torrington,Western Connecticut,4844309, 89 | RI,Providence,Lincoln Woods,5224151, 90 | ME,Bar Harbor,Acadia National Park,4957320, 91 | ME,Bethel,Shagg Crag,4958084, 92 | ME,Portland,Great Head,4975802, 93 | MA,Great Barrington,Great Barrington,4938157, 94 | MA,Amherst,Rose Ledge,4929023, 95 | MA,Boston,Boston vicinity,4930956, 96 | OK,Lawton,Wichita Wildlife Refuge,4540737, 97 | OK,Mangum,Quartz Mountain,4542100, 98 | OK,Wilburton,Robber's Cave,4555423, 99 | OK,Tulsa,Chandler Park,4553433, 100 | MN,Worthington,Blue Mounds,5053460, 101 | MN,Red Wingq,Red Wing,5042773, 102 | MN,Duluth,Duluth vicinity,5024719, 103 | MN,Silver Bay,Lake Superior Areas,5047308, 104 | SD,Sioux City,Palisades State Park,5231851, 105 | SD,Spearfish,Spearfish Canyon,5769288, 106 | SD,Rapid City,The Needles,5768233, 107 | WY,Gillette,Devil's Tower,5826027, 108 | WY,Laramie,Vedauwoo,5830062, 109 | WY,Casper,Fremont Canyon,5820705, 110 | WY,Lander,Sinks Canyon/Wild Iris,5830007, 111 | WY,Pinedale,Wind River Range,5835178, 112 | WY,Buffalo,Ten Sleep,5819881, 113 | WY,Cody,Cody vicinity,5821593, 114 | WY,Driggs,Grand Tetons,5591399, 115 | CO,Boulder,Front Range Areas,5574991, 116 | CO,Golden,Clear Creek Canyon,5423294, 117 | CO,Fort Collins,Poudre Canyon,5577147, 118 | CO,Estes Park,Rocky Mountain National Park,5576882, 119 | CO,Idaho Springs,Mt. Evans,5425911, 120 | CO,Colorado Springs,Shelf Road,5417598, 121 | CO,Rifle,Rifle,5436363, 122 | CO,Grand Junction,Western Slope Areas,5423573, 123 | CO,Durango,Southwest Colorado,5420241, 124 | CO,Ouray,Ouray Vicinity,5433676, 125 | CO,Gunnison,Black Canyon,5424099, 126 | CO,Aspen,Independence Pass,5412230, 127 | UT,Salt Lake City,Salt Lake City vicinity,5780993, 128 | UT,Logan,Logan Canyon,5777544, 129 | UT,Moab,Moab Vicinity,5543307, 130 | UT,St. George,St. George vicinity,5546220, 131 | UT,Orangeville,Joe's Valley,5544402, 132 | UT,Hurricane,Zion National Park,5540831, 133 | UT,Monticello,Indian Creek,5543377, 134 | NV,Las Vegas,Red Rocks,5506956, 135 | NV,Carson City,Washoe Boulders,5501350, 136 | NV,Fernley,Pyramid Lake areas,5504003, 137 | NV,Eureka,Wild Granites,5503804, 138 | NV,Lamoille,Ruby Mountains,5703670, 139 | NV,Incline Village,Lake Tahoe east shore,5505963, 140 | MT,Bozeman,Hyalite Canyon,5641727, 141 | MT,Big Sky,Gallatin Canyon,5640193, 142 | MT,Helena,Whiskey Gulch,5656882, 143 | MT,Missoula,Missoula vicinity,5666639, 144 | MT,Kalispell,Northwest Montana,5660340, 145 | ID,Idaho Falls,The Fins,5596475, 146 | ID,Twin Falls,Twin Falls vicinity,5610810, 147 | ID,Burley,City of Rocks,5587385, 148 | ID,Boise,Boise vicinity,5586437, 149 | ID,Stanley,Sawtooth Range,5609286, 150 | ID,Grangeville,Riggins,5594474, 151 | ID,Couer D'Alene,Northern Panhandle,5589173, 152 | OR,Bend,Smith Rocks,5713587, 153 | OR,Eugene,Wilamette Valley,5725846, 154 | OR,Portland,Portland vicinity,5746545, 155 | OR,Hood River,Mt. Hood vicinity,5731777, 156 | WA,Leavenworth,Leavenworth,5800683, 157 | WA,Spokane,Spokane vicinity,5811696, 158 | WA,Omak,Vantage,5805734, 159 | WA,Bellingham,Bellingham vicinity,5786899, 160 | WA,North Bend,Little Si,5804915, 161 | WA,Gold Bar,Index/Gold Bar,5795678, 162 | WA,Rainier,Mt. Rainier vicinity,5747402, 163 | WA,Yakima,Yakima vicinity,5816605, 164 | WA,Pullman,Southeastern Washington,5807540, 165 | CA,Mount Shasta,Mt. Shasta vicinity,5568295, 166 | CA,Arcata,Humboldt County,5558953, 167 | CA,Truckee,North Lake Tahoe,5403676, 168 | CA,South Lake Tahoe,South Lake Tahoe,5397664, 169 | CA,Oakland,Bay Area Climbing,5378538, 170 | CA,Sonora,Sonora Pass,5397165, 171 | CA,Yosemite Valley,Yosemite National Park,7262586, 172 | CA,Bridgeport,Tuolumne Meadows,5330736, 173 | CA,Mammoth Lakes,Mammoth Lakes vicinity,5370006, 174 | CA,Bishop,Bishop vicinity,5328808, 175 | CA,Visalia,The Needles,5406567, 176 | CA,San Luis Obispo,Central Coast,5392323, 177 | CA,Malibu,Malibu Creek,5369906, 178 | CA,Simi Valley,Stoney Point,5396003, 179 | CA,Riverside,Riverside Quarry,5387877, 180 | CA,Big Bear Lake,Big Bear vicinity,5328163, 181 | CA,Hemet,Tahquitz/Suicide Rock,5356277, 182 | CA,Twentynine Palms,Joshua Tree National Park,5404198, 183 | CA,San Diego,San Diego vicinity,5391811, 184 | AK,Juneau,Juneau vicinity,5554072, 185 | AK,Seward,Kenai Peninsula,5873776, 186 | AK,Palmer,Hatcher Pass,5871146, 187 | AK,Denali,Denali National Park,5860541, 188 | AK,Fairbanks,Fairbanks vicinity,5861897, 189 | AK,Anchorage,Seward Highway,5879400, --------------------------------------------------------------------------------