Pine Script plot() Options: Color, Style, Linewidth and More
March 17, 2026
The plot() function is the primary way to display data on a TradingView chart in Pine Script. Every indicator that draws a line, area, histogram, or set of dots uses plot() or its siblings. Understanding the full range of parameters — especially conditional coloring, transparency, the 9 plot styles, and the difference between plot(), plotshape(), and plotchar() — will unlock every visual pattern you'll want to build.
1. Basic plot() Syntax
//@version=5
indicator("Plot Demo", overlay=true)
ema9 = ta.ema(close, 9)
ema21 = ta.ema(close, 21)
// Minimal call
plot(ema9)
// Full parameter reference
plot(
series = ema9, // any numeric series (required)
title = "Fast EMA", // name in legend and data window
color = color.blue, // line color
linewidth = 2, // 1–4 pixels
style = plot.style_line // see all styles below
)
2. Color — Solid, Transparent, and Conditional
//@version=5
indicator("Color Demo", overlay=true)
ema = ta.ema(close, 20)
rsi = ta.rsi(close, 14)
// Solid color
plot(ema, color=color.blue)
// color.new() adds transparency (0=opaque, 100=invisible)
plot(ema, color=color.new(color.blue, 60)) // 60% transparent
// Conditional color: ternary operator
bullColor = color.new(color.green, 0)
bearColor = color.new(color.red, 0)
plot(ema, color = close > ema ? bullColor : bearColor)
// More complex: based on RSI level
emaColor = rsi > 70 ? color.red : rsi < 30 ? color.lime : color.gray
plot(ema, color=emaColor, linewidth=2)
// Color from input (user-selectable)
lineColor = input.color(color.blue, "Line Color")
plot(ema, color=lineColor)
3. All 9 plot.style_ Constants
//@version=5
indicator("All Styles", overlay=false)
val = ta.ema(close, 20) - ta.sma(close, 20)
plot(val, style=plot.style_line) // standard line
plot(val, style=plot.style_stepline) // staircase / stepped line
plot(val, style=plot.style_area) // line + fill to zero
plot(val, style=plot.style_areabr) // area that breaks on na values
plot(val, style=plot.style_columns) // vertical columns from zero (like volume bars)
plot(val, style=plot.style_histogram) // histogram bars
plot(val, style=plot.style_circles) // dot at each bar close
plot(val, style=plot.style_cross) // cross marker at each bar
plot(val, style=plot.style_linebr) // line that breaks on na (gaps where no data)
4. linewidth, offset, and display
ema = ta.ema(close, 20)
// linewidth: 1 to 4 (integers only)
plot(ema, linewidth=3)
// offset: shift plot left (negative) or right (positive) bars
plot(ema, offset=-5) // shift 5 bars to the left (forward-looking — use carefully)
// display: control where the plot appears
plot(ema, display=display.all) // show everywhere (default)
plot(ema, display=display.none) // hide the plot (useful for internal calculations)
plot(ema, display=display.pane) // show only in the pane, not in data window
plot(ema, display=display.data_window) // show only in data window hover tooltip
// show_last: only plot the most recent N bars
plot(ema, show_last=100) // only show last 100 bars
// trackprice: horizontal price line at current value
plot(ema, trackprice=true, show_last=1) // current EMA price line across chart
5. Handling na Values
//@version=5
indicator("NA Handling", overlay=true)
// plot() automatically skips na values (no crash, just a gap in the line)
// This is safe — use na to conditionally show/hide a plot
signalVal = ta.crossover(ta.ema(close, 9), ta.ema(close, 21)) ? close : na
plot(signalVal, style=plot.style_circles, color=color.lime, linewidth=5)
// style_linebr vs style_line: linebr shows a gap at na values
// style_line connects across na points (usually undesirable for sparse data)
// style_linebr shows actual data gaps
// Force a value when na (fill forward)
val = ta.ema(close, 20)
safeVal = na(val) ? nz(val, close) : val // nz() replaces na with a default
6. plotshape() and plotchar()
//@version=5
indicator("Shapes and Chars", overlay=true)
buySignal = ta.crossover(ta.ema(close, 9), ta.ema(close, 21))
sellSignal = ta.crossunder(ta.ema(close, 9), ta.ema(close, 21))
// plotshape(): draw a shape at signal bars
plotshape(buySignal, title="Buy", style=shape.triangleup, location=location.belowbar, color=color.lime, size=size.small)
plotshape(sellSignal, title="Sell", style=shape.triangledown, location=location.abovebar, color=color.red, size=size.small)
// plotchar(): draw a text character at signal bars
plotchar(buySignal, "Buy Char", "▲", location.belowbar, color.lime, size=size.tiny)
plotchar(sellSignal, "Sell Char", "▼", location.abovebar, color.red, size=size.tiny)
// Shapes available: shape.circle, shape.square, shape.diamond,
// shape.triangleup, shape.triangledown, shape.arrowup, shape.arrowdown,
// shape.labelup, shape.labeldown, shape.xcross, shape.cross, shape.flag
7. overlay=true vs Separate Pane
//@version=5
// overlay=true: indicator draws ON the price chart
indicator("On Chart", overlay=true)
plot(ta.ema(close, 20)) // draws on the candlestick chart
//@version=5
// overlay=false (default): indicator draws in a SEPARATE pane below
indicator("Oscillator", overlay=false)
rsi = ta.rsi(close, 14)
plot(rsi, "RSI")
hline(70, "Overbought", color.red)
hline(30, "Oversold", color.green)
For strategies that use these visual indicators to trigger entries, see the Pine Script strategy.entry guide. To add alert conditions to your indicator plots, see the Pine Script alerts guide.
Summary
plot(series, title, color, linewidth, style) is the core call. Use color.new(color.blue, 50) for transparency, ternary expressions for conditional colors, and plot.style_histogram or plot.style_columns for bar-based visuals. Use plotshape() for signal markers above/below bars and plot.style_linebr to show gaps where data is missing. Set overlay=true in indicator() to draw on the price pane.