Skip to main content

Overview

Veydra’s chart system is driven by a configuration file (config/outputs.json) in each model’s directory. This file controls which variables are returned from simulations and how they are grouped into charts for visualization.

Configuration File Structure

The outputs.json file has four main sections:
{
  "stocks": ["list of stock variables to return"],
  "flows": ["list of flow variables to return"],
  "auxiliaries": ["list of computed auxiliary metrics"],
  "charts": [/* chart grouping configuration */],
  "ui": {
    "showPhasePlot": false
  }
}

Stocks and Flows

Define which simulation variables are returned to the frontend:
{
  "stocks": [
    "health.s_healthy_well",
    "health.s_healthy_ill",
    "market.s_insured_healthy_type"
  ],
  "flows": [
    "market.actuarial_premium",
    "market.wtp_healthy",
    "market.insurance_coverage_ratio"
  ]
}
All stocks and flows are calculated internally during simulation. Only those listed here are included in the results sent to the frontend.

Auxiliaries

Auxiliaries are derived metrics computed post-simulation from stocks and flows. Define them in outputs.json and implement the calculation in your model’s _calculate_auxiliaries method.
{
  "auxiliaries": [
    "auxiliary.healthy_to_sickly_ratio"
  ]
}
Example auxiliary calculation (ratio of two population groups):
  • Input: health.s_healthy_well, health.s_healthy_ill, health.s_sickly_well, health.s_sickly_ill
  • Output: (healthy_well + healthy_ill) / (sickly_well + sickly_ill)

Chart Configuration

Basic Chart Definition

Each chart groups one or more series together:
{
  "charts": [
    {
      "id": "coverage",
      "title": "Insurance Coverage Ratio",
      "yAxisLabel": "Fraction",
      "comparison": true,
      "series": [
        { "key": "market.insurance_coverage_ratio", "label": "Coverage", "color": "#2196F3" }
      ]
    }
  ]
}

Chart Properties

PropertyTypeDescription
idstringUnique identifier for the chart
titlestringDisplay title shown above the chart
yAxisLabelstringLabel for the left Y-axis
yAxisLabelRightstringLabel for the right Y-axis (optional)
comparisonbooleanShow baseline vs scenario lines
seriesarrayList of data series to display

Series Properties

PropertyTypeDescription
keystringVariable name from stocks, flows, or auxiliaries
labelstringLegend label for this series
colorstringHex color code (e.g., #4CAF50)
yAxisstring"right" for secondary axis (optional)
dashedbooleanUse dashed line style (optional)

Chart Examples

Single Series with Comparison

Shows baseline (dashed gray) vs scenario (solid color) for one variable:
{
  "id": "healthy_sickly_ratio",
  "title": "Healthy-to-Sickly Population Ratio",
  "yAxisLabel": "Ratio",
  "comparison": true,
  "series": [
    { "key": "auxiliary.healthy_to_sickly_ratio", "label": "Healthy/Sickly Ratio", "color": "#673AB7" }
  ]
}

Multiple Series with Dual Y-Axis

Combine variables with different scales using left and right axes:
{
  "id": "death_spiral",
  "title": "Insurance Death Spiral",
  "yAxisLabel": "People",
  "yAxisLabelRight": "$/year",
  "comparison": true,
  "series": [
    { "key": "market.s_insured_healthy_type", "label": "Insured Healthy-Type", "color": "#2196F3" },
    { "key": "market.s_insured_sickly_type", "label": "Insured Sickly-Type", "color": "#FF9800" },
    { "key": "market.actuarial_premium", "label": "Premium", "color": "#9C27B0", "yAxis": "right" }
  ]
}

Multiple Series without Comparison

When comparison: false, only the current scenario is shown (no baseline lines):
{
  "id": "wtp_vs_premium",
  "title": "Willingness to Pay vs Premium",
  "yAxisLabel": "$/year",
  "comparison": false,
  "series": [
    { "key": "market.wtp_healthy", "label": "WTP Healthy-Type", "color": "#4CAF50" },
    { "key": "market.wtp_sickly", "label": "WTP Sickly-Type", "color": "#F44336" },
    { "key": "market.actuarial_premium", "label": "Premium", "color": "#9C27B0", "dashed": true }
  ]
}
Use comparison: false for charts with many series to avoid visual clutter. With comparison enabled, each series generates two lines (baseline + scenario).

Coverage by Subpopulation

Break down aggregate metrics into component parts:
{
  "id": "coverage",
  "title": "Insurance Coverage by Type",
  "yAxisLabel": "Fraction",
  "comparison": true,
  "series": [
    { "key": "market.insurance_coverage_ratio_healthy", "label": "Healthy-Type Coverage", "color": "#4CAF50" },
    { "key": "market.insurance_coverage_ratio_sickly", "label": "Sickly-Type Coverage", "color": "#F44336" },
    { "key": "market.insurance_coverage_ratio", "label": "Overall Coverage", "color": "#2196F3", "dashed": true }
  ]
}

UI Configuration

Phase Plot

Control whether the phase plot (stock vs stock scatter plot) is displayed:
{
  "ui": {
    "showPhasePlot": false
  }
}
Set to true to enable the interactive phase plot selector, which requires at least 2 stocks.

Time Units

The X-axis label automatically pulls units from the simulation.duration parameter definition in your model. For example, if your model defines:
'simulation.duration': {
    'units': 'year',
    ...
}
The chart will display “Time (years)” on the X-axis.

Fallback Behavior

If no charts array is defined, the system falls back to displaying one chart per stock in the stocks array. This provides backward compatibility with models that haven’t been configured with grouped charts.

Best Practices

Only use the right Y-axis when scales differ significantly (e.g., people vs dollars). Too many dual-axis charts can confuse users.
Set comparison: false for charts with 3+ series to keep them readable. Reserve comparison: true for key analytical charts.
Use consistent color coding across charts (e.g., green for healthy, red for sickly). Material Design colors work well: #4CAF50 (green), #F44336 (red), #2196F3 (blue).

Next Steps

Stock-Flow Diagrams

Learn about model structure visualization

Model Development

Build models that output these variables