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.zip

The 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):

QGIS Python Console qgis
!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:

Linux / macOS terminal shell
pip install rasterio numba
# optional GPU support:
pip install "numba-cuda"
Windows — OSGeo4W Shell shell
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:

  1. Open QGIS and go to Plugins → Manage and Install Plugins…
  2. Click the Install from ZIP tab.
  3. Click and select the downloaded plmapcalc_qgis_plugin.zip.
  4. Click Install Plugin. QGIS unpacks the ZIP and registers the plugin automatically.
  5. 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

ParameterCLI equivalentDescription
Input layers-iOne 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-ePython expression evaluated per pixel. Multi-line expressions are supported. Leave empty if using a program file.
Number of output layersHow 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:dtypefloat64 float32 int32 uint32 int16 uint16 uint8
Output nodata value:nodataNodata value written to the output GeoTIFF header and used for pixels with nodata input.
Output compression:compressNONE 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.tif
The .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 folderDirectory for output GeoTIFFs. Used only when Output files is empty.
Output filename prefixPrefix for auto-generated filenames. Used only when Output files is empty. Default: plmc_out.
Threads-tNumber of CPU compute threads. Default: 1. Ignored when GPU mode is active.

Advanced parameters

Click Advanced at the bottom of the dialog to reveal:

ParameterCLI equivalentDescription
Cell program file-pPath to a .mc file. Used instead of the cell expression field.
Begin expression--execute-beginCode 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-endCode executed once after scanning finishes. Call RESTART() to trigger another pass. Read shared variables with G.var.
MEM cells-mNumber of persistent MEM[] cells. Default: 0.
Load MEM from file-rInitialise MEM[] from a text file before processing.
Save MEM to file-sWrite MEM[] values to a text file after processing.
Include zero MEM cells-0Include MEM[i] == 0 entries when saving the memory file.
Use GPU (numba.cuda)--gpuRun 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-jitDisables 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--crsReproject 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--resolutionOutput pixel size: empty = first layer (default), highest, lowest, or a numeric value in CRS units. Activates WarpedVRT alignment.
Output extent--extentSpatial extent of output: empty = first layer (default), intersection (only pixels covered by all layers), or union (full extent, missing areas = nodata).
Resampling method--resampleWarpedVRT resampling: nearest (default, for discrete data), bilinear, cubic, average, mode, lanczos.
Overwrite existing outputs-fForce overwrite of output files. Enabled by default.
Treat NaN as value--use-nanDo not treat NaN as nodata.
Ignore georef checks--ignore-georefSkip 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

cell expression python
x = IN[0] + IN[1]
OUT[0] = -9999 if x == 0 else (IN[0] - IN[1]) / x

Binary mask from threshold

cell expression python
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.

cell expression python
if ITERATION() == 1:
    MEM[int(IN[0])] += 1
else:
    OUT[0] = MEM[int(IN[0])]
end expression python
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:

Begin expression
G.total = 0.0
G.count = 0
Cell expression
G.total += IN[0]
G.count += 1
End expression
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

SymptomLikely cause & fix
Algorithm not visible in ToolboxPlugin not enabled. Go to Plugins → Manage and Install Plugins and enable plMapcalc.
ModuleNotFoundError: rasteriorasterio not installed in QGIS Python. Run pip install rasterio in the OSGeo4W shell (Windows) or QGIS Python environment.
Output not added to projectThe 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 runNormal — numba compiles the kernel on first use. Subsequent runs reuse the compiled code.
Red error output in Log tabCheck 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 CPUCUDA 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 setCRS 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 foundThe 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-endThe 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 startupInstall numba via the QGIS Python Console: import subprocess, sys; subprocess.check_call([sys.executable, "-m", "pip", "install", "numba"]) — then restart QGIS.
rasterio not foundInstall 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

QGIS Python Console qgis
# 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.