I wrote a python code below in anaconda and have no issues successfully running in through the Spyder IDE.

import PySimpleGUI as sg
import os
import matplotlib.pyplot as plt
import rioxarray as rxr
import geopandas as gpd
import rasterio
from rasterio.plot import show
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from shapely.geometry import mapping

# Define a function to plot geospatial data
def plot_geospatial_data(geotiff_path, shapefile_path, canvas_elem):
    # Read GeoTIFF and Shapefile
    geotiff = rasterio.open(geotiff_path)
    shapefile = gpd.read_file(shapefile_path)

    # Create a figure and axis for plotting with a specific size (770 x 400)
    fig, ax = plt.subplots(figsize=(10.7, 5.5))

    # Plot the GeoTIFF
    show(geotiff, ax=ax, cmap='summer')
    ax.set_title('GeoTiff/Shapefile Plot')

    # Plot the Shapefile
    shapefile.plot(ax=ax, edgecolor='red', alpha=0.7, legend=True, label='Shapefile')

    # Show the plot on the canvas
    canvas = FigureCanvasTkAgg(fig, master=canvas_elem.Widget)
    canvas.draw()
    canvas.get_tk_widget().pack(fill='both', expand=1)
    return fig

def trim_function(existing_surface_path, fill_boundary_path, output_path_elem):

    # Open the GeoTIFF using rioxarray
    existing_surface = rxr.open_rasterio(existing_surface_path, masked=True).squeeze()

    # Open Shapefile
    aoi = os.path.join(fill_boundary_path)

    # Open crop extent (your study area extent boundary)
    crop_extent = gpd.read_file(aoi)

    # Crop the Existing Surface using rioxarray
    fill_surface = existing_surface.rio.clip(crop_extent.geometry.apply(mapping), crop_extent.crs)

    # Ask the user to select an output file path
    output_path = sg.popup_get_file("Select Output Path", save_as=True, file_types=(("GeoTIFF Files", "*.tif"),))

    # If the user selected an output path, ensure it has a .tif extension
    if output_path:
        if not output_path.endswith(".tif"):
            output_path += ".tif"

        # Export the trimmed surface as a GeoTIFF
        fill_surface.rio.to_raster(output_path, driver="GTiff")

# Define the layout of the GUI window
layout = [

    [sg.Frame("Data Selection", layout=[
        [
            sg.Column([
                [sg.Text("Select a GeoTIFF file: ", font=("Helvetica", 14))],
                [sg.Text("Select a Shapefile file:", font=("Helvetica", 14))],
            ]),
            sg.Column([
                [sg.InputText(key="geotiff_path", size=(60, 1)), sg.FileBrowse(file_types=(("GeoTIFF Files", "*.tif"),))],
                [sg.InputText(key="shapefile_path", size=(60, 1)), sg.FileBrowse(file_types=(("Shapefile Files", "*.shp"),))],
            ])
        ]
    ], expand_x=True)],

    [sg.Canvas(key="canvas", background_color="white", size=(770, 400))],

    [sg.Button("Plot Me", size=(10, 1), font=("Helvetica", 14)),
     sg.Text("", size=(95, 1)),  # Spacer
     sg.Button("Export Me", size=(10, 1), font=("Helvetica", 14))
    ]
]

# Create the GUI window
window = sg.Window("CropMe", layout, finalize=True, size=(800, 600))
canvas_elem = window["canvas"]  # Initialize canvas_elem
current_plot = None

while True:
    event, values = window.read()

    if event == sg.WIN_CLOSED:
        break
    if event == "Plot Me":
        geotiff_path = values["geotiff_path"]
        shapefile_path = values["shapefile_path"]
        if geotiff_path and shapefile_path:
            if current_plot is not None:
                plt.close(current_plot)
            current_plot = plot_geospatial_data(geotiff_path, shapefile_path, canvas_elem)
    if event == "Export Me":
        geotiff_path = values["geotiff_path"]
        shapefile_path = values["shapefile_path"]
        if geotiff_path and shapefile_path:
            trim_function(geotiff_path, shapefile_path, window)
    
    window.read(timeout=0)  # Force a GUI refresh

window.close()

When I attempt to package the code using pyinstaller on macOS I do the following steps:

1.) Open the terminal and run the environment: conda activate Crop_Environment

2.) Navigate to the location of my python script using the cd ~/to/python/script

3.) Run the code to compile the python script using pyinstaller pyinstaller --onefile Crop_Script.py

Opening the file it creates in the Terminal yields the following Error: ModuleNotFoundError: No module named 'rasterio.sample' Why do I receive this error and how can I fix it?

1

There are 1 answers

1
Schmohlo On

This is due to how the rasterio package is laid out. To fix it, either explicitly add import rasterio.sample to your script (and iteratively every other rasterio module it will complain about afterwards), or add the rasterio modules as hidden imports to the pyinstaller build .spec. See also this thread.