$npx -y skills add K-Dense-AI/scientific-agent-skills --skill geomasterComprehensive geospatial science skill covering remote sensing, GIS, spatial analysis, machine learning for earth observation, and 30+ scientific domains. Supports satellite imagery processing (Sentinel, Landsat, MODIS, SAR, hyperspectral), vector and raster data operations, spat
| 1 | # GeoMaster |
| 2 | |
| 3 | Comprehensive geospatial science skill covering GIS, remote sensing, spatial analysis, and ML for Earth observation across 70+ topics with 500+ code examples in 8 programming languages. |
| 4 | |
| 5 | ## Installation |
| 6 | |
| 7 | ```bash |
| 8 | # Core Python stack (conda recommended) |
| 9 | conda install -c conda-forge gdal rasterio fiona shapely pyproj geopandas |
| 10 | |
| 11 | # Remote sensing & ML |
| 12 | uv pip install rsgislib torchgeo earthengine-api |
| 13 | uv pip install scikit-learn xgboost torch-geometric |
| 14 | |
| 15 | # Network & visualization |
| 16 | uv pip install osmnx networkx folium keplergl |
| 17 | uv pip install cartopy contextily mapclassify |
| 18 | |
| 19 | # Big data & cloud |
| 20 | uv pip install xarray rioxarray dask-geopandas |
| 21 | uv pip install pystac-client planetary-computer |
| 22 | |
| 23 | # Point clouds |
| 24 | uv pip install laspy pylas open3d pdal |
| 25 | |
| 26 | # Databases |
| 27 | conda install -c conda-forge postgis spatialite |
| 28 | ``` |
| 29 | |
| 30 | ## Quick Start |
| 31 | |
| 32 | ### NDVI from Sentinel-2 |
| 33 | |
| 34 | ```python |
| 35 | import rasterio |
| 36 | import numpy as np |
| 37 | |
| 38 | with rasterio.open('sentinel2.tif') as src: |
| 39 | red = src.read(4).astype(float) # B04 |
| 40 | nir = src.read(8).astype(float) # B08 |
| 41 | ndvi = (nir - red) / (nir + red + 1e-8) |
| 42 | ndvi = np.nan_to_num(ndvi, nan=0) |
| 43 | |
| 44 | profile = src.profile |
| 45 | profile.update(count=1, dtype=rasterio.float32) |
| 46 | |
| 47 | with rasterio.open('ndvi.tif', 'w', **profile) as dst: |
| 48 | dst.write(ndvi.astype(rasterio.float32), 1) |
| 49 | ``` |
| 50 | |
| 51 | ### Spatial Analysis with GeoPandas |
| 52 | |
| 53 | ```python |
| 54 | import geopandas as gpd |
| 55 | |
| 56 | # Load and ensure same CRS |
| 57 | zones = gpd.read_file('zones.geojson') |
| 58 | points = gpd.read_file('points.geojson') |
| 59 | |
| 60 | if zones.crs != points.crs: |
| 61 | points = points.to_crs(zones.crs) |
| 62 | |
| 63 | # Spatial join and statistics |
| 64 | joined = gpd.sjoin(points, zones, how='inner', predicate='within') |
| 65 | stats = joined.groupby('zone_id').agg({ |
| 66 | 'value': ['count', 'mean', 'std', 'min', 'max'] |
| 67 | }).round(2) |
| 68 | ``` |
| 69 | |
| 70 | ### Google Earth Engine Time Series |
| 71 | |
| 72 | ```python |
| 73 | import ee |
| 74 | import pandas as pd |
| 75 | |
| 76 | ee.Initialize(project='your-project') |
| 77 | roi = ee.Geometry.Point([-122.4, 37.7]).buffer(10000) |
| 78 | |
| 79 | s2 = (ee.ImageCollection('COPERNICUS/S2_SR_HARMONIZED') |
| 80 | .filterBounds(roi) |
| 81 | .filterDate('2020-01-01', '2023-12-31') |
| 82 | .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 20))) |
| 83 | |
| 84 | def add_ndvi(img): |
| 85 | return img.addBands(img.normalizedDifference(['B8', 'B4']).rename('NDVI')) |
| 86 | |
| 87 | s2_ndvi = s2.map(add_ndvi) |
| 88 | |
| 89 | def extract_series(image): |
| 90 | stats = image.reduceRegion(ee.Reducer.mean(), roi.centroid(), scale=10, maxPixels=1e9) |
| 91 | return ee.Feature(None, {'date': image.date().format('YYYY-MM-dd'), 'ndvi': stats.get('NDVI')}) |
| 92 | |
| 93 | series = s2_ndvi.map(extract_series).getInfo() |
| 94 | df = pd.DataFrame([f['properties'] for f in series['features']]) |
| 95 | df['date'] = pd.to_datetime(df['date']) |
| 96 | ``` |
| 97 | |
| 98 | ## Core Concepts |
| 99 | |
| 100 | ### Data Types |
| 101 | |
| 102 | | Type | Examples | Libraries | |
| 103 | |------|----------|-----------| |
| 104 | | Vector | Shapefile, GeoJSON, GeoPackage | GeoPandas, Fiona, GDAL | |
| 105 | | Raster | GeoTIFF, NetCDF, COG | Rasterio, Xarray, GDAL | |
| 106 | | Point Cloud | LAS, LAZ | Laspy, PDAL, Open3D | |
| 107 | |
| 108 | ### Coordinate Systems |
| 109 | |
| 110 | - **EPSG:4326** (WGS 84) - Geographic, lat/lon, use for storage |
| 111 | - **EPSG:3857** (Web Mercator) - Web maps only (don't use for area/distance!) |
| 112 | - **EPSG:326xx/327xx** (UTM) - Metric calculations, <1% distortion per zone |
| 113 | - Use `gdf.estimate_utm_crs()` for automatic UTM detection |
| 114 | |
| 115 | ```python |
| 116 | # Always check CRS before operations |
| 117 | assert gdf1.crs == gdf2.crs, "CRS mismatch!" |
| 118 | |
| 119 | # For area/distance calculations, use projected CRS |
| 120 | gdf_metric = gdf.to_crs(gdf.estimate_utm_crs()) |
| 121 | area_sqm = gdf_metric.geometry.area |
| 122 | ``` |
| 123 | |
| 124 | ### OGC Standards |
| 125 | |
| 126 | - **WMS**: Web Map Service - raster maps |
| 127 | - **WFS**: Web Feature Service - vector data |
| 128 | - **WCS**: Web Coverage Service - raster coverage |
| 129 | - **STAC**: Spatiotemporal Asset Catalog - modern metadata |
| 130 | |
| 131 | ## Common Operations |
| 132 | |
| 133 | ### Spectral Indices |
| 134 | |
| 135 | ```python |
| 136 | def calculate_indices(image_path): |
| 137 | """NDVI, EVI, SAVI, NDWI from Sentinel-2.""" |
| 138 | with rasterio.open(image_path) as src: |
| 139 | B02, B03, B04, B08, B11 = [src.read(i).astype(float) for i in [1,2,3,4,5]] |
| 140 | |
| 141 | ndvi = (B08 - B04) / (B08 + B04 + 1e-8) |
| 142 | evi = 2.5 * (B08 - B04) / (B08 + 6*B04 - 7.5*B02 + 1) |
| 143 | savi = ((B08 - B04) / (B08 + B04 + 0.5)) * 1.5 |
| 144 | ndwi = (B03 - B08) / (B03 + B08 + 1e-8) |
| 145 | |
| 146 | return {'NDVI': ndvi, 'EVI': evi, 'SA |