GEOG 336 Demo follow-along guide
Open OnDemand | GlobalProtect VPN
Part 1: Logging in to Open OnDemand
For your convenience, the cluster can be accessed through a graphical user interface (GUI) called Open OnDemand. This interface will allow you to access all of the features you will need for GEOG 336ds.
- Navigate to https://ondemand.hpc.uwec.edu (Requires on-campus or VPN connection).
- Enter your UWEC login and authenticate with Okta.
- Complete the first time sign-in process if you have never used the cluster before. * Follow the instructions on screen exactly. Make sure you accept all the terms of service.
Trouble with setup?
If you're struggling with first time sign-in or accepting the terms of service, try following our detailed guide at https://docs.hpc.uwec.edu/ood/first-time/
Part 2 - Copying Class Files
Before you are able to run the demo in this guide, you'll need to copy files on the cluster to your own personal directory.
- Click on the "Home Directory" tile on the main dashboard page.
- Note that you should see a
my_geog336
directory in your files. This is important for the demo.
- On the left side click on "Class Files: GEOG336"
- Click the checkmark box for
EC_rasters
andNDVI_NDWI_Demo.ipynb
to indicate you want to copy them. - In the top right click on
Copy/Move
- This will show a popup on the left side. This is just telling you that you are in "Copy/Move" mode.
- Navigate to "Your Files: GEOG336" in the left sidebar to go to your own directory.
- Click the "Copy" button on the left to copy the files to your directory.
Part 3: Jupyter Notebook
You will be using a program called Jupyter Notebook for this demo. Jupyter allows you to interactively run code on the cluster with an easy-to-use interface.
Starting a Jupyter session
To use Jupyter, you must request resources from the cluster. First, click on the "Jupyter Notebook" tile on the OnDemand home screen. Once you click it, request the following resources on the next screen:
- Accounting Group: 2255.geog.336.001
- Slurm Partition: Week (7 days) - Default
- CPU Cores: 1
- Memory: 15G
- #GPU Cards: No GPUs - Default
- Number of Hours: 2
- Working Directory: (Leave this blank)
- Email Notifications: None - No Email
Double-check that all of your values are right, then click the blue Launch button.
Accessing your session
Once you launch the session, it will need to start. This can take some time, but once your session changes from "Starting" to "Running", click the blue Connect to Jupyter button.
Opening the demo notebook
Once you open Jupyter, you will be in your "Home Directory". You should see a folder called "my_geog336
". Open this folder, then click on the "NDVI_NDWI_Demo.ipynb
" file inside. Once opened, you will be on the Jupyter Notebook screen, and you can now begin entering code.
Part 4 - Notebook Cells
Each "Chunk" of code in a notebook is called a Cell. Below you will find each cell used in the demo, which you can copy for convenience. Make sure to run each cell after you copy it. If you don't run them in order, it will not work.
Initial Set Up
Cell 1:
This cell is already in the notebook for you!
# By default, Python can't really do a whole lot, but it really shines by importing code
# that *other* people make.
from tifffile import imread
import matplotlib.pyplot as plt
import numpy as np
import rasterio
# ---- DO THIS ---- #
# Click on this cell and either hit "Run" at the top or press "shift+enter" on your keyboard.
# - If the left side says "In [#]" then you've successfully completed this step.
# - Do this for every new cell you type.
# --- READ ABOVE ---- #
Output
Nothing will show if this is successful.
Cell 2:
#Read the raster tiff files and find out how many channels are there
EC_april_23 = imread('EC_rasters/EC_april23.tif')
print(EC_april_23.shape)
EC_aug_23 = imread('EC_rasters/EC_aug23.tif')
print(EC_aug_23.shape)
Cell 3:
#Find the min and max in the dataset. Then normalize to have all pixels between 0 and 1
print(f"Original April Image Min: {EC_april_23.min()}")
print(f"Original April Image Max: {EC_april_23.max()}")
# Normalize image using NumPy
april_normalized = (EC_april_23 - EC_april_23.min()) / (EC_april_23.max() - EC_april_23.min())
#Check for consistency:
print(f"Normalized April Image Min: {april_normalized.min()}")
print(f"Normalized April Image Max: {april_normalized.max()}")
Output
Cell 4:
#Find the min and max in the dataset. Then normalize to have all pixels between 0 and 1
print(f"Original August Image Min: {EC_aug_23.min()}")
print(f"Original August Image Max: {EC_aug_23.max()}")
# Normalize image using NumPy
aug_normalized = (EC_aug_23 - EC_aug_23.min()) / (EC_aug_23.max() - EC_aug_23.min())
#Check for consistency:
print(f"Normalized Aug Image Min: {aug_normalized.min()}")
print(f"Normalized Aug Image Max: {aug_normalized.max()}")
Output
Cell 5:
#Print using first channel (Red) for April and Aug image side by side:
# Create subplots with 1 row, 2 columns
fig, axes = plt.subplots(1, 2, figsize=(12, 6))
# First Image (April Red Channel with Viridis Colormap)
img1 = axes[0].imshow(april_normalized[:, :, 0], cmap='viridis')
axes[0].set_title("April Red Channel Image")
axes[0].axis("off") # Hide axis
# Second Image (Aug Red Channel with Viridis Colormap)
img2= axes[1].imshow(aug_normalized[:, :, 0], cmap='viridis') # Display as RGB
axes[1].set_title("August Red Channel Image")
axes[1].axis("off") # Hide axis
Output
Then afterwards there should be two images showing April and August Red Channels.
NDVI
Cell 6:
#Perform NDVI for April
#Note that the image has 4 channels.
#The channels are Red, Green, Blue, and Infrared
# NDVI will be done on the first channel (Red) and the fourth channel (Infrared)
# Extract Red and NIR channels
red_apr = april_normalized[:, :, 0] # First channel (Red)
nir_apr = april_normalized[:, :, 3] # Fourth channel (Infrared)
# Compute NDVI with handling for division by zero
denominator_apr = nir_apr + red_apr
ndvi_apr = np.where(denominator_apr == 0, 0, (nir_apr - red_apr) / denominator_apr)
#Do the same for August
# Extract Red and NIR channels
red_aug = aug_normalized[:, :, 0] # First channel (Red)
nir_aug = aug_normalized[:, :, 3] # Fourth channel (Infrared)
# Compute NDVI with handling for division by zero
denominator_aug = nir_aug + red_aug
ndvi_aug = np.where(denominator_aug == 0, 0, (nir_aug - red_aug) / denominator_aug)
Output
You should see a red note about "RuntimeWarning: Invalid value encountered in true_device". This is perfectly ok! It's just letting you know it wasn't able to do some math on parts of the drone images.
Cell 7:
#Check to see that the NDVI's are between -1 and 1
#Find the min and max in the NDVI.
print(f"April NDVI Min: {ndvi_apr.min()}")
print(f"April NDVI Max: {ndvi_apr.max()}")
#Check for consistency:
print(f"Aug NDVI Min: {ndvi_aug.min()}")
print(f"Aug NDVI Max: {ndvi_aug.max()}")
Output
Cell 8:
#Print NDVI for April and August with legend
# Define NDVI colormap range
vmin, vmax = -1, 1 # NDVI ranges from -1 to 1
# Create subplots with 1 row, 2 columns
fig, axes = plt.subplots(1, 2, figsize=(12, 6))
# First Image (April NDVI)
img1 = axes[0].imshow(ndvi_apr, cmap='viridis', vmin=vmin, vmax=vmax)
axes[0].set_title("April NDVI Image")
axes[0].axis("off") # Hide axis
# Second Image (Aug NDVI)
img2 = axes[1].imshow(ndvi_aug, cmap='viridis', vmin=vmin, vmax=vmax) # Display as RGB
axes[1].set_title("August NDVI Image")
axes[1].axis("off") # Hide axis
plt.colorbar(img1, ax=axes.ravel().tolist())
# Show the plot
plt.show()
Output
Once generated, you should see two images showing the NDVI for April and August.
NDWI
Cell 9:
#Perform NDWI for April
#Note that the image has 4 channels.
#The channels are Red, Green, Blue, and Infrared
# NDWI will be done on the second channel (Green) and the fourth channel (Infrared)
# Extract Green and NIR channels
green_apr = april_normalized[:, :, 1] # Second channel (Green)
nir_apr = april_normalized[:, :, 3] # Fourth channel (Infrared)
# Compute NDWI with handling for division by zero
denominator_apr = nir_apr + green_apr
ndwi_apr = np.where(denominator_apr == 0, 0, (green_apr - nir_apr) / denominator_apr)
#Do the same for August
# Extract Green and NIR channels
green_aug = aug_normalized[:, :, 1] # Second channel (Green)
nir_aug = aug_normalized[:, :, 3] # Fourth channel (Infrared)
# Compute NDWI with handling for division by zero
denominator_aug = nir_aug + green_aug
ndwi_aug = np.where(denominator_aug == 0, 0, (green_aug - nir_aug) / denominator_aug)
Output
You should see a red note about "RuntimeWarning: Invalid value encountered in true_device". Just like with previous code for NDVI, it's just letting you know it wasn't able to do some math on parts of the drone images.
Cell 10:
#Check to see that the NDWI's are between -1 and 1
#Find the min and max in the NDVI.
print(f"April NDWI Min: {ndwi_apr.min()}")
print(f"April NDWI Max: {ndwi_apr.max()}")
#Check for consistency:
print(f"Aug NDWI Min: {ndwi_aug.min()}")
print(f"Aug NDWI Max: {ndwi_aug.max()}")
Output
Cell 11:
#Print NDWI for April and August with legend
# Define NDWI colormap range
vmin, vmax = -1, 1 # NDWI ranges from -1 to 1
# Create subplots with 1 row, 2 columns
fig, axes = plt.subplots(1, 2, figsize=(12, 6))
# First Image (April NDWI)
img1 = axes[0].imshow(ndwi_apr, cmap='viridis', vmin=vmin, vmax=vmax)
axes[0].set_title("April NDWI Image")
axes[0].axis("off") # Hide axis
# Second Image (Aug NDWI)
img2 = axes[1].imshow(ndwi_aug, cmap='viridis', vmin=vmin, vmax=vmax) # Display as RGB
axes[1].set_title("August NDWI Image")
axes[1].axis("off") # Hide axis
plt.colorbar(img1, ax=axes.ravel().tolist())
# Show the plot
plt.show()
Output
Once generated, you should see two images showing the NDWI for April and August.