Research-as-code framework for sociological surveys.
Project description
siamang
Research-as-code framework for sociological surveys.
Define variables, questionnaires, and logic in pure Python — then
deploy, collect, and analyze in a single pipeline.
Quick start · Full pipeline example · API Reference
pip install git+https://github.com/hanelias/siamang.git
siamang validate my_survey.py
siamang preview my_survey.py # local preview
siamang deploy my_survey.py --backend supabase --frontend vercel
What it does
siamang turns a survey into a running web application from a single Python script:
my_survey.py ← you write this
│
├─ siamang validate → catches errors before deployment
├─ siamang preview → local frontend (hot-reload)
├─ siamang deploy → Vercel + Supabase (cloud deployment)
└─ survey.simulate() → synthetic data for testing
No GUI builders. No drag-and-drop. No lock-in. Your survey is a Python module — version-control it, test it, reuse it.
Quick start
from siamang.core import (
Variable, SingleChoice, LikertScale, Page, Questionnaire,
)
# Define variables with full metadata
satisfaction = Variable(
"satisfaction", scale="ordinal",
label="Overall satisfaction",
labels={1: "Very dissatisfied", 2: "Dissatisfied",
3: "Neutral", 4: "Satisfied", 5: "Very satisfied"},
)
remote_freq = Variable(
"remote_freq", scale="ordinal",
label="Remote work frequency",
labels={1: "Never", 2: "1-2 days/week",
3: "3-4 days/week", 4: "Fully remote"},
)
# Build questions
q_sat = LikertScale("How satisfied are you with your current role?",
var=satisfaction, points=5, required=True)
q_remote = SingleChoice("How often do you work remotely?",
var=remote_freq, display="radio", required=True)
# Assemble questionnaire
survey = Questionnaire(
title="Work Attitudes Study",
pages=[Page("main", items=[q_sat, q_remote])],
)
# Simulate and analyze
data = survey.simulate(n=200)
print(data.report.freq("satisfaction").to_markdown())
# Visualize (requires: pip install siamang[charts])
data.plot.bar("satisfaction").show()
Full Pipeline Example
The examples/full_pipeline/ directory contains a complete Jupyter notebook demonstrating the entire research workflow — from survey design to statistical analysis:
- Survey Design — 12 variables, 5 pages, conditional routing (
show_if), matrix questions, Likert scales - Simulation & Deployment — 250 synthetic respondents, local SQLite storage, interactive HTML preview
- Declarative Reporting — frequency tables, cross-tabs with Chi², grouped means with auto-selected tests, correlation heatmaps
- Visualizations — bar charts, boxplots, heatmaps, scatter plots — all with one line of code
cd examples/full_pipeline
jupyter notebook full_pipeline_demo.ipynb
The folder also includes survey_preview.html — an interactive HTML survey you can open in any browser to see how the questionnaire looks for respondents.
Features
| Area | Capabilities |
|---|---|
| Core | Variables (nominal/ordinal/interval/ratio), questions (single/multi/open/numeric/likert/matrix/ranking), pages, skip logic (show_if/hide_if), quotas, validation |
| Reporting | Declarative tables (FreqTable, CrossTable, GroupMeanTable) and charts (BarChart, BoxPlot, HeatMap, ScatterPlot) — automatic labels, statistical tests, and metadata awareness |
| Scripts | Inline JavaScript for survey-side behaviour — 7 trigger points |
| Frontend | SurveyJS and React 18 runtimes, dark mode, auto-save, access codes, 6 theme presets |
| Backend | Local SQLite for development, Supabase for production, Google Sheets for collaborative access |
| Deploy | Vercel and Netlify frontends with CSP headers; self-contained HTML bundle for offline use |
| Data I/O | CSV, Excel (.xlsx), SPSS (.sav), Stata (.dta), R (.rda) — round-trip with labels and missing values preserved |
Declarative Reporting API
Siamang automatically uses variable metadata (labels, scales, missing values) to produce publication-ready outputs — like SPSS, but in Python:
data = survey.simulate(n=300)
# Tables — automatic labels, tests, and formatting
data.report.freq("it_role") # frequency table
data.report.crosstab("gender", "satisfaction", pct="col") # cross-tab + Chi²
data.report.means("autonomy", by="remote_freq") # means + Kruskal-Wallis
# Charts — one line, automatic axis labels
data.plot.bar("it_role")
data.plot.boxplot("satisfaction", by="remote_freq", show_points=True)
data.plot.heatmap(["surv_keystroke", "surv_camera"], by="remote_freq")
data.plot.scatter("satisfaction", "autonomy", hue="gender")
# Export
data.report.freq("it_role").to_markdown() # Markdown string
data.report.freq("it_role").to_frame() # pandas DataFrame
data.report.freq("it_role").to_html() # HTML table
Deployment
Local (development)
siamang preview my_survey.py # → http://127.0.0.1:8000
Cloud — Vercel + Supabase (high concurrency)
siamang init # one-time: stores credentials
siamang deploy my_survey.py --backend supabase --frontend vercel
Cloud — Netlify + Google Sheets (lightweight)
export SIAMANG_GSHEETS_CREDENTIALS_FILE=./service-account-key.json
export NETLIFY_AUTH_TOKEN=nfp_...
siamang deploy my_survey.py --backend gsheets --frontend netlify
Responses are written to a Google Spreadsheet (one row per respondent) via an Apps Script proxy that acts as a secure intermediary. The survey is hosted on Netlify CDN with automatic HTTPS and global edge distribution.
Note: The Google Sheets backend is currently experimental for public web deployments. Browser-to-Sheets writes require an Apps Script Web App URL to avoid exposing credentials. See
docs/reference/deploy.mdfor setup instructions.
Deployment combinations
| Use case | Backend | Frontend |
|---|---|---|
| Local development / testing | local |
local |
| Small survey, shared with team | gsheets |
netlify |
| Production, high concurrency | supabase |
vercel or netlify |
| Offline / air-gapped | local |
local (HTML bundle) |
Project Layout
siamang/
├── core/ Variable, Question types, Block, Page, Questionnaire, Expression, Quota, Script
├── data/ SurveyData, DataAnalysis, DataProcessing, SurveyTables
├── reporting/ Declarative tables (FreqTable, CrossTable, GroupMeanTable) and charts (BarChart, BoxPlot, HeatMap, ScatterPlot)
├── frontend/ SurveyJS & React runtimes, bundle builder, UIConfig theme engine, presets
├── deploy/ Backends (SQLite, Supabase, Google Sheets), frontends (Vercel, Netlify, local), pipeline orchestration
├── cli/ validate, preview, deploy, init
├── io/ Import/export for CSV, Excel, SPSS, Stata, R
└── config/ User configuration (~/.siamang.toml), secrets
Documentation
| Resource | Description |
|---|---|
docs/reference/core.md |
API reference — Variable, Expression, all Question types, Page, Questionnaire |
docs/reference/data.md |
API reference — SurveyData, DataAnalysis, DataProcessing, SurveyTables |
docs/reference/reporting.md |
API reference — Declarative tables and charts |
docs/reference/frontend.md |
API reference — UIConfig, theme presets, runtimes, bundle builder |
docs/reference/deploy.md |
API reference — Backends (Local, Supabase, Google Sheets), Frontends (Local, Vercel, Netlify), pipeline |
examples/full_pipeline/ |
Complete worked example: design → deploy → analyze |
Requirements
- Python 3.11+
- For cloud deployment (option A): a Supabase project and a Vercel account
- For cloud deployment (option B): a Google Cloud service account and a Netlify account
Dependencies
All core dependencies are installed automatically with pip install siamang.
Core (installed automatically)
| Package | Version | Purpose |
|---|---|---|
pandas |
≥ 2.0 | Data manipulation, SurveyData backbone |
scipy |
≥ 1.11 | Statistical tests (chi-square, t-test, ANOVA) |
openpyxl |
≥ 3.1 | Excel (.xlsx) import/export |
pyreadstat |
≥ 1.2 | SPSS (.sav) and Stata (.dta) import/export |
fastapi |
≥ 0.110 | Local preview server (siamang preview) |
uvicorn |
≥ 0.29 | ASGI server for local preview |
supabase |
≥ 2.0 | Supabase backend (Postgres + RLS + Edge Functions) |
requests |
≥ 2.31 | HTTP client for Netlify/Vercel deployment APIs |
Charts (optional)
pip install siamang[charts]
| Package | Version | Purpose |
|---|---|---|
matplotlib |
≥ 3.7 | Chart rendering (data.plot.bar(), .boxplot(), .scatter(), .heatmap()) |
seaborn |
≥ 0.13 | Statistical visualization helpers |
Charts are optional — if you only use tables (data.report.freq(), data.report.crosstab()), matplotlib is not needed. A clear error message will guide you if you try to render a chart without it.
Google Sheets backend (optional)
pip install siamang[gsheets]
| Package | Version | Purpose |
|---|---|---|
google-auth |
≥ 2.0 | Service account authentication |
google-auth-httplib2 |
≥ 0.1 | HTTP transport for Google APIs |
google-api-python-client |
≥ 2.0 | Google Sheets API and Google Drive API client |
Development
pip install siamang[dev]
| Package | Version | Purpose |
|---|---|---|
ruff |
≥ 0.4 | Linting and formatting |
mypy |
≥ 1.10 | Static type checking |
pytest |
≥ 8.0 | Test runner |
matplotlib |
≥ 3.7 | Required for chart tests |
seaborn |
≥ 0.13 | Required for chart tests |
License
Siamang is released under the MIT License. Free for any use — academic, commercial, personal.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file siamang-0.5.0.tar.gz.
File metadata
- Download URL: siamang-0.5.0.tar.gz
- Upload date:
- Size: 228.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0abd345ca1bf48ea2f7c96f64221463aff48d63b6c627b3337b0f6624875884b
|
|
| MD5 |
89ce809b769c8d8b2f80b5ed49922557
|
|
| BLAKE2b-256 |
c256d8b86e32fb5808d4bb6f0bcd61e9b878d5ca582340301d69888af5adfee7
|
File details
Details for the file siamang-0.5.0-py3-none-any.whl.
File metadata
- Download URL: siamang-0.5.0-py3-none-any.whl
- Upload date:
- Size: 216.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4a821ade0995e6878a702cf4a6faaa0e42c36aed8f7f8260e51d3766bb7c3c0b
|
|
| MD5 |
e1ce8675a0f3ea204a3abe032f20cd2b
|
|
| BLAKE2b-256 |
c78c12f755292044e53d6c94a4304c2a16a6c3d60629914d49800402f0fd528c
|