Giter VIP home page Giter VIP logo

Comments (5)

mbostock avatar mbostock commented on August 27, 2024 1

The error is here:

var sankey = sankey()

You’ve defined both a local var sankey and an imported symbol import {sankey}. The local var takes priority (it masks the import), so you’re trying to initialize the var sankey with the value undefined, making the above statement equivalent to var sankey = undefined().

You must use a different name for your local variable (the Sankey instance) and the Sankey constructor. For example, you could import the symbol with a capital letter:

import {sankey as Sankey} from "d3-sankey";

var sankey = Sankey();

Or you could use a different name for the local variable:

import {sankey} from "d3-sankey";

var graph = sankey();

Also note that your code is importing both the d3 default bundle and individual D3 modules (such as d3-scale). This should work if you have your bundler configured correctly, but is not idiomatic. If you are using ES imports, I recommend you import only the D3 modules and avoid the default bundle.

In the future, please use Stack Overflow tag d3.js to ask for help. Although I make an effort to assist everyone that asks, I am not always available to provide help promptly or directly. Stack Overflow provides a better collaborative forum for self-help: tens of thousands of D3-related questions have already been asked there, and some answered questions may be relevant to you.

When asking for help, please include a link to a live example that demonstrates the issue, preferably on bl.ocks.org. It is often impossible to debug from code snippets alone. Isolate the issue and reduce your code as much as possible before asking for help. The less code you post, the easier it is for someone to debug, and the more likely you are to get a helpful response.

If you have a question about D3’s behavior and want to discuss it with other users, also consider the d3-js Google Group or joining the d3-js Slack.

Thank you! 🤗

from d3-sankey.

mbostock avatar mbostock commented on August 27, 2024 1

You’ll need to use sankey.nodeId if you want to identify nodes by name rather than numeric index.

Again, please use Stack Overflow tag d3.js to ask for help. Although I make an effort to assist everyone that asks, I am not always available to provide help promptly or directly. Stack Overflow provides a better collaborative forum for self-help: tens of thousands of D3-related questions have already been asked there, and some answered questions may be relevant to you.

Thank you! 🤗

from d3-sankey.

CSMR-DB avatar CSMR-DB commented on August 27, 2024

Right, I've joined the Slack workspace and will reference this issue there. Just to update on this, as I feel a new post would be unnecessary. I've been trying out some different alterations to the code posted in the OC, including importing all the modules and leaving the import * as d3 out. I'm fine taking this approach as everything that was working seems to be working in this case as well. After posting I tried actually renaming the var declaration and that solved the undefined error. As of right now it looks like.

import React, { Component } from 'react';

import { json } from 'd3-request';
import { rgb } from 'd3-color';
import { interpolateHcl } from 'd3-interpolate';
import { scaleLinear, scaleOrdinal } from 'd3-scale';
import { arc, line, pie, curveMonotoneX } from 'd3-shape';
import { format } from 'd3-format';
import { min, max } from 'd3-array';
import { select } from 'd3-selection';
import { sankey as sankeyGraph, sankeyLinkHorizontal } from 'd3-sankey';

class Graph extends React.Component {
    constructor(props) {
        super(props);

        this.createLineGraph = this.createLineGraph.bind(this);
        this.createBarChart = this.createBarChart.bind(this);
        this.createPieChart = this.createPieChart.bind(this);
        this.createSankeyGraph = this.createSankeyGraph.bind(this);
        // this.createRadialChart = this.createRadialChart.bind(this);

        this.createTheGraphs = this.createTheGraphs.bind(this);

        this.state = {
            loading: false
        };
    }

    getDimensions() {
        const margin = {top: 20, right: 20, bottom: 20, left: 20},
            padding = {top: 40, right: 40, bottom: 40, left: 40},
            outerWidth = parseInt(this.props.size[0]),
            outerHeight = parseInt(this.props.size[1]),
            innerWidth = outerWidth - margin.left - margin.right,
            innerHeight = outerHeight - margin.top - margin.bottom,
            width = innerWidth - padding.left - padding.right,
            height = innerHeight - padding.top - padding.botto,
            radius = parseInt(min([innerWidth, innerHeight]) / 2),
            donutHole = this.props.type === "DONUT" ? radius / 2 : 0,
            color = scaleLinear()
                .domain([1, this.props.data.length])
                .interpolate(interpolateHcl)
                .range([rgb("#AF2192"), rgb("#98D719")]);

        // DON'T DO DATA MAPPING ON SANKEY GRAPH SINCE DATA STRUCTURE IS DIFFERENT
        if (this.props.type !== "SANKEY") {

            // HIGHEST VALUE OF ITEMS IN DATA ARRAY
            const dataMax = max(this.props.data.map(item => item.value)),
                dataSpread = (innerWidth / this.props.data.length),
                // DEPEND SCALE OF ITEMS ON THE Y AXIS BASED ON HIGHEST VALUE
                yScale = scaleLinear()
                    .domain([0, dataMax])
                    .range([0, innerHeight]),
                // GENERATE THE LINE USING THE TOTAL SPACE AVAILABLE FROM THE SIZE PROP DIVIDED BY THE LENGTH OF THE DATA ARRAY
                lineGen = line()
                    .x((d, i) => i * dataSpread)
                    .y(d => innerHeight - yScale(d))
                    // CURVEMONOTONEX GAVE THE BEST RESULTS
                    .curve(curveMonotoneX);

            dimensions = {margin, padding, outerWidth, outerHeight, innerWidth, innerHeight, radius, donutHole, color, dataMax, dataSpread, yScale, lineGen};

        } else {

            dimensions = {margin, padding, outerWidth, outerHeight, innerWidth, innerHeight, radius, donutHole, color};

        }

    }

    // *** ---

    createSankeyGraph(data) {
        const sankeyNode = this.node;

        let graphData = this.props.data;

        console.log(this.props.data);
        console.log(this.props.data.links);
        console.log(this.props.data.nodes);
        
        // GET DIMENSIONS IN A GLOBAL-VAR-LIKE WAY
        this.getDimensions();

        const formatNumber = format('.1f');
        const formatted = function(d) {return formatNumber(d) + " Potential Guests"};
        const color = scaleLinear()
            .domain([1, 3])
            .interpolate(interpolateHcl)
            .range([rgb('#126382'), rgb('#417685')]);

        var sankey = sankeyGraph()
            .nodeWidth(15)
            .nodePadding(10)
            .extent([1, 1], [dimensions.outerWidth - 1, dimensions.outerHeight - 6]);

        var SVG = select(sankeyNode)
            .append('g')
            .attr('transform', 'translate(' + dimensions.margin.left + ',' + dimensions.margin.top +')');

        var node = SVG.append('g')
            .attr('class', 'nodes')
            .attr("font-family", "sans-serif")
            .attr("font-size", 10)
            .selectAll('g')
            // .attr('class', 'node');

        var link = SVG.append('g')
            .attr('class', 'links')
            .attr("fill", "none")
            .attr("stroke", "#000")
            .attr("stroke-opacity", 0.2)
            .selectAll('path')
            // .attr('class', 'link');

        // console.log(sankey(this.props.data))

        sankeyGraph(graphData);

        node = node
            .data(graphData.nodes)
            .enter()
            .append('g')
            .attr('class', 'node');

        node.append('rect')
            .attr('x', function(d) { console.log(d.x0); return d.x0; }) // undefined
            .attr('y', function(d) { console.log(d.y0); return d.y0; }) // undefined
            .attr('height', function(d) { console.log(d.y1, d.y0); return d.y1 - d.y0}) // undefined undefined
            .attr('width', function(d) { console.log(d.x1, d.x0); return d.x1 - d.x0}) // undefined undefined
            .attr("fill", function(d, i) { return color(i); })
            .attr('stroke', 'black');

        node.append('text')
            .attr('x', function(d) {return d.x0 - 6})
            .attr('y', function(d) {return (d.y1 + d.y0) / 2})
            .attr('dy', '.35em')
            .attr('text-anchor', 'end')
            .text(function(d) { return d.name; })
            .filter(function(d) { return d.x0 < dimensions.innerWidth / 2; })
            .attr('x', function(d) { return d.x1 + 6; })
            .attr('text-anchor', 'start');

        node.append('title')
            .text(d => d.name + "\n" + formatted(d.value));

        link = link
            .data(graphData.links)
            .enter()
            .append('path')
            .attr('class', 'link')
            .attr('d', sankeyLinkHorizontal())
            .attr('stroke-width', function(d) { return Math.max(1, d.width); });

        link.append('title')
            .text(function(d) { return d.source.name + " → " + d.target.name + "\n" + formatted(d.value); });

    }

    createTheGraphs() {
        (this.props.type === "LINE") ? this.createLineGraph() : "";
        (this.props.type === "BAR") ? this.createBarChart() : "";
        (this.props.type === "PIE" || this.props.type === "DONUT") ? this.createPieChart() : "";
        (this.props.type === "SANKEY") ? this.createSankeyGraph() : "";
        (this.props.type === "RADIAL") ? this.createRadialChart() : "";
    }

    componentWillMount() {
        this.setState({ loading: true });
    }

    componentDidMount() {
        this.createTheGraphs();
    }

    componentDidUpdate() {
        this.createTheGraphs();
    }

    render() {
        return(
            <div className="Graph">
                <svg className='Graph_Container' ref={node => this.node = node}></svg>
                <h2>{this.props.type} Placeholder</h2>
            </div>
        );
    }
}

export default Graph;

The issue I'm facing right now is in the comments above. I get returned

node.append('rect')
            .attr('x', function(d) { console.log(d.x0); return d.x0; }) // undefined
            .attr('y', function(d) { console.log(d.y0); return d.y0; }) // undefined
            .attr('height', function(d) { console.log(d.y1, d.y0); return d.y1 - d.y0}) // undefined undefined
            .attr('width', function(d) { console.log(d.x1, d.x0); return d.x1 - d.x0}) // undefined undefined
            .attr("fill", function(d, i) { return color(i); })
            .attr('stroke', 'black');

And as such, it's unable to place the nodes in the SVG container. The text gets processed just fine, it's just the x and y coordinates are not getting returned correctly. The console also shows that

console.log(this.props.data);
console.log(this.props.data.links);
console.log(this.props.data.nodes);

Outputs the data as expected, giving me

Object { nodes: Array[4], links: Array[4] }  
Array [ Object, Object, Object, Object ] 
Array [ Object, Object, Object, Object ]

Or at least, I figured that's what it should expect given that the contents within (in this case, the text) is getting parsed as it should and shows up in the DOM where it needs to. It has something to do with the d.x and the d.y not getting the data they expect. To add to it, I've been following along with https://bl.ocks.org/mbostock/ca9a0bb7ba204d12974bca90acc507c0, slightly rewriting it to suit the React lifecycle methods just as I did with the other graphs.

--- UPDATE

Changing
sankeyGraph(graphData);
To
sankey(graphData);

Gives a different issue. Here it's missing the nodes which it needs to render the paths / lines between them. Even though the sankey var was declared after importing the sankeyGraph, they both have their quirks.

--- UPDATE2

The error in particular looks like this:

Error: missing: Peter  modules.js:54276:20
	find http://localhost:3000/packages/modules.js:54276:20
	computeNodeLinks/< http://localhost:3000/packages/modules.js:54353:62
	forEach self-hosted:267:13
	computeNodeLinks http://localhost:3000/packages/modules.js:54350:5
	sankey http://localhost:3000/packages/modules.js:54292:5
	createSankeyGraph http://localhost:3000/app/app.js:554:13
	createSankeyGraph self-hosted:941:17
	createTheGraphs http://localhost:3000/app/app.js:598:44
	createTheGraphs self-hosted:941:17
	componentDidMount http://localhost:3000/app/app.js:617:13
	mountComponent/</< http://localhost:3000/packages/modules.js:17838:20
	measureLifeCyclePerf http://localhost:3000/packages/modules.js:17649:12
	mountComponent/< http://localhost:3000/packages/modules.js:17837:11
	notifyAll http://localhost:3000/packages/modules.js:10464:9
	close http://localhost:3000/packages/modules.js:20865:5
	closeAll http://localhost:3000/packages/modules.js:11623:11
	perform http://localhost:3000/packages/modules.js:11570:11
	batchedMountComponentIntoNode http://localhost:3000/packages/modules.js:22897:3
	perform http://localhost:3000/packages/modules.js:11557:13
	batchedUpdates http://localhost:3000/packages/modules.js:20563:14
	batchedUpdates http://localhost:3000/packages/modules.js:10225:10
	_renderNewRootComponent http://localhost:3000/packages/modules.js:23090:5
	_renderSubtreeIntoContainer http://localhost:3000/packages/modules.js:23172:21
	render http://localhost:3000/packages/modules.js:23193:12
	routes.js/< http://localhost:3000/app/app.js:1504:3
	maybeReady http://localhost:3000/packages/meteor.js:821:6
	loadingCompleted http://localhost:3000/packages/meteor.js:833:5

The graphData object looks like this:

{
    nodes: [
        {name: "Peter"},
        {name: "Test.com"},
        {name: "Thing.com"},
        {name: "AnotherName"}
    ], links: [
        {source: "Peter", target: "Test.com", value: 50},
        {source: "Peter", target: "Thing.com", value: 50},
        {source: "Test.com", target: "AnotherName", value: 50},
        {source: "Thing.com", target: "AnotherName", value: 50}
    ]
}

from d3-sankey.

CSMR-DB avatar CSMR-DB commented on August 27, 2024

I've made a post regarding the issue on SO, but no responses as of yet. I'm trying out the numeric approach, using numbers as id's instead of names. Again, it returns the correct HTML, but no size attributes are parsed apart from in the text field. That last bit never happened before either.

<svg class="Graph_Container">
    <g transform="translate(20,20)">
        <g class="links" fill="none" stroke="#000" stroke-opacity="0.2">
            <path d="MNaN,NaNCNaN,NaN,NaN,NaN,NaN,NaN" stroke-width="NaN">
                <title>Peter → Test.com 50.0 Potential Guests</title>
            </path>
        </g>
        <g class="nodes" font-family="sans-serif" font-size="10">
            <g>
                <rect x="NaN" y="NaN" height="NaN" width="NaN" fill="rgb(0, 89, 128)" stroke="black"></rect>
                <text x="NaN" y="NaN" dy=".35em" text-anchor="end">Peter</text>
                <title>Peter 100.0 Potential Guests</title>
            </g>
        </g>
    </g>
</svg>

The data structure using numeric ids looks like this:

{
    nodes: [
        {id: 0, name: "Peter"},
        {id: 1, name: "Test.com"},
        {id: 2, name: "Thing.com"},
        {id: 3, name: "AnotherName"}
    ], 
    links: [
        {source: 0, target: 1, value: 50},
        {source: 0, target: 2, value: 50},
        {source: 1, target: 3, value: 50},
        {source: 2, target: 3, value: 50}
    ]
}

Returning

Unexpected value NaN parsing x attribute. modules.js:53768:9
Unexpected value NaN parsing y attribute. modules.js:53768:9
Unexpected value NaN parsing height attribute. modules.js:53768:9
Unexpected value NaN parsing width attribute. modules.js:53768:9
Unexpected value NaN parsing x attribute. modules.js:53768:9
Unexpected value NaN parsing y attribute.

I couldn't figure out how to use the .nodeId() in the original example. If you can show me how to use it, I'll have another thing to try out. Numeric ids are a no-no so far :(

from d3-sankey.

CSMR-DB avatar CSMR-DB commented on August 27, 2024

Okay, so I got the system finally working using the numeric node ids, changing:

var sankey = sankeyGraph()
            .nodes(graphData.nodes)
            .links(graphData.links)
            .nodeWidth(15)
            .nodePadding(10)
            .extent([1, 1], [parseInt(width) - 1, parseInt(height) - 6]);

To:

var sankey = sankeyGraph()
            .nodes(graphData.nodes)
            .links(graphData.links)
            .nodeWidth(15)
            .nodePadding(10)
            .size([width, height])

Now on to the .nodeId() stuff, as I don't even want to imagine what converting all the source / target stuff to id numbers would be like. I can't simply put in the array of objects, as it won't find the id fields. I also seemingly can't use a .map() inside the nodes array, which returns an array with all the field values needed for source / target but won't process it properly.

from d3-sankey.

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.