OHLC Bar Chart — plotnine

An OHLC (Open-High-Low-Close) bar chart displays financial price data using vertical bars with horizontal tick marks. Each bar shows the price range from high to low as a thin vertical line, with a left tick indicating the opening price and a right tick indicating the closing price. Unlike candlestick charts that use colored bodies, OHLC bars provide a cleaner, less cluttered view favored by technical analysts who prefer to focus on price levels rather than visual patterns.

OHLC Bar Chart rendered with plotnine

Renders

Python source (plotnine)

""" anyplot.ai
ohlc-bar: OHLC Bar Chart
Library: plotnine 0.15.4 | Python 3.13.13
Quality: 91/100 | Updated: 2026-05-17
"""

import os

import numpy as np
import pandas as pd
from plotnine import (
    aes,
    element_blank,
    element_line,
    element_rect,
    element_text,
    geom_segment,
    ggplot,
    labs,
    scale_color_manual,
    scale_x_continuous,
    theme,
    theme_minimal,
)


# Theme tokens
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"

# imprint semantic anchors for up/down distinction
UP_COLOR = "#009E73"  # green - up bars
DOWN_COLOR = "#AE3030"  # red - down bars

# Data - Generate 50 days of realistic stock OHLC data
np.random.seed(42)
n_days = 50
start_price = 150.0

# Generate price movements using random walk
returns = np.random.normal(0.001, 0.02, n_days)
close_prices = start_price * np.cumprod(1 + returns)

# Generate open, high, low based on close
open_prices = np.roll(close_prices, 1)
open_prices[0] = start_price

# High and low are generated around the open-close range
daily_volatility = np.abs(np.random.normal(0, 0.015, n_days))
high_prices = np.maximum(open_prices, close_prices) * (1 + daily_volatility)
low_prices = np.minimum(open_prices, close_prices) * (1 - daily_volatility)

# Create date range (business days)
dates = pd.bdate_range(start="2024-06-01", periods=n_days)

# Create DataFrame
df = pd.DataFrame(
    {
        "date": dates,
        "day_num": range(n_days),
        "open": open_prices,
        "high": high_prices,
        "low": low_prices,
        "close": close_prices,
    }
)

# Determine bar direction for coloring
df["direction"] = np.where(df["close"] >= df["open"], "up", "down")

# Define tick width for open/close marks
tick_width = 0.3

# Create data for open ticks (extend left from bar)
df["open_x_start"] = df["day_num"] - tick_width
df["open_x_end"] = df["day_num"]

# Create data for close ticks (extend right from bar)
df["close_x_start"] = df["day_num"]
df["close_x_end"] = df["day_num"] + tick_width

# Create the OHLC bar chart
plot = (
    ggplot(df)
    # High-Low vertical line
    + geom_segment(aes(x="day_num", xend="day_num", y="low", yend="high", color="direction"), size=1.2)
    # Open tick (left horizontal line)
    + geom_segment(aes(x="open_x_start", xend="open_x_end", y="open", yend="open", color="direction"), size=1.2)
    # Close tick (right horizontal line)
    + geom_segment(aes(x="close_x_start", xend="close_x_end", y="close", yend="close", color="direction"), size=1.2)
    # Colors: up (Okabe-Ito position 1) and down (Okabe-Ito position 2)
    + scale_color_manual(
        values={"up": UP_COLOR, "down": DOWN_COLOR}, labels={"up": "Up (Close > Open)", "down": "Down (Close < Open)"}
    )
    # X-axis labels - show every 10th date
    + scale_x_continuous(
        breaks=list(range(0, n_days, 10)), labels=[dates[i].strftime("%b %d") for i in range(0, n_days, 10)]
    )
    # Labels
    + labs(title="ohlc-bar · plotnine · anyplot.ai", x="Date", y="Price (USD)", color="Direction")
    # Theme
    + theme_minimal()
    + theme(
        figure_size=(16, 9),
        plot_title=element_text(size=24, weight="bold", color=INK),
        axis_title=element_text(size=20, color=INK),
        axis_text=element_text(size=16, color=INK_SOFT),
        axis_text_x=element_text(size=16, color=INK_SOFT),
        legend_title=element_text(size=18, color=INK),
        legend_text=element_text(size=16, color=INK_SOFT),
        legend_position="right",
        legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT),
        panel_grid_major=element_line(color=INK, alpha=0.10, size=0.3),
        panel_grid_minor=element_blank(),
        panel_background=element_rect(fill=PAGE_BG, color=None),
        plot_background=element_rect(fill=PAGE_BG, color=None),
        axis_line=element_line(color=INK_SOFT, size=0.5),
    )
)

# Save the plot
plot.save(f"plot-{THEME}.png", dpi=300, verbose=False)

Retrieve this implementation

Runnable source as JSON, for any HTTP client: https://api.anyplot.ai/specs/ohlc-bar/plotnine/code. Any spec id and library id listed in llms-full.txt fit the same URL shape; every URL below is complete and callable.

{
  "spec_id": "ohlc-bar",
  "language": "python",
  "library": "plotnine",
  "page": "https://anyplot.ai/ohlc-bar/python/plotnine",
  "hub": "https://anyplot.ai/ohlc-bar",
  "code_json": "https://api.anyplot.ai/specs/ohlc-bar/plotnine/code",
  "spec_json": "https://api.anyplot.ai/specs/ohlc-bar",
  "render_light_png": "https://storage.googleapis.com/anyplot-images/plots/ohlc-bar/python/plotnine/plot-light.png",
  "render_dark_png": "https://storage.googleapis.com/anyplot-images/plots/ohlc-bar/python/plotnine/plot-dark.png",
  "quality_score": 91.0,
  "license": "MIT",
  "guide": "https://anyplot.ai/llms.txt"
}

Part of OHLC Bar Chart on anyplot.ai.

Other implementations