mirror of
https://github.com/K-Dense-AI/claude-scientific-skills.git
synced 2026-03-27 07:09:27 +08:00
- Added SKILL.md with installation, quick start, core concepts, workflows - Added 12 reference documentation files covering 70+ topics - Includes 500+ code examples across 7 programming languages - Covers remote sensing, GIS, ML/AI, 30+ scientific domains - MIT License Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Co-Authored-By: Dr. Umair Rabbani <umairrs@gmail.com>
370 lines
9.1 KiB
Markdown
370 lines
9.1 KiB
Markdown
# GIS Software Integration
|
|
|
|
Guide to integrating with major GIS platforms: QGIS, ArcGIS, GRASS GIS, and SAGA GIS.
|
|
|
|
## QGIS / PyQGIS
|
|
|
|
### Running Python Scripts in QGIS
|
|
|
|
```python
|
|
# Processing framework script
|
|
from qgis.core import (QgsProject, QgsVectorLayer, QgsRasterLayer,
|
|
QgsProcessingAlgorithm, QgsProcessingParameterRasterLayer)
|
|
|
|
# Load layers
|
|
vector_layer = QgsVectorLayer("path/to/shapefile.shp", "layer_name", "ogr")
|
|
raster_layer = QgsRasterLayer("path/to/raster.tif", "raster_name", "gdal")
|
|
|
|
# Add to project
|
|
QgsProject.instance().addMapLayer(vector_layer)
|
|
QgsProject.instance().addMapLayer(raster_layer)
|
|
|
|
# Access features
|
|
for feature in vector_layer.getFeatures():
|
|
geom = feature.geometry()
|
|
attrs = feature.attributes()
|
|
```
|
|
|
|
### Creating QGIS Processing Scripts
|
|
|
|
```python
|
|
from qgis.PyQt.QtCore import QCoreApplication
|
|
from qgis.core import (QgsProcessingAlgorithm, QgsProcessingParameterRasterDestination,
|
|
QgsProcessingParameterRasterLayer)
|
|
|
|
class NDVIAlgorithm(QgsProcessingAlgorithm):
|
|
INPUT = 'INPUT'
|
|
OUTPUT = 'OUTPUT'
|
|
|
|
def tr(self, string):
|
|
return QCoreApplication.translate('Processing', string)
|
|
|
|
def createInstance(self):
|
|
return NDVIAlgorithm()
|
|
|
|
def name(self):
|
|
return 'ndvi_calculation'
|
|
|
|
def displayName(self):
|
|
return self.tr('Calculate NDVI')
|
|
|
|
def group(self):
|
|
return self.tr('Raster')
|
|
|
|
def groupId(self):
|
|
return 'raster'
|
|
|
|
def shortHelpString(self):
|
|
return self.tr("Calculate NDVI from Sentinel-2 imagery")
|
|
|
|
def initAlgorithm(self, config=None):
|
|
self.addParameter(QgsProcessingParameterRasterLayer(
|
|
self.INPUT, self.tr('Input Sentinel-2 Raster')))
|
|
|
|
self.addParameter(QgsProcessingParameterRasterDestination(
|
|
self.OUTPUT, self.tr('Output NDVI')))
|
|
|
|
def processAlgorithm(self, parameters, context, feedback):
|
|
raster = self.parameterAsRasterLayer(parameters, self.INPUT, context)
|
|
|
|
# NDVI calculation
|
|
# ... implementation ...
|
|
|
|
return {self.OUTPUT: destination}
|
|
```
|
|
|
|
### Plugin Development
|
|
|
|
```python
|
|
# __init__.py
|
|
def classFactory(iface):
|
|
from .my_plugin import MyPlugin
|
|
return MyPlugin(iface)
|
|
|
|
# my_plugin.py
|
|
from qgis.PyQt.QtCore import QSettings
|
|
from qgis.PyQt.QtWidgets import QAction
|
|
from qgis.core import QgsProject
|
|
|
|
class MyPlugin:
|
|
def __init__(self, iface):
|
|
self.iface = iface
|
|
|
|
def initGui(self):
|
|
self.action = QAction("My Plugin", self.iface.mainWindow())
|
|
self.action.triggered.connect(self.run)
|
|
self.iface.addPluginToMenu("My Plugin", self.action)
|
|
|
|
def run(self):
|
|
# Plugin logic here
|
|
pass
|
|
|
|
def unload(self):
|
|
self.iface.removePluginMenu("My Plugin", self.action)
|
|
```
|
|
|
|
## ArcGIS / ArcPy
|
|
|
|
### Basic ArcPy Operations
|
|
|
|
```python
|
|
import arcpy
|
|
|
|
# Set workspace
|
|
arcpy.env.workspace = "C:/data"
|
|
|
|
# Set output overwrite
|
|
arcpy.env.overwriteOutput = True
|
|
|
|
# Set scratch workspace
|
|
arcpy.env.scratchWorkspace = "C:/data/scratch"
|
|
|
|
# List features
|
|
feature_classes = arcpy.ListFeatureClasses()
|
|
rasters = arcpy.ListRasters()
|
|
```
|
|
|
|
### Geoprocessing Workflows
|
|
|
|
```python
|
|
import arcpy
|
|
from arcpy.sa import *
|
|
|
|
# Check out Spatial Analyst extension
|
|
arcpy.CheckOutExtension("Spatial")
|
|
|
|
# Set environment
|
|
arcpy.env.workspace = "C:/data"
|
|
arcpy.env.cellSize = 10
|
|
arcpy.env.extent = "study_area"
|
|
|
|
# Slope analysis
|
|
out_slope = Slope("dem.tif")
|
|
out_slope.save("slope.tif")
|
|
|
|
# Aspect
|
|
out_aspect = Aspect("dem.tif")
|
|
out_aspect.save("aspect.tif")
|
|
|
|
# Hillshade
|
|
out_hillshade = Hillshade("dem.tif", azimuth=315, altitude=45)
|
|
out_hillshade.save("hillshade.tif")
|
|
|
|
# Viewshed analysis
|
|
out_viewshed = Viewshed("observer_points.shp", "dem.tif", obs_elevation_field="HEIGHT")
|
|
out_viewshed.save("viewshed.tif")
|
|
|
|
# Cost distance
|
|
cost_raster = CostDistance("source.shp", "cost.tif")
|
|
cost_raster.save("cost_distance.tif")
|
|
|
|
# Hydrology: Flow direction
|
|
flow_dir = FlowDirection("dem.tif")
|
|
flow_dir.save("flowdir.tif")
|
|
|
|
# Flow accumulation
|
|
flow_acc = FlowAccumulation(flow_dir)
|
|
flow_acc.save("flowacc.tif")
|
|
|
|
# Stream delineation
|
|
stream = Con(flow_acc > 1000, 1)
|
|
stream_raster = StreamOrder(stream, flow_dir)
|
|
```
|
|
|
|
### Vector Analysis
|
|
|
|
```python
|
|
# Buffer analysis
|
|
arcpy.Buffer_analysis("roads.shp", "roads_buffer.shp", "100 meters")
|
|
|
|
# Spatial join
|
|
arcpy.SpatialJoin_analysis("points.shp", "zones.shp", "points_joined.shp",
|
|
join_operation="JOIN_ONE_TO_ONE",
|
|
match_option="HAVE_THEIR_CENTER_IN")
|
|
|
|
# Dissolve
|
|
arcpy.Dissolve_management("parcels.shp", "parcels_dissolved.shp",
|
|
dissolve_field="OWNER_ID")
|
|
|
|
# Intersect
|
|
arcpy.Intersect_analysis(["layer1.shp", "layer2.shp"], "intersection.shp")
|
|
|
|
# Clip
|
|
arcpy.Clip_analysis("input.shp", "clip_boundary.shp", "output.shp")
|
|
|
|
# Select by location
|
|
arcpy.SelectLayerByLocation_management("points_layer", "HAVE_THEIR_CENTER_IN",
|
|
"polygon_layer")
|
|
|
|
# Feature to raster
|
|
arcpy.FeatureToRaster_conversion("landuse.shp", "LU_CODE", "landuse.tif", 10)
|
|
```
|
|
|
|
### ArcGIS Pro Notebooks
|
|
|
|
```python
|
|
# ArcGIS Pro Jupyter Notebook
|
|
import arcpy
|
|
import pandas as pd
|
|
import matplotlib.pyplot as plt
|
|
|
|
# Use current project's map
|
|
aprx = arcpy.mp.ArcGISProject("CURRENT")
|
|
m = aprx.listMaps()[0]
|
|
|
|
# Get layer
|
|
layer = m.listLayers("Parcels")[0]
|
|
|
|
# Export to spatial dataframe
|
|
sdf = pd.DataFrame.spatial.from_layer(layer)
|
|
|
|
# Plot
|
|
sdf.plot(column='VALUE', cmap='YlOrRd', legend=True)
|
|
plt.show()
|
|
|
|
# Geocode addresses
|
|
locator = "C:/data/locators/composite.locator"
|
|
results = arcpy.geocoding.GeocodeAddresses(
|
|
"addresses.csv", locator, "Address Address",
|
|
None, "geocoded_results.gdb"
|
|
)
|
|
```
|
|
|
|
## GRASS GIS
|
|
|
|
### Python API for GRASS
|
|
|
|
```python
|
|
import grass.script as gscript
|
|
import grass.script.array as garray
|
|
|
|
# Initialize GRASS session
|
|
gscript.run_command('g.gisenv', set='GISDBASE=/grassdata')
|
|
gscript.run_command('g.gisenv', set='LOCATION_NAME=nc_spm_08')
|
|
gscript.run_command('g.gisenv', set='MAPSET=user1')
|
|
|
|
# Import raster
|
|
gscript.run_command('r.in.gdal', input='elevation.tif', output='elevation')
|
|
|
|
# Import vector
|
|
gscript.run_command('v.in.ogr', input='roads.shp', output='roads')
|
|
|
|
# Get raster info
|
|
info = gscript.raster_info('elevation')
|
|
print(info)
|
|
|
|
# Slope analysis
|
|
gscript.run_command('r.slope.aspect', elevation='elevation',
|
|
slope='slope', aspect='aspect')
|
|
|
|
# Buffer
|
|
gscript.run_command('v.buffer', input='roads', output='roads_buffer',
|
|
distance=100)
|
|
|
|
# Overlay
|
|
gscript.run_command('v.overlay', ainput='zones', binput='roads',
|
|
operator='and', output='zones_roads')
|
|
|
|
# Calculate statistics
|
|
stats = gscript.parse_command('r.univar', map='elevation', flags='g')
|
|
```
|
|
|
|
## SAGA GIS
|
|
|
|
### Using SAGA via Command Line
|
|
|
|
```python
|
|
import subprocess
|
|
import os
|
|
|
|
# SAGA path
|
|
saga_cmd = "/usr/local/saga/saga_cmd"
|
|
|
|
# Grid Calculus
|
|
def saga_grid_calculus(input1, input2, output, formula):
|
|
cmd = [
|
|
saga_cmd, "grid_calculus", "GridCalculator",
|
|
f"-GRIDS={input1};{input2}",
|
|
f"-RESULT={output}",
|
|
f"-FORMULA={formula}"
|
|
]
|
|
subprocess.run(cmd)
|
|
|
|
# Slope analysis
|
|
def saga_slope(dem, output_slope):
|
|
cmd = [
|
|
saga_cmd, "ta_morphometry", "SlopeAspectCurvature",
|
|
f"-ELEVATION={dem}",
|
|
f"-SLOPE={output_slope}"
|
|
]
|
|
subprocess.run(cmd)
|
|
|
|
# Morphometric features
|
|
def saga_morphometry(dem):
|
|
cmd = [
|
|
saga_cmd, "ta_morphometry", "MorphometricFeatures",
|
|
f"-DEM={dem}",
|
|
f"-SLOPE=slope.sgrd",
|
|
f"-ASPECT=aspect.sgrd",
|
|
f"-CURVATURE=curvature.sgrd"
|
|
]
|
|
subprocess.run(cmd)
|
|
|
|
# Channel network
|
|
def saga_channels(dem, threshold=1000):
|
|
cmd = [
|
|
saga_cmd, "ta_channels", "ChannelNetworkAndDrainageBasins",
|
|
f"-ELEVATION={dem}",
|
|
f"-CHANNELS=channels.shp",
|
|
f"-BASINS=basins.shp",
|
|
f"-THRESHOLD={threshold}"
|
|
]
|
|
subprocess.run(cmd)
|
|
```
|
|
|
|
## Cross-Platform Workflows
|
|
|
|
### Export QGIS to ArcGIS
|
|
|
|
```python
|
|
import geopandas as gpd
|
|
|
|
# Read data processed in QGIS
|
|
gdf = gpd.read_file('qgis_output.geojson')
|
|
|
|
# Ensure CRS
|
|
gdf = gdf.to_crs('EPSG:32633')
|
|
|
|
# Export for ArcGIS (File Geodatabase)
|
|
gdf.to_file('arcgis_input.gpkg', driver='GPKG')
|
|
# ArcGIS can read GPKG directly
|
|
|
|
# Or export to shapefile
|
|
gdf.to_file('arcgis_input.shp')
|
|
```
|
|
|
|
### Batch Processing
|
|
|
|
```python
|
|
import geopandas as gpd
|
|
from pathlib import Path
|
|
|
|
# Process multiple files
|
|
input_dir = Path('input')
|
|
output_dir = Path('output')
|
|
|
|
for shp in input_dir.glob('*.shp'):
|
|
gdf = gpd.read_file(shp)
|
|
|
|
# Process
|
|
gdf['area'] = gdf.geometry.area
|
|
gdf['buffered'] = gdf.geometry.buffer(100)
|
|
|
|
# Export for various platforms
|
|
basename = shp.stem
|
|
gdf.to_file(output_dir / f'{basename}_qgis.geojson')
|
|
gdf.to_file(output_dir / f'{basename}_arcgis.shp')
|
|
```
|
|
|
|
For more GIS-specific examples, see [code-examples.md](code-examples.md).
|