Contour Surfaces
Turn a matrix into a dense, colored 3D heightmap using contour bands, stitched disjoint paths, cached geometry, and in-place data updates.
Contour band rendering
Naive triangle drawing exhausts TradingView’s 100-polyline limit quickly. Pine3D quantizes elevation into colored bands, groups all cells from a band, and stitches disconnected islands into one hole-aware path using invisible bridges.
- One band path can carry many disconnected triangle-equivalent regions.
- Band paths are depth-sorted and near-plane culled.
- Contour geometry is cached between data changes.
- Large heightmaps can fit within the fixed polyline budget.
Create a surface
//@version=6
indicator("Pine3D Contour Surface", overlay = false,
max_polylines_count = 100, max_lines_count = 500, max_labels_count = 500)
import Alien_Algorithms/Pine3D/1 as p3d
var p3d.Scene scene = p3d.newScene()
var p3d.Mesh heatmap = na
if barstate.isfirst
int N = 20
matrix<float> data = matrix.new<float>(N, N, 0.0)
for r = 0 to N - 1
for c = 0 to N - 1
float dx = c - (N - 1) / 2.0
float dz = r - (N - 1) / 2.0
float d = math.sqrt(dx * dx + dz * dz) * 0.7
data.set(r, c, math.cos(d) * math.exp(-d * 0.12) * 50.0)
heatmap := p3d.surface(data, 200.0, color.blue, color.red, 24)
.gridBox()
.gridLabels(color.white, "X", "Amplitude", "Z")
scene.add(heatmap)
scene.camera.orbit(35.0, 25.0, 380.0)
if barstate.islast
p3d.render(scene, lighting = true)surface(heights, size, lowCol, highCol, levels, axisX, axisZ) reads a matrix<float>, maps values to vertical position, and grades color from low to high.
Grid cage and labels
.gridBox()adds a wireframe bounding cage..gridLabels(color, xName, yName, zName)adds axis titles and tick values.- Tick labels refresh when the data range changes.
Non-uniform grids
Optional axisX and axisZ arrays provide explicit column and row coordinates. This supports irregular timestamps, logarithmic strike spacing, or other non-uniform domains without resampling.
Update data in place
if barstate.islast
heatmap.updateSurface(newDataMatrix)
p3d.render(scene, lighting = true)updateSurface() on the last bar.Budget guidance
- Reduce contour levels before reducing matrix resolution.
- Use the linefill backend for in-place updates.
- Lower occlusion resolution for faster dense-scene rendering.
- Do not rebuild labels or cages every frame.
- Use
scene.totalFaces()and drawing monitor tables while profiling.
Common uses
Volatility surfaces, parameter sensitivity maps, depth heatmaps, correlation landscapes, optimization objectives, and any matrix-valued market feature.