Writing a plot
When the built-in previews are not the figure you want, write a plot: a small script that draws a chart from a workflow output port. Plots are preview-only — they are a quick way to look at a result, not a step in the pipeline. They show in the plots tab and you can write them in Python (matplotlib / seaborn) or R (ggplot2).
The one rule: render(collection)
A plot script defines exactly one function — render(collection) in Python,
render <- function(collection) in R — and imports nothing from SciStudio.
The harness runs your script, hands it the data from the port you pointed it at
as collection, calls render, and shows whatever figure you return.
def render(collection):
import matplotlib.pyplot as plt
df = collection.items.open_one() # the port's data as a pandas DataFrame
fig, ax = plt.subplots()
ax.bar(df["compound"], df["intensity"])
ax.set_ylabel("intensity")
return fig # a matplotlib figure
Bind the plot to a block's output port and it draws every time you look. That is the whole contract.
What collection gives you
The collection is the batch of items on the port you chose. You read it with a
tiny, fixed surface — no SciStudio types involved:
| You write | You get |
|---|---|
collection.types |
the type name(s) on the port, e.g. ("DataFrame",) |
collection.items |
the items: len(), iterate, index [i] |
collection.items.open_one() |
the first item, opened to a native object |
collection.items.open() |
all items, opened, as a list (size-guarded) |
item.type |
the item's type name ("Array", "DataFrame", …) |
item.metadata |
the item's metadata (read-only) |
item.open() |
the item as a plain scientific object (see below) |
open() hands you ordinary objects, never a SciStudio wrapper:
item.type |
item.open() gives you |
|---|---|
Array |
a numpy ndarray |
DataFrame |
a pandas DataFrame |
Series |
a pandas Series (or DataFrame if it has two columns, e.g. a spectrum's lambda/intensity) |
Text |
a str |
Artifact |
a pathlib.Path |
CompositeData |
a dict of opened parts |
So a one-item table port is collection.items.open_one() → a pandas DataFrame,
and a batch of images is collection.items.open() → a list of numpy arrays.
What to return
render returns one of:
- a figure — a matplotlib figure (anything with
.savefig); the harness saves it for you; - a file path — a
strorpathlib.Pathto an image you wrote yourself (it must live in the plot's working directory); - a list of either, to produce several figures.
Returning None is an error — always return your figure.
A batch example
Overlay every spectrum in a batch on one axis:
def render(collection):
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
for item in collection.items:
s = item.open() # a pandas Series/DataFrame per spectrum
ax.plot(s.index, s.values)
ax.set_xlabel("wavelength")
ax.set_ylabel("intensity")
return fig
R
The same contract, in R with ggplot2:
render <- function(collection) {
library(ggplot2)
df <- collection$items$open_one() # a data.frame
ggplot(df, aes(x = compound, y = intensity)) + geom_col()
}
Plots vs blocks
A plot is not a block: it never becomes a node in your workflow and never
feeds another step. It is a viewer bound to a port. If you need the figure to be
a real, saved output of the pipeline, make a block that produces an Artifact
instead. For a quick look while you work, a plot is the right tool — and the
AI assistant will write one for you from a description.