# Plotting

Lines, histograms with per-bar colors, fills, hlines, and shape markers.

<a id="plot"></a>
## plot

```python
plot(series, name, color?, linewidth?, plot_type?, opacity?, colors?, align?, width_px?)
```

Draw a data series on the chart.

Draws a line, histogram, area, or step line from a pandas Series. Each `plot()` call creates a named series visible in the chart legend.

For per-bar coloring (e.g. yellow for block trades, gray for normal), pass a `colors=` array the same length as `series`. Per-bar colors are only valid for `HISTOGRAM`, `COLUMNS`, `CROSS`, `CIRCLES`. Lines, areas, and step lines stay single-color.

`align=` reshapes the geometry instead of laying bars along the time axis:
- `pinned_top` / `pinned_bottom` - horizontal strip glued to chart top/bottom (volume-pane layout). Bars time-align to candles via `timeToCoordinate`; height proportional to value normalized to visible range.
- `pinned_left` / `pinned_right` - vertical strip glued to chart left/right edge (HUD layout). Anchored to the price axis.
- `left_of_range` / `right_of_range` - anchored to the first/last visible bar.
- `over_range` - stretches across the visible range.

Pair with `width_px=` to control the pinned strip width (left/right) or thickness (top/bottom).

### Parameters

- `series` (`Series`, default `required`): pandas Series of values to plot
- `name` (`str`, default `required`): Legend label (must be unique per indicator)
- `color` (`str`, default `"#2962FF"`): Hex color string (fallback when `colors[i]` is None). Accepts 6-char `#rrggbb` or 8-char `#rrggbbaa`.
- `linewidth` (`int`, default `2`): Line thickness in pixels
- `plot_type` ([`PlotType`](https://quantchartsllc.com/docs/python/py-logging.md#plottype), default `LINE`): `LINE`, `HISTOGRAM`, `COLUMNS`, `CROSS`, `CIRCLES`, `AREA`, or `STEPLINE`
- `opacity` (`int`, default `100`): Opacity 0-100 for area fills
- `colors` (`list[str | None]`, default `None`): Per-bar color override array. Same length as `series`. None entries fall back to `color`. HISTOGRAM/COLUMNS/CROSS/CIRCLES only.
- `align` (`str`, default `None`): `pinned_top`, `pinned_bottom`, `pinned_left`, `pinned_right`, `left_of_range`, `right_of_range`, or `over_range`. HISTOGRAM/COLUMNS/AREA only.
- `width_px` (`int`, default `60`): CSS pixels for the pinned region. Strip width for `pinned_left`/`pinned_right`; strip thickness for `pinned_top`/`pinned_bottom`.

### Returns

None

### Example

```python
sma = close.rolling(20).mean()
plot(sma, "SMA(20)", color="#2962FF", linewidth=2)

# Per-bar histogram coloring: yellow on big trades, gray otherwise
import numpy as np
big = volume > volume.rolling(50).mean() * 3
colors = np.where(big, "#e0af68", "#3a3a45").tolist()
plot(volume, "Volume", color="#3a3a45", plot_type=PlotType.HISTOGRAM, colors=colors)
```

### Notes

- `colors=` is the per-bar override. Pass a list of hex strings or `None` (None falls back to `color`).
- Convenience helpers: `plot_histogram_colored`, `plot_columns_colored`, `plot_cross_colored`, `plot_circles_colored`.
- Mismatched length between `colors` and `series` raises `ValueError`.
- `plot()` has no `style` or `linestyle` parameter (this is not Pine Script). Use `plot_type` for line shape; `linestyle` exists only on `hline`. Passing `style=` or `linestyle=` to `plot()` raises a `TypeError`.

<a id="plot_histogram_colored"></a>
## plot_histogram_colored

```python
plot_histogram_colored(series, name, base_color, colors)
```

Histogram with per-bar color overrides.

Convenience wrapper for `plot(..., plot_type=HISTOGRAM, colors=...)`. Same shape as the Rust `plot_histogram_colored` builder.

### Parameters

- `series` (`Series`, default `required`): Values to plot
- `name` (`str`, default `required`): Legend label
- `base_color` (`str`, default `required`): Fallback color for bars where `colors[i]` is None
- `colors` (`list[str | None]`, default `required`): Per-bar color overrides

### Returns

None

### Example

```python
from quant_charts import plot_histogram_colored
colors = ["#e0af68" if x > thresh else None for x in trade_size]
plot_histogram_colored(trade_size, "Trade Size", "#3a3a45", colors)
```

<a id="hline"></a>
## hline

```python
hline(value, name, color?, linewidth?, linestyle?)
```

Draw a horizontal reference line at a fixed value.

Draws a horizontal line at a constant Y-axis value. Common for overbought/oversold levels in oscillators.

### Parameters

- `value` (`float`, default `required`): Y-axis value
- `name` (`str`, default `required`): Legend label
- `color` (`str`, default `"#787B86"`): Hex color string
- `linewidth` (`int`, default `1`): Line thickness in pixels
- `linestyle` (`str`, default `"solid"`): `"solid"`, `"dashed"`, or `"dotted"`

### Returns

None

### Example

```python
hline(70, "Overbought", color="#EF5350", linestyle="dashed")
hline(30, "Oversold", color="#26A69A", linestyle="dashed")
```

<a id="fill"></a>
## fill

```python
fill(series1_name, series2_name, color?, opacity?)
```

Fill the area between two plotted series.

Fills the space between two previously plotted series. Both must have been drawn with `plot()` first, referenced by their `name` string.

### Parameters

- `series1_name` (`str`, default `required`): Name of the first `plot()` series
- `series2_name` (`str`, default `required`): Name of the second `plot()` series
- `color` (`str`, default `"#2962FF"`): Fill color as hex string
- `opacity` (`int`, default `10`): Fill opacity 0-100

### Returns

None

### Example

```python
plot(upper, "Upper", color="#2962FF")
plot(lower, "Lower", color="#2962FF")
fill("Upper", "Lower", color="#2962FF", opacity=10)
```

<a id="vp_visual"></a>
## vp_visual

```python
vp_visual(anchor_ts, end_ts, price_min, price_step, bins, poc_price, vah, val, ...)
```

Emit a horizontal volume profile histogram (POC + value area).

Pure-Python parity with the Rust `push_vp_visual(...)` builder. The renderer draws bars at each price row, an accent line at the Point of Control, and the Value Area High / Low as a translucent zone.

`anchor_ts` and `end_ts` are Unix milliseconds (the executor converts to seconds for Lightweight Charts). `bins[i]` is the volume in the price row starting at `price_min + i * price_step`. `align` defaults to `right_of_range`; pass `pinned_right` to glue to the chart edge regardless of pan.

Progressive trails (`poc_trail`, `value_area_trail`) draw a moving POC/VA line across each session anchor instead of a single static profile.

### Parameters

- `anchor_ts` (`int`, default `required`): Anchor timestamp (Unix ms). Where the histogram baseline starts.
- `end_ts` (`int`, default `required`): End timestamp (Unix ms).
- `price_min` (`float`, default `required`): Lower edge of the lowest bin.
- `price_step` (`float`, default `required`): Row height in price units. Must be > 0.
- `bins` (`list[float]`, default `required`): Volume per row, length = number of rows.
- `poc_price` (`float`, default `required`): Point of Control (highest-volume row center).
- `vah` (`float`, default `required`): Value Area High.
- `val` (`float`, default `required`): Value Area Low.
- `color` (`str`, default `"#7aa2f7"`): Bar color (overridden per-bin by `bin_colors[i]`).
- `poc_color` (`str`, default `"#e0af68"`): POC accent line color.
- `value_area_color` (`str`, default `"#73daca"`): Value-area zone color.
- `opacity` (`int`, default `60`): Bar opacity 0-100.
- `width_px` (`int`, default `80`): Histogram width in CSS pixels.
- `align` (`str`, default `"right_of_range"`): `right_of_range`, `left_of_range`, `over_range`, `pinned_right`, `pinned_left`, `pinned_top`, `pinned_bottom`.
- `style` (`str`, default `"bars"`): `bars`, `line`, or `area`.
- `bin_colors` (`list[str | None]`, default `None`): Per-row color override (same length as `bins`).
- `hvn_levels` (`list[float]`, default `None`): High-volume node prices (drawn as bright lines).
- `lvn_levels` (`list[float]`, default `None`): Low-volume node prices.
- `poc_trail` (`list[dict]`, default `None`): List of `{ts: ms, price: float}` for a moving POC line.
- `value_area_trail` (`list[dict]`, default `None`): List of `{ts: ms, vah: float, val: float}` for VA bands.
- `draw_level_lines` (`bool`, default `True`): Draw POC/VAH/VAL horizontal lines across the range.

### Returns

None

### Example

```python
from quant_charts import vp_visual
import numpy as np

# bin all session ticks into 0.25 price rows
bins = np.histogram(typical, range=(lo, hi), bins=int((hi-lo)/0.25))[0]
poc_idx = int(np.argmax(bins))
poc_price = lo + (poc_idx + 0.5) * 0.25

vp_visual(
    anchor_ts=int(ts[0]), end_ts=int(ts[-1]),
    price_min=lo, price_step=0.25,
    bins=bins.tolist(),
    poc_price=poc_price, vah=poc_price + 4.0, val=poc_price - 4.0,
    width_px=80, opacity=55,
    align="right_of_range",
)
```

### Notes

- Timestamps are Unix MILLISECONDS; the executor converts to seconds.
- `opacity` is rejected if outside 0-100. NaN/Inf in any price field is rejected.
- `align` validates against the five known values; unknown strings raise.
- Calling `vp_visual()` multiple times in one calculate() emits multiple histograms (one per anchor).
