Plotly.js 带 mesh3d 的球体

Plotly.js sphere with mesh3d

我正在尝试用 plotly.js 绘制一个简单的球体。然而,当使用 mesh3d 选项时,球体的图看起来非常粗糙和不精致​​。任何有关如何平滑它的建议将不胜感激。

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>

最简单的解决方案是绘制两个半球:

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>

来自@Josef Wittmann 的重要来源,这是一个可以复制到您的代码中的函数:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
  <meta name="generator" content="PSPad editor, www.pspad.com">
  <title></title>
 
  </head>
  <body>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
  <script>

/////////////////////
function getSphereData(name, width, height, color, opacity) {

    var layout = {
        title: name,
        autosize: false,
        width: width,
        height: height,
        margin: {
            l: 65,
            r: 50,
            b: 65,
            t: 90,
        }
    };

    
    a = [];
    b = [];
    c = [];
    
    var phiArr = [];
    var thetaArr = [];
    var numPoints = 20;
    
    var startValue = 0;
    var stopValuePhi = Math.PI/2;
    var stopValueTheta = 2*Math.PI;
    var stepPhi = stopValuePhi / (numPoints - 1);
    var stepTheta = stopValueTheta / (numPoints - 1);
    for (var i = 0; i < numPoints; i++) {
      phiArr.push(stepPhi * i);
      thetaArr.push(stepTheta * i);
    }

    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: opacity,
        color: 'rgb(211,211,211)',
        type: 'mesh3d',
        x: a,
        y: b,
        z: c,
    }   
        

    // 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)}
    ];
    
    return {data:data, layout:layout};
}
////////////////////    

// Example usage:
window.onload = function () {
    var sphere = getSphereData("Sphere", 600,600, 0.3, 'rgb(211,211,211)');
    Plotly.newPlot('myDiv',  sphere.data, sphere.layout);  
}
  </script>
  
  
    <div id="myDiv" name="myDiv"></div>
  </body>
</html>

JSFiddle: https://jsfiddle.net/spacexplorer2020/wceo7hmn/