> ## Documentation Index
> Fetch the complete documentation index at: https://docs.veydra.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Charts and Visualization

> Configure model output charts using outputs.json

## 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:

```json theme={null}
{
  "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:

```json theme={null}
{
  "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"
  ]
}
```

<Note>
  All stocks and flows are calculated internally during simulation. Only those listed here are included in the results sent to the frontend.
</Note>

## 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.

```json theme={null}
{
  "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:

```json theme={null}
{
  "charts": [
    {
      "id": "coverage",
      "title": "Insurance Coverage Ratio",
      "yAxisLabel": "Fraction",
      "comparison": true,
      "series": [
        { "key": "market.insurance_coverage_ratio", "label": "Coverage", "color": "#2196F3" }
      ]
    }
  ]
}
```

### Chart Properties

| Property          | Type    | Description                           |
| ----------------- | ------- | ------------------------------------- |
| `id`              | string  | Unique identifier for the chart       |
| `title`           | string  | Display title shown above the chart   |
| `yAxisLabel`      | string  | Label for the left Y-axis             |
| `yAxisLabelRight` | string  | Label for the right Y-axis (optional) |
| `comparison`      | boolean | Show baseline vs scenario lines       |
| `series`          | array   | List of data series to display        |

### Series Properties

| Property | Type    | Description                                      |
| -------- | ------- | ------------------------------------------------ |
| `key`    | string  | Variable name from stocks, flows, or auxiliaries |
| `label`  | string  | Legend label for this series                     |
| `color`  | string  | Hex color code (e.g., `#4CAF50`)                 |
| `yAxis`  | string  | `"right"` for secondary axis (optional)          |
| `dashed` | boolean | Use dashed line style (optional)                 |

## Chart Examples

### Single Series with Comparison

Shows baseline (dashed gray) vs scenario (solid color) for one variable:

```json theme={null}
{
  "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:

```json theme={null}
{
  "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):

```json theme={null}
{
  "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 }
  ]
}
```

<Tip>
  Use `comparison: false` for charts with many series to avoid visual clutter. With comparison enabled, each series generates two lines (baseline + scenario).
</Tip>

### Coverage by Subpopulation

Break down aggregate metrics into component parts:

```json theme={null}
{
  "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:

```json theme={null}
{
  "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:

```python theme={null}
'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

<AccordionGroup>
  <Accordion title="Group Related Variables">
    Combine variables that tell a story together—like premium, willingness to pay, and enrollment—rather than scattering them across separate charts.
  </Accordion>

  <Accordion title="Use Dual Y-Axis Sparingly">
    Only use the right Y-axis when scales differ significantly (e.g., people vs dollars). Too many dual-axis charts can confuse users.
  </Accordion>

  <Accordion title="Disable Comparison for Busy Charts">
    Set `comparison: false` for charts with 3+ series to keep them readable. Reserve `comparison: true` for key analytical charts.
  </Accordion>

  <Accordion title="Choose Meaningful Colors">
    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).
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Stock-Flow Diagrams" icon="diagram-project" href="/components/stock-flow-diagrams">
    Learn about model structure visualization
  </Card>

  <Card title="Model Development" icon="code" href="/model-development">
    Build models that output these variables
  </Card>
</CardGroup>
