Part 1 – Python Foundations for
Geospatial Beginners
Chapter 1: What is Programming?
Programming is the art of giving clear instructions to a computer so it can perform tasks.
Computers are powerful, but they are also very literal.
They do exactly what you say, nothing more, nothing less.
1.1 Why do we need programming?
● To automate tasks (no need to do the same work repeatedly).
● To process large amounts of data (e.g., analyzing thousands of satellite images).
● To solve problems faster and more accurately (computers can handle complex
calculations instantly).
1.2 What happens when we write a program?
1. We write instructions in a programming language (like Python).
2. Python translates those instructions into something the computer understands
(machine code).
3. The computer executes the instructions.
1.3 How is programming like giving directions?
Imagine you want a robot to make tea. You need to give exact steps:
1. Boil water.
2. Add tea leaves.
3. Add sugar.
4. Pour into a cup.
If you skip a step (like “check if there is water in the kettle”), the robot will fail.
That’s how programming works: clear, step-by-step, unambiguous instructions.
Chapter 2: Why Python? (History, Philosophy, Career
Relevance)
2.1 History of Python
● Created in 1991 by Guido van Rossum.
● Named after the British comedy show Monty Python’s Flying Circus (not the snake).
● Designed to be easy to read and beginner-friendly.
2.2 Philosophy of Python
Python follows The Zen of Python (type import this in Python to see it).
Some key ideas:
● Beautiful is better than ugly → Code should look clean.
● Simple is better than complex → Fewer confusing steps.
● Readability counts → Anyone can understand your code.
2.3 Why Python for GIS?
● Python is built into most GIS software (ArcGIS, QGIS).
● Python has special GIS libraries like:
○ GeoPandas → Vector data
○ Shapely → Geometry
○ Rasterio → Raster images
○ Folium → Interactive maps
○ OSMnx → OpenStreetMap data
● Python skills can open careers as:
○ GIS Developer
○ Remote Sensing Analyst
○ Geospatial Data Scientist
Chapter 3: Understanding Python Syntax & Semantics
3.1 Syntax = Grammar of Python
Python has rules about how code must be written.
If you break them, Python gives a SyntaxError.
Example:
print("Hello World") # ✅ Correct
print "Hello World" # ❌ Wrong (missing parentheses)
3.2 Semantics = Meaning of Code
Even if syntax is correct, the meaning must make sense.
Example:
5 / 0 # Syntax is fine, but dividing by zero is meaningless → Error
3.3 Why indentation matters
In Python, spaces at the start of a line (indentation) show which code belongs together.
Example:
if True:
print("This is indented properly")
If indentation is wrong, you’ll see IndentationError.
Chapter 4: Writing Your First Python Program
4.1 The simplest Python program
print("Welcome to Python for GIS!")
● print() shows text on screen.
● "Welcome to Python for GIS!" is text (string).
4.2 Adding comments
Comments help you (and others) understand code later.
# This program prints a welcome message
print("Welcome to Python for GIS!")
● # starts a comment — Python ignores it.
Chapter 5: Data Types & Variables
5.1 What is a variable?
A variable is like a box with a label. You store values in it and refer to them later.
Example:
city_name = "Delhi"
● city_name is the label.
● "Delhi" is the value inside the box.
5.2 Common data types in Python
String (str) – Text inside quotes.
name = "India"
Strings are like labels on maps.
Integer (int) – Whole numbers.
population = 1380000000
Used for counts (population, number of roads).
Float (float) – Decimal numbers.
area = 3287.263
Used for measurements (area in sq km).
Boolean (bool) – True/False values.
is_capital = True
Used for yes/no questions.
Chapter 6: Operators & Expressions
6.1 Arithmetic Operators
a = 10
b=5
print(a + b) # 15
print(a - b) # 5
print(a * b) # 50
print(a / b) # 2.0
6.2 Comparison Operators
print(a > b) # True
print(a == b) # False
Chapter 7: Control Flow
7.1 If Statements
temperature = 32
if temperature > 30:
print("It's hot")
7.2 Loops
tools = ["QGIS", "ArcGIS", "GeoPandas"]
for tool in tools:
print(tool)
7.3 Error Handling
try:
result = 10 / 0
except ZeroDivisionError:
print("Cannot divide by zero")
Chapter 8: Functions & Scope
8.1 Functions
def area_square(side):
return side * side
8.2 Scope
Variables inside a function exist only inside that function.
Chapter 9: Modules & Libraries
9.1 Importing built-in modules
import math
print(math.sqrt(16))
9.2 Installing external libraries
pip install geopandas
Chapter 10: Writing Clean Code (PEP 8)
● Use 4 spaces for indentation.
● Use descriptive variable names.
● Keep code organized and commented.
Part 2 – Python in the Geospatial World
Chapter 11: What is Geospatial Technology? (With
Code & Explanation)
Geospatial technology is all about data that has a location.
Python lets us work with that data to read it, analyze it, and create maps.
Let’s see the simplest example of plotting a single point on a map using Python.
Code:
import folium
# Create a map centered on New Delhi
m = folium.Map(location=[28.6139, 77.2090], zoom_start=6)
# Save map
m.save("delhi_map.html")
Step-by-step explanation:
import folium
● import → loads the Folium library.
● Folium is used to make interactive maps.
m = folium.Map(location=[28.6139, 77.2090], zoom_start=6)
● folium.Map() → creates a new map.
● location=[28.6139, 77.2090] → latitude, longitude of map center. Change
these values to center on any place.
● zoom_start=6 → zoom level (higher = more zoom).
m.save("delhi_map.html")
● Saves map as HTML file.
● Change file name if you want another map file.
Open delhi_map.html in your browser to see your interactive map.
Chapter 12: Types of Geospatial Data (Vector & Raster)
Python can work with two main data types:
Vector Data Example (Points, Lines, Polygons)
Code:
import geopandas as gpd
# Load cities shapefile
cities = gpd.read_file("cities.shp")
# Show first 5 rows
print(cities.head())
Explanation:
import geopandas as gpd
● Loads GeoPandas (for vector data).
● as gpd → shortcut name.
cities = gpd.read_file("cities.shp")
● gpd.read_file() → opens spatial file.
● "cities.shp" → path to shapefile. Change to any file you want.
print(cities.head())
● Shows first 5 records in the file.
Raster Data Example (Pixel Grids)
Code:
import rasterio
# Load raster file
raster = rasterio.open("elevation.tif")
# Show metadata
print(raster.crs, raster.width, raster.height)
Explanation:
import rasterio
● Loads Rasterio (for raster files).
raster = rasterio.open("elevation.tif")
● Opens raster file. Change filename to open any other .tif.
print(raster.crs, raster.width, raster.height)
● Shows CRS (coordinate system), width (pixels), height (pixels).
Chapter 13: Key Python Libraries for GIS (With Use
Examples)
GeoPandas Example
import geopandas as gpd
gdf = gpd.read_file("roads.shp")
print(gdf.crs)
● Reads vector data.
● gdf.crs → shows coordinate system.
Shapely Example
from shapely.geometry import Point
p = Point(77.2090, 28.6139)
print(p)
● Creates a point geometry.
● Change numbers for different coordinates.
Rasterio Example
import rasterio
raster = rasterio.open("satellite.tif")
print(raster.count)
● .count → number of bands in raster.
Chapter 14: Setting up Your Python GIS Environment
(Customizing Install)
Install libraries using pip:
pip install geopandas shapely rasterio pyproj folium osmnx
● Add or remove libraries depending on what you need.
Or install using Anaconda:
conda install geopandas rasterio folium osmnx
● Installs from conda package manager.
Chapter 15: Reading & Exploring Spatial Data
(Customizable)
Reading Vector Data
import geopandas as gpd
gdf = gpd.read_file("states.shp")
print(gdf.head())
● Change "states.shp" to any shapefile name.
Reading Raster Data
import rasterio
raster = rasterio.open("landcover.tif")
print(raster.meta)
● .meta → shows details (bands, CRS, resolution).
Chapter 16: Spatial Analysis Basics (Customizing)
Buffer
gdf["buffer"] = gdf.buffer(5000)
● 5000 = distance in meters. Change to increase/decrease buffer.
Spatial Join
joined = gpd.sjoin(cities, states, predicate="within")
● predicate="within" → only keep cities inside states. Change to "intersects" to
include touching boundaries.
Chapter 17: Raster Processing Basics
Working with Bands
red = raster.read(3)
nir = raster.read(4)
● 3 = band number. Change to pick other bands.
NDVI Calculation
ndvi = (nir - red) / (nir + red)
● Formula can be customized for other indices (like NDWI for water).
Chapter 18: Map Visualization (Word-by-Word)
(Already shown earlier — static + interactive map with full explanation and customization
tips)
Chapter 19: Coordinate Reference Systems
(Customizing)
Reproject
gdf = gdf.to_crs(epsg=3857)
● epsg=3857 → Web Mercator. Change EPSG for your target CRS.
Chapter 20: Real-World Projects & Career Paths
Here you can modify data sources for your own region:
● Change shapefiles for your country
● Change raster for different satellite data
● Change CRS depending on your local projection system
Part 3 – Intermediate GIS Python
Chapter 21: Adding Basemaps to Maps
Code:
import geopandas as gpd
import matplotlib.pyplot as plt
import contextily as ctx
# Load shapefile
gdf = gpd.read_file("cities.shp")
# Convert to Web Mercator
gdf = gdf.to_crs(epsg=3857)
# Plot map
ax = gdf.plot(figsize=(10, 10), color="orange", edgecolor="black")
# Add basemap
ctx.add_basemap(ax, source=ctx.providers.Stamen.TonerLite)
# Show map
plt.show()
Explanation:
● ctx.providers.Stamen.TonerLite → basemap style. Change to
OpenStreetMap.Mapnik, Esri.WorldImagery for different backgrounds.
● color="orange" → customize feature color.
● edgecolor="black" → change border color.
Chapter 22: Creating Interactive Maps
Code:
import folium
import geopandas as gpd
# Load cities
gdf = gpd.read_file("cities.shp")
# Create interactive map centered on India
m = folium.Map(location=[20, 78], zoom_start=5)
# Add city markers
for idx, row in gdf.iterrows():
folium.Marker(
[row.geometry.y, row.geometry.x],
popup=row['name'],
tooltip="Click for name"
).add_to(m)
# Save map
m.save("interactive_cities.html")
Explanation:
● popup=row['name'] → Shows city name when clicked. Change column to show
population, area, etc.
● tooltip="Click for name" → Text shown when hovering. Change to any
message.
Chapter 23: Working with OpenStreetMap Data (OSMnx)
Code:
import osmnx as ox
# Download Bangalore road network
g = ox.graph_from_place("Bangalore, India", network_type="drive")
# Plot network
ox.plot_graph(g)
Explanation:
● network_type="drive" → downloads roads for cars. Change to "walk",
"bike" for pedestrian/bicycle networks.
● "Bangalore, India" → Change city name to download another place.
Chapter 24: Time Series Geospatial Data
Code:
import glob
import rasterio
import numpy as np
# Get list of MODIS images
rasters = sorted(glob.glob("data/modis/*.tif"))
ndvi_list = []
for raster in rasters:
with rasterio.open(raster) as src:
red = src.read(3)
nir = src.read(4)
ndvi = (nir - red) / (nir + red)
ndvi_list.append(ndvi.mean())
Explanation:
● glob.glob() → finds all raster files.
● src.read(3) → reads band 3 (red). Change to another band number for other
indices.
Chapter 25: Map Projections (Deep Customization)
Code:
gdf = gdf.to_crs(epsg=32643)
● epsg=32643 → UTM Zone 43N. Change EPSG for your location.
Chapter 26: Handling Large Datasets
Code:
import dask_geopandas as dgpd
dgdf = dgpd.read_file("large_dataset.geojson")
● Use Dask for large datasets. Replace file name for your dataset.
Chapter 27: Data Cleaning
Code:
gdf = gdf[~gdf.geometry.is_empty & gdf.geometry.notnull()]
gdf["geometry"] = gdf.buffer(0)
● .buffer(0) → fixes invalid geometries.
Chapter 28: Remote Sensing Basics (Rasterio)
Code:
import rasterio
landsat = rasterio.open("landsat.tif")
print(landsat.count)
● .count → number of bands.
Chapter 29: NDVI Calculation
Code:
red = landsat.read(3)
nir = landsat.read(4)
ndvi = (nir - red) / (nir + red)
● Customize to calculate NDWI or SAVI by changing formula.
Chapter 30: Classification (Scikit-learn)
Code:
from sklearn.ensemble import RandomForestClassifier
clf = RandomForestClassifier()
clf.fit(X_train, y_train)
● Customize n_estimators for number of trees.
Part 4 – Intermediate GIS Python
Chapter 31: Change Detection
Change detection helps identify what has changed between two dates (e.g., vegetation loss,
urban growth).
Code:
import rasterio
import numpy as np
# Open two NDVI rasters
with rasterio.open("ndvi_2020.tif") as src1:
ndvi_2020 = src1.read(1)
with rasterio.open("ndvi_2024.tif") as src2:
ndvi_2024 = src2.read(1)
# Calculate change
ndvi_change = ndvi_2024 - ndvi_2020
Explanation:
● "ndvi_2020.tif" & "ndvi_2024.tif" → File names for two different years.
Change to any two rasters you have.
● src1.read(1) → Reads band 1 of NDVI raster.
● ndvi_change → Positive values = increase, negative = decrease.
Chapter 32: Spatial Interpolation
Interpolation predicts values where no direct measurements exist.
Concept only (Code depends on library like PyKrige):
● Input: Known rainfall values at stations.
● Output: Predicted rainfall in surrounding areas.
● Customizable: Number of nearby points to consider, interpolation type (IDW,
Kriging).
Chapter 33: Network Analysis with OSMnx
Find shortest path on road networks.
Code:
import osmnx as ox
# Get road network
G = ox.graph_from_place("Bangalore, India", network_type="drive")
# Shortest path between two points
orig_node = list(G.nodes())[0]
dest_node = list(G.nodes())[50]
route = ox.shortest_path(G, orig_node, dest_node, weight='length')
# Plot route
ox.plot_graph_route(G, route)
Explanation:
● network_type="drive" → For car roads. Change to "walk" for walking paths.
● orig_node & dest_node → IDs of start and end. You can pick your own nodes
using coordinates.
● weight='length' → Shortest distance. Change to "travel_time" if network
has speed limits.
Chapter 34: Heatmaps (Folium)
Code:
from folium.plugins import HeatMap
import folium
# Create map
m = folium.Map(location=[20, 78], zoom_start=5)
# Add heatmap
HeatMap([[row.geometry.y, row.geometry.x] for idx, row in gdf.iterrows()]).add_to(m)
# Save map
m.save("heatmap.html")
Explanation:
● row.geometry.y, row.geometry.x → Y = latitude, X = longitude.
● Customize: Add weight to points:
HeatMap([[row.geometry.y, row.geometry.x, row['intensity']] for idx, row in gdf.iterrows()])
Chapter 35: 3D Visualization (Pydeck)
Code:
import pydeck as pdk
# Create hexagon layer
layer = pdk.Layer(
"HexagonLayer",
data=gdf,
get_position='[longitude, latitude]',
radius=200,
elevation_scale=4,
elevation_range=[0, 1000],
extruded=True,
# View state
view_state = pdk.ViewState(latitude=20, longitude=78, zoom=5)
# Render
r = pdk.Deck(layers=[layer], initial_view_state=view_state)
r.show()
Explanation:
● radius=200 → Size of hexagons in meters.
● elevation_scale=4 → Height scale. Change to exaggerate height.
Chapter 36: Time-Enabled Maps
Code:
from folium.plugins import TimestampedGeoJson
TimestampedGeoJson(
{'type': 'FeatureCollection', 'features': features},
period='P1D',
add_last_point=True
).add_to(m)
Explanation:
● period='P1D' → One step per day. Change to P1M for months.
Chapter 37: PyQGIS Basics
(Runs inside QGIS Python console)
Code:
layer = iface.activeLayer()
print(layer.name())
Explanation:
● iface.activeLayer() → Gets selected layer in QGIS.
● Customize: Change layer operations (filter, export).
Chapter 38: PostGIS Database Connection
Code:
import geopandas as gpd
import sqlalchemy
engine = sqlalchemy.create_engine('postgresql://user:pass@localhost:5432/gisdb')
gdf.to_postgis('cities', engine)
Explanation:
● 'cities' → Table name. Change table name as needed.
● Database credentials must match your setup.
Chapter 39: Web Mapping with Flask + Folium
Code:
from flask import Flask
import folium
app = Flask(__name__)
@app.route('/')
def map():
m = folium.Map(location=[20, 78], zoom_start=5)
return m._repr_html_()
Explanation:
● return m._repr_html_() → Renders interactive map inside webpage.
● Customize location, zoom, and markers.
Chapter 40: Automating Workflows
Linux Cron Job Example:
0 9 * * * python /home/user/scripts/update_map.py
Explanation:
● Runs Python script every day at 9 AM. Change time or frequency as needed.
Awesome 👍
Let’s continue with Chapters 41–50 in the same word-by-word, customizable
explanation style.
Part 4 – Intermediate GIS Python
(Continued)
Chapter 41: API Integration – Google Maps API
APIs let you fetch live data (coordinates, routes, elevation) directly into Python.
Code:
import requests
url = "https://maps.googleapis.com/maps/api/geocode/json"
params = {"address": "New York", "key": "YOUR_API_KEY"}
response = requests.get(url, params=params)
print(response.json())
Explanation:
● url → Google Maps API endpoint.
● params → Dictionary of request parameters:
○ "address": "New York" → Location to search. Change this to any
address.
○ "key": "YOUR_API_KEY" → Replace with your API key.
● response.json() → API reply in JSON format.
Chapter 42: Google Earth Engine (GEE) Python API
Code:
import ee
ee.Initialize()
# Load image
image = ee.Image("COPERNICUS/S2/20210101T000000_20210131T235959")
# Print info
print(image.getInfo())
Explanation:
● ee.Initialize() → Connects to GEE account.
● "COPERNICUS/S2/..." → Sentinel-2 dataset. Change ID for different datasets.
Chapter 43: Machine Learning for Land Use
Code:
from sklearn.ensemble import RandomForestClassifier
clf = RandomForestClassifier(n_estimators=100)
clf.fit(X_train, y_train)
Explanation:
● n_estimators=100 → Number of trees. Change to adjust accuracy/speed.
Chapter 44: Deep Learning for Imagery
Code:
import tensorflow as tf
from tensorflow.keras import layers, models
model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(64,64,3)))
model.add(layers.Flatten())
model.add(layers.Dense(10, activation='softmax'))
Explanation:
● Conv2D(32, (3,3)) → 32 filters, size 3×3. Change filters or size for different
model complexity.
Chapter 45: Environmental Applications
Examples:
● Deforestation mapping
● Flood risk analysis
● Air quality mapping
Chapter 46: Urban Planning Applications
Examples:
● Site selection for hospitals
● Public transport optimization
Chapter 47: Disaster Management Applications
Examples:
● Wildfire spread prediction
● Earthquake damage assessment
Chapter 48: Best Practices in Large Projects
● Use version control (Git).
● Document all workflows.
● Keep data organized in folders.
Chapter 49: Future of Python in GIS
● AI-driven real-time mapping
● Integration with IoT sensors
● Cloud-based spatial analytics
Chapter 50: Summary & Next Steps
You’ve learned:
● Python basics for GIS
● Vector & raster operations
● APIs, ML, cloud tools
Next:
● Advanced Remote Sensing (Chapters 51–75)
● GeoAI & Automation (Chapters 76–100)
Part 5 – Advanced GIS + Remote
Sensing (RS)
Chapter 51: Introduction to Remote Sensing in Python
Remote Sensing = collecting information about Earth from satellites or aircraft without
physical contact.
Python lets us:
● Read raw satellite images (GeoTIFF)
● Process multiple bands
● Calculate indices (NDVI, NDWI, etc.)
● Classify land cover
Chapter 52: Sentinel-2 Data in Python
Code:
import rasterio
sentinel = rasterio.open("sentinel2_image.tif")
print(sentinel.count)
Explanation:
● "sentinel2_image.tif" → Sentinel-2 image file. Change filename for your
own dataset.
● .count → Number of bands in the image.
Chapter 53: Landsat Data in Python
Code:
landsat = rasterio.open("landsat8_image.tif")
print(landsat.count)
Explanation:
● Works same as Sentinel but different band order. Check documentation for band
assignments.
Chapter 54: Atmospheric Correction Basics
Atmospheric correction improves image accuracy by removing haze and scattering effects.
In Python:
● Use libraries like Py6S (SixS radiative transfer model)
● Or download pre-corrected products from GEE
Chapter 55: Extracting Bands
Code:
red = sentinel.read(3) # Band 3
nir = sentinel.read(4) # Band 4
Explanation:
● Band numbers differ by sensor. Check satellite band guide to pick correct band for
NDVI, NDWI, etc.
Chapter 56: NDVI Calculation
Code:
ndvi = (nir - red) / (nir + red)
Explanation:
● nir & red → Near-infrared and red bands.
● Formula gives values between -1 and 1.
● Customize: For NDWI, use green & NIR bands.
Chapter 57: NDWI (Water Index)
Code:
green = sentinel.read(2)
ndwi = (green - nir) / (green + nir)
Explanation:
● green = Band 2 for Sentinel. Change depending on sensor.
Chapter 58: NDBI (Built-up Index)
Code:
swir = sentinel.read(11)
ndbi = (swir - nir) / (swir + nir)
Explanation:
● swir = Short-wave infrared band. Different band number for Landsat.
Chapter 59: Creating False Color Composites
Code:
import matplotlib.pyplot as plt
import numpy as np
rgb = np.dstack((nir, red, green))
plt.imshow(rgb)
plt.show()
Explanation:
● np.dstack() → Stacks bands to form RGB image.
● Customize band order for different composites (e.g., 4-3-2 = natural color, 5-4-3 =
false color).
Chapter 60: Saving Processed Rasters
Code:
from rasterio import Affine
from rasterio import MemoryFile
with rasterio.open(
'ndvi_output.tif', 'w',
driver='GTiff',
height=ndvi.shape[0],
width=ndvi.shape[1],
count=1,
dtype=ndvi.dtype,
crs=sentinel.crs,
transform=sentinel.transform
) as dst:
dst.write(ndvi, 1)
Explanation:
● 'ndvi_output.tif' → Output filename. Change to save multiple products.
● dtype → Data type must match array type (float32, int16, etc.).
Part 5– Advanced GIS + Remote
Sensing (Continued)
Chapter 61: Image Classification – Introduction
Image classification assigns each pixel a class label (water, forest, urban).
Two main types:
● Supervised: We provide training samples.
● Unsupervised: Algorithm groups pixels without samples.
Chapter 62: Supervised Classification – Random Forest
Code:
from sklearn.ensemble import RandomForestClassifier
clf = RandomForestClassifier(n_estimators=100)
clf.fit(X_train, y_train)
predictions = clf.predict(X_test)
Explanation:
● n_estimators=100 → Number of trees. Change for accuracy vs speed tradeoff.
● X_train → Pixel values (features).
● y_train → Known classes (labels).
● predictions → Output class for each test pixel.
Chapter 63: Unsupervised Classification – KMeans
Code:
from sklearn.cluster import KMeans
kmeans = KMeans(n_clusters=5)
kmeans.fit(pixel_values)
labels = kmeans.labels_
Explanation:
● n_clusters=5 → Number of classes. Change to group into more/fewer clusters.
Chapter 64: Change Detection with Classified Maps
Code:
change_map = classified_2024 - classified_2020
Explanation:
● Positive = new class appeared.
● Negative = old class disappeared.
Chapter 65: SAR / Radar Data in Python
Code:
sar = rasterio.open("sentinel1_image.tif")
print(sar.count)
Explanation:
● SAR images often have VV, VH polarizations.
● Use different polarizations for flood detection, urban mapping.
Chapter 66: Mosaicking Multiple Images
Code:
from rasterio.merge import merge
import glob
files = glob.glob("tiles/*.tif")
src_files = [rasterio.open(f) for f in files]
mosaic, out_trans = merge(src_files)
Explanation:
● tiles/*.tif → Folder of images to merge. Change folder or file pattern.
Chapter 67: Cloud Masking
Code:
cloud_mask = qa_band == 0
Explanation:
● qa_band → Quality assessment band. Different satellites have different mask
values.
Chapter 68: Google Earth Engine – Advanced
Code:
import ee
ee.Initialize()
image = ee.ImageCollection("COPERNICUS/S2").filterDate('2024-01-01', '2024-01-31')
print(image.size().getInfo())
Explanation:
● filterDate() → Select images by date. Change date range.
Chapter 69: Exporting Data from GEE
Code:
task = ee.batch.Export.image.toDrive(
image=image.first(),
description="SentinelExport",
scale=10
task.start()
Explanation:
● description → Export task name. Change name as needed.
● scale=10 → Pixel resolution in meters.
Chapter 70: Automating RS Analysis
Python Script Scheduler Example (Linux cron):
0 6 * * 1 python weekly_ndvi_update.py
Explanation:
● Runs every Monday at 6 AM. Change schedule to daily, monthly, etc.
Part 6 – GeoAI & Automation
Chapter 71: Introduction to GeoAI
GeoAI = Geographic Artificial Intelligence
● Uses ML/DL to analyze spatial data.
● Common applications:
○ Land cover classification
○ Building detection
○ Road extraction
○ Flood mapping
Python connects GIS data with ML/DL frameworks like Scikit-learn, TensorFlow, PyTorch.
Chapter 72: Preparing Data for GeoAI
Data preparation is 80% of ML success.
Code:
import geopandas as gpd
import rasterio
import numpy as np
# Load vector data
gdf = gpd.read_file("training_points.shp")
# Load raster
raster = rasterio.open("landsat8_image.tif")
Explanation:
● "training_points.shp" → Points with known classes. Change file to your
training data.
● "landsat8_image.tif" → Satellite raster. Can be Sentinel, MODIS, etc.
Chapter 73: Feature Extraction
Features are values (pixel bands, indices) that ML models use.
Code:
red = raster.read(3)
nir = raster.read(4)
ndvi = (nir - red) / (nir + red)
Explanation:
● You can add more features: NDWI, NDBI, texture, slope, etc.
Chapter 74: Machine Learning Model – Random Forest
Code:
from sklearn.ensemble import RandomForestClassifier
clf = RandomForestClassifier(n_estimators=200)
clf.fit(X_train, y_train)
predictions = clf.predict(X_test)
Explanation:
● n_estimators=200 → Increase trees for more accuracy. Trade-off: Slower
training.
Chapter 75: Deep Learning Model – CNN
Code:
import tensorflow as tf
from tensorflow.keras import layers, models
model = models.Sequential([
layers.Conv2D(32, (3, 3), activation='relu', input_shape=(64,64,3)),
layers.MaxPooling2D((2, 2)),
layers.Flatten(),
layers.Dense(64, activation='relu'),
layers.Dense(5, activation='softmax')
])
Explanation:
● (64,64,3) → Image patch size (64×64 pixels, 3 bands). Change size for your
dataset.
● Dense(5) → Number of classes (e.g., 5 land cover types). Change as needed.
Chapter 76: Object Detection – YOLOv8 for Buildings
Code:
from ultralytics import YOLO
model = YOLO("yolov8n.pt")
results = model.predict(source="satellite_image.jpg")
Explanation:
● "yolov8n.pt" → Pretrained YOLO model. Change to custom model trained on
buildings.
● source="satellite_image.jpg" → Input image.
Chapter 77: Semantic Segmentation – UNet for Land
Cover
Code:
import segmentation_models as sm
model = sm.Unet('resnet34', classes=5, activation='softmax')
Explanation:
● classes=5 → Number of land cover classes. Change for your project.
Chapter 78: Automating GeoAI Inference
Code:
import glob
for img in glob.glob("input_images/*.tif"):
results = model.predict(source=img)
Explanation:
● "input_images/*.tif" → Folder of images to process. Change folder path.
Chapter 79: Pipeline Automation with Airflow
Code (DAG example):
from airflow import DAG
from airflow.operators.python import PythonOperator
def process_data():
print("Processing data...")
dag = DAG('geoai_pipeline', schedule_interval='@daily')
task = PythonOperator(task_id='process', python_callable=process_data, dag=dag)
Explanation:
● schedule_interval='@daily' → Runs daily. Change to weekly/monthly.
Chapter 80: Integrating GeoAI Results into GIS
Code:
import geopandas as gpd
gdf = gpd.read_file("predicted_buildings.geojson")
gdf.plot()
Explanation:
● "predicted_buildings.geojson" → Model output. Replace with your AI
results.
Part 6 – GeoAI & Automation (Continued)
Chapter 81: Introduction to PyQGIS (QGIS Python API)
PyQGIS allows automation of QGIS tasks using Python.
Code (inside QGIS Python Console):
layer = iface.activeLayer()
print(layer.name())
Explanation:
● iface.activeLayer() → Gets currently selected layer.
● .name() → Prints its name.
● You can change this to:
layer.setName("New Layer Name")
to rename the layer.
Chapter 82: Adding a Layer in QGIS with PyQGIS
Code:
layer = QgsVectorLayer("path/to/cities.shp", "Cities", "ogr")
QgsProject.instance().addMapLayer(layer)
Explanation:
● "path/to/cities.shp" → Path to your shapefile. Change path for your data.
● "Cities" → Display name in QGIS. Change as needed.
Chapter 83: Automating Buffer Creation in QGIS
Code:
import processing
processing.run("native:buffer", {
'INPUT': 'cities.shp',
'DISTANCE': 5000,
'OUTPUT': 'buffered_cities.shp'
})
Explanation:
● 'DISTANCE': 5000 → Buffer in meters. Change value as needed.
● 'OUTPUT' → Output shapefile name.
Chapter 84: Batch Processing Multiple Layers in QGIS
Code:
layers = ["layer1.shp", "layer2.shp"]
for l in layers:
processing.run("native:reprojectlayer", {
'INPUT': l,
'TARGET_CRS': 'EPSG:3857',
'OUTPUT': f"{l}_reprojected.shp"
})
Explanation:
● Loops through multiple layers to reproject.
● Change CRS or output naming pattern as needed.
Chapter 85: Automating Map Export in QGIS
Code:
layout = QgsProject.instance().layoutManager().layoutByName("MyLayout")
exporter = QgsLayoutExporter(layout)
exporter.exportToImage("map_export.png", QgsLayoutExporter.ImageExportSettings())
Explanation:
● "MyLayout" → Layout name in QGIS. Change to your layout name.
● "map_export.png" → Output image file.
Chapter 86: WebGIS Deployment – Basics
WebGIS lets you share maps online.
● Python + Flask + Folium for small apps.
● GeoServer or MapServer for enterprise.
Chapter 87: WebGIS Deployment with Flask + Folium
Code:
from flask import Flask
import folium
app = Flask(__name__)
@app.route('/')
def home():
m = folium.Map(location=[20, 78], zoom_start=5)
return m._repr_html_()
Explanation:
● Runs a simple web app that displays a map.
● Change location, zoom, add layers to customize.
Chapter 88: WebGIS Deployment with GeoServer
Steps:
1. Install GeoServer
2. Add your shapefile or raster as a layer
3. Publish as WMS/WFS
4. Access in Python using owslib
Chapter 89: Automated Report Generation (PDF)
Code:
from reportlab.pdfgen import canvas
c = canvas.Canvas("report.pdf")
c.drawString(100, 750, "GIS Report")
c.save()
Explanation:
● "report.pdf" → Output filename.
● .drawString() → Add text. You can add images, tables, charts.
Chapter 90: API Integration for AI Model Results
Code:
import requests
url = "https://mygeoaiapi.com/predict"
files = {'file': open('satellite_image.tif','rb')}
response = requests.post(url, files=files)
print(response.json())
Explanation:
● url → API endpoint. Change to your AI API.
● 'file': open(...) → Uploads satellite image to API.
Part 6 – GeoAI & Automation (Final
Section)
Chapter 91: Full Workflow Automation – Concept
A GIS automation pipeline:
1. Fetch new satellite images automatically (API / GEE)
2. Process (clip, reproject, classify)
3. Generate outputs (maps, reports)
4. Upload results to WebGIS automatically
We will implement step by step.
Chapter 92: Batch Download of Satellite Images (GEE)
Code:
import ee
ee.Initialize()
collection = ee.ImageCollection("COPERNICUS/S2").filterDate('2024-01-01', '2024-01-31')
count = collection.size().getInfo()
print(f"Images found: {count}")
Explanation:
● .filterDate() → Change date range for automation schedule.
● .size() → Checks number of images before processing.
Chapter 93: Automated Clipping of Images
Code:
clip_geom = ee.Geometry.Polygon([...]) # Your AOI coordinates
clipped = collection.map(lambda img: img.clip(clip_geom))
Explanation:
● clip_geom → Geometry of area of interest. Change coordinates as needed.
Chapter 94: Automated Index Calculation (NDVI)
Code:
def add_ndvi(img):
ndvi = img.normalizedDifference(['B8', 'B4']).rename('NDVI')
return img.addBands(ndvi)
ndvi_collection = clipped.map(add_ndvi)
Explanation:
● 'B8', 'B4' → Sentinel bands (NIR, Red). Change for Landsat.
Chapter 95: Batch Export of Processed Images
Code:
task = ee.batch.Export.image.toDrive(
image=ndvi_collection.mean(),
description="NDVI_AOI",
scale=10
task.start()
Explanation:
● .mean() → Averages NDVI for time range. Change to .median() for different
output.
Chapter 96: Cloud Automation with Google Cloud
Functions
Concept:
● Trigger processing whenever new imagery is available.
● Use Cloud Functions to call Python script automatically.
Chapter 97: Full Pipeline with Apache Airflow
Code (simplified DAG):
from airflow import DAG
from airflow.operators.python import PythonOperator
def download_data():
print("Downloading imagery...")
def process_data():
print("Processing imagery...")
dag = DAG('gis_pipeline', schedule_interval='@weekly')
task1 = PythonOperator(task_id='download', python_callable=download_data, dag=dag)
task2 = PythonOperator(task_id='process', python_callable=process_data, dag=dag)
task1 >> task2
Explanation:
● @weekly → Runs every week. Change schedule as needed.
Chapter 98: WebGIS Auto-Update
Code:
import requests
geoserver_url = "http://localhost:8080/geoserver/rest/reload"
requests.post(geoserver_url, auth=('admin', 'password'))
Explanation:
● Reloads GeoServer to update published layers automatically after processing.
Chapter 99: Automated Report Generation with Maps
Code:
from reportlab.pdfgen import canvas
c = canvas.Canvas("weekly_report.pdf")
c.drawString(100, 750, "Weekly NDVI Report")
c.drawImage("ndvi_map.png", 50, 500, width=500, height=300)
c.save()
Explanation:
● "ndvi_map.png" → Generated map from workflow. Replace with your latest
output.
Chapter 100: End-to-End GeoAI + GIS Automation
Project
Final Project Flow:
1. Data Fetch: Automated Sentinel/Landsat download (GEE or API)
2. Preprocessing: Clip, reproject, mask clouds
3. Analysis: NDVI, classification (RF/Deep Learning)
4. Output: Maps, shapefiles, GeoTIFFs
5. Deployment: Auto-update WebGIS (GeoServer/Flask)
6. Reporting: Auto-generate weekly reports (PDF)
This is a fully automated production pipeline — no manual steps.
Chapter 101: QGIS Layout Manager – Creating Professional Maps
Code/Process:
# In QGIS (not Python code)
1. Open QGIS Layout Manager
2. Add map frame (Insert → Map)
3. Add legend, north arrow, and scale bar
4. Set page size (A4, A3)
5. Export as PDF or PNG
Explanation:
● Legend → Automatically lists map layers.
● Scale Bar → Shows real-world distances. Change units (meters, km) in properties.
● Export Options → Use 300 dpi for print-quality maps.
Chapter 102: GPS/GNSS Data Collection with QField
Workflow:
1. Install QField (Android/iOS)
2. Prepare project in QGIS (layers, forms)
3. Upload to QFieldCloud or device
4. Collect points/lines/polygons in field
5. Sync back to QGIS for analysis
Customization:
● Add custom form fields (e.g., tree species, road type).
● Set projection to WGS84 for GPS accuracy.
Chapter 103: WebGIS with Leaflet JS
Code:
<!DOCTYPE html>
<html>
<head>
<title>Leaflet Map</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css"/>
</head>
<body>
<div id="map" style="height:500px;"></div>
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<script>
var map = L.map('map').setView([20, 78], 5);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
</script>
</body>
</html>
Explanation:
● setView([20, 78], 5) → Center & zoom. Change coordinates for your
location.
● tileLayer() → Background style. Replace with Mapbox tiles for custom
styling.
Chapter 104: Map Styling with Mapbox Studio
Steps:
1. Create account at Mapbox Studio
2. Choose template style (Light, Dark, Satellite)
3. Customize colors, fonts, line thickness
4. Publish style → copy style URL
5. Use in Leaflet:
L.tileLayer('https://api.mapbox.com/styles/v1/YOUR_STYLE/tiles/{z}/{x}/{y}?access_token=Y
OUR_TOKEN').addTo(map);
Chapter 105: Accuracy Assessment for Classification Models
Code:
from sklearn.metrics import confusion_matrix, classification_report
y_true = [0, 0, 1, 1, 2, 2]
y_pred = [0, 0, 1, 2, 2, 2]
print(confusion_matrix(y_true, y_pred))
print(classification_report(y_true, y_pred))
Explanation:
● confusion_matrix() → Shows correct vs wrong predictions.
● classification_report() → Shows precision, recall, F1-score.
Chapter 106: Portfolio Deployment – GitHub Pages
Steps:
1. Create GitHub repository
2. Upload HTML maps (Folium/Leaflet outputs)
3. Go to Settings → Pages → Branch: main → Save
4. Share URL like https://username.github.io/project
Customization:
● Organize maps into folders (maps/heatmap.html)
● Add index page listing projects
Chapter 107–110: Capstone Integration Projects
● Urban Planning WebGIS (Leaflet + QGIS + GeoServer)
● Environmental Monitoring Dashboard (GEE + Folium + Flask)
● Disaster Management AI (YOLO building detection + live flood mapping)
● Portfolio Compilation (GitHub Pages hosting + Auto update)