domitry / elegans

Elegant 3D plots generator with WebGL.
http://elegans.readthedocs.org/
Other
59 stars 20 forks source link

stage.dispose() and stage.clear() does not remove charts #14

Closed kpykc closed 8 years ago

kpykc commented 8 years ago

Hi,

I'm trying to use your library for visualisation in a Jupyter notebook (the code is below) .

I'm encountering following problem, when i'm sending new data to js and do stage.clear(); and stage.dispose();

this does not clear charts in fact, moreover second update of data (in this fashion) leads to 2 point sets but 3 labels (e.g. particles1, particles1, particles2).

It would be also nice to have a way to reuse THREEjs WebGL context, by e.g. specifying scene argument to stage.render (https://stackoverflow.com/questions/21548247/clean-up-threejs-webgl-contexts).

Though, Eleganse was not designed for a purpose I want to use it probably.

%%javascript

require.config({
    paths: {
        "THREE": 'http://localhost:8888/notebooks/Notebooks/_haptics/static/three.min',
        "Elegans": "http://localhost:8888/notebooks/Notebooks/_haptics/static/elegans.min",
        "d3": "http://localhost:8888/notebooks/Notebooks/_haptics/static/d3.min",
    },
    shim: {
        "THREE": {exports: "THREE"},
        "d3": {exports: "d3"},
        "Elegans": {deps: ["THREE"], exports: "Elegans"}
    },
});

    require(["d3", "THREE"], function(d3){
      window["d3"] = d3;
               d3.select(document)
        .on("contextmenu", function(){
        d3.selectAll("canvas").style("z-index", 10);
        d3.selectAll(".download_menu").style("z-index", 100);
      });
    });

var particles;
var stage;
element.append("<div id='vis'></div>");

require(['Elegans'], function(){

    //var line_data = {x:[],y:[],z:[]};
    var particles_data = {x:[],y:[],z:[]};

    stage = new Elegans.Stage(d3.select("#vis")[0][0]);
    var idx = 1;
    var comm_manager=Jupyter.notebook.kernel.comm_manager
    var handle_msg=function(msg){
        console.log('got msg');

        var data = JSON.parse(msg.content.data);
        stage.clear();
        stage.dispose();

        //stage.charts = []
        console.log("Data loaded");
        //var dataLoaded = 1;
        var particles_data = {x:[],y:[],z:[]};

        particles_data.x = Object.keys(data['x']).map(function(k){return data['x'][k];});
        particles_data.y = Object.keys(data['y']).map(function(k){return data['y'][k];});
        particles_data.z = Object.keys(data['z']).map(function(k){return data['z'][k];});
        data = [];
        particles = [];
        var markerColor = new THREE.Color();
        markerColor.setHSL( Math.random(), 1.0, 0.5 )
        particles = new Elegans.Particles(particles_data, {
             name: "particles"+idx,
             size: 0.1,
             color: '#'+markerColor.getHexString(),
             has_legend: true
        });
     stage.add(particles); 
     //stage.add(line);
     stage.render();
     idx += 1;
    }

    comm_manager.register_target('myTarget', function(comm,msg){
        console.log('opened comm');
        console.log(msg);
        // register callback
        comm.on_msg(handle_msg)
    })

});

P.S. BTW, THREE.js suggests to

THREE.PlaneGeometry: Consider using THREE.PlaneBufferGeometry for lower memory footprint.

Thank you for a nice library!

domitry commented 8 years ago

Yeah, maybe the design of Elegans is not suitable with the interaction using Comm API. But a hack shown below will help you.

<html lang="en">
  <head>
    <title>Plot Sample - Particles</title>
    <link rel='stylesheet' href='common.css'>
    <script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/three.js/r71/three.min.js"></script>
    <script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/d3/3.4.4/d3.min.js"></script>
    <script type="text/javascript" src="../release/elegans.js"></script>
    <script src="http://cdn.rawgit.com/mrdoob/three.js/r49/examples/js/ImprovedNoise.js"></script>
    <script type="text/javascript">
     window.onload = function(){
       var stage = new Elegans.Stage(d3.select("#vis")[0][0], {
         save_image: true
       });

       var MAX=10, DATA_NUM=3, INTERVAL_MIN=0.5, INTERVAL_MAX=3, X_NUM=10, Y_NUM=10;
       var color_scale = d3.scale.category20();
       for(var n=0;n < DATA_NUM;n++){
         var x_arr = [], y_arr = [], z_arr = [];
         var point = {x:Math.random()*MAX,y:Math.random()*MAX};
         var noise = ImprovedNoise();
         for(var i=0;i < X_NUM;i++){
           point.x = point.x + Math.random()*(INTERVAL_MAX - INTERVAL_MIN) + INTERVAL_MIN;
           for(var j=0;j < Y_NUM;j++){
             point.y = point.y + Math.random()*(INTERVAL_MAX - INTERVAL_MIN) + INTERVAL_MIN;
             point.z = noise.noise(point.x,point.y,0);
             x_arr.push(point.x);
             y_arr.push(point.y);
             z_arr.push(point.z);
           }
         }
         var data = {x:x_arr, y:y_arr, z:z_arr};
         var color = color_scale(n);
         stage.add(new Elegans.Particles(data, {color: color, name: "molecule"+String(n)}));
       }
       stage.render();
       /**  Remove legend, meshes in the stage and chart objects **/
       stage.legend_space.selectAll("div").remove();
       stage.clear();
       stage.charts = [];
       /** Add charts again **/
       stage.add(new Elegans.Particles({x: [1,2,3], y: [2,3,4], z: [1,1,1,]}, {color: "#000", name: "molecule"}));
       stage.render();
     };
    </script>
  </head>
  <body>
    <div id="vis">
    </div>
  </body>
</html>

Three lines below are the essential part.

/**  Remove legend, meshes in the stage and chart objects **/
stage.legend_space.selectAll("div").remove();
stage.clear();
stage.charts = [];

I cannot modify stage.clear because components/player depends on it but If you have an idea feel free to send pull-request :~)

kpykc commented 8 years ago

Thanks this solves the question partially. My javascript experience is about month or two, so it will take some time before pull requests, but i'll remember about this proposition :).

Should I close this issue?

domitry commented 8 years ago

Yes please, add another issue if the second problem about the reuse of WebGL context is important for you.