Code Monkey home page Code Monkey logo

d3-sankey-diagram's People

Contributors

harisbal avatar ricklupton avatar sliceking avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

d3-sankey-diagram's Issues

Strange link layout gliches

Take this data:

{
  "nodes": [ 
    { "id": "a" }, { "id": "b" }, { "id": "c" }, {"id": "d" }, {"id": "e" }, {"id": "f" }
  ],
  "links": [
    { "source": "a", "target": "b", "value": 1 },
    { "source": "a", "target": "c", "value": 1000 }, 
    { "source": "b", "target": "d", "value": 1 },
    { "source": "c", "target": "d", "value": 1000 },
    { "source": "d", "target": "e", "value": 1 },
    { "source": "e", "target": "f", "value": 1 }
  ]
}

put into https://ricklupton.github.io/d3-sankey-diagram/

Observe strange layout if links from "a" to "c" (largest one)

Calling `update()` breaks circular link paths

First of all, thank you for this very nice library @ricklupton

I have seen a strange behavior when using update: when calling sankey.update(graph) with an unmodified graph object, circular links (usually made out of 4 segments) are now made out of 2 segments.

The layout goes from:
screenshot_2019-02-04_14-07-10
to the following wrong result upon calling update:
screenshot_2019-02-04_14-07-22

Programmatically, this can be seen by running the following:

            var graph = sankey(data);
            var before = graph.links.map(function(link) {
                return link.points.map(function(pts) {
                    return pts.d;
                });
            });
            console.log(before);
            // [['r', 'r'], ['r', 'r', 'r', 'r'], ['r', 'r'], ['r', 'r'], ['r', 'l', 'l', 'r'], ['r', 'r'], ['r', 'l', 'l', 'r']]

            graph = sankey.update(graph);
            var after = graph.links.map(function(link) {
              return link.points.map(function(pts) {
                  return pts.d;
              });
            });
            console.log(after);
            // [['r', 'r'], ['r', 'r'], ['r', 'r'], ['r', 'r'], ['r', 'r'], ['r', 'r'], ['r', 'r']]

Basic example on wiki does work - crashes with TypeError: Cannot read properties of undefined (reading 'length')

Using the basic example on https://ricklupton.github.io/d3-sankey-diagram/, I get the following:

-sankey-diagram.umd.js:20584 Uncaught TypeError: Cannot read properties of undefined (reading 'length')
at titlePosition (d3-sankey-diagram.umd.js:20584:1)
at HTMLUnknownElement.eval (d3-sankey-diagram.umd.js:20467:1)
at Selection.eval [as each] (each.js:5:1)
at sankeyNode (d3-sankey-diagram.umd.js:20458:1)
at Selection.eval [as call] (call.js:4:1)
at updateNodes (d3-sankey-diagram.umd.js:20744:1)
at HTMLDivElement.eval (d3-sankey-diagram.umd.js:20711:1)
at Wn.each (d3.min.js:2:25626)
at exports (d3-sankey-diagram.umd.js:20674:1)
at Wn.call (d3.min.js:2:25196)
t

0.8.0 d3-sankey-diagram
7.8.4 d3

Allow custom classes to be added to nodes, links

What do you think about there being a customisation method to support adding CSS classes to nodes and links? This should (I think) then allow the image styling to be performed in CSS rather than via color settings in the data config.

Great work on extending the original D3 sankey lib :)

[info] Compatibility with version 7 of d3js

Hello,
I managed to update the bundle d3-sankey-diagram.js to make it compatible with the version 7 of d3.js.

Main changes is that d3-collection no longer exists. See migration guide for version 6, here, still working for version 7 https://observablehq.com/@d3/d3v6-migration-guide#collection

Modified file:
d3-sankey-diagram.js.txt

Changes:

  • d3Collection.map() >>> new Map() [7 occurences]
  • d3Collection.set() >>> new Set() [3 occurences]
  • line 19250 node.ports = ports.values() >>> node.ports = ports
  • line 19251 node.ports.sort(sortPorts) >>> line removed - didn't find better fix

With these changes, that example https://bl.ocks.org/ricklupton/6344d23aa6418702f120b34343dce7cb works.

Is it possible to use the params data to move nodes

Hi,

In the original d3-sankey it is possible to store specific position of each nodes, as you can see in https://sankey.csaladen.es/.

The data structure uses the following format:

params":[0.5,0.25,0,0,0],"fixedlayout":[[400.5,218.78016596921236],[0,497.0588235294118],[0,61.70588235294119],[587.25,0],[195.75,274.87527492724956],[790,0],[581.75,0]]}

Can this be used in the d3-sankey-diagram?

Deal better with incremental layout & rendering

Currently, it works fine if we do all the layout on a new graph, OR the graph is supplied with nodePositions set. But it's difficult to do little bits.

For example,

  • when dragging a node to tweak the layout of a diagram, I want to recalculate the link ordering and radii for just that node (or maybe the neighbours too)
  • when reloading a tweaked layout, I want to use predefined node positions and link point coordinates, but still setup the 'linked' structure of the graph object (link source and target as node objects, node incoming and outgoing as lists)

Undocumented and unused fields in example json

The following json file is used as example:
https://ricklupton.github.io/d3-sankey-diagram/uk_energy.json

I'm seeing a lot of unused and undocumented fields:

  • links:
    • time (seems unused and undocumented, always set to "*")
    • type (used in default linkTitle but otherwise not documented)
    • title (seems unused and undocumented)
  • groups:
    • bundle (seems unused and undocumented, always set to null)
    • def_pos (seems unused and undocumented, always set to null)
    • id (seems unused and undocumented)
    • type (seems unused and undocumented)
  • nodes:
    • bundle (seems unused and undocumented, always set to null)
    • def_pos (seems unused and undocumented, always set to null)
    • visibility (seems unused and undocumented, always set to visible)
    • style (seems unused and undocumented, always set to visible)
    • direction (used by nodeBackwards but otherwise not documented)

fsevents dependency prohibits installation on linux

$ npm install d3-sankey-diagram

npm ERR! code EBADPLATFORM
npm ERR! notsup Unsupported platform for [email protected]: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
npm ERR! notsup Valid OS:    darwin
npm ERR! notsup Valid Arch:  any
npm ERR! notsup Actual OS:   linux
npm ERR! notsup Actual Arch: x64

The use of fsevents is unclear and since it was added in conjunction with the addition of prettier, it is probably not needed as a dependency.

https://github.com/ricklupton/d3-sankey-diagram/blame/d8a126e9fc2bf4c4b98cc444544068bbd6c4d283/package.json#L37

Upgrade to d3 v4

d3 version 4 is much more modular and changes some APIs.

While upgrading, I'm planning to revise the diagram API and bring the sankey-layout package into this package, with a clean separation between graph layout (ranking and ordering node), Sankey node/link layout (curve radii etc) and SVG components.

extent difficult to compute

the extent() property nicely bounds the verticals for the chart, but it doesn't account for labels and paths which happen to appear outside of the area bounded by those verticals. as a result i need to manually set an extent after i've seen a rending to know how much padding i'm going to need to properly render the chart without obscuring the labels and paths which appear outside the extent. it would nice to have a way to bound the chart which included these outlying labels and paths so i can ensure my entire chart is plotted inside my target rectangle.

Direction not consistent when grouping nodes

Hi @ricklupton ,

Really great visualization!

When grouping nodes the direction of the links seem to do whatever direction suits best. I would like them to always go right side out left side in. In many cases this is going OK but in this example the diagram doing it (for me) the wrong way.

image

Is there any way in correcting this?

I tried direction: "r" on the nodes with no success.

This is part(!) of my JSON:"

{
    "nodes": [{
            "id": "01 - Homepage",
            "direction": "r"
        },
        {
            "id": "02 - Park - Homepages",
            "direction": "r"
        },
        {
            "id": "03 - Park - Content pages",
            "direction": "r"
        },
        {
            "id": "04 - Park - Acco(detail)",
            "direction": "r"
        }
    ],
    "links": [{
            "source": "Enter",
            "target": "02 - Park - Homepages",
            "value": 64223,
            "type": "enter"
        },
        {
            "source": "02 - Park - Homepages",
            "target": "04 - Park - Acco(detail)",
            "value": 55397,
            "type": "homepage"
        },
        {
            "source": "04 - Park - Acco(detail)",
            "target": "Exit",
            "value": 45991,
            "type": "exit"
        },
        {
            "source": "02 - Park - Homepages",
            "target": "Exit",
            "value": 38980,
            "type": "exit"
        },
        {
            "source": "Enter",
            "target": "01 - Homepage",
            "value": 34687,
            "type": "enter"
        },
        {
            "source": "02 - Park - Homepages",
            "target": "03 - Park - Content pages",
            "value": 30135,
            "type": "homepage"
        }
    ],
    "groups": [{
            "type": "Group",
            "title": "Enter",
            "bundle": null,
            "id": "Enter",
            "nodes": ["Enter"],
            "def_pos": null
        },
        {
            "type": "Group",
            "title": "Broad - Shopping",
            "bundle": null,
            "id": "Broad",
            "nodes": ["01 - Homepage", "05 - Theme - Home", "06 - Theme - Content", "07 - Offer - Overview", "08 - Offer - Detail", "09 - Search - Lists results", "11 - Maps", "14 - Site-Content"],
            "def_pos": null
        },
        {
            "type": "Group",
            "title": "Narrow - Shopping",
            "bundle": null,
            "id": "Narrow",
            "nodes": ["02 - Park - Homepages", "03 - Park - Content pages", "04 - Park - Acco(detail)", "15 - Compare"],
            "def_pos": null
        },
        {
            "type": "Group",
            "title": "Booking",
            "bundle": null,
            "id": "Booking",
            "nodes": ["12 - IBE", "17 - My Vacation", "NoMatch"],
            "def_pos": null
        },
        {
            "type": "Group",
            "title": "Pre Holiday",
            "bundle": null,
            "id": "Pre Holiday",
            "nodes": ["13 - My Account"],
            "def_pos": null
        },
        {
            "type": "Group",
            "title": "Exit",
            "bundle": null,
            "id": "Exit",
            "nodes": ["Exit"],
            "def_pos": null
        }
    ],
    "order": [
        [
            ["Enter"],
            [],
            []
        ],
        [
            ["01 - Homepage", "05 - Theme - Home", "06 - Theme - Content", "07 - Offer - Overview", "08 - Offer - Detail", "09 - Search - Lists results", "11 - Maps", "14 - Site-Content"],
            [],
            []
        ],
        [
            ["02 - Park - Homepages", "03 - Park - Content pages", "04 - Park - Acco(detail)", "15 - Compare"],
            [],
            []
        ],
        [
            ["12 - IBE", "17 - My Vacation", "NoMatch"],
            [],
            []
        ],
        [
            ["13 - My Account"],
            [],
            []
        ],
        [
            ["Exit"],
            [],
            []
        ]
    ],
    "rankSets": [{
            "type": "min",
            "nodes": ["Enter"]
        },
        {
            "type": "min",
            "nodes": ["01 - Homepage", "05 - Theme - Home", "06 - Theme - Content", "07 - Offer - Overview", "08 - Offer - Detail", "09 - Search - Lists results", "11 - Maps", "14 - Site-Content"]
        },
        {
            "type": "min",
            "nodes": ["02 - Park - Homepages", "03 - Park - Content pages", "04 - Park - Acco(detail)", "15 - Compare"]
        },
        {
            "type": "min",
            "nodes": ["12 - IBE", "17 - My Vacation", "NoMatch"]
        },
        {
            "type": "min",
            "nodes": ["13 - My Account"]
        }, {
            "type": "min",
            "nodes": ["Exit"]
        }
    ]
}

d3-sankey migration guide?

I might be missing a piece of the puzzle but I'm looking for the source of a complete example using d3-sankey-diagram.
I'm mostly missing the svg creation part.

This is the source of the github page, but it's transpiled and therefore hard to read:
https://github.com/ricklupton/d3-sankey-diagram/blob/gh-pages/d3-sankey-diagram.js

I'm currently coming from d3-sankey where d3.sankeyLinkHorizontal is used to extract the svg pathdata for the links. This function doesn't seem to exist when using d3-sankey-diagram.

Ability to pass custom labels for linkTitle

Love the package so far, but would be great to be able to pass custom strings to append to the label (i.e. d.custlabel) when passing the links. Use case for me would be for including in addition to the total count the percent of records from a particular node moving down a given forward.

Current implementation

const fmt = d3.format('.3s')
function linkTitle(d) {
  const parts = []
  const sourceTitle = nodeTitle(d.source)
  const targetTitle = nodeTitle(d.target)
  const matTitle = d.type

  parts.push(`${sourceTitle} โ†’ ${targetTitle}`)
  if (matTitle) parts.push(matTitle)
  parts.push(fmt(d.value))
  return parts.join('\n')
}

Proposed

const fmt = d3.format('.3s')
function linkTitle(d) {
  const parts = []
  const sourceTitle = nodeTitle(d.source)
  const targetTitle = nodeTitle(d.target)
  const matTitle = d.type
  const custTitle = d.custlabel

  parts.push(`${sourceTitle} โ†’ ${targetTitle}`)
  if (matTitle) parts.push(matTitle)
  parts.push(fmt(d.value))
  if (custTitle) parts.push(custTitle)
  return parts.join('\n')
}

> 1 nodeWidth creates angled circular link paths

When a nodeWidth of more than 1 is used some circular link paths are drawn angled / rotated.

nodeWidth of 1

Screenshot from 2019-09-05 13-29-28@2x

nodeWidth of 30

Screenshot from 2019-09-05 13-29-01@2x

Example code:
https://codesandbox.io/s/nodewidth-d3-sankey-diagram-phmpr

Copy of example code

import * as d3Base from "d3";
import * as sankey from "d3-sankey-diagram";

const d3 = {
  ...d3Base,
  ...sankey
};

var data = {
  nodes: [
    {
      id: "a",
      title: "a",
      direction: "r"
    },
    {
      id: "b",
      title: "b",
      direction: "r"
    },
    {
      id: "c",
      title: "c",
      direction: "r"
    }
  ],
  links: [
    {
      source: "a",
      target: "b",
      value: 1
    },
    {
      source: "b",
      target: "c",
      value: 1.2
    },
    {
      source: "c",
      target: "a",
      value: 0.2
    }
  ]
};

var svg = d3.select("svg");
var width = +svg.attr("width");
var height = +svg.attr("height");
var margin = { top: 10, left: 50, bottom: 10, right: 50 };

var layout = d3
  .sankey()
  .nodeWidth(30)
  .extent([
    [margin.left, margin.top],
    [width - margin.left - margin.right, height - margin.top - margin.bottom]
  ]);

// Render
var color = d3.scaleOrdinal(d3.schemeCategory10);
var diagram = d3
  .sankeyDiagram()
  .linkMinWidth(() => 0.1)
  .linkColor(d => color(d.type));

svg.datum(layout(data)).call(diagram);

More clearly defined expected nodes and links data

This one kind of builds on #22. Node groups clearly states "should be given in the following format" which then gives a clear example.

I noticed that the expected format for links, nodes data on the other hand is kind of undocumented. Especially since there are properties like the following which are otherwise only documented elsewhere.

  • links โ†’ type Used in default linkTitle
  • nodes โ†’ direction Used in default nodeBackwards

Support for links with gradient?

With d3-sankey I have to manually draw the svg for the links, but this does give me more control, for example to add gradients. What would be the best way to tackle this in d3-sankey-diagram?

I've used Vue to handle the actual drawing of the svg, here's an example of te links drawing part, where I include a linearGradient per link:

<g id="links" fill="none" stroke-opacity="0.5">
    <g
    v-for="link in links"
    :key="`${link.source.name}>${link.target.name}`"
    style="mix-blend-mode: multiply"
    >
    <linearGradient
        :id="link.uid"
        gradientUnits="userSpaceOnUse"
        :x1="link.source.x1"
        :x2="link.target.x0"
    >
        <stop offset="0%" :stop-color="color(link.source.name)"></stop>
        <stop offset="100%" :stop-color="color(link.target.name)"></stop>
    </linearGradient>
    <path
        :d="pathData(link)"
        :stroke="`url(#${link.uid})`"
        :stroke-width="Math.max(minStrokeWidth, link.width)"
    ></path>
    <title>{{ linkTitleText(link) }}</title>
    </g>
</g>

(This approach also works when loading the svg into applications like Inkscape and Illustrator)

Angular 5 integration

Hi @ricklupton,

Thanks for your great library. It's really awesome.
I would like to integrate it with Angular 5.
Have you tested if this works with Angular 5?

Thanks

Export

Is it possible to export the generated diagram as an image like a SVG or similar?

Allow customizing the link title

I'm aware you can customize part of the link title using linkTypeTitle but I couldn't find a way of completely configuring the link title.

Duplicate links are not processed

If links includes duplicates as far as (source, target, type) is concerned, the later links aren't processed -- and you then get errors if you try to render them

Remove unused code from linkPath.js

excuse me, when i read the source code.
i wonder why if (true) {...} else {...}?
test code?

if (true) {
path = ("M" + [x0, y0-h ] + " " +
arc(+1, r0) + [x2+hs, y2-hc] + " " +
"L" + [x3+hs, y3-hc] + " " +
arc(-1, r1) + [x1, y1-h ] + " " +
"L" + [x1, y1+h ] + " " +
arc(+1, r1) + [x3-hs, y3+hc] + " " +
"L" + [x2-hs, y2+hc] + " " +
arc(-1, r0) + [x0, y0+h ] + " " +
"Z");
} else {
// keep same number of points
theta = Math.abs(theta);
path = ("M" + [x0, y0-h ] + " " +
arc(+1, r0) + [x1, y1-h ] + " " +
"L" + [x1, y1-h ] + " " +
arc(-1, r1) + [x1, y1-h ] + " " +
"L" + [x1, y1+h ] + " " +
arc(+1, r1) + [x0, y0+h ] + " " +
"L" + [x0, y0+h ] + " " +
arc(-1, r0) + [x0, y0+h ] + " " +
"Z");
}

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.