DocsBCILattice Custom Blocks
BCILattice Documentation

BCILattice Custom Blocks

All custom and built-in special blocks available in the ML Suite (MLFlow) and Workflow Designer canvases, injected at runtime by the training server.

v1.0BCINexus Platform · 2026-05-20[email protected]

Overview

In addition to the 5,400+ catalog blocks loaded from the CSV, BCILattice injects a set of custom built-in blocks at server startup. These cover analysis utilities, pipeline I/O, code execution, file selection, and Workflow graph controls.

Custom blocks are not classes; they run as functions or server-side routines and appear in the block palette alongside catalog blocks. They are marked is_custom: true internally.

BlockCategoryCanvas
Channel SelectionAnalysis (BCILattice)MLFlow + Workflow
Signal ProjectionAnalysis (BCILattice)MLFlow + Workflow
Time-Frequency FeaturesAnalysis (BCILattice)MLFlow + Workflow
Custom LabelsInputs (BCILattice)MLFlow + Workflow
Input BlockInputs (BCILattice)MLFlow + Workflow
Output BlockOutputs (BCILattice)MLFlow + Workflow
Loop BlockFlow Control (BCILattice)MLFlow + Workflow
Custom CodePipeline BlocksMLFlow + Workflow
Data GraphGraphs (BCILattice)MLFlow + Workflow
Confusion Matrix GraphGraphs (BCILattice)MLFlow + Workflow
Graph OutputGraphs (BCILattice)MLFlow + Workflow
Graph EndpointPipeline BlocksWorkflow only
Select FilesInputs (BCILattice)Workflow only
Compiled PipelineModel/Pipelines (Compiled)Workflow (runtime)

Analysis Blocks

These blocks call the local training server's analysis routes (/xlb9/…) and are available in both the ML Suite and Workflow Designer canvases.

Channel Selection

AnalysisML SuiteWorkflow DesignerFunction (custom)

Ranks and filters EEG/fNIRS/EMG channels by statistical relevance. Calls /xlb9/channel_selection/run. The Workflow canvas exposes an extra data_type selector; the ML Suite version omits it.

Inputs

Data:AnyLabels:Any

Outputs

Selected Data:AnySelected Channels:AnyScores:Any

Settings

SettingTypeDefaultDescription
method_nameselectt-Value MethodChannel ranking algorithm
rest_labelint0Integer label for the rest/baseline class
percentileint5Top-N percentile of channels to keep
ignore_classesstrComma-separated class labels to exclude
data_typeselectfNIRSWorkflow only

Custom Labels

AnalysisML SuiteWorkflow DesignerFunction (custom)

Injects or overrides the label column used by downstream blocks. Accepts a path to a label CSV or a comma-separated string of manual labels.

Inputs

Data:Any

Outputs

Labels:Any

Settings

SettingTypeDefaultDescription
label_filestrPath to a CSV file whose first column is used as labels
manual_labelsstrComma-separated label values (overrides label_file if set)

Signal Projection

AnalysisML SuiteWorkflow DesignerFunction (custom)

Converts 2-D time-series signals into 2-D images using time-frequency or recurrence transforms. Calls /xlb9/signal_projection/run. Useful for feeding EEG into CNN-based image classifiers.

Inputs

Data:Any

Outputs

Projected Images:AnyShape:Any

Settings

SettingTypeDefaultDescription
method_nameselectGramian Angular Field (GAF)Projection algorithm
image_sizeint64Output image resolution in pixels (square)

Time-Frequency Features

Analysis (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Turns the Analysis suite's time-frequency output into a trainable feature table. It reduces a per-trial ERSP cube — (epochs, channels, freqs, times) — down to X[n_trials, n_features] with labels that stay index-aligned, so a time-frequency analysis can actually train a decoder instead of only rendering a figure.

On fNIRS data, time-frequency peaks read roughly 30% low. That is a resolution limit of the transform in the very low fNIRS band, not a defect in this block — treat the peak frequency as approximate when interpreting fNIRS results.

Inputs

Trials:AnyLabels:AnyFreqs:AnyTimes:Any

Outputs

Features:AnyLabels:AnyFeature Names:AnyX:AnyY:AnyInfo:Any

Settings

SettingTypeDefaultDescription
aggregationselectband_meansHow the freq × time cube collapses to features. band_means = one value per band per channel; flatten keeps everything (very wide)
tminfloat0Start of the analysis window in seconds. 0 with tmax 0 means the whole epoch
tmaxfloat0End of the analysis window in seconds
n_time_windowsint4Windows per band when aggregation is band_time_windows
bandsstrCustom bands as "name:low-high" pairs. Empty uses the standard delta/theta/alpha/beta/gamma set
standardizeboolfalsez-score each feature across trials before returning

Pipeline Blocks

Structural blocks that control data flow and code execution within a pipeline. Available in both canvases unless noted otherwise.

Input Block

Pipeline BlocksML SuiteWorkflow DesignerFunction (custom)

Marks one entry point of the pipeline. Drag one onto the canvas for each data stream the pipeline accepts. It carries exactly one port, because each Input Block becomes exactly one input port on the compiled-pipeline block when this pipeline is dropped into a Workflow.

The canvas port is labelled with port_name, so what you see here is exactly what you will wire to on the compiled block. Give each Input Block a distinct name — two blocks sharing one name compile to two identically named ports.

Outputs

port_name:Any

Settings

SettingTypeDefaultDescription
port_namestrIn_1Names both the port drawn on the canvas and the port exposed on the compiled block
subject_scopeselectper_subjectper_subject runs one job per subject; all pools every selected subject into one run, which is what makes cross-subject (LOSO) cross-validation possible

File Path

Inputs (BCILattice)MLFlow DesignerWorkflow DesignerFunction (custom)

Points at file(s) on disk and emits their paths. It reads nothing — that is the point: a block that does its own file reading needs the path, and Select Files cannot give it one usefully, because Select Files exists to load a processing stage into a table.

Both output shapes are filled for a single pick, so one file can feed either a scalar-path input or a list-shaped one with no adapter in between. Its first consumer is Cedalion SNIRF Reader, where a wired path always beats the reader's own file_path property.

Outputs

File Paths:AnyFile Path:AnyCount:AnyOutput:Any

Settings

SettingTypeDefaultDescription
file_pathfileOne file, and the common case
file_pathsstrSeveral, separated by ";" or newlines
must_existbooltrueRefuse a path that is not on disk, naming it. Turn off for a file an earlier step produces

Output Block

Pipeline BlocksML SuiteWorkflow DesignerFunction (custom)

Marks one exit point of the pipeline. Whatever is connected here becomes one output port on the compiled-pipeline block. Every pipeline needs exactly one final output node — an Output Block, Graph Output or Graph Endpoint — or compiling fails.

It forwards the first non-null value arriving on a connected edge. Ambient values deliberately lose: an embedded pipeline runs with the caller's inputs pre-seeded, so a naive “first non-null” would forward the pipeline's own input and return the data unchanged while appearing to have run.

Inputs

port_name:Any

Settings

SettingTypeDefaultDescription
port_namestrOut_1Names both the port drawn on the canvas and the port exposed on the compiled block

Loop Block

Pipeline BlocksML SuiteWorkflow DesignerFunction (custom)

Repeats a sub-section of the pipeline for N iterations or epoch-by-epoch. Set start_node and end_node to the labels of the blocks that mark the loop boundary.

Inputs

Loop Input:Any

Outputs

Loop Output:Any

Settings

SettingTypeDefaultDescription
iterationsint1Number of times to repeat the loop body
start_nodestrLabel of the first block inside the loop
end_nodestrLabel of the last block inside the loop
modeselectEpochSequential runs the whole loop N times; Epoch iterates once per data epoch

Custom Code

Pipeline BlocksML SuiteWorkflow DesignerFunction (custom)

Executes an arbitrary Python function inline inside the pipeline. The function receives the upstream data tensor as its first argument and must return the transformed result.

def custom_process(data):
    # data is the input tensor from the previous block
    # transform it here
    return data

Inputs

Data:Any

Outputs

Result:Any

Settings

SettingTypeDefaultDescription
codecodedef custom_process(data): return dataPython function body: must accept data and return output

Model Structure Blocks

The only two blocks that take models in and hand a model out. Everything else on the canvas moves data; these build the shape of one network.

Chaining layer blocks already composes them in order — these are for the case a chain cannot express: several branches over the same input, joined back together. Each wired Branch N receives the identical input inside the composed module's forward.

Do not confuse these with Feature Concatenator, Parallel Fan-out or Ensemble Voter in Data Routing and Flow Control. Those combine arrays — data between models, or predictions from several models. These combine models, inside one network. Wiring data into a Branch N port is refused with a message saying which block you wanted.

Model Concat

Model Structure (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Runs every wired branch on the same input and concatenates the results into one tensor. This is how a multi-scale CNN or a two-stream model is drawn: three Conv1d branches with different kernel sizes, joined here, then a shared head.

A single wired branch collapses to that branch, so the block is safe to leave in place while you build the other paths.

Inputs

Branch 1:AnyBranch 2:AnyBranch 3:Any

Outputs

model_obj:Any

Settings

SettingTypeDefaultDescription
n_inputsint3Number of Branch ports (1–12)
dimint1Axis to join on. 1 is the feature axis of a (batch, features, …) tensor — joining the last axis of a conv output concatenates along time instead, which is rarely what you want

Model Add

Model Structure (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Runs every wired branch on the same input and sums the results. Put a transformed path on one branch and an Identity layer on the other, and you have a residual/skip connection.

Every branch must produce the same shape — addition has no broadcasting rule that would be safe to guess here.

Inputs

Branch 1:AnyBranch 2:Any

Outputs

model_obj:Any

Settings

SettingTypeDefaultDescription
n_inputsint2Number of Branch ports (1–12)

Trainer Trigger

Model Structure (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Hands one side of the trainer's train/test split to a block that fits on its own. Use it when a model block shows X and y ports — that block is a constructor and a fit call in one, and it must not see the rows the trainer will score against.

The source is chosen by name, not by a wire, so one Select Files can feed a dozen triggers without a dozen edges crossing the canvas.

It uses the trainer’s split, not its own. The split settings are read from the BCILattice Trainer in the same graph, and the partition is derived with the identical call the trainer makes — same strategy, same test_size, same seed, so the same rows. Every trigger in a run shares one partition, which is what keeps X and y index-aligned.

Outputs

Data:Any

Settings

SettingTypeDefaultDescription
source_blockselectWhich block the data comes from — the list is read from the canvas, so it is always what actually exists
source_portselectWhich of its outputs — for example Select Files → X, or → Y
splitselecttrainWhich side of the trainer’s split to hand over. train by default: a block that fits must not see the test rows

Graph Blocks

Four ways to get a picture out of a run. The important distinction is tap vs. terminal: Data Graph passes its value straight through, so it can be spliced anywhere, any number of times. Graph Output and Graph Endpoint are terminal nodes, so they compete for the “exactly one final output” slot every compiled graph must have.

Data Graph

Graphs (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

A general-purpose plot tap: it renders whatever reaches it and passes the same value out unchanged on its Data port. Because it is not a terminal node, you can drop it onto an existing connection to inspect what is flowing through mid-pipeline without rewiring anything downstream.

A value that cannot be drawn never silently disappears — the reason lands on the Graph Error port. Wire it somewhere, or read it in the node inspector, when a plot does not appear.

Inputs

Data:Any

Outputs

Graph:AnyData:AnyGraph File:AnyGraph Error:Any

Settings

SettingTypeDefaultDescription
graph_namestrData GraphTitles the plot, so several taps stay distinguishable in the Training dashboard Graphs tab
plot_typeselectautoauto picks by shape: curves for training history, an annotated matrix for a confusion matrix, lines/heatmap for arrays
save_pathstrOptional path to write the image
image_formatselectpngpng · jpg

Confusion Matrix Graph

Graphs (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Draws a confusion matrix from true and predicted labels. Wire it to a trainer's True Labels and Predictions outputs, or to a Cross-Validation block's equivalents.

Inputs

y_true:Anyy_pred:Any

Outputs

Graph:Any

Settings

SettingTypeDefaultDescription
titlestrConfusion Matrix
normalizeselectnonetrue = row-normalised (recall per class), pred = column-normalised (precision), all = over the whole matrix
colormapstrBluesAny matplotlib colormap name
display_labelsstrComma-separated class names. Empty uses the raw label values

Graph Output

Graphs (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Terminal plot node: renders the incoming value and saves it to disk. Counts as a pipeline's single final output, so it can end a graph in place of an Output Block.

Inputs

Graph Data:Any

Outputs

Graph File:AnyGraph:AnyGraph Error:Any

Settings

SettingTypeDefaultDescription
graph_namestrWorkflow GraphDisplay title embedded in the image
save_pathstrFile path to write the output image
image_formatselectpngpng · jpg · pdf

Graph Endpoint

Pipeline BlocksWorkflow DesignerFunction (custom)

The other terminal plot node. Behaves like Graph Output but writes to its own output_path, and is the node the workflow HTTP route targets when a graph is executed over REST.

Inputs

Graph Data:Any

Outputs

Graph File:AnyGraph:AnyGraph Error:Any

Settings

SettingTypeDefaultDescription
graph_namestrWorkflow Graph
output_pathstrFile path to write the rendered image

Workflow-Only Blocks

Loading real recordings is a Workflow-canvas concern, so this block exists only there. An ML Suite pipeline takes its data through an Input Block instead, and is fed by whatever the Workflow wires into it.

Select Files

Inputs (BCILattice)Workflow DesignerFunction (custom)

Loads real recordings from the Data Manager: pick a modality, a processing stage, a session and the subjects, and it emits the feature table X and labels Y. This is where a workflow actually gets its data.

The extra output ports change with data_source: a recording publishes Channels, a reducer's output publishes Components, a feature table publishes Feature Names, epochs publish Epoch Index. X and Y are always present, and so is File Paths — the recordings you picked, for a block that does its own reading (see File Path).

Outputs

X:AnyY:AnyFiles:AnyFile Paths:Any+ source-specific:Any

Settings

SettingTypeDefaultDescription
modalityselectfNIRSSignal modality filter
data_sourceselectClean DataWhich processing stage to load — clean, channel-selected, quality-checked, normalised, features, epochs, time-frequency, …
sessionselectAll SessionsSession filter
chromophoreselectAllfNIRS only: keep only hbo or only hbr. "All" feeds every optode in twice, once per chromophore
selected_filesstrSerialised list of file records chosen in the picker
selected_subjectsstrSubject IDs extracted from the selected files
selected_featureslist[]Optional column subset to keep

Compiled Pipeline Block

When you compile and register a pipeline from the ML Suite or Workflow Designer, BCILattice dynamically injects it as a reusable block into the Pipeline Blocks category. These blocks are created at runtime via POST /xlb9/register_compiled_pipeline or POST /xlb9/register_compiled_workflow.

Compiled Pipeline

Pipeline BlocksWorkflow DesignerDynamicFunction (custom)

A compiled and registered pipeline exposed as a single reusable block, collected in the Model/Pipelines (Compiled) palette group. It has one input port per Input Block and one output port per Output Block in the original pipeline, each named from that block's port_name.

Inputs

one per Input Block:Any

Outputs

one per Output Block:Any

Settings

SettingTypeDefaultDescription
descriptionstrCompiled pipeline: …Auto-filled with the pipeline name
block_roleselectProcessing PipelineDetermines training behaviour and loss function selection
optimizerstrAdamOptimiser name passed to the training loop
epochsint10Training epochs when block_role is ML Model or DL Model
learning_ratefloat0.001Learning rate for the optimiser
BCILattice Custom Blocks v1.0 · BCINexus Platform · 2026-05-20