Visual Pipelines Without the Lock-In: What Ciaren Actually Exports

python dev.to

Every visual data tool I've tried has the same trade-off: drag nodes onto a canvas, move fast — and then you're stuck. The pipeline only runs inside that tool. Want to review it in a PR? Test it? Move off the platform later? Good luck. That trade-off is exactly why a lot of engineers skip "visual" tools entirely and just write the pandas by hand from day one.

I wanted the speed of a canvas without that trade, so I built Ciaren: a visual builder for Python data and ML pipelines where the actual deliverable is the exported code — not the canvas.

Here's what that looks like in practice:

A concrete example

Say you're cleaning a customer churn CSV and training a quick baseline model. In Ciaren, that's a handful of nodes: load CSV → drop nulls → encode a categorical column → train/test split → visualize the data → train a classifier. You get a live preview of the dataframe at every step, so you catch a bad join or an unexpected null before it propagates three nodes downstream — which is usually where you'd normally find out, deep in a stack trace.

When you're done, here's what comes out when you click export (pandas or Polars, your choice of backend) — a plain .py file, not a proprietary format:

import pandas as pd
import joblib
import numpy as np
from sklearn.compose import ColumnTransformer
from sklearn.ensemble import RandomForestClassifier
from sklearn.impute import SimpleImputer
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder
from sklearn.preprocessing import StandardScaler

df_web_events = pd.read_csv('web_events.csv')

df_web_events = (
    df_web_events.dropna()
    .assign(high_value=lambda _d: np.select([_d['revenue'] >= 75], ['1'], default='0'))
)

df_1, df_2 = train_test_split(df_web_events, test_size=0.2, random_state=42, stratify=df_web_events['high_value'])
df_1 = df_1.reset_index(drop=True)
df_2 = df_2.reset_index(drop=True)
_features = ['channel', 'duration_sec']
_X = df_1[_features]
_numeric = [c for c in _features if pd.api.types.is_numeric_dtype(_X[c])]
_categorical = [c for c in _features if c not in _numeric]
_transformers = []
if _numeric:
    _transformers.append(('num', Pipeline([('impute', SimpleImputer(strategy='median')), ('scale', StandardScaler())]), _numeric))
if _categorical:
    _transformers.append(('cat', Pipeline([('impute', SimpleImputer(strategy='most_frequent')), ('encode', OneHotEncoder(handle_unknown='ignore'))]), _categorical))
_preprocessor = ColumnTransformer(_transformers, remainder='drop')
_y = df_1['high_value']
df_3 = Pipeline([('preprocessor', _preprocessor), ('model', RandomForestClassifier(random_state=42))])
df_3.fit(_X, _y)
Enter fullscreen mode Exit fullscreen mode

That's it. No Ciaren import, no proprietary runtime to install in production. You could delete Ciaren tomorrow and this script keeps running exactly as-is.

Why this matters more than it sounds

The visual part is genuinely just for speed — seeing the shape of your data change at every step is a faster way to build than writing-testing-printing in a REPL loop. But the reason I built it this way instead of as a hosted "workflow platform" is that I don't think engineers should have to choose between prototyping speed and owning their code. The output is Python you can:

  • Code review like any other PR, because it is a normal PR.
  • Run without Ciaren installed anywhere it needs to run — CI, a cron job, someone else's laptop.
  • Test with your normal test suite, since there's no black-box execution layer to mock around.

Where it's at

Ciaren is early — the core builder and export are solid, but the plugin ecosystem is small, and the roadmap is still taking shape based on what people actually need. If you try it and something's rough or missing, issues are the fastest way to reach me.

If you want to see the full code for a pipeline or just poke around, the repo is here: https://github.com/ciaren-labs/Ciaren

Source: dev.to

arrow_back Back to Tutorials