AdaptivePlot#

AdaptivePlot renders adaptive comfort charts following ASHRAE 55 or EN 16798. The x-axis shows the prevailing mean outdoor temperature (Tpma or Trm), the y-axis shows operative temperature. Pass the model function (adaptive_ashrae or adaptive_en) and set air speed via set_params(v=...). When v 0.6 m/s and operative temperature exceeds 25 °C, the model applies a cooling effect that expands the upper boundary of each band.

import matplotlib.pyplot as plt

from pythermalcomfort.models import adaptive_ashrae, adaptive_en
from pythermalcomfort.plots.matplotlib import AdaptivePlot, RegionsConfig

1. ASHRAE 55 — Default Chart#

With no set_regions call, all available bands are shown using their default colours. The dashed line marks the optimal comfort temperature.

ashrae_result = (
    AdaptivePlot(adaptive_ashrae)
    .set_params(v=0.1)
    .plot(title="Adaptive Comfort — ASHRAE 55")
)
plt.show()
../../../_images/712e06181194011a25b33e01201bca64993b459212fb1ecfb0272edede0b4f62.png

2. EN 16798 — Default Chart#

EN 16798 defines three categories (I, II, III) with progressively wider bands. Category I represents the strictest comfort requirement.

en_result = (
    AdaptivePlot(adaptive_en)
    .set_params(v=0.1)
    .plot(title="Adaptive Comfort — EN 16798")
)
plt.show()
../../../_images/f4e46414f0728fcf1b91f8ffdb40b2a19cc17a152eb776fb8a5d719b2746db51.png

3. Selecting Specific Bands#

Pass a list of band keys to set_regions(show=...) to display only the bands you need. ASHRAE 55 uses '80' and '90' for 80 % and 90 % acceptability. EN 16798 uses 'cat_i', 'cat_ii', 'cat_iii'.

fig, (ax0, ax1) = plt.subplots(1, 2, figsize=(12, 5), constrained_layout=True)

(
    AdaptivePlot(adaptive_ashrae)
    .set_params(v=0.1)
    .set_regions(show=["90"])
    .plot(ax=ax0, title="ASHRAE 55 — 90 % Acceptability Only")
)

(
    AdaptivePlot(adaptive_en)
    .set_params(v=0.1)
    .set_regions(show=["cat_i", "cat_ii"])
    .plot(ax=ax1, title="EN 16798 — Categories I & II")
)

plt.show()
../../../_images/019060b90e2d839c1c15dc2387a3df3483308a208f03ab6f739dcdde1e2bc59e.png

4. Custom Labels and Colors#

Band labels and colors can be overridden by passing labels and colors to set_regions. The list length must match the number of bands shown.

en_custom = (
    AdaptivePlot(adaptive_en)
    .set_params(v=0.1)
    .set_regions(
        show=["cat_i", "cat_ii", "cat_iii"],
        labels=["Category I (±2 °C)", "Category II (±3 °C)", "Category III (±4 °C)"],
        colors=["#1a9850", "#91cf60", "#d9ef8b"],
    )
    .plot(title="EN 16798 — Custom Labels and Colors")
)
plt.show()
../../../_images/8ce74adbc721fef1aded232dd46fa322a632d49a1d97b31f836a64e9d263b25e.png

5. Reusable Band Configuration with RegionsConfig#

RegionsConfig stores a band selection with optional custom labels and colors. Create it once and pass it to set_regions(show=config) to reuse the same definition across multiple plots.

ashrae_config = RegionsConfig(
    show=["90"],
    labels=["90 % Acceptability Zone"],
    colors=["#0067B2"],
)

fig, (ax0, ax1) = plt.subplots(1, 2, figsize=(12, 5), constrained_layout=True)

AdaptivePlot(adaptive_ashrae).set_params(v=0.1).set_regions(show=ashrae_config).plot(
    ax=ax0, title="Still Air (v = 0.1 m/s)"
)
AdaptivePlot(adaptive_ashrae).set_params(v=1.2).set_regions(show=ashrae_config).plot(
    ax=ax1, title="Moving Air (v = 1.2 m/s)"
)

plt.show()
../../../_images/f2c8aeb231902b5fd0f09cd48594dad2c97c11de9dd44697c553711f851c414f.png

6. Cooling Effect: Still Air vs Elevated Air Speed#

When v 0.6 m/s and operative temperature exceeds 25 °C, the model shifts the upper comfort boundary upward. The side-by-side comparison shows the practical benefit of ceiling fans or natural cross-ventilation in warm climates.

fig, (ax0, ax1) = plt.subplots(
    2, 1, figsize=(8, 8), constrained_layout=True, sharex=True
)

AdaptivePlot(adaptive_ashrae).set_params(v=0.1).plot(
    ax=ax0, title="v = 0.1 m/s — no cooling effect"
)
AdaptivePlot(adaptive_ashrae).set_params(v=1.2).plot(
    ax=ax1, title="v = 1.2 m/s — upper boundary shifts up"
)

plt.show()
../../../_images/5fae29ff5b0c76c4e7a9afa63ecffe3d2993df8aa83a325d07b41cf0baa75dbc.png

7. Returned Artists#

result.ax is the Matplotlib Axes with all the standard methods. Use it to overlay measured operative temperatures on the chart.

import numpy as np

rng = np.random.default_rng(0)
t_outdoor = rng.uniform(10, 32, 60)  # prevailing mean outdoor temperature
t_operative = t_outdoor + rng.normal(3, 2, 60)  # typical indoor-outdoor offset

result = (
    AdaptivePlot(adaptive_ashrae)
    .set_params(v=0.1)
    .plot(title="ASHRAE 55 — Measured Operative Temperatures")
)

result.ax.scatter(
    t_outdoor, t_operative, color="black", s=25, zorder=5, label="Measured"
)
result.ax.legend(loc="upper left")
plt.show()
../../../_images/0155563c972c4e479e9bd74fe197310a9e07d1e122515f92616cf7d64e082215.png