Real-time animation of the pendulum motion alongside the time series data:
### Phase Portrait
State variables accept a [Distribution](/datamodel/classes/Distribution.html) for initial conditions. The presence of a distribution declares that the variable should be sampled — no runtime flags needed. The resolution order is:
| Configuration | Behavior |
|---|---|
| `initial_value: 1.0` (no distribution) | Deterministic — always starts at 1.0 |
| `distribution:` present + `n_trials > 1` | Each trial samples a new IC from the distribution |
| `distribution:` present, single run | Uses `initial_value` as fallback |
| `distribution.domain` not set | Falls back to the state variable's `domain` |
```yaml
# Case 1: Fixed IC (no distribution)
theta:
initial_value: 1.0 # → Always starts at 1.0
# Case 2: Sampled IC (distribution present)
theta:
initial_value: 0.0 # fallback if sampling disabled
distribution:
name: Uniform
domain: {lo: -3.14, hi: 3.14}
# → Sampled when n_trials > 1, else uses 0.0
# Case 3: Distribution without explicit domain → inherits SV domain
theta:
initial_value: 0.0
domain: {lo: -3.14, hi: 3.14}
distribution:
name: Uniform # domain falls back to SV domain
# → Uniform(-3.14, 3.14)
An Exploration with n_trials runs them in parallel — each trial samples a different starting point, revealing the full phase portrait without any Python loop:
from tvbo.datamodel.schema import Distribution, Range, Explorationimport numpy as np# Attach sampling distributions to the state variablespendulum.dynamics.state_variables["theta"].distribution = Distribution( name="Uniform", domain=Range(lo=-np.pi, hi=np.pi))pendulum.dynamics.state_variables["omega"].distribution = Distribution( name="Uniform", domain=Range(lo=-0.005,hi=0.005))# 20 parallel trials from different initial conditionspendulum.explorations["ICs"] = Exploration(name="ICs", n_trials=20)result = pendulum.run(duration=10_000)