vasturiano / 3d-force-graph

3D force-directed graph component using ThreeJS/WebGL
https://vasturiano.github.io/3d-force-graph/example/large-graph/
MIT License
4.66k stars 821 forks source link

How to map an icon to a node #408

Open jaygray0919 opened 3 years ago

jaygray0919 commented 3 years ago

We have successfully constructed a force directed graph.

Our question: is there a method to assign an image to a specific node?

For example, we like this: https://vasturiano.github.io/3d-force-graph/example/custom-node-geometry/

and would like to adapt this structure:

  .nodeThreeObject(({ id }) => new THREE.Mesh(
    [
      new THREE.BoxGeometry(Math.random() * 20, Math.random() * 20, Math.random() * 20),
      new THREE.ConeGeometry(Math.random() * 10, Math.random() * 20),
      new THREE.TorusKnotGeometry(Math.random() * 10, Math.random() * 2)
    ][id%7],
    new THREE.MeshLambertMaterial({
      color: Math.round(Math.random() * Math.pow(2, 24)),
      transparent: true,
      opacity: 0.75
    })
  ))
  .graphData(gData);

In a JSON source file we have {id}

But we do not see the method to associate a specific statement, e.g.:

  new THREE.ConeGeometry(Math.random() * 10, Math.random() * 20)

with a specific {id}

For example, we do not use:

  .nodeAutoColorBy("group")

to assign color to nodes.

Instead we use:

  .nodeColor(d => {
    else if (d.id === "id-term-value"){return "#005af0";}
  }

We're looking for one or a combination of methods (i.e. JavaScript and JSON), similar to color assignment, to link an image or a THREE.Mesh calculation to a node.

Thanks for help here.

vasturiano commented 3 years ago

@jaygray0919 have you looked into this example: https://vasturiano.github.io/3d-force-graph/example/img-nodes/

jaygray0919 commented 3 years ago

Yes we did. We see how either images or math expressions are loaded. In the image case, the order appears to parent/child but, after the root parent/child sequence, we don't see the pattern, or how to invoke the pattern. We're missing the insight about how to associate a specific image or math expression with a specific node. For example, we might use a conventional circle (with specific size and color) for many nodes. But for specific nodes, we would like to use either an image or math expression. Is there documentation that we're not seeing?

vasturiano commented 3 years ago

@jaygray0919 the method used to build a custom node for these cases is nodeThreeObject. This uses an accessor method pattern that includes the node object as parameter. F.e.:

myGraph.nodeThreeObject(node => /* your logic according to node */)

Inside this method you can include all the node based logic required for your use case. For instance if you wish to make some nodes yellow and other green, you can do something like:

const nodeColor = isNodeYellow(node) ? 'yellow' : 'green';

Naturally the implementation of isNodeYellow() is up to you. It can be for example pre-set on an attribute of the node object or calculated dynamically from other fields.

jaygray0919 commented 3 years ago

Will work on this today. Thanks for the instructions.

jaygray0919 commented 3 years ago

@vasturiano would you be willing to modify one of your examples to show how to apply your instructions above? We have not been able to make it work.

We can control color and node size, per my initial post. However, we have not been able to map a specific symbol to a node. We would prefer to use one method to assign an object (e.g. math expression/symbol) and color to a node, so hoping you can provide an example we can emulate.

Also, we use id for linking nodes, and name for the label (vs. your examples that use the target label for id). The reason is: we have nodes with the same label that appear in more than one branch of a graph (i.e. "poly terms"). It's easier to handle this issue using id for links than using the label in the id (using name and id). Despite our original post above, we assign color like this: (d.name === "<logical label>"){return "#005af0";}

Aside: we have looked at several other examples (https://codepen.io/raulprop/pen/gOrQLex?editors=1011 and https://github.com/mrdoob/three.js/blob/master/examples/webgl_postprocessing_unreal_bloom_selective.html) but do not see a pattern that we can reuse.

Thanks for help here.

RaulPROP commented 3 years ago

If the json file has a property with the symbol to use (let's call that property icon and pretend that it is a link to an image with that icon), then you can do something like this:

graph.nodeThreeObject((node) => {
    const iconTexture = new THREE.TextureLoader().load(node.icon);
    const material = new THREE.MeshBasicMaterial({
        map: iconTexture,
        side: THREE.DoubleSide
    });
    const sprite = new THREE.Sprite(material);
    sprite.scale.set(12, 12);
    obj.add(sprite);

    return obj;
});

Codepen reproducing this.

jaygray0919 commented 3 years ago

Thank you @RaulPROP. Will work in this today.

jaygray0919 commented 3 years ago

@vasturiano @RaulPROP

We have successfully created several three.js instances (based on excellent examples). We'd like to share the instances and then ask for

We'll reference these 5 instances below

  1. baseline-v3
  2. three-js-selector__name
  3. three-js-selector_id
  4. three-js-json-image
  5. three-js-math-symbols

We use the same JSON data for:
baseline-v3
three-js-selector__name
three-js-selector_id
baseline-v3 uses these libraries
//unpkg.com/three@0.119.1/build/three.js
//unpkg.com/three-spritetext@1.5.2/dist/three-spritetext.min.js
//unpkg.com/3d-force-graph@1.66.6/dist/3d-force-graph.min.js
three-js-selector_id and three-js-selector__name use these libraries
//unpkg.com/three@0.107.0/build/three.js
//unpkg.com/three-spritetext@1.1.1/dist/three-spritetext.min.js
//unpkg.com/3d-force-graph@1.52.0/dist/3d-force-graph.min.js
//code.jquery.com/jquery-1.12.4.min.js

As you can see in baseline-v3, we now are reasonably proficient using a simple representation.

We're not proficient using a complex representation like this:

const graph = ForceGraph3D()(document.getElementById("3d-graph"))
    .jsonUrl("data.json")

    .nodeThreeObject((node) => {
        const obj = new THREE.Mesh(
            new THREE.SphereGeometry(7),
            new THREE.MeshBasicMaterial({
                depthWrite: false,
                transparent: true,
                opacity: 0
            })
        );

For example, in three-js-selector__name and three-js-selector_id we learned how to use logical names in the selector, but don't know how to use logical names as node labels (which currently uses the index id)

Strategicly, we would like to define data in JSON. Such data should include:

We would like to avoid using variables in JavaScript (i.e. reduce dependencies between data and format). This idea echoes concepts in Vega Visualization Grammar

Tactical questions:

  1. How to specify link length in JSON
    • For example, reduce the default link length for nodes with multiple children
  2. How to specify a node object in JSON
    • Have tested image-on-node: three-js-json-image
      • How to mix images and default node (sphere)
      • How to mix math symbols and default node (we would really like to learn how to assign specific math symbols to specific nodes)
  3. When using selector, how to assign logical name to node: three-js-selector__name
    • can use name on selector
    • cannot assign name to node
  4. Selector currently is 1-down (parent\:center/child)
    • How to make 1-up and 1-down (grandparent/parent\:center/child)
    • How to make 2-up and 2-down (great-grandparent/grandparent/parent\:center/child/grandchild)
  5. How to fomally cite this work in documentation (primary contributions and related contributions)?

General question:

Reference:

Documentation and comments

Links, gradients

Link distance

Manipulate-link-force

Link length based on link attribute

CSV access

Advisers

jaygray0919 commented 3 years ago

@vasturiano @RaulPROP would it be helpful if I submitted these as separate issues? we are very close to our objectives but hope to learn how to solve these last remaining issues. Nevertheless, we are where we are based on your examples and documentation.

RaulPROP commented 3 years ago

I'll try to answer each questions individually, trying my best because - at least for rme- those questions are not very well formatted, they are missing a lot of information and details about what exactly are you trying or what you are trying to achieve.


How to specify link length in JSON

  • For example, reduce the default link length for nodes with multiple children

Check the Manipulate link force distance (source)

How to specify a node object in JSON

Just create the data wherever you want (locally or in a server) and fetch it. If that data can be fetched with jsonUrl (passing a url), do it. If not, you can always use graphData (passing an object).

How to mix images and default node (sphere)

I think that you will need to use a custom shader and pass it to your node Material.

How to mix math symbols and default node (we would really like to learn how to assign specific math symbols to specific nodes)

If you mean that the node should be the math symbol, you can either create a mesh with the symbol. Or you could create an image dynamically with the symbol add just set the image to a plane.

When using selector, how to assign logical name to node: three-js-selector__name

  • can use name on selector
  • cannot assign name to node

Just edit the data of the graph with graphData. Check incremental updates.

Selector currently is 1-down (parent:center/child)

  • How to make 1-up and 1-down (grandparent/parent:center/child)
  • How to make 2-up and 2-down (great-grandparent/grandparent/parent:center/child/grandchild)

I don't get what you mean.

How to fomally cite this work in documentation (primary contributions and related contributions)?

This library has an MIT license, so this is up to @vasturiano .


General questions:

there are many WebGL warnings are we doing something wrong? how to reduce warnings?

Without the warnings it is difficult to say, but I would say that yes, you are doing something wrong (I have 0 warnings everytime I use this library).

jaygray0919 commented 3 years ago

Thank you @RaulPROP I'll work on improving future questions.