Search code examples
javascriptplotlyplotly.js

Plotly.js sphere with mesh3d


I'm trying to plot a simple sphere with plotly.js. However when using the mesh3d option the plot of the sphere comes out looking very rough and unrefined. Any advice on how to smooth it out would be appreciated.

a = [];
b = [];
c = [];

phiArr = [];
thetaArr = [];
function makeInterval(startValue, stopValue, numPoints) {
    var arr = [];
    var step = (stopValue - startValue) / (numPoints - 1);
    for (var i = 0; i < numPoints; i++) {
      arr.push(startValue + (step * i));
    }
    return arr;
  }
phiArr = makeInterval(0, Math.PI, 20);
thetaArr = makeInterval(0, 2*Math.PI, 20); 

for (i=0; i<thetaArr.length; i++){
    for (j=0; j<phiArr.length; j++){
        a.push(Math.cos(thetaArr[i]) * Math.sin(phiArr[j]));
        b.push(Math.sin(thetaArr[i]) * Math.sin(phiArr[j]));   
        c.push(Math.cos(phiArr[j]));
    }
}

var data = [{
    opacity: 0.2,
    color: 'rgb(211,211,211)',
    type: 'mesh3d',
    x: a,
    y: b,
    z: c,
}];


var layout = {
    title: 'My Sphere',
    autosize: false,
    width: 600,
    height: 600,
    margin: {
        l: 65,
        r: 50,
        b: 65,
        t: 90,
    }
};
Plotly.newPlot('myDiv', data, layout);
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<div id="myDiv"></div>

Wrong sphere


Solution

  • The simplest solution draws two semispheres:

    a = [];
    b = [];
    c = [];
    
    phiArr = [];
    thetaArr = [];
    function makeInterval(startValue, stopValue, numPoints) {
        var arr = [];
        var step = (stopValue - startValue) / (numPoints - 1);
        for (var i = 0; i < numPoints; i++) {
          arr.push(startValue + (step * i));
        }
        return arr;
      }
    
    ////////////////
    // EDIT 1: calculate only upper half of the sphere
    
    phiArr = makeInterval(0, Math.PI/2, 20);  
    ///////////////
    thetaArr = makeInterval(0, 2*Math.PI, 20); 
    
    for (i=0; i<thetaArr.length; i++){
        for (j=0; j<phiArr.length; j++){
            a.push(Math.cos(thetaArr[i]) * Math.sin(phiArr[j]));
            b.push(Math.sin(thetaArr[i]) * Math.sin(phiArr[j]));   
            c.push(Math.cos(phiArr[j]));
        }
    }
    
    const dataitem = {
        opacity: 0.2,
        color: 'rgb(211,211,211)',
        type: 'mesh3d',
        x: a,
        y: b,
        z: c,
    }
    
    //////////////////////
    // EDIT 2: obtain the second half of the sphere by duplicating 
    // the upper semisphere ("..." operator before "dataitem") and 
    // changing its "z" attribute into negative vales:
    
    var data = [
        dataitem,
        {...dataitem, z: c.map(v => -v)}
    ];
    //////////////////////
    
    var layout = {
        title: 'My Sphere',
        autosize: false,
        width: 600,
        height: 600,
        margin: {
            l: 65,
            r: 50,
            b: 65,
            t: 90,
        }
    };
    Plotly.newPlot('myDiv', data, layout);
    <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
    <div id="myDiv"></div>

    God sphere