Guides

Performance & Large Images

A picture's cost follows its boundaries and its colours, not its cell count. This page covers what to reduce first, how to stay inside Pine's time limits, and how the million-cell demos are put together.

Updated Publisher Alien_AlgorithmsPine Script v6

What costs time

DriverWhy it matters
Boundary lengthEvery corner of every region becomes a polyline point. Fragmented, noisy pictures have long boundaries.
Number of regionsEach separate region is traced and linked. Thousands of single-cell speckles cost more than a few large shapes.
Colour levelsEach visible level needs its own polylines, and more levels split regions into smaller ones.
Opaque areaTransparent cells are skipped. Opaque cells have to be scanned, grouped, and joined.
Your own loopsFilling the source is the script's work. It is often the larger share.

Resolution on its own is cheap. A smooth image of a million cells can be lighter than a noisy one of fifty thousand.

Tuning order

  • Lower the colour levels: try 32 or fewer before changing anything else.
  • Add a transparent floor: write na or -1 for cells that carry no information.
  • Smooth the data: averaging neighbouring cells turns speckle into regions.
  • Redraw less often: render on closed bars instead of every tick.
  • Reduce the grid: fewer rows or columns, last, because it costs the most detail.

Unchanged frames are nearly free

PineCanvas caches its contour work. When the source, the style, and the placement are unchanged, a draw call skips replacing the drawings. When only part of a picture changed, cached geometry for the rest is reused. A script that redraws on every tick therefore pays for a full render only when the picture actually differs.

The loop time limit

Pine stops a script when a single loop runs for more than 500 milliseconds on one bar. The limit applies to each outermost loop separately, not to the bar as a whole. That shapes how heavy work should be arranged:

  • Several shorter loops in sequence are safer than one long loop.
  • A loop that wraps other heavy calls puts all of their work under one limit. Call them one after another instead.
  • Keep each loop well below the limit. A loop that usually takes 300 milliseconds will sometimes overrun on a busy server.

PineCanvas already splits its own heavy passes into shorter loops. The same applies to the loops that fill your source.

Spread work across bars

A script runs once on every historical bar while the chart loads. A large picture can be produced a slice at a time on those bars, then drawn once on the last one.

One row per bar, one render at the endpine
// ROWS, COLUMNS, colours and paletteIndexAt() are the script's own
var pc.PaletteField picture = pc.paletteField(ROWS, COLUMNS)
var pc.Canvas canvas = pc.newCanvas(colours)
var bool rendered = false

// The first bar that writes a row, so the last row lands just before the end
bool enoughBars = last_bar_index > math.max(ROWS, COLUMNS) + 1
int firstRowBar = last_bar_index - ROWS - 1
int step = bar_index - firstRowBar

// One row of the picture on each bar
if enoughBars and step >= 0 and step < ROWS
    array<int> target = picture.row(step)
    for column = 0 to COLUMNS - 1
        target.set(column, paletteIndexAt(step, column))

// One render, when the chart has finished loading
if barstate.islastconfirmedhistory and enoughBars and step >= ROWS and not rendered
    canvas.drawLookback(picture, 0, 0.0, float(ROWS))
    rendered := true
  • The picture is written through row(), which hands back the field's own storage for that row.
  • The render waits for barstate.islastconfirmedhistory, so it runs once when loading finishes.
  • The chart must have more bars than the picture has rows to write and columns to place.

Toward a million cells

What happens automatically

Above 100,000 cells a source moves to the large renderer. It processes the picture in tiles, stores its data in bands, and caches each tile's geometry. Nothing in the calling script changes.

Strips on separate canvases

The published 1344 × 804 Julia fractal is split into vertical strips. Each strip is its own palette field, drawn by its own Canvas beside the previous one with draw(), and each Canvas is given a share of the 100 polylines through drawingLimit().

  • Each strip's render is a separate piece of work under the loop limit.
  • The strips are rendered by separate calls, not from inside a loop, for the same reason.
  • Each strip is offered an even share of the polylines still free, so the last strip is not starved.

Few colours

The same fractal uses 13 colour levels. A level count that low is what lets a million cells fit in 100 polylines.

Smooth backgrounds

In the large renderer, neighbouring tiles are joined wherever cells of the same colour meet across a tile border. A smooth, fully opaque background makes that happen at nearly every border cell, and the cost then grows with the picture's area.

Keep the detailed layer transparent
Leave the high-resolution layer's background at -1and draw the backdrop on a second, much coarser Canvas underneath. The library's cover scene draws its nebula on a 320 × 180 field and only the black hole at full resolution.

Memory

  • A field of a million cells is a million array elements. Scripts have a memory limit as well as a time limit.
  • For a picture that is rendered once, set the field variable to na after drawing so its storage can be released. The polylines stay on the chart.
  • Render large layers one after another, not in the same moment, so their working storage is never held together.

Measure it

What the last render producedpine
plot(float(canvas.componentCount()), "Regions", display = display.data_window)
plot(float(canvas.drawingCount()), "Polylines", display = display.data_window)

A high region count for the picture's size points at fragmentation. A polyline count near the Canvas's limit points at too many colours or too much boundary. The Pine Profiler shows whether the time goes into your own loops or into the render. Common Pitfalls lists the errors a render can raise.

PineCanvas is a graphics library for Pine Script. TradingView drawing, memory, and execution limits still apply. © Alien_Algorithms.