plMapcalc QGIS Plugin
plMapcalc is available as a QGIS Processing algorithm. After installation it appears in the Processing Toolbox under plMapcalc → plMapcalc and supports all options of the CLI, including multi-layer input, output data type and compression selection, MEM cells, begin/end expressions, and multi-pass (RESTART) workflows.
Download
↓ plmapcalc_qgis_plugin.zipThe archive contains the complete plmapcalc/ plugin folder with
the engine (plmapcalc.py), Processing algorithm, provider, metadata,
and icon. No compilation step required.
Installation
1 — Install dependencies
The plugin runs inside QGIS's own Python interpreter. The easiest way to install the required packages is directly from the QGIS Python Console (Plugins → Python Console or Ctrl+Alt+P):
!pip install rasterio numba # for GPU support (optional — needs NVIDIA GPU + driver): !pip install "numba-cuda"
The leading ! passes the command directly to the system shell,
so pip installs into the same Python that QGIS uses. numpy is
already bundled with every QGIS installation and does not need to be installed.
numba is optional but strongly recommended — without it
plMapcalc falls back to pure Python cell-by-cell processing which is
significantly slower. If numba installation fails (e.g. no
compatible compiler on Windows), the plugin still works without it.
Alternatively, if you prefer an external shell:
pip install rasterio numba # optional GPU support: pip install "numba-cuda"
python -m pip install rasterio numba # optional GPU support: python -m pip install "numba-cuda"
On Windows the external shell method requires the OSGeo4W Shell
that ships with QGIS — not the system Command Prompt or PowerShell. Using the
QGIS Python Console with !pip install is simpler and always targets
the correct interpreter automatically.
2 — Install the plugin from ZIP
The easiest way — no unzipping needed:
- Open QGIS and go to Plugins → Manage and Install Plugins…
- Click the Install from ZIP tab.
- Click … and select the downloaded
plmapcalc_qgis_plugin.zip. - Click Install Plugin. QGIS unpacks the ZIP and registers the plugin automatically.
- Switch to the Installed tab and confirm plMapcalc is ticked.
The ZIP must contain a single top-level folder named plmapcalc/
with metadata.txt inside — this is the standard QGIS plugin layout.
The provided plmapcalc_qgis_plugin.zip is already structured correctly.
Opening the algorithm dialog
In the Processing Toolbox expand plMapcalc and double-click plMapcalc. The dialog shows all parameters grouped into a Parameters tab and a Log tab for runtime messages.
Parameters
Standard parameters
| Parameter | CLI equivalent | Description |
|---|---|---|
| Input layers | -i | One or more raster layers from the QGIS layer panel. The order determines IN[0], IN[1], … All layers must share CRS, extent, and resolution (unless Ignore georef checks is enabled). |
| Cell expression | -e | Python expression evaluated per pixel. Multi-line expressions are supported. Leave empty if using a program file. |
| Number of output layers | — | How many OUT[i] layers to produce. Controls the number of lines shown in Output files. When Output files is empty, files are named <prefix>.tif or <prefix>_1.tif, <prefix>_2.tif, … |
| Output data type | :dtype | float64 float32 int32 uint32 int16 uint16 uint8 |
| Output nodata value | :nodata | Nodata value written to the output GeoTIFF header and used for pixels with nodata input. |
| Output compression | :compress | NONE DEFLATE DEFLATE2 DEFLATE3 LZW LZW2 LZW3 |
| Output files | — |
One output file per line. Each line can be: • a bare filename: ndvi → saved in Output folder• a relative path: results/ndvi• an absolute path: /data/ndvi.tifThe .tif extension is added automatically. Leading line numbers
(1. or 1:) are stripped automatically.Spaces and Polish characters in names are fully supported. Leave empty to use Output folder + prefix + index. |
| Output folder | — | Directory for output GeoTIFFs. Used only when Output files is empty. |
| Output filename prefix | — | Prefix for auto-generated filenames. Used only when Output files is empty. Default: plmc_out. |
| Threads | -t | Number of CPU compute threads. Default: 1. Ignored when GPU mode is active. |
Advanced parameters
Click Advanced at the bottom of the dialog to reveal:
| Parameter | CLI equivalent | Description |
|---|---|---|
| Cell program file | -p | Path to a .mc file. Used instead of the cell expression field. |
| Begin expression | --execute-begin | Code executed once before scanning starts. Runs as regular Python (not JIT-compiled). Use G.var = value here to initialise shared variables visible in Cell and End phases. |
| End expression | --execute-end | Code executed once after scanning finishes. Call RESTART() to trigger another pass. Read shared variables with G.var. |
| MEM cells | -m | Number of persistent MEM[] cells. Default: 0. |
| Load MEM from file | -r | Initialise MEM[] from a text file before processing. |
| Save MEM to file | -s | Write MEM[] values to a text file after processing. |
| Include zero MEM cells | -0 | Include MEM[i] == 0 entries when saving the memory file. |
| Use GPU (numba.cuda) | --gpu | Run the pixel kernel on a CUDA-capable GPU. Falls back to CPU automatically if CUDA is unavailable. Expressions that write to MEM[] fall back to serial CPU. Read-only access to MEM[] works on GPU. |
| Disable JIT / CUDA — run as plain Python | --no-jit | Disables numba JIT compilation and CUDA. The cell expression runs as plain Python with full numpy support — dynamic slices (IN[i:i+3]), dict, print(), and all numpy functions work without restriction. Slower than JIT, but useful for complex expressions (e.g. BioClim, Köppen-Geiger) or debugging JIT errors. |
| Target CRS | --crs | Reproject all layers to this CRS on-the-fly via WarpedVRT (e.g. EPSG:4326). Leave empty to require all inputs to share the same CRS (default behaviour). Warning: reprojection is ~3–4× slower — pre-reproject with QGIS Warp (Reproject layer) for large datasets. |
| Target resolution | --resolution | Output pixel size: empty = first layer (default), highest, lowest, or a numeric value in CRS units. Activates WarpedVRT alignment. |
| Output extent | --extent | Spatial extent of output: empty = first layer (default), intersection (only pixels covered by all layers), or union (full extent, missing areas = nodata). |
| Resampling method | --resample | WarpedVRT resampling: nearest (default, for discrete data), bilinear, cubic, average, mode, lanczos. |
| Overwrite existing outputs | -f | Force overwrite of output files. Enabled by default. |
| Treat NaN as value | --use-nan | Do not treat NaN as nodata. |
| Ignore georef checks | --ignore-georef | Skip CRS and extent validation between input layers. |
Log tab
While the algorithm runs, the Log tab shows layer info, JIT mode, dependency versions, and timing. Errors and warnings appear there too.
Processing progress is shown in the QGIS progress bar at the bottom of the algorithm dialog — the printed percentage line used in CLI mode is suppressed and replaced by the native QGIS progress indicator.
Expression examples
NDVI from two input layers
x = IN[0] + IN[1] OUT[0] = -9999 if x == 0 else (IN[0] - IN[1]) / x
Binary mask from threshold
OUT[0] = 1 if IN[0] > 500 else 0
Count pixels per class (multi-pass)
Set MEM cells to the number of possible class values (e.g. 256), Number of output layers to 1.
if ITERATION() == 1: MEM[int(IN[0])] += 1 else: OUT[0] = MEM[int(IN[0])]
if ITERATION() == 1: RESTART()
After the algorithm finishes, output layers are automatically added to the QGIS project and appear in the Layers panel. You can then style them, export them, or use them as inputs to another plMapcalc run.
Batch processing
Click Run as Batch Process… in the algorithm dialog to open the QGIS batch processing interface. Each row corresponds to one run. You can set different input layers, expressions, and output paths per row, and run all of them sequentially with a single click.
Shared variables — G proxy
Variables set in the Cell expression are local to each pixel call and
not visible in Begin or End expressions. The built-in G object provides
attribute-style access to a shared dictionary visible across all three phases:
G.total = 0.0 G.count = 0
G.total += IN[0] G.count += 1
MEM[0] = G.total / G.count if G.count > 0 else 0.0
MEM[] auto-sizing: if MEM cells is 0 but the expression
contains literal indices like MEM[4008], plmapcalc automatically
allocates max_index + 1 cells and logs
[INFO] MEM[] auto-sized to N cells.
Set MEM cells explicitly for dynamic indices like
MEM[COLS * ROW + COL].
Troubleshooting
| Symptom | Likely cause & fix |
|---|---|
| Algorithm not visible in Toolbox | Plugin not enabled. Go to Plugins → Manage and Install Plugins and enable plMapcalc. |
ModuleNotFoundError: rasterio | rasterio not installed in QGIS Python. Run pip install rasterio in the OSGeo4W shell (Windows) or QGIS Python environment. |
| Output not added to project | The output file path may be read-only or the folder does not exist. Choose a writable output folder. |
| JIT compilation takes a long time on first run | Normal — numba compiles the kernel on first use. Subsequent runs reuse the compiled code. |
| Red error output in Log tab | Check the full error message. Common causes: syntax error in expression, mismatched layer extents (enable Ignore georef checks), or missing MEM cells (-m too small). |
| Use GPU checked but runs on CPU | CUDA is not available on this machine (no NVIDIA GPU, or missing driver). The plugin falls back automatically. Check the Processing Log for a warning with the exact reason. |
Use GPU + expression writes to MEM[] | GPU mode does not support MEM[] writes (parallel threads would cause race conditions). The plugin automatically switches to serial CPU mode and logs a warning. |
| Processing slow with Target CRS set | CRS reprojection via WarpedVRT adds ~3–4× I/O overhead. Pre-reproject inputs with Warp (Reproject layer) in QGIS Processing, then clear the Target CRS field. |
JIT compilation fails (TypingError, dynamic slices) | Enable Disable JIT / CUDA — run as plain Python (--no-jit) in the Advanced parameters. The expression will run as regular Python with full numpy support, at the cost of slower processing. |
[ERROR] --program file not found | The path in Cell program file does not exist. Check the path — on Windows use forward slashes or double backslashes. |
IndexError: index N is out of bounds in execute-end | The expression uses MEM[N] but MEM cells is 0 or too small. Set MEM cells to at least N+1 in Advanced parameters, or let plmapcalc auto-size it (works for literal indices only). |
numba not installed warning at startup | Install numba via the QGIS Python Console: import subprocess, sys; subprocess.check_call([sys.executable, "-m", "pip", "install", "numba"]) — then restart QGIS. |
rasterio not found | Install via QGIS Python Console: import subprocess, sys; subprocess.check_call([sys.executable, "-m", "pip", "install", "rasterio"]) — then restart QGIS. |
Dependency check at startup
When QGIS loads the plugin, it automatically probes all runtime dependencies and reports the result in three places:
- Install dialog — appears automatically at startup when any package is missing. Shows the missing package names, explains the impact, and provides a Copy to clipboard button with the exact install command. Click Show Details… to see the full command if needed.
- Message bar (top of the QGIS window) — a persistent red banner
for critical packages (
numpy,rasterio), or yellow for optional packages (numba,numba-cuda). - QGIS Python Console — a full report listing each package version (or MISSING) with ready-to-paste install commands. Open via Plugins → Python Console.
Packages checked: numpy, rasterio, numba ≥ 0.61,
numba-cuda, nvidia-cuda-runtime-cu12,
nvidia-cuda-nvcc-cu12, nvidia-cuda-nvrtc-cu12,
nvidia-nvjitlink-cu12.
Install commands for QGIS Python Console
# Required
import subprocess, sys
subprocess.check_call([sys.executable, "-m", "pip", "install", "rasterio"])
# Optional — JIT acceleration (CPU)
subprocess.check_call([sys.executable, "-m", "pip", "install", "numba"])
# Optional — GPU acceleration (dedicated venv recommended, see Installation page)
subprocess.check_call([sys.executable, "-m", "pip", "install", "numba-cuda"])
subprocess.check_call([sys.executable, "-m", "pip", "install",
"nvidia-cuda-runtime-cu12", "nvidia-cuda-nvcc-cu12",
"nvidia-cuda-nvrtc-cu12", "nvidia-nvjitlink-cu12"])
Using sys.executable ensures pip installs into the exact Python
interpreter that QGIS uses — avoiding version mismatches when using the system
pip. The install dialog's Copy to clipboard button copies
the correct command automatically.