Skip to content

How to plot simulation results

The simulation module provides pluggable plotting backends for visualizing results with matplotlib or plotly.

Not in JavaScript yet

Plotting simulation results is available in Python and is not in JavaScript today. A temporary gap, not a boundary. The port is tracked in idfkit-js#24.

The full entry, including the vocabulary this capability owns, is on the capability parity page.

Quick Start

from idfkit.simulation import simulate

result = simulate(model, weather)

# Plot time series
ts = result.sql.get_timeseries(
    "Zone Mean Air Temperature",
    "ZONE 1",
)
fig = ts.plot()  # Auto-detects available backend

Installation

Install a plotting backend:

# Matplotlib (recommended for static plots)
pip install idfkit[plot]

# Plotly (for interactive plots)
pip install idfkit[plotly]

# Both
pip install idfkit[plot,plotly]

Built-in Visualizations

Each of these takes the SQL database from a completed run, result.sql, shown below as sql.

Temperature Profile

from idfkit.simulation import plot_temperature_profile

# `sql` is result.sql from a completed simulation
fig = plot_temperature_profile(
    sql,
    ["THERMAL ZONE 1", "THERMAL ZONE 2"],
    title="Zone Temperatures",
)

Energy Balance

from idfkit.simulation import plot_energy_balance

# `sql` is result.sql from a completed simulation
fig = plot_energy_balance(
    sql,
    title="Annual Energy Balance",
)

Comfort Hours

from idfkit.simulation import plot_comfort_hours

# `sql` is result.sql from a completed simulation
fig = plot_comfort_hours(
    sql,
    ["THERMAL ZONE 1"],
    title="Thermal Comfort Analysis",
)

Time Series Plotting

TimeSeriesResult has a built-in plot() method:

ts = result.sql.get_timeseries(
    "Zone Mean Air Temperature",
    "ZONE 1",
)

# Default plot
fig = ts.plot()

# Custom title
fig = ts.plot(title="My Custom Title")

# Explicit backend
from idfkit.simulation.plotting.matplotlib import MatplotlibBackend

fig = ts.plot(backend=MatplotlibBackend())

Backend Selection

Auto-Detection

By default, the first available backend is used:

from idfkit.simulation import get_default_backend

backend = get_default_backend()
print(type(backend).__name__)  # MatplotlibBackend or PlotlyBackend

Priority: matplotlib → plotly

Explicit Backend

from idfkit.simulation.plotting.matplotlib import MatplotlibBackend
from idfkit.simulation.plotting.plotly import PlotlyBackend

# Force matplotlib
fig = ts.plot(backend=MatplotlibBackend())

# Force plotly
fig = ts.plot(backend=PlotlyBackend())

PlotBackend Protocol

Create custom backends by implementing the PlotBackend protocol:

from idfkit.simulation import PlotBackend


class MyBackend(PlotBackend):
    def line(
        self,
        x: list,
        y: list,
        *,
        title: str = "",
        xlabel: str = "",
        ylabel: str = "",
        label: str | None = None,
    ):
        # Return a figure object
        ...

    def bar(
        self,
        categories: list[str],
        values: list[float],
        *,
        title: str = "",
        xlabel: str = "",
        ylabel: str = "",
    ):
        # Return a figure object
        ...

The backend classes live in their own modules so that importing idfkit.simulation never pulls in matplotlib or plotly.

Matplotlib Backend

Basic Usage

from idfkit.simulation.plotting.matplotlib import MatplotlibBackend

backend = MatplotlibBackend()
fig = backend.line(
    x=list(ts.timestamps),
    y=list(ts.values),
    title="Zone Temperature",
    xlabel="Time",
    ylabel="Temperature (°C)",
)

# Save to file
fig.savefig("temperature.png")

Customization

import matplotlib.pyplot as plt

# Create custom figure
fig, ax = plt.subplots(figsize=(12, 6))

# Plot multiple series
for zone_name in zone_names:
    ts = result.sql.get_timeseries(
        "Zone Mean Air Temperature",
        zone_name,
    )
    ax.plot(ts.timestamps, ts.values, label=zone_name)

ax.legend()
ax.set_xlabel("Time")
ax.set_ylabel("Temperature (°C)")
plt.show()

Plotly Backend

Basic Usage

from idfkit.simulation.plotting.plotly import PlotlyBackend

backend = PlotlyBackend()
fig = backend.line(
    x=list(ts.timestamps),
    y=list(ts.values),
    title="Zone Temperature",
)

# Interactive display
fig.show()

# Save to HTML
fig.write_html("temperature.html")

Customization

import plotly.graph_objects as go

fig = go.Figure()

for zone_name in zone_names:
    ts = result.sql.get_timeseries(
        "Zone Mean Air Temperature",
        zone_name,
    )
    fig.add_trace(
        go.Scatter(
            x=list(ts.timestamps),
            y=list(ts.values),
            name=zone_name,
        )
    )

fig.update_layout(
    title="Zone Temperatures",
    xaxis_title="Time",
    yaxis_title="Temperature (°C)",
)
fig.show()

DataFrame Integration

Convert to pandas and use native plotting:

# Get DataFrame
df = ts.to_dataframe()

# Matplotlib via pandas
df.plot(figsize=(12, 6))

# Plotly via pandas
import plotly.express as px

fig = px.line(df.reset_index(), x="timestamp", y=ts.variable_name)

Multiple Time Series

Same Variable, Multiple Keys

import matplotlib.pyplot as plt

fig, ax = plt.subplots()

for zone_name in ["ZONE 1", "ZONE 2", "ZONE 3"]:
    ts = result.sql.get_timeseries(
        "Zone Mean Air Temperature",
        zone_name,
    )
    ax.plot(ts.timestamps, ts.values, label=zone_name)

ax.legend()
plt.show()

Different Variables

fig, axes = plt.subplots(2, 1, figsize=(12, 8), sharex=True)

# Temperature
ts_temp = result.sql.get_timeseries("Zone Mean Air Temperature", "ZONE 1")
axes[0].plot(ts_temp.timestamps, ts_temp.values)
axes[0].set_ylabel("Temperature (°C)")

# Humidity
ts_rh = result.sql.get_timeseries("Zone Air Relative Humidity", "ZONE 1")
axes[1].plot(ts_rh.timestamps, ts_rh.values)
axes[1].set_ylabel("Relative Humidity (%)")

plt.tight_layout()
plt.show()

Saving Figures

Matplotlib

fig.savefig("plot.png", dpi=300, bbox_inches="tight")
fig.savefig("plot.pdf")
fig.savefig("plot.svg")

Plotly

fig.write_html("plot.html")
fig.write_image("plot.png")  # Requires kaleido
fig.write_image("plot.pdf")

See Also