Drag and drop object on a SVG element in d3.js - d3.js

I have an object (the skier on the image) that I want to be able to drag and drop on the line (the slope). My goal is to drag the skier up the slope, calculate the energy the skier has at that point, and when I drop him, he descends down the slope and then I calculate his speed based on the energy he had where he was the dropped.
I have managed to generate the line path but I don't know how I can limit the drag and drop area to to the line path that I have generated. I have tried to find relevant d3.drag() but I cannot find what I am looking. Some ideas how I can accomplish this?
Here is all my code:
const skierIconSvg = "skier.svg";
const margin = {top: 20, right: 20, bottom: 30, left: 50},
width = 600 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
const svg = d3.select('body').append('svg')
.attr("width", width)
.attr("height", height)
const data = [
{"x": 1, "y": 100},
{"x": 2, "y": 99},
{"x": 3, "y": 98},
{"x": 4, "y": 97},
{"x": 5, "y": 96},
{"x": 6, "y": 95},
{"x": 7, "y": 94},
{"x": 8, "y": 93},
{"x": 9, "y": 92},
{"x": 10, "y": 91},
{"x": 11, "y": 90},
{"x": 12, "y": 89},
{"x": 13, "y": 88},
{"x": 14, "y": 87},
{"x": 15, "y": 86},
{"x": 16, "y": 85},
{"x": 17, "y": 84},
{"x": 18, "y": 83},
{"x": 19, "y": 82},
{"x": 20, "y": 81},
{"x": 21, "y": 80},
{"x": 22, "y": 79},
{"x": 23, "y": 78},
{"x": 24, "y": 77},
{"x": 25, "y": 76},
{"x": 26, "y": 75},
{"x": 27, "y": 74},
{"x": 28, "y": 73},
{"x": 29, "y": 72},
{"x": 30, "y": 71},
{"x": 31, "y": 70},
{"x": 32, "y": 69},
{"x": 33, "y": 68},
{"x": 34, "y": 67},
{"x": 35, "y": 66},
{"x": 36, "y": 65},
{"x": 37, "y": 64},
{"x": 38, "y": 63},
{"x": 39, "y": 62},
{"x": 40, "y": 61},
{"x": 41, "y": 60},
{"x": 42, "y": 59},
{"x": 43, "y": 58},
{"x": 44, "y": 57},
{"x": 45, "y": 56},
{"x": 46, "y": 55},
{"x": 47, "y": 54},
{"x": 48, "y": 53},
{"x": 49, "y": 52},
{"x": 50, "y": 51},
{"x": 51, "y": 50},
{"x": 52, "y": 49},
{"x": 53, "y": 48},
{"x": 54, "y": 47},
{"x": 55, "y": 46},
{"x": 56, "y": 45},
{"x": 57, "y": 44},
{"x": 58, "y": 43},
{"x": 59, "y": 42},
{"x": 60, "y": 41},
{"x": 61, "y": 40},
{"x": 62, "y": 39},
{"x": 63, "y": 38},
{"x": 64, "y": 37},
{"x": 65, "y": 36},
{"x": 66, "y": 35},
{"x": 67, "y": 34},
{"x": 68, "y": 33},
{"x": 69, "y": 32},
{"x": 70, "y": 31},
{"x": 71, "y": 30},
{"x": 72, "y": 29},
{"x": 73, "y": 28},
{"x": 74, "y": 27},
{"x": 75, "y": 26},
{"x": 76, "y": 25},
{"x": 77, "y": 24},
{"x": 78, "y": 23},
{"x": 79, "y": 22},
{"x": 80, "y": 21},
{"x": 81, "y": 20},
{"x": 82, "y": 19},
{"x": 83, "y": 18},
{"x": 84, "y": 17},
{"x": 85, "y": 16},
{"x": 86, "y": 15},
{"x": 87, "y": 14},
{"x": 88, "y": 13},
{"x": 89, "y": 12},
{"x": 90, "y": 11},
{"x": 91, "y": 10},
{"x": 92, "y": 9},
{"x": 93, "y": 8},
{"x": 94, "y": 7},
{"x": 95, "y": 6},
{"x": 96, "y": 5},
{"x": 97, "y": 4},
{"x": 98, "y": 3},
{"x": 99, "y": 2},
{"x": 100, "y": 1},
];
const xScale = d3.scaleLinear()
.domain([d3.min(data, function(d) { return d.x; }), d3.max(data, function(d) { return d.x; }) ])
.range([0, width]);
const yScale = d3.scaleLinear()
.domain([0, d3.max(data, function(d) { return d.y; }) ])
.range([height, 0]);
const linje = d3.line()
.x(d => xScale(d.x))
.y(d => yScale(d.y))
const gLinje = svg.append("g")
const loypegenerator = gLinje.append("path")
.attr("d", linje(data))
.attr("stroke", "blue")
.attr("stroke-width", 1)
.attr("class", "loypeprofil")
.attr("fill", "none")
const newG = svg.append("g")
const nyLoypegenerator = newG.append("path")
.attr("d", linje(data))
.attr("stroke", "none")
.attr("stroke-width", 1)
.attr("class", "loypeprofil")
.attr("fill", "none")
// This finds the x coordinate on the G element using d3.mouse
nyLoypegenerator.append("rect")
.attr("height", height)
.attr("width", width)
.attr("fill", "none")
.attr("pointer-events", "all")
.on("mousemove", () => {
const x = d3.mouse(g.node())[1];
const hoveredX = yScale.invert(x)
console.log(hoveredX)
});
// Here I append the skier object
const skier = newG.append("image")
.attr("id", "skier")
.attr("href", skierIconSvg)
.attr("x", 130)
.attr("y", 150)
.attr("width", 100)
.attr("height", 100)
.call(d3
.drag()
.on('start', start)
.on('drag', dragged));
function start() {
let current = d3.select(this)
deltaX = current.attr("x") - d3.event.x;
deltaY = current.attr("y") - d3.event.y;
};
function dragged() {
d3.select(this)
.attr("x", d3.mouse(newG.node())[0])
.attr("y", d3.mouse(newG.node())[1])
};

Related

Vega-lite heatmap "transform" isn't working right

1) There's a X - coordinate and Y - coordinate. There's a Z - value. Z needs to calculate AVG.
"data": {
"values": [
{"x": 0, "y": 0, "z": 0},
{"x": 1, "y": 0, "z": 1},
{"x": 2, "y": 0, "z": 5},
{"x": 2, "y": 0, "z": 10},
{"x": 4, "y": 0, "z": 16},
{"x": 0, "y": 1, "z": 1},
{"x": 1, "y": 1, "z": 2},
{"x": 2, "y": 1, "z": 5},
{"x": 3, "y": 1, "z": 10},
{"x": 5, "y": 1, "z": 26}
]},
If the data:
"encoding": {
"x": {"field": "x", "type": "ordinal", "title": "X"},
"y": {"field": "y", "type": "ordinal", "title": "Y"} },
then AVG that's right:
Vega Editor
If I use "transform" with "groupby" :
"transform": [ {"window": [{"op": "count", "field": "x", "as": "x2"}], "groupby": ["y"]}],
"encoding": {
"x": {"field": "x2", "type": "ordinal", "title": "X"},
"y": {"field": "y", "type": "ordinal", "title": "Y"}
},
then AVG it's not true:
Vega Editor
The transform is doing exactly what you're telling it to do:
{"window": [{"op": "count", "field": "x", "as": "x2"}], "groupby": ["y"]}
It groups your data by y. Schematically it looks like this:
y=0: x: [0, 1, 2, 2, 4]
z: [0, 1, 5, 10, 16]
y=1: x: [0, 1, 2, 3, 5]
z: [1, 2, 5, 10, 26]
Then it does a sliding window and assigns the count to x2:
y=0: x: [0, 1, 2, 2, 4]
z: [0, 1, 5, 10, 16]
x2: [1, 2, 3, 4, 5]
y=1: x: [0, 1, 2, 3, 5]
z: [1, 2, 5, 10, 26]
x2: [1, 2, 3, 4, 5]
As you can see, when you create a plot of y vs x2, there is now a single z value at each location, and this is correctly reflected in the chart that you show above.
If you want different behavior, you should specify a different transform.

Vega-lite heatmap add text to a variable

"data": {
"values": [
{"x": 0, "y": 0, "z": 0},
{"x": 1, "y": 0, "z": 1},
{"x": 2, "y": 0, "z": 5},
{"x": 2, "y": 0, "z": 10},
{"x": 4, "y": 0, "z": 16},
{"x": 0, "y": 1, "z": 1},
{"x": 1, "y": 1, "z": 2},
{"x": 2, "y": 1, "z": 5},
{"x": 3, "y": 1, "z": 10},
{"x": 5, "y": 1, "z": 26}
]},
How to add text to a variable, so like "AVG:"?
Vega Editor
You can use a calculate transform to create specifically-formatted text to display in a text mark. For example (vega editor):
{
"data": {
"values": [
{"x": 0, "y": 0, "z": 0},
{"x": 1, "y": 0, "z": 1},
{"x": 2, "y": 0, "z": 5},
{"x": 2, "y": 0, "z": 10},
{"x": 4, "y": 0, "z": 16},
{"x": 0, "y": 1, "z": 1},
{"x": 1, "y": 1, "z": 2},
{"x": 2, "y": 1, "z": 5},
{"x": 3, "y": 1, "z": 10},
{"x": 5, "y": 1, "z": 26}
]
},
"transform": [
{
"aggregate": [{"op": "mean", "field": "z", "as": "z"}],
"groupby": ["x", "y"]
},
{"calculate": "'avg: ' + datum.z", "as": "z"}
],
"mark": "text",
"encoding": {
"x": {"field": "x", "type": "ordinal"},
"y": {"field": "y", "type": "ordinal"},
"text": {"field": "z", "type": "nominal"}
},
"width": 300,
"height": 100
}

D3: Efficient visualization of a complex directed acyclic graph (project dependencies)

I am currently exploring a large proprietary code base with many individual projects and interdependencies. To get a better overview, I would like to create a graphical representation of the dependencies, which are represented by a directed acyclic graph. The hope is, to finally better understand dependency clusters and (with knowledge about the individual project's contents) to aid restructuring of projects and dependencies.
Currently, I am using D3 for the visualization. Below is the full code of my current attempt (with project names replaced by a dummy). As you can see, it still looks pretty messy. Some order can be seen when hovering over project nodes.
I already looked at (but did not try out, yet) d3-dag, which might be promising but only contains examples with rather small data sets.
I also thought about something like a graph using hierarchical edge bundling, but there is not really a hierarchy here.
Does anybody have a recommendation for a better approach than the currently used force simulation layout?
<!DOCTYPE html>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.2/d3.min.js"></script>
<style>
#controls {
position: fixed;
left: 0px;
width: 20%;
top: 0px;
height: 10%;
}
#chart {
position: fixed;
left: 0px;
right: 0px;
top: 0px;
bottom: 0px;
}
path.link {
fill: none;
stroke: #c5c5c5;
stroke-width: 1.0px;
}
circle {
fill: #ccc;
stroke: #fff;
stroke-width: 1.5px;
}
text {
fill: #000000;
font: 11px sans-serif;
pointer-events: none;
}
.ingoing {
stroke: #237690!important;
stroke-width: 1.5px!important;
}
.outgoing {
stroke: #FA1209!important;
stroke-width: 1.5px!important;
}
.selected {
stroke: #000000!important;
stroke-width: 1.5px!important;
}
</style>
<body>
<div id="chart"></div>
<div id="controls">
<input type="checkbox" id="cb_hierarchical" checked="True" onclick='redraw();'>Order by dependency chain<br>
<input type="checkbox" id="cb_curved" checked="True" onclick='redraw();'>Curved Lines<br>
</div>
<script>
graph = JSON.parse('{"directed": true, "graph": [], "nodes": [{"id": 0, "name": "Project", "level": 7}, {"id": 1, "name": "Project", "level": 2}, {"id": 2, "name": "Project", "level": 12}, {"id": 3, "name": "Project", "level": 12}, {"id": 4, "name": "Project", "level": 3}, {"id": 5, "name": "Project", "level": 3}, {"id": 6, "name": "Project", "level": 8}, {"id": 7, "name": "Project", "level": 9}, {"id": 8, "name": "Project", "level": 1}, {"id": 9, "name": "Project", "level": 5}, {"id": 10, "name": "Project", "level": 12}, {"id": 11, "name": "Project", "level": 8}, {"id": 12, "name": "Project", "level": 10}, {"id": 13, "name": "Project", "level": 4}, {"id": 14, "name": "Project", "level": 3}, {"id": 15, "name": "Project", "level": 6}, {"id": 16, "name": "Project", "level": 7}, {"id": 17, "name": "Project", "level": 3}, {"id": 18, "name": "Project", "level": 9}, {"id": 19, "name": "Project", "level": 9}, {"id": 20, "name": "Project", "level": 7}, {"id": 21, "name": "Project", "level": 13}, {"id": 22, "name": "Project", "level": 7}, {"id": 23, "name": "Project", "level": 8}, {"id": 24, "name": "Project", "level": 3}, {"id": 25, "name": "Project", "level": 0}, {"id": 26, "name": "Project", "level": 6}, {"id": 27, "name": "Project", "level": 7}, {"id": 28, "name": "Project", "level": 15}, {"id": 29, "name": "Project", "level": 8}, {"id": 30, "name": "Project", "level": 9}, {"id": 31, "name": "Project", "level": 3}, {"id": 32, "name": "Project", "level": 8}, {"id": 33, "name": "Project", "level": 3}, {"id": 34, "name": "Project", "level": 2}, {"id": 35, "name": "Project", "level": 12}, {"id": 36, "name": "Project", "level": 8}, {"id": 37, "name": "Project", "level": 6}, {"id": 38, "name": "Project", "level": 8}, {"id": 39, "name": "Project", "level": 8}, {"id": 40, "name": "Project", "level": 6}, {"id": 41, "name": "Project", "level": 8}, {"id": 42, "name": "Project", "level": 8}, {"id": 43, "name": "Project", "level": 5}, {"id": 44, "name": "Project", "level": 15}, {"id": 45, "name": "Project", "level": 1}, {"id": 46, "name": "Project", "level": 12}, {"id": 47, "name": "Project", "level": 8}, {"id": 48, "name": "Project", "level": 7}, {"id": 49, "name": "Project", "level": 1}, {"id": 50, "name": "Project", "level": 14}, {"id": 51, "name": "Project", "level": 1}, {"id": 52, "name": "Project", "level": 6}, {"id": 53, "name": "Project", "level": 15}, {"id": 54, "name": "Project", "level": 15}, {"id": 55, "name": "Project", "level": 9}, {"id": 56, "name": "Project", "level": 4}, {"id": 57, "name": "Project", "level": 8}, {"id": 58, "name": "Project", "level": 1}, {"id": 59, "name": "Project", "level": 1}, {"id": 60, "name": "Project", "level": 15}, {"id": 61, "name": "Project", "level": 7}, {"id": 62, "name": "Project", "level": 8}, {"id": 63, "name": "Project", "level": 7}, {"id": 64, "name": "Project", "level": 3}, {"id": 65, "name": "Project", "level": 7}, {"id": 66, "name": "Project", "level": 1}, {"id": 67, "name": "Project", "level": 14}, {"id": 68, "name": "Project", "level": 5}, {"id": 69, "name": "Project", "level": 8}, {"id": 70, "name": "Project", "level": 7}, {"id": 71, "name": "Project", "level": 7}, {"id": 72, "name": "Project", "level": 5}, {"id": 73, "name": "Project", "level": 6}, {"id": 74, "name": "Project", "level": 2}, {"id": 75, "name": "Project", "level": 7}, {"id": 76, "name": "Project", "level": 4}, {"id": 77, "name": "Project", "level": 3}, {"id": 78, "name": "Project", "level": 8}, {"id": 79, "name": "Project", "level": 4}, {"id": 80, "name": "Project", "level": 3}, {"id": 81, "name": "Project", "level": 2}, {"id": 82, "name": "Project", "level": 16}, {"id": 83, "name": "Project", "level": 13}, {"id": 84, "name": "Project", "level": 12}, {"id": 85, "name": "Project", "level": 11}, {"id": 86, "name": "Project", "level": 3}, {"id": 87, "name": "Project", "level": 9}, {"id": 88, "name": "Project", "level": 2}, {"id": 89, "name": "Project", "level": 6}, {"id": 90, "name": "Project", "level": 5}, {"id": 91, "name": "Project", "level": 3}, {"id": 92, "name": "Project", "level": 5}, {"id": 93, "name": "Project", "level": 5}, {"id": 94, "name": "Project", "level": 4}, {"id": 95, "name": "Project", "level": 1}, {"id": 96, "name": "Project", "level": 13}, {"id": 97, "name": "Project", "level": 8}, {"id": 98, "name": "Project", "level": 5}, {"id": 99, "name": "Project", "level": 4}, {"id": 100, "name": "Project", "level": 6}, {"id": 101, "name": "Project", "level": 8}, {"id": 102, "name": "Project", "level": 11}, {"id": 103, "name": "Project", "level": 5}, {"id": 104, "name": "Project", "level": 10}], "links": [{"source": 0, "target": 57}, {"source": 0, "target": 36}, {"source": 0, "target": 23}, {"source": 0, "target": 82}, {"source": 0, "target": 39}, {"source": 0, "target": 18}, {"source": 0, "target": 41}, {"source": 0, "target": 6}, {"source": 0, "target": 85}, {"source": 0, "target": 60}, {"source": 1, "target": 50}, {"source": 1, "target": 4}, {"source": 1, "target": 77}, {"source": 1, "target": 85}, {"source": 1, "target": 75}, {"source": 1, "target": 14}, {"source": 2, "target": 50}, {"source": 2, "target": 83}, {"source": 2, "target": 67}, {"source": 3, "target": 50}, {"source": 3, "target": 67}, {"source": 3, "target": 21}, {"source": 4, "target": 50}, {"source": 4, "target": 7}, {"source": 4, "target": 20}, {"source": 5, "target": 75}, {"source": 5, "target": 60}, {"source": 5, "target": 85}, {"source": 6, "target": 104}, {"source": 7, "target": 50}, {"source": 7, "target": 12}, {"source": 7, "target": 85}, {"source": 8, "target": 50}, {"source": 8, "target": 35}, {"source": 8, "target": 91}, {"source": 8, "target": 96}, {"source": 8, "target": 26}, {"source": 8, "target": 68}, {"source": 9, "target": 101}, {"source": 9, "target": 7}, {"source": 9, "target": 62}, {"source": 12, "target": 85}, {"source": 12, "target": 102}, {"source": 13, "target": 22}, {"source": 13, "target": 52}, {"source": 13, "target": 27}, {"source": 13, "target": 47}, {"source": 13, "target": 30}, {"source": 13, "target": 43}, {"source": 13, "target": 60}, {"source": 13, "target": 61}, {"source": 13, "target": 62}, {"source": 13, "target": 92}, {"source": 13, "target": 7}, {"source": 13, "target": 9}, {"source": 13, "target": 70}, {"source": 13, "target": 68}, {"source": 13, "target": 12}, {"source": 13, "target": 37}, {"source": 13, "target": 73}, {"source": 13, "target": 15}, {"source": 13, "target": 16}, {"source": 13, "target": 100}, {"source": 13, "target": 101}, {"source": 13, "target": 20}, {"source": 13, "target": 103}, {"source": 14, "target": 75}, {"source": 14, "target": 50}, {"source": 14, "target": 85}, {"source": 14, "target": 56}, {"source": 14, "target": 98}, {"source": 15, "target": 70}, {"source": 15, "target": 22}, {"source": 15, "target": 7}, {"source": 16, "target": 85}, {"source": 16, "target": 101}, {"source": 17, "target": 50}, {"source": 17, "target": 85}, {"source": 18, "target": 35}, {"source": 25, "target": 30}, {"source": 25, "target": 51}, {"source": 25, "target": 80}, {"source": 25, "target": 4}, {"source": 25, "target": 95}, {"source": 25, "target": 13}, {"source": 25, "target": 59}, {"source": 25, "target": 77}, {"source": 25, "target": 1}, {"source": 25, "target": 75}, {"source": 25, "target": 8}, {"source": 25, "target": 64}, {"source": 25, "target": 14}, {"source": 25, "target": 49}, {"source": 25, "target": 33}, {"source": 25, "target": 58}, {"source": 25, "target": 66}, {"source": 25, "target": 45}, {"source": 20, "target": 85}, {"source": 20, "target": 7}, {"source": 21, "target": 67}, {"source": 22, "target": 85}, {"source": 24, "target": 50}, {"source": 24, "target": 85}, {"source": 26, "target": 30}, {"source": 26, "target": 50}, {"source": 26, "target": 35}, {"source": 26, "target": 0}, {"source": 26, "target": 63}, {"source": 26, "target": 48}, {"source": 26, "target": 75}, {"source": 26, "target": 65}, {"source": 27, "target": 101}, {"source": 29, "target": 50}, {"source": 29, "target": 60}, {"source": 29, "target": 87}, {"source": 29, "target": 19}, {"source": 30, "target": 60}, {"source": 30, "target": 44}, {"source": 30, "target": 85}, {"source": 30, "target": 21}, {"source": 30, "target": 53}, {"source": 32, "target": 50}, {"source": 32, "target": 60}, {"source": 32, "target": 18}, {"source": 32, "target": 19}, {"source": 33, "target": 99}, {"source": 33, "target": 48}, {"source": 33, "target": 26}, {"source": 33, "target": 75}, {"source": 33, "target": 98}, {"source": 33, "target": 68}, {"source": 33, "target": 79}, {"source": 34, "target": 75}, {"source": 34, "target": 17}, {"source": 34, "target": 33}, {"source": 37, "target": 27}, {"source": 37, "target": 70}, {"source": 37, "target": 101}, {"source": 38, "target": 67}, {"source": 38, "target": 96}, {"source": 40, "target": 67}, {"source": 41, "target": 82}, {"source": 66, "target": 75}, {"source": 66, "target": 74}, {"source": 66, "target": 88}, {"source": 45, "target": 81}, {"source": 47, "target": 30}, {"source": 47, "target": 67}, {"source": 47, "target": 46}, {"source": 47, "target": 96}, {"source": 48, "target": 32}, {"source": 48, "target": 18}, {"source": 48, "target": 29}, {"source": 49, "target": 50}, {"source": 49, "target": 60}, {"source": 49, "target": 85}, {"source": 49, "target": 5}, {"source": 50, "target": 60}, {"source": 50, "target": 44}, {"source": 50, "target": 54}, {"source": 50, "target": 53}, {"source": 51, "target": 75}, {"source": 51, "target": 65}, {"source": 51, "target": 34}, {"source": 51, "target": 33}, {"source": 52, "target": 7}, {"source": 52, "target": 101}, {"source": 56, "target": 75}, {"source": 56, "target": 65}, {"source": 56, "target": 98}, {"source": 58, "target": 75}, {"source": 58, "target": 17}, {"source": 58, "target": 33}, {"source": 59, "target": 50}, {"source": 59, "target": 35}, {"source": 59, "target": 1}, {"source": 59, "target": 31}, {"source": 59, "target": 85}, {"source": 59, "target": 72}, {"source": 59, "target": 75}, {"source": 59, "target": 14}, {"source": 59, "target": 67}, {"source": 60, "target": 82}, {"source": 62, "target": 50}, {"source": 62, "target": 60}, {"source": 62, "target": 85}, {"source": 62, "target": 55}, {"source": 63, "target": 87}, {"source": 63, "target": 36}, {"source": 63, "target": 69}, {"source": 63, "target": 23}, {"source": 63, "target": 82}, {"source": 63, "target": 60}, {"source": 63, "target": 41}, {"source": 63, "target": 85}, {"source": 63, "target": 97}, {"source": 63, "target": 11}, {"source": 64, "target": 15}, {"source": 64, "target": 16}, {"source": 64, "target": 22}, {"source": 64, "target": 52}, {"source": 64, "target": 100}, {"source": 64, "target": 101}, {"source": 64, "target": 85}, {"source": 64, "target": 9}, {"source": 64, "target": 62}, {"source": 64, "target": 94}, {"source": 65, "target": 42}, {"source": 67, "target": 28}, {"source": 68, "target": 50}, {"source": 68, "target": 60}, {"source": 70, "target": 50}, {"source": 70, "target": 62}, {"source": 70, "target": 84}, {"source": 70, "target": 85}, {"source": 70, "target": 7}, {"source": 70, "target": 47}, {"source": 71, "target": 38}, {"source": 71, "target": 67}, {"source": 71, "target": 78}, {"source": 72, "target": 30}, {"source": 73, "target": 50}, {"source": 73, "target": 16}, {"source": 73, "target": 22}, {"source": 73, "target": 60}, {"source": 73, "target": 61}, {"source": 73, "target": 85}, {"source": 73, "target": 20}, {"source": 74, "target": 30}, {"source": 74, "target": 50}, {"source": 74, "target": 80}, {"source": 74, "target": 35}, {"source": 74, "target": 24}, {"source": 74, "target": 14}, {"source": 74, "target": 13}, {"source": 74, "target": 77}, {"source": 74, "target": 5}, {"source": 74, "target": 91}, {"source": 74, "target": 62}, {"source": 74, "target": 64}, {"source": 74, "target": 72}, {"source": 74, "target": 86}, {"source": 74, "target": 103}, {"source": 74, "target": 26}, {"source": 74, "target": 101}, {"source": 74, "target": 31}, {"source": 74, "target": 75}, {"source": 75, "target": 85}, {"source": 76, "target": 90}, {"source": 76, "target": 67}, {"source": 77, "target": 50}, {"source": 77, "target": 76}, {"source": 77, "target": 85}, {"source": 77, "target": 42}, {"source": 80, "target": 50}, {"source": 80, "target": 85}, {"source": 83, "target": 50}, {"source": 84, "target": 96}, {"source": 85, "target": 50}, {"source": 85, "target": 35}, {"source": 85, "target": 21}, {"source": 85, "target": 82}, {"source": 85, "target": 60}, {"source": 85, "target": 83}, {"source": 85, "target": 2}, {"source": 85, "target": 46}, {"source": 85, "target": 84}, {"source": 85, "target": 3}, {"source": 85, "target": 10}, {"source": 86, "target": 13}, {"source": 86, "target": 37}, {"source": 87, "target": 104}, {"source": 88, "target": 85}, {"source": 89, "target": 50}, {"source": 89, "target": 71}, {"source": 90, "target": 50}, {"source": 91, "target": 67}, {"source": 92, "target": 50}, {"source": 92, "target": 85}, {"source": 93, "target": 67}, {"source": 94, "target": 85}, {"source": 94, "target": 52}, {"source": 94, "target": 62}, {"source": 95, "target": 50}, {"source": 95, "target": 85}, {"source": 95, "target": 68}, {"source": 43, "target": 16}, {"source": 43, "target": 22}, {"source": 43, "target": 37}, {"source": 43, "target": 101}, {"source": 43, "target": 85}, {"source": 43, "target": 20}, {"source": 96, "target": 67}, {"source": 97, "target": 104}, {"source": 98, "target": 75}, {"source": 98, "target": 65}, {"source": 98, "target": 26}, {"source": 98, "target": 89}, {"source": 98, "target": 40}, {"source": 99, "target": 50}, {"source": 99, "target": 67}, {"source": 99, "target": 93}, {"source": 99, "target": 72}, {"source": 100, "target": 50}, {"source": 101, "target": 7}, {"source": 103, "target": 30}, {"source": 103, "target": 15}, {"source": 103, "target": 22}, {"source": 103, "target": 52}, {"source": 103, "target": 60}, {"source": 103, "target": 61}, {"source": 103, "target": 100}, {"source": 103, "target": 35}, {"source": 103, "target": 73}, {"source": 103, "target": 20}, {"source": 103, "target": 70}, {"source": 103, "target": 7}], "multigraph": false}')
var cb_hierarchical = document.getElementById("cb_hierarchical");
var cb_curved = document.getElementById("cb_curved");
var chartDiv = document.getElementById("chart");
var svg = d3.select(chartDiv).append("svg");
var linkedByIndex = {};
var num_links = {};
var num_links_incoming = {};
graph.links.forEach(function(d) {
linkedByIndex[d.source + "," + d.target] = 1;
num_links[d.target] = (num_links[d.target] != undefined ? num_links[d.target] + 1 : 1)
num_links[d.source] = (num_links[d.source] != undefined ? num_links[d.source] + 1 : 1)
num_links_incoming[d.target] = (num_links_incoming[d.target] != undefined ? num_links_incoming[d.target] + 1 : 1)
d.distance = graph.nodes[d.target].level - graph.nodes[d.source].level;
});
const maxlevel = graph.nodes.reduce(function(currentValue, node) {
return Math.max(node.level, currentValue);
}, 0);
var maxlinks = Object.values(num_links).reduce(function(currentValue, entry) {
return Math.max(entry, currentValue);
}, 0);
var white_background = svg.append("svg:defs")
.append("filter")
.attr("x", 0)
.attr("y", 0)
.attr("width", 1)
.attr("height", 1)
.attr("id", "white_background");
white_background
.append("feFlood")
.attr("flood-color", "white");
white_background
.append("feComposite")
.attr("in", "SourceGraphic")
var simulation = d3.forceSimulation(graph.nodes)
.on('tick', tick);
// add the links
var path = svg.selectAll("path")
.data(graph.links)
.enter().append("svg:path")
.attr("class", "link");
// define the nodes
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("g")
.attr("class", "node")
.on("mouseover", highlight(true))
.on("mouseout", highlight(false))
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
// add the node-circles
var circle = node.append("circle")
.attr("z", 0);
// add the text to nodes
var title = node.append("text")
.attr("x", 12)
.attr("z", 5)
.attr("dy", ".35em")
.attr("filter", "url(#white_background)")
.text(function(d) {
return d.name;
});
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart()
d.fx = d.x;
d.fy = d.y;
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
function tick(e) {
var width = chartDiv.clientWidth;
var height = chartDiv.clientHeight;
node
.attr("cx", function(d) {
return d.x = Math.max(d.radius, Math.min(width - d.radius - 75, d.x));
})
.attr("cy", function(d) {
return d.y = Math.max(d.radius, Math.min(height - d.radius, d.y));
})
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
path.attr("d", function(d) {
if (cb_curved.checked) {
return "M" + d.source.x + "," + d.source.y + "C" + d.target.x + "," + d.source.y + "," + d.source.x + "," + d.target.y + "," + d.target.x + "," + d.target.y;
} else {
return "M" + d.source.x + "," + d.source.y + "L" + d.target.x + "," + d.target.y;
}
});
}
function highlight(active) {
return function(d, i) {
path.classed("ingoing", function(link) {
return active && link.target === d;
});
path.classed("outgoing", function(link) {
return active && link.source === d;
});
node.classed("ingoing", function(node) {
return active && linkedByIndex[node.id + "," + d.id];
});
node.classed("outgoing", function(node) {
return active && linkedByIndex[d.id + "," + node.id];
});
node.classed("selected", function(node) {
return active && d.id === node.id;
});
circle.classed("ingoing", function(node) {
return active && linkedByIndex[node.id + "," + d.id];
});
circle.classed("outgoing", function(node) {
return active && linkedByIndex[d.id + "," + node.id];
});
circle.classed("selected", function(node) {
return active && d.id === node.id;
});
title.classed("ingoing", function(node) {
return active && linkedByIndex[node.id + "," + d.id];
});
title.classed("outgoing", function(node) {
return active && linkedByIndex[d.id + "," + node.id];
});
title.classed("selected", function(node) {
return active && d.id === node.id;
});
};
}
function redraw() {
var width = chartDiv.clientWidth;
var height = chartDiv.clientHeight;
svg.attr("width", width).attr("height", height);
const radius = 25;
const charge = 10;
const link_strength = .75;
graph.nodes.forEach(function(d) {
d.radius = radius * Math.atan((num_links[d.id] != undefined ? num_links[d.id] : 0) / maxlinks * 2 * Math.PI);
});
graph.nodes.forEach(function(d) {
d.radius_inc = radius * Math.atan((num_links_incoming[d.id] != undefined ? num_links_incoming[d.id] : 0) / maxlinks * 2 * Math.PI);
});
circle.attr('r', function(d) {
return d.radius;
});
var leveldist = width / (maxlevel + 1);
if (cb_hierarchical.checked) {
simulation
.force('x', d3.forceX()
.x(function(d) {
return (d.level + 0.5) * leveldist;
})
.strength(2.))
.force('y', d3.forceY()
.y(height / 2)
.strength(0.025));
} else {
simulation
.force('x', d3.forceX()
.x(width / 2)
.strength(0.05))
.force('y', d3.forceY()
.y(height / 2)
.strength(0.05));
}
simulation.force('link', d3.forceLink()
.links(graph.links)
.strength(function(d) {
return link_strength / d.target.radius_inc;
})
.distance(function(d) {
return d.distance * leveldist
}))
.force('charge', d3.forceManyBody()
.strength(function(d) {
return -charge * d.radius;
}))
.force('collision', d3.forceCollide()
.radius(function(d) {
return d.radius;
}))
.alphaTarget(0.3)
.restart();
}
redraw();
d3.select(window).on("resize", redraw)
</script>
</body>
</html>
Using the comments by #Coola, I extended my recent attempts with a Sankey diagram, added padding and zooming capabilities and the possibility to switch between the different visualization modes. Furthermore, I added some link drawing style, to the force simulation approach, that tries to resemble bundling of electrical wires to prevent the mess.
Posting this as an answer instead of editing the original question as the change is rather huge and contains significant progress. Hope, this is OK.
Still, things are a bit messy as you can see. Thus, I would still be happy to see more ideas.
Currently, I do have the feeling that the Hierarchical Edge bundling is best-suited for this problem. To be able to create such a graph, I introduced an artificial hierarchy indirectly via the shortest path between the main project and its dependants.
Hierarchical Edge Bundling
Force Layout
Sankey Diagram
Unfortunately, the full code is too large to be posted.
Use the networkX library, first create a networkX graph and then call the layout function, I used spectral_layout as I feel it is a better way to visualize DAGs. The layout function will return a dictionary of node names with x,y positions. I did this in python, converted the dictionary to json and passed over the json to D3.

nvd3 plot with too many points fails - Cannot read property 'x' of null

I have a line chart with nvd3.
It works fine when I have fewer points, but I get a javascript error when I have more point:
Cannot read property 'x' of null
Here is the full html for the case with more data which fails:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.7.0/nv.d3.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.7.0/nv.d3.min.js"></script>
</head>
<body>
<div id="coverage"><svg style="width:1200px;height:400px;"></svg></div>
<script>
coverage=[{"values": [{"y": 0.1, "x": 0}, {"y": 0.1, "x": 1}, {"y": 0.1, "x": 2}, {"y": 0.1, "x": 3}, {"y": 0.1, "x": 4}, {"y": 0.1, "x": 5}, {"y": 0.1, "x": 6}, {"y": 0.1, "x": 7}, {"y": 0.1, "x": 8}, {"y": 0.1, "x": 9}, {"y": 0.1, "x": 10}, {"y": 0.1, "x": 11}, {"y": 0.1, "x": 12}, {"y": 0.1, "x": 13}, {"y": 0.1, "x": 14}, {"y": 0.1, "x": 15}, {"y": 0.1, "x": 16}, {"y": 0.1, "x": 17}, {"y": 0.1, "x": 18}, {"y": 0.1, "x": 19}, {"y": 0.1, "x": 20}, {"y": 0.1, "x": 21}, {"y": 0.1, "x": 22}, {"y": 0.1, "x": 23}, {"y": 0.1, "x": 24}, {"y": 0.1, "x": 25}, {"y": 0.1, "x": 26}, {"y": 0.1, "x": 27}, {"y": 0.1, "x": 28}, {"y": 0.1, "x": 29}, {"y": 0.1, "x": 30}, {"y": 0.1, "x": 31}, {"y": 0.1, "x": 32}, {"y": 0.1, "x": 33}, {"y": 0.1, "x": 34}, {"y": 0.1, "x": 35}, {"y": 0.1, "x": 36}, {"y": 0.1, "x": 37}, {"y": 0.1, "x": 38}, {"y": 0.1, "x": 39}, {"y": 0.1, "x": 40}, {"y": 0.1, "x": 41}, {"y": 0.1, "x": 42}, {"y": 0.1, "x": 43}, {"y": 0.1, "x": 44}, {"y": 0.1, "x": 45}, {"y": 0.1, "x": 46}, {"y": 0.1, "x": 47}, {"y": 0.1, "x": 48}, {"y": 0.1, "x": 49}], "key": "qq003.1.3", "yAxis": "1"}, {"values": [{"y": 0.1, "x": 0}, {"y": 0.1, "x": 1}, {"y": 0.1, "x": 2}, {"y": 0.1, "x": 3}, {"y": 0.1, "x": 4}, {"y": 0.1, "x": 5}, {"y": 0.1, "x": 6}, {"y": 0.1, "x": 7}, {"y": 0.1, "x": 8}, {"y": 0.1, "x": 9}, {"y": 0.1, "x": 10}, {"y": 0.1, "x": 11}, {"y": 0.1, "x": 12}, {"y": 0.1, "x": 13}, {"y": 0.1, "x": 14}, {"y": 0.1, "x": 15}, {"y": 0.1, "x": 16}, {"y": 0.1, "x": 17}, {"y": 0.1, "x": 18}, {"y": 0.1, "x": 19}, {"y": 0.1, "x": 20}, {"y": 0.1, "x": 21}, {"y": 0.1, "x": 22}, {"y": 0.1, "x": 23}, {"y": 0.1, "x": 24}, {"y": 0.1, "x": 25}, {"y": 0.1, "x": 26}, {"y": 0.1, "x": 27}, {"y": 0.1, "x": 28}, {"y": 0.1, "x": 29}, {"y": 0.1, "x": 30}, {"y": 0.1, "x": 31}, {"y": 0.1, "x": 32}, {"y": 0.1, "x": 33}, {"y": 0.1, "x": 34}, {"y": 0.1, "x": 35}, {"y": 0.1, "x": 36}, {"y": 0.1, "x": 37}, {"y": 0.1, "x": 38}, {"y": 0.1, "x": 39}, {"y": 0.1, "x": 40}, {"y": 0.1, "x": 41}, {"y": 0.1, "x": 42}, {"y": 0.1, "x": 43}, {"y": 0.1, "x": 44}, {"y": 0.1, "x": 45}, {"y": 0.1, "x": 46}, {"y": 0.1, "x": 47}, {"y": 0.1, "x": 48}, {"y": 0.1, "x": 49}], "key": "qq003.1.67", "yAxis": "1"}, {"values": [{"y": 247677.0, "x": 0}, {"y": 250012.0, "x": 1}, {"y": 287416.0, "x": 2}, {"y": 327385.0, "x": 3}, {"y": 276739.0, "x": 4}, {"y": 247264.0, "x": 5}, {"y": 234246.0, "x": 6}, {"y": 252476.0, "x": 7}, {"y": 263584.0, "x": 8}, {"y": 244878.0, "x": 9}, {"y": 263238.0, "x": 10}, {"y": 223955.0, "x": 11}, {"y": 147838.0, "x": 12}, {"y": 216088.0, "x": 13}, {"y": 219334.0, "x": 14}, {"y": 464921.0, "x": 15}, {"y": 253147.0, "x": 16}, {"y": 143214.0, "x": 17}, {"y": 263756.0, "x": 18}, {"y": 289643.0, "x": 19}, {"y": 219631.0, "x": 20}, {"y": 280396.0, "x": 21}, {"y": 228272.0, "x": 22}, {"y": 205129.0, "x": 23}, {"y": 277684.0, "x": 24}, {"y": 336930.0, "x": 25}, {"y": 206536.0, "x": 26}, {"y": 184942.0, "x": 27}, {"y": 288391.0, "x": 28}, {"y": 265598.0, "x": 29}, {"y": 214029.0, "x": 30}, {"y": 205708.0, "x": 31}, {"y": 238413.0, "x": 32}, {"y": 173776.0, "x": 33}, {"y": 231737.0, "x": 34}, {"y": 189285.0, "x": 35}, {"y": 299765.0, "x": 36}, {"y": 254324.0, "x": 37}, {"y": 231075.0, "x": 38}, {"y": 425653.0, "x": 39}, {"y": 344885.0, "x": 40}, {"y": 394357.0, "x": 41}, {"y": 184156.0, "x": 42}, {"y": 251984.0, "x": 43}, {"y": 236977.0, "x": 44}, {"y": 280948.0, "x": 45}, {"y": 305699.0, "x": 46}, {"y": 249000.0, "x": 47}, {"y": 281287.0, "x": 48}, {"y": 247748.0, "x": 49}], "key": "qq001.2.047", "yAxis": "1"}];
nv.addGraph(function() {
var chart = nv.models.lineChart();
chart.margin({top: 30, right: 60, bottom: 100, left: 60});
var datum = coverage;
chart.xAxis
.rotateLabels(-25).tickFormat(d3.format(',.1f'));
chart.yAxis
.axisLabel('Coverage').tickFormat(d3.format(',.02f'));
chart.showLegend(true);
d3.select('#coverage svg')
.datum(datum)
.transition().duration(500)
.attr('width', 1200)
.attr('height', 400)
.call(chart);
});
</script>
</body>
</html>
Does anyone know how to fix this?
This is probably because you have identical points in the three series. Refer to https://github.com/novus/nvd3/issues/873
Try using useVoronoi(false);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.7.0/nv.d3.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.7.0/nv.d3.min.js"></script>
</head>
<body>
<div id="coverage"><svg style="width:1200px;height:400px;"></svg></div>
<script>
coverage=[{"values": [{"y": 0.2, "x": 0}, {"y": 0.1, "x": 1}, {"y": 0.1, "x": 2}, {"y": 0.1, "x": 3}, {"y": 0.1, "x": 4}, {"y": 0.1, "x": 5}, {"y": 0.1, "x": 6}, {"y": 0.1, "x": 7}, {"y": 0.1, "x": 8}, {"y": 0.1, "x": 9}, {"y": 0.1, "x": 10}, {"y": 0.1, "x": 11}, {"y": 0.1, "x": 12}, {"y": 0.1, "x": 13}, {"y": 0.1, "x": 14}, {"y": 0.1, "x": 15}, {"y": 0.1, "x": 16}, {"y": 0.1, "x": 17}, {"y": 0.1, "x": 18}, {"y": 0.1, "x": 19}, {"y": 0.1, "x": 20}, {"y": 0.1, "x": 21}, {"y": 0.1, "x": 22}, {"y": 0.1, "x": 23}, {"y": 0.1, "x": 24}, {"y": 0.1, "x": 25}, {"y": 0.1, "x": 26}, {"y": 0.1, "x": 27}, {"y": 0.1, "x": 28}, {"y": 0.1, "x": 29}, {"y": 0.1, "x": 30}, {"y": 0.1, "x": 31}, {"y": 0.1, "x": 32}, {"y": 0.1, "x": 33}, {"y": 0.1, "x": 34}, {"y": 0.1, "x": 35}, {"y": 0.1, "x": 36}, {"y": 0.1, "x": 37}, {"y": 0.1, "x": 38}, {"y": 0.1, "x": 39}, {"y": 0.1, "x": 40}, {"y": 0.1, "x": 41}, {"y": 0.1, "x": 42}, {"y": 0.1, "x": 43}, {"y": 0.1, "x": 44}, {"y": 0.1, "x": 45}, {"y": 0.1, "x": 46}, {"y": 0.1, "x": 47}, {"y": 0.1, "x": 48}, {"y": 0.1, "x": 49}], "key": "qq003.1.3", "yAxis": "1"}, {"values": [{"y": 0.1, "x": 0}, {"y": 0.1, "x": 1}, {"y": 0.1, "x": 2}, {"y": 0.1, "x": 3}, {"y": 0.1, "x": 4}, {"y": 0.1, "x": 5}, {"y": 0.1, "x": 6}, {"y": 0.1, "x": 7}, {"y": 0.1, "x": 8}, {"y": 0.1, "x": 9}, {"y": 0.1, "x": 10}, {"y": 0.1, "x": 11}, {"y": 0.1, "x": 12}, {"y": 0.1, "x": 13}, {"y": 0.1, "x": 14}, {"y": 0.1, "x": 15}, {"y": 0.1, "x": 16}, {"y": 0.1, "x": 17}, {"y": 0.1, "x": 18}, {"y": 0.1, "x": 19}, {"y": 0.1, "x": 20}, {"y": 0.1, "x": 21}, {"y": 0.1, "x": 22}, {"y": 0.1, "x": 23}, {"y": 0.1, "x": 24}, {"y": 0.1, "x": 25}, {"y": 0.1, "x": 26}, {"y": 0.1, "x": 27}, {"y": 0.1, "x": 28}, {"y": 0.1, "x": 29}, {"y": 0.1, "x": 30}, {"y": 0.1, "x": 31}, {"y": 0.1, "x": 32}, {"y": 0.1, "x": 33}, {"y": 0.1, "x": 34}, {"y": 0.1, "x": 35}, {"y": 0.1, "x": 36}, {"y": 0.1, "x": 37}, {"y": 0.1, "x": 38}, {"y": 0.1, "x": 39}, {"y": 0.1, "x": 40}, {"y": 0.1, "x": 41}, {"y": 0.1, "x": 42}, {"y": 0.1, "x": 43}, {"y": 0.1, "x": 44}, {"y": 0.1, "x": 45}, {"y": 0.1, "x": 46}, {"y": 0.1, "x": 47}, {"y": 0.1, "x": 48}, {"y": 0.1, "x": 49}], "key": "qq003.1.67", "yAxis": "1"}, {"values": [{"y": 247677.0, "x": 0}, {"y": 250012.0, "x": 1}, {"y": 287416.0, "x": 2}, {"y": 327385.0, "x": 3}, {"y": 276739.0, "x": 4}, {"y": 247264.0, "x": 5}, {"y": 234246.0, "x": 6}, {"y": 252476.0, "x": 7}, {"y": 263584.0, "x": 8}, {"y": 244878.0, "x": 9}, {"y": 263238.0, "x": 10}, {"y": 223955.0, "x": 11}, {"y": 147838.0, "x": 12}, {"y": 216088.0, "x": 13}, {"y": 219334.0, "x": 14}, {"y": 464921.0, "x": 15}, {"y": 253147.0, "x": 16}, {"y": 143214.0, "x": 17}, {"y": 263756.0, "x": 18}, {"y": 289643.0, "x": 19}, {"y": 219631.0, "x": 20}, {"y": 280396.0, "x": 21}, {"y": 228272.0, "x": 22}, {"y": 205129.0, "x": 23}, {"y": 277684.0, "x": 24}, {"y": 336930.0, "x": 25}, {"y": 206536.0, "x": 26}, {"y": 184942.0, "x": 27}, {"y": 288391.0, "x": 28}, {"y": 265598.0, "x": 29}, {"y": 214029.0, "x": 30}, {"y": 205708.0, "x": 31}, {"y": 238413.0, "x": 32}, {"y": 173776.0, "x": 33}, {"y": 231737.0, "x": 34}, {"y": 189285.0, "x": 35}, {"y": 299765.0, "x": 36}, {"y": 254324.0, "x": 37}, {"y": 231075.0, "x": 38}, {"y": 425653.0, "x": 39}, {"y": 344885.0, "x": 40}, {"y": 394357.0, "x": 41}, {"y": 184156.0, "x": 42}, {"y": 251984.0, "x": 43}, {"y": 236977.0, "x": 44}, {"y": 280948.0, "x": 45}, {"y": 305699.0, "x": 46}, {"y": 249000.0, "x": 47}, {"y": 281287.0, "x": 48}, {"y": 247748.0, "x": 49}], "key": "qq001.2.047", "yAxis": "1"}];
nv.addGraph(function() {
var chart = nv.models.lineChart();
chart.margin({top: 30, right: 60, bottom: 100, left: 60});
var datum = coverage;
chart.xAxis
.rotateLabels(-25).tickFormat(d3.format(',.1f'));
chart.yAxis
.axisLabel('Coverage').tickFormat(d3.format(',.02f'));
chart.showLegend(true).useVoronoi(false);
d3.select('#coverage svg')
.datum(datum)
.transition().duration(500)
.attr('width', 1200)
.attr('height', 400)
.call(chart);
});
</script>
</body>
</html>

D3.js stacked layout - for repeated X values

Currently d3.layout.stack calculates the stacked-Y value based on the layers or series given.
Now I would like to generate stacked layout by both "X" value and by series. Anyway I am having 2-dimensional array of equal size.
For eg if my given data is,
var layers = [
{
"name": "apples",
"values": [
{ "x": 0, "y": 91},
{ "x": 1, "y": 290},
{ "x": 1, "y": 190},
{ "x": null, "y": null}
]
},
{
"name": "oranges",
"values": [
{ "x": 0, "y": 9},
{ "x": 1, "y": 49},
{ "x": 1, "y": 50},
{ "x": 2, "y": 220}
]
}
];
Here I have two layers ("apple","oranges"). My "x" values are [0,1,2];But If "X " values in the same layers looks same, then Y coordinate should be calculated based on the previous X value and series. Currently Y coordinate was calculated mapped by index.
Actual output for previous data:
var stacked_actual= [
{
"name": "apples",
"values": [
{ "x": 0, "y": 91,"y0":0},
{ "x": 1, "y": 290, ,"y0":0},
{ "x": 1, "y": 190, ,"y0":0},
{ "x": null, "y": null, ,"y0":0}
]
},
{
"name": "oranges",
"values": [
{ "x": 0, "y": 9,"y0":91},
{ "x": 1, "y": 49,"y0":290},
{ "x": 1, "y": 50,"y0":190},
{ "x": 2, "y": 220,"y0":0}
]
}
];
Expected output for previous data:
var stacked_expected= [
{
"name": "apples",
"values": [
{ "x": 0, "y": 91,"y0":0},
{ "x": 1, "y": 290 ,"y0":0},
{ "x": 1, "y": 190,"y0":190},
{ "x": null, "y": null ,"y0":0}
]
},
{
"name": "oranges",
"values": [
{ "x": 0, "y": 9,"y0":91},
{ "x": 1, "y": 49,"y0":480},
{ "x": 1, "y": 50,"y0":520},
{ "x": 2, "y": 220,"y0":0}
]
}
];
Is there any way to achieve this model?
Pls check the reference image
enter link description here

Resources