Range Interval Chart — Seaborn

A range interval chart displays min-max ranges or intervals as vertical or horizontal bars/segments for each category, making it ideal for visualizing uncertainty bounds, confidence intervals, or value spreads. Unlike error bars which extend from a central data point, range intervals show the full span between two values as a filled bar or line segment, emphasizing the range itself rather than deviation from a center. This visualization excels at comparing ranges across multiple categories simultaneously.

Range Interval Chart rendered with Seaborn

Python source (Seaborn)

""" anyplot.ai
range-interval: Range Interval Chart
Library: seaborn 0.13.2 | Python 3.13.13
Quality: 89/100 | Updated: 2026-05-18
"""

import os

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns


# Theme tokens (see prompts/default-style-guide.md)
THEME = os.getenv("ANYPLOT_THEME", "light")
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
ELEVATED_BG = "#FFFDF6" if THEME == "light" else "#242420"
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0"
BRAND = "#009E73"  # Okabe-Ito position 1 — ALWAYS first series
SECONDARY = "#C475FD"  # Okabe-Ito position 2

# Data - Salary ranges by job title in tech industry
np.random.seed(42)
job_titles = [
    "Junior Developer",
    "Senior Developer",
    "DevOps Engineer",
    "Data Scientist",
    "Product Manager",
    "UX Designer",
    "QA Engineer",
    "Engineering Manager",
]

# Realistic salary ranges (in thousands USD)
min_salaries = np.array([65, 95, 85, 75, 80, 70, 60, 100])
max_salaries = np.array([95, 160, 140, 130, 150, 120, 100, 180])

# Create DataFrame for plotting
df = pd.DataFrame(
    {"Job Title": job_titles, "Min Salary": min_salaries, "Max Salary": max_salaries, "idx": range(len(job_titles))}
)

# Create plot
fig, ax = plt.subplots(figsize=(16, 9), facecolor=PAGE_BG)
ax.set_facecolor(PAGE_BG)

# Draw vertical range bars connecting min and max salaries
for i, row in df.iterrows():
    ax.plot(
        [i, i],
        [row["Min Salary"], row["Max Salary"]],
        color=BRAND,
        linewidth=14,
        alpha=0.85,
        solid_capstyle="round",
        zorder=2,
    )

# Add min/max markers
sns.scatterplot(
    data=df, x="idx", y="Min Salary", color=BRAND, s=300, edgecolor=PAGE_BG, linewidth=2, ax=ax, zorder=3, legend=False
)

sns.scatterplot(
    data=df,
    x="idx",
    y="Max Salary",
    color=SECONDARY,
    s=300,
    edgecolor=PAGE_BG,
    linewidth=2,
    ax=ax,
    zorder=3,
    legend=False,
)

# Configure axes
ax.set_xticks(range(len(job_titles)))
ax.set_xticklabels(job_titles, rotation=45, ha="right")
ax.set_xlabel("Job Title", fontsize=20, color=INK)
ax.set_ylabel("Annual Salary (thousands USD)", fontsize=20, color=INK)
ax.set_title("range-interval · python · seaborn · anyplot.ai", fontsize=24, fontweight="medium", color=INK)
ax.tick_params(axis="both", labelsize=16, colors=INK_SOFT)

# Style spines
ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)
for spine in ["left", "bottom"]:
    ax.spines[spine].set_color(INK_SOFT)

# Grid styling
ax.yaxis.grid(True, alpha=0.10, linewidth=0.8, color=INK)
ax.set_axisbelow(True)

plt.tight_layout()
plt.savefig(f"plot-{THEME}.png", dpi=300, bbox_inches="tight", facecolor=PAGE_BG)

Part of Range Interval Chart on anyplot.ai.

Other implementations