Build With EMDS
Extend EMDS across both products β EMDS for ArcGIS Pro and EMDS for QGIS β through shared workflow formats, custom connectors, scripting, and published engine contracts. Write in Python, C#, and R.
One Workflow Definition, Both Products
EMDS workflows are plain JSON documents. The same workflow-definition file runs unmodified on EMDS for ArcGIS Pro and EMDS for QGIS β identical step types, identical operators, identical variable semantics. Author once, run on either product.
Verified parity
Both products execute the same six step types and resolve {{variable}} substitutions identically:
taskβ run an engine, connector, or Python scriptset_variableβ assign or compute a workflow variablefor_loopβ iterate over a list or each featureif_elseβ branch on a conditionlogβ write to the execution logtry_catchβ handle errors and keep going
Conditions use the same 13 operators on both products:
equals Β· not_equals Β· less_than Β· greater_than Β·
less_than_or_equals Β· greater_than_or_equals Β· is_empty Β·
is_not_empty Β· is_truthy Β· is_falsy Β· contains Β·
in_list Β· between
{
"name": "Run a model on every feature",
"steps": [
{
"step_type": "for_loop",
"config": {
"loop_type": "each",
"variable_name": "feature",
"index_variable_name": "feature_index",
"list_value": "{{study_area_features}}"
},
"children": [
{
"step_type": "try_catch",
"config": { "error_variable": "feature_error" },
"children": [
{
"step_type": "task",
"config": {
"input_source": "named_result",
"input_variable": "feature",
"store_result_as": "feature_result"
}
}
],
"else_children": [
{
"step_type": "log",
"config": {
"level": "warning",
"message": "Feature {{feature_index}} failed: {{feature_error}}"
}
}
]
}
]
}
]
}What is β and isn't β interoperable
EMDS is built for honest cross-product interoperability at the data and workflow layer:
- Shared & mutually inspectable: the metadata database schema and the workflow-definition JSON are common to both products. A study's metadata authored in one product can be read by the other.
- Not interchangeable: the project files are product-specific β
.qgzfor QGIS,.aprxfor ArcGIS Pro. You cannot open one product's project in the other, and studies do not execute cross-product.
In short: portable formats and a shared schema β not a shared project file. Move workflows and data between products; run each study on its own product.
Connect Any Data Source
A connector translates raw spatial or tabular data into inputs the analytical engines can consume. Write connectors in Python on both products, or in C# for the deepest integration on ArcGIS Pro.
from emds import Connector, DataLayer
class MyForestConnector(Connector):
name = "Forest Condition Layer"
def compute(self, context) -> DataLayer:
# Load your spatial data
gdf = context.load_vector("forest_stands.shp")
# Transform to EMDS scale [0, 1]
gdf["condition"] = normalize(
gdf["basal_area"], method="zscore"
)
return DataLayer.from_geodataframe(gdf, "condition")using EmdsFramework.Connectors;
using EmdsFramework.Layers;
public class ForestConnector : IEmdsConnector
{
public string Name => "Forest Condition";
public DataLayer Compute(EmdsContext ctx)
{
var fc = ctx.OpenFeatureClass("ForestStands");
var values = fc.Select("BasalArea")
.Normalize(NormMethod.ZScore);
return new DataLayer("condition", values);
}
}Drive the Engines From Python
EMDS for QGIS ships with the analytical engines as bundled .NET CLIs alongside a Python bridge. Call them headless for batch and server automation, or run your own Python inside a workflow Task.
Headless engine calling
The python-bridge exposes NetWeaverBridge and CDPBridge, which drive the bundled .NET CLI engines over Apache Arrow IPC β efficient, near-zero-copy data transfer that scales to large datasets. It is a clean fit for unattended batch jobs and server-side automation.
Custom Python script tasks
A workflow task step can run a developer's own Python script in its own interpreter. The contract is deliberately simple:
- Workflow variables arrive as JSON in the
EMDS_WORKFLOW_VARIABLES_JSONenvironment variable. - A JSON object written to stdout becomes the task result (and any
store_result_asvariable). - stderr streams line-by-line into the execution log, so users see live progress.
- A non-zero exit code signals failure (unless the step sets
continue_on_error).
The plugin and CLIs ship together as three platform distributions: Windows x64, macOS (Intel + Apple Silicon), and Linux x64.
import pandas as pd
from engine_bridge import NetWeaverBridge
# Bundled .NET CLI shipped with the plugin
nw = NetWeaverBridge("NetWeaverCLI.dll")
# Read inputs
data = pd.read_csv("sites.csv")
# Run the model β data moves over Arrow IPC
results = nw.process_data(
data=data,
model_path="ConditionAssessment.nw2",
use_arrow=True,
)
# Write outputs
results.to_csv("scored_sites.csv", index=False)The QGIS extension surface is workflows plus Python script tasks β there is no plugin-to-plugin API. That keeps the contract small, stable, and scriptable.
Extend a Layered .NET 10 Design
EMDS for ArcGIS Pro is built on published contracts. Partners extend it by implementing those interfaces β add an engine, build on the data model, or reuse the domain library β without forking the application.
Engine contracts
Every engine implements the generic IEngineService<TParams, TResult>. Five engine contracts ship today β ICdpEngine, INetWeaverEngine, ILpaEngine, IPortfolioEngine, and ISmileEngine. Implement an adapter against the service interface to add your own engine.
Repository layer
A repository layer sits over an EF Core / SQLite metadata database β IWorkspaceRepository, IStudyRepository, ITaskRepository, IWorkflowRepository, and more. Build on the EMDS data model directly; the libraries target net10.0 with no ArcGIS dependency.
Reusable domain library
Emds.Core is the reusable domain model that ties it together: Workspace β Study β Analysis β Task β Result.
public interface IEngineService<TParams, TResult>
{
Task<EngineRunHandle> StartAsync(
TParams parameters,
CancellationToken cancellationToken);
IAsyncEnumerable<EngineProgress> ObserveProgress(
EngineRunHandle handle,
CancellationToken cancellationToken);
Task<TResult> AwaitResultAsync(
EngineRunHandle handle,
CancellationToken cancellationToken);
}Write in the Language You Know
Python
Full connector SDK, the engine bridge, and workflow script tasks. Supported on both ArcGIS Pro and QGIS.
Both ProductsC#
Native connectors and engine adapters against the published .NET 10 contracts. Deepest integration.
ArcGIS ProR
Statistical computing connectors for research-grade ecological modeling and analysis.
Research ConnectorsJavaScript
Web connector framework for browser-based integrations and custom tools.
EMDS OnlineReady to build?
Download EMDS, explore the documentation, or get in touch with the team for developer support.