This codepen has a minimal repro of my attempt to color the interpolated surface formed by 3d scatterplot: https://codepen.io/salazarm/pen/jOWprBj
const colorScale = [
['0', 'rgb(0,0,134)'],
['0.25', 'rgb(144, 252, 227)'],
['0.5', 'rgb(170, 255, 137)'],
['0.6', 'rgb(252, 242, 57)'],
['0.72', 'rgb(232, 162, 38)'],
['1.0', 'rgb(255,0,0)']
]
const rows = [40, 60, 80, 100, 120, 140, 160, 180, 190, 200, 210, 220, 230, 240, 250, 260, 270, 280, 290, 300, 320, 340, 360, 400, 440, 480, 520, 560, 600, 640, 680, 720, 760, 800, 840, 880]
const columns = [0.052739649650399546, 0.12945197841527142, 0.2061643071803019, 0.4554793756714548, 0.7047944441625761]
const values = [[null, null, null, 113.806298215936, null], [null, null, 103.900929577649, 103.394281813932, null], [135.34303782888, null, 103.900929577649, 96.4973275646427, null], [108.288007618313, null, 96.9374808519993, 88.4701807557266, null], [104.806931150651, null, 89.5941932328483, 81.0825414680379, null], [104.262156815898, null, 79.1466980571445, 77.981025578435, 80.0538058935848], [89.6207952967281, 76.567630405239, 73.6338682016538, 75.5243937833531, 78.1929983961292], [78.6892837901259, 69.2653363438868, 69.5817969484183, 74.111832337461, 77.6079458081274], [71.293351459305, 65.8569996458742, 68.0180909105966, 73.5734063243125, 77.5322852147224], [65.316047859924, 62.9838274346249, 67.0338854156817, 73.163493152822, 77.5147957849701], [59.6157671081532, 60.8971725567913, 66.6950117095839, 72.9733237849779, 77.5166924729988], [55.1465270015558, 59.7339264506726, 66.6759894665981, 72.9064986987144, 77.5147957849701], [52.6725276546741, 59.4912189277008, 66.6499758394995, 72.8618164884652, 77.5013633559977], [52.2188230062308, 59.721594700194, 66.6759894665981, 72.9064986987144, 77.5147957849701], [53.02866259277, 60.027680355529, 66.8842775134721, 73.107512411912, 77.5893277994543], [56.4295083378783, 60.6570150804307, 67.3041397692378, 73.3623839123188, 77.6963876779564], [59.9360968033528, 61.8925547790689, 67.9398636688808, 73.5710625126337, 77.8237117578229], [63.6186218043185, 63.514009626044, 68.7966346073292, 73.812630437495, 78.0870750608216], [67.6258116769059, 65.2426087397014, 69.8548427173008, 74.161369209824, 78.5620296691413], [72.006223225742, 67.068902742936, 70.9947991227318, 74.4932246337334, 79.0351972222315], [79.5551153843496, 71.0841035058806, 73.197205726249, 74.9114996023901, 79.4670910856406], [86.4307015102761, 75.2126803652063, 75.4671545770312, 75.8159276839487, 79.9092718210033], [92.5723194923175, null, 77.8862376081645, 77.0097238990493, 80.2613632791949], [null, null, 82.9364788630799, 78.9515920825482, 81.1207508800967], [null, null, 87.2205084420847, 80.6484118067602, 82.0448991846857], [null, null, 90.7719613032328, 82.2187731625783, 82.5748468616411], [null, null, 94.2510493862921, 84.0224223301196, 83.7975850079844], [null, null, 96.9608162058347, 85.9512358715619, 85.2001342699325], [null, null, 99.7323836131293, 87.7804051319916, 85.9969166858732], [null, null, 101.615505349713, 89.439360691515, 86.4768217400097], [null, null, 104.207611221204, 90.9224637411827, 87.197355777999], [null, null, 104.988811665223, 92.3295586808031, 88.7160251454981], [null, null, 106.48007083975, 93.786860712374, null], [null, null, 107.865511408241, 95.4205850378931, null], [null, null, 111.099384393054, null, null], [null, null, 111.854356575734, null, null]]
const fValues = flatten(values);
const valuesNoNan = fValues.filter(val => !isNaN(val))
const min = Math.min(...valuesNoNan)
const max = Math.max(...valuesNoNan)
const diff = max - min;
const colors = fValues.map(v => (v - min) / diff);
const chart = [{
type: 'scatter3d',
mode: 'markers',
surfaceaxis: 2,
colorScale: colorScale,
marker: {
color: colors,
cMin: min,
cMax: max,
size: 5,
symbol: 'circle',
opacity: 0.8
},
connectgaps: true,
x: flatten(values.map((row, rowIndex) => row.map(() => rows[rowIndex]))),
y: flatten(values.map((row) => row.map((_, colIndex) => columns[colIndex]))),
z: fValues,
}];
const layout = {
title: 'Implied Volatility',
autosize: true,
width: 980,
height: 980,
margin: {
l: 65,
r: 50,
b: 65,
t: 90,
},
scene: {
aspectratio: { x: 1, y: 1, z: 1 }
},
xaxis: {
title: {
text: 'Strike Price',
font: {
family: 'Courier New, monospace',
size: 18,
color: '#7f7f7f'
}
},
},
yaxis: {
title: {
text: 'Time To Expiration',
font: {
family: 'Courier New, monospace',
size: 18,
color: '#7f7f7f'
}
}
}
};
Plotly.plot('graph', chart, layout);
function flatten(array) {
const result = [];
$flatten(array, result);
return result;
}
/**
* Internal flatten function recursively passes `result`.
*/
function $flatten(array, result) {
for (let i = 0; i < array.length; i++) {
const value = array[i];
if (Array.isArray(value)) {
$flatten(value, result);
} else {
result.push(value);
}
}
}
I've tried a couple of different things and have been googling around even reading the source code but I can't seem to figure out how to color the surface and points according to my color scale.
It looks Plotly doesn't support color the surface when its being drawn due to
surfaceaxis
being set on ascatter3d
plot: https://codepen.io/salazarm/pen/jOWprBjInstead what I did was 2 separate plots, a Surface and a scatter3d.