Pine Script plot() Options: Color, Style, Linewidth and More

March 17, 2026

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.

style_line style_area style_histogram style_stepline
Four of the nine plot() style options: line, area, histogram (with conditional color), and stepline

1. Basic plot() Syntax

pine
//@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

pine
//@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.