Installing Python and Jupyter Notebook
You can download and install Python from https://www.python.org/downloads/
Check Add python.exe to PATH, then Install Now.
To confirm installation, from a command prompt enter:
Code Block |
---|
py --version
python --version |
Both commands should show the version that you downloaded.
Jupyter Notebook is a popular tool for running Python scripts, offering the added benefit of displaying plots directly within the interface. You can install it by running:
Code Block |
---|
pip install notebook |
You can then run:
Code Block |
---|
jupyter lab /path/to/folder |
Basic conversions
...
R
...
Python
...
Arithmetic operators
...
Code Block |
---|
x + y
x - y
x * y
x / y
x ^ y |
...
Code Block |
---|
x + y
x - y
x * y
x / y
x ** y |
...
The only difference is that R uses ^
for exponentiation, while Python uses **
.
...
Comparison operators
...
Code Block |
---|
# R and Python
x == y
x != y
x > y
x < y
x >= y
x <= y |
...
No differences here.
...
Logical operators
...
Code Block |
---|
x && y
x || y
!x
v1 & v2
v1 | v2 |
...
Code Block |
---|
import numpy as np
x and y
x or y
not x
np.logical_and(v1, v2)
np.logical_or(v1, v2) |
...
Python doesn’t have built-in logical operations for vectors.
numpy is a popular library for this purpose, but it’s not as clean as R’s syntax.
...
Variable assignment
...
name <- "John Doe"
...
name = "John Doe"
...
R does accept the =
syntax for assignment. However, it’s non-idiomatic and can lead to unexpected errors.
For example,
Code Block | ||
---|---|---|
| ||
my_function <- function(y = 3, x = 5) {
print(paste(y, x))
}
my_function(x = 10) # Passes 10 to the x parameter, and outputs "3 10"
my_function(x <- 20) # Assigns 20 to the global x variable, which it passes to the y parameter. Outputs "20 5" |
To avoid confusion, always use <-
for assignment, and use =
for passing arguments within function calls.
...
Ranges
...
Code Block | ||
---|---|---|
| ||
1:10
seq(1, 20, 2)
print(1:10) |
...
Code Block | ||
---|---|---|
| ||
range(1, 11)
range(1, 21, 2)
print(list(range(1, 11))) |
...
Ouch. Python’s code is not only longer, but it excludes the final number.range(1, 11)
creates a range object in Python, which represents the numbers 1 through 10.
list(range(1, 11))
creates a list object in Python, which represents [1, 2, 3, … 10]
Both function similarly to the 1:10
vector in R. However, you need to change a range to a list in order to output it.
...
Conditional Statements
...
Code Block |
---|
if (x > 5) {
print("x is greater than 5")
} else if (x >= 2) {
print("x is between 2 and 5")
} else {
print("x is less than 2")
} |
...
Code Block |
---|
if x > 5:
print("x is greater than 5")
elif x >= 2:
print("x is between 2 and 5")
else:
print("x is less than 2") |
...
R requires the condition to be in parentheses. That would also work in Python, but it’s not required.
R begins a block statement with an opening curly brace ({
), and it ends it with a closing curly brace (}
).
Python is the oddball here, using a colon (:
) to begin a block statement. It then uses indentation for the block’s statements. To end a block, you stop indenting.
This can take some getting used to, because very few computer languages have similar syntax.
Note that the recommended indentation for Python is 4 spaces, but consistency is all that matters.
...
For Loops
...
Code Block |
---|
for (i in 1:5) {
print(i)
} |
...
Code Block |
---|
for i in range(1, 6):
print(i) |
...
Note the similarity to the if
statement comparisons above – particularly the absence of parentheses in the iteration expression, and the block syntax.
...
Functions
...
Code Block |
---|
my_function <- function(x, y) {
return(x + y)
} |
...
Code Block |
---|
def my_function(x, y):
return x + y
|
...
Indexing
...
Code Block |
---|
my_list[0] |
...
Code Block |
---|
my_list[1] |
...
R uses 1-based indexing.
Python uses 0-based indexing.
R is actually the oddball here.
Example conversions
The following examples demonstrate how to convert the R code at https://github.com/jjennewein/MDA_2023-24 into equivalent Python code.
...
0.field buffer.R
...
0.field buffer.py
...
Code Block | ||
---|---|---|
| ||
library(sf) |
...
Code Block |
---|
import geopandas as gpd |
...
Loads a library for handling geospatial data, including working with shapefiles.
In the Python code, gpd is an alias for the geopandas library, which we use to reduce typing and improve code readability.
...
Code Block | ||
---|---|---|
| ||
setwd(dirname(rstudioapi::getActiveDocumentContext()$path)) |
...
RStudio defaults to a global working directory, which means file paths must be specified explicitly.
Python defaults to the folder where the source code is located.
Jupyter Notebook defaults to where you launch the notebook server.
You could launch it from the command line within the source folder:
Code Block cd \psa\MDA_2023-24\python jupyter notebook
Or you could specify the folder directly when launching Jupyter:
Code Block jupyter notebook \psa\MDA_2023-24\python
The original file path was "E:/Eastern_Shore/MD_enrollment_data_2023_24/fields/"
, but I don't have access to that location.
To avoid referencing "E:/Eastern_Shore..."
explicitly, I saved all the necessary project files to the same folder as the source code, and I added a setwd()
statement to the R source. I then removed all references to "E:/Eastern_Shore..."
This way, the R program can run without requiring the full path in filenames.
...
Code Block | ||
---|---|---|
| ||
mda = st_read("MDAEnrollment2023-2024.shp") %>%
st_transform(., crs = 32618) %>%
st_buffer(., dist = -30) %>%
dplyr::filter(!st_is_empty(.)) |
...
Code Block | ||
---|---|---|
| ||
mda = gpd.read_file("MDAEnrollment2023-2024.shp") \
.to_crs(epsg=32618)
mda["geometry"] = mda.geometry.buffer(-30)
mda = mda[~mda.geometry.is_empty] |
...
This code:
Reads a shapefile into a spatial data frame (R) or a GeoDataFrame (Python).
Converts the coordinate reference system (CRS) to EPSG 32618 (WGS 84).
Applies a negative buffer of 30 meters to shrink the geometries.
Note thatsf
objects in R have a designated geometry column, but in GeoPandas you need to explicitly reference the geometry column.Filters out any empty geometries resulting from the buffering.
In Python,~
is a bitwise NOT operator.
R uses %>%
for chaining operations, while Python uses .
(dot notation).
In Python, a backslash (\
) means line continuation. I used it here to align the code with the R version. But I could have also written it as:mda = gpd.read_file("MDAEnrollment2023-2024.shp").to_crs(epsg=32618)
Also, note that the dots in st_transform(., crs = 32618)
and st_buffer(., dist = -30)
are optional but may improve readability.
...
Code Block |
---|
st_write(mda, "MDAEnrollment2023-2024_Buff30m.shp", append=FALSE) |
...
Code Block |
---|
mda.to_file("MDAEnrollment2023-2024_Buff30m.shp") |
...
Writes the buffered data frame to a new shapefile.
I added append=FALSE
to the original source so the file would be overwritten if it exists. GeoPandas automatically overwrites existing files.
...
1.Extract_HLS_L30 .R
...
1.Extract_HLS_L30 .py
...
Code Block | ||
---|---|---|
| ||
library(dplyr)
library(terra)
library(sf)
library(exactextractr) |
...
Code Block |
---|
import pandas as pd
import rasterio
import geopandas as gpd
from rasterstats import zonal_stats |
...
Syntax is easy. Knowing which libraries to use – not so much!
...
Code Block | ||
---|---|---|
| ||
setwd(dirname(rstudioapi::getActiveDocumentContext()$path)) |
...
Explained previously.
...
Code Block | ||
---|---|---|
| ||
fields = st_read("MDAEnrollment2023-2024_Buff30m.shp") |
...
Code Block | ||
---|---|---|
| ||
fields = gpd.read_file("MDAEnrollment2023-2024_Buff30m.shp") |
...
Reads the buffered shapefile.
...
Code Block |
---|
plot(fields[1]) |
...
Code Block |
---|
fields.plot(edgecolor='black') |
Plots the shapefile.
...
This section provides guidance for converting R programs to Python.
It assumes the user is already familiar with R syntax.