Giter Club home page Giter Club logo

Comments (8)

erikbrinkman avatar erikbrinkman commented on May 21, 2024 1

The general complexity of laying this out with respect to the intended shape and dimension of nodes is very difficult. But I can briefly comment on other other two.

  1. non circular nodes: As I commended before, the section in observable where the nodes are created is:
    // Plot node circles
    nodes.append('circle')
      .attr('r', 20)
      .attr('fill', n => colorMap[n.id]);
    
    to make them squares you could do something like:
    nodes.append('rect')
      .attr('width', 40)
      .attr('height', 40)
      .attr('x', -20)
      .attr('y', -20)
      .attr('fill', n => colorMap[n.id]);
    
    where it's 40 because for circles you specify readius, and I set x and y to -20 as a way to center them, but there are many ways to accomplish that that ar eindependent of size.
    Note, that this is just d3, it has nothing to do with my library, so I encourage you to look up more of d3 if you want other things, for example, see the d3-shape library.
  2. For varying node sizes, this is supported somewhat, but it's poor and not super easy to use, but I can explain how to structure it. First because sugiyama used a layered layout, all nodes must have the same height. You can render nodes with different heights of course, but the coordinates they'll be assigned will be evenly spaced, so if you want to make a node taller, you'll have to give all the nodes the same space. In principle, each layer could have a different height, but I haven't implemented that. If you have a suitable idea, the change isn't hard and PRs are very welcome.
    For width there's a little more flexibility, but it's not super easy to use. There are two independent features that relate that you'll need to use.
    1. First is to use nodeSize this will tell the layout to scale based off the number of nodes, rather than cramming them into a fixed space. Set the height to be the spacing you want between nodes vertically, and the width to be the "approximate" distance you want between nodes horizontally. Note, if you want a gap, you'll want to set the larger than the height of the nodes you want to render.
    2. The second it to set the separation accessor to take the width you want per node into account. This accessor takes two nodes, and should output the relative spacing you want between them. A good rule of thumb is to structure this as left_width + right_width. If you know how large you want to make the nodes already, this should be relatively easy. Note, that this will be called on more nodes than in the original dag, as there are some dummy nodes that correspond to edges that are getting wrapped around other nodes. You'll likely want to treat these as width 0, or maybe as some minimum value, but that choice is up to you. These nodes will have a distinct type so branching off of node instanceof d3_dag.SugiDummyNode will tell you if a node is a dummy or not.

Hopefully that helps. If you have a good example that illustrates this (preferably with observable, but it doesn't really matter), I'm happy to add it to the examples section.

from d3-dag.

BenPortner avatar BenPortner commented on May 21, 2024

Hi @hadrienk,

very much like in d3, you can change the appearance of nodes and links by assigning them a css class. This done by selecting the corresponding links / nodes and changing the "class" attribute:

(selected object).attr('class', 'yourclass');

from d3-dag.

erikbrinkman avatar erikbrinkman commented on May 21, 2024

Yes, as @BenPortner suggested, d3-dag is just for computing coordinates to help you lay out appropriate html / svg elements. If you look (for example) at the observable demo, the actual image gets passed in an already laidout dag, and uses d3 to create the elements. Expanding the selection you;ll see code like:

  // Select nodes
  const nodes = svgSelection.append('g')
    .selectAll('g')
    .data(dag.descendants())
    .enter()
    .append('g')
    .attr('transform', ({x, y}) => `translate(${x}, ${y})`);

which is essentially creating svg groups, that are translated so that they're in the "correct" position from the layout.

Then we do two steps:

  // Plot node circles
  nodes.append('circle')
    .attr('r', 20)
    .attr('fill', n => colorMap[n.id]);

this takes those groups and adds a circle with radius 20 and the appropriate color.

then we do:

  // Add text to nodes
  nodes.append('text')
    .text(d => d.id)
    .attr('font-weight', 'bold')
    .attr('font-family', 'sans-serif')
    .attr('text-anchor', 'middle')
    .attr('alignment-baseline', 'middle')
    .attr('fill', 'white');

this adds the text with the id and sets appropriate attributes to it.

Observable supports live editing of this code, so if you're interested in changing the appearance of nodes, I suggest trying to tweak this and see if you get your desired results.

from d3-dag.

Trias avatar Trias commented on May 21, 2024

do you have recommendations on how to use non-circle nodes? like for example rectangles or ellipses?

And do you think it may be possible for the algorithms to respect width and height, such that nodes/edges for example never overlap?

Not a feature request (only slightly ;), i'm thinking of implementing it myself but may be helpful if you have some pointers / complexity estimate :)

from d3-dag.

hadrienk avatar hadrienk commented on May 21, 2024

Thanks a lot for your help. I managed to change the appearance with your advices. It looks great now.

from d3-dag.

hadrienk avatar hadrienk commented on May 21, 2024

One last thing, is there a way to let the lib decide what would be the best size?
If I remove the .size([w,h]) the node are all on top of another.

from d3-dag.

erikbrinkman avatar erikbrinkman commented on May 21, 2024

It's not really possible for this to set the layout size, as what you consider a node, might change. Conceivably you could do something like look at the elements that were updated from a node, look at the bounding box of those elements and then adjust the layout, but that is not really the way this library or d3 are designed.

The good news is that opposite, it seems like you are setting some reasonable size for your nodes, so getting something close to what you want should be possible.

The size([w, h]) argument is meant to be sued if you know the size of the area you want to lay out the nodes in. If you omit it,, it assumes 1, 1, which is probably not what you want. The alternative option is to use nodeSize([w, h]) which says to lay out the dag assuming nodes are roughly w x h. I assume at some point in your code (or in the observable) you're setting the nodes to some fixed size (40 x 40 in the observable). Then you'll want to set a node width and height of something like 60 to provide ample spacing. The downside of this approach is that you'll need to adjust the size of your rendering environment to the size of the dag that you layout.

Hope that helps!

from d3-dag.

erikbrinkman avatar erikbrinkman commented on May 21, 2024

Closing this out since it seems like things are resolved. Feel free to open a new issue or potentially ask on stackoverflow if you have questions like this.

from d3-dag.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.