Tooltip using ng-bootstrap on SVG elements not showing - d3.js

I created circle using D3.js. I used ng-bootstrap for Tooltip but It is not showing on svg element,
g.append("g").selectAll("circle").data(this.RecordDaily).enter().append("circle")
.attr("r", 5).attr("fill", "purple")
.attr("cx", function (d) { return x(parseTime(d.moy)); })
.attr("cy", function (d, i) { return y(d.session); })
.attr("data-toggle", "tooltip").attr("title", function (d) { return d.session })
.attr("ngbTooltip", function (d) { return d.session })
.attr("placement", "top")

Related

vue and d3 force layout, network visualization

So I'm new to d3 and very little experimented with vue.
What I want to do is graph the network after the data has been fetched in a vue component.
I tried to recreate some of the older codes about vue and d3 force layout, and tried to adapt this example, but none of them worked out and I don't really know why.
The closest I got to what I want is probably this answer, but I want it to graph after the data has been fetched.
My code looks like this right now :
<script>
import * as d3 from "d3";
export default {
name: "MapComponent",
data() {
return {
mapData: {}
};
},
created() {
this.mapdataget();
},
computed() {
this.data_vis();
},
methods: {
mapdataget: function () {
this.$store
.dispatch("mapData_get")
.then(() => {
this.mapData = this.$store.getters.mapData;
})
.catch();
},
data_vis() {
let nodes = this.mapData.nodes;
let links = this.mapData.links;
let svg = d3.select("svg")
this.simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function (d) {
return d.id;
}))
.force("charge", d3.forceManyBody())
let link = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(links) //graph.links)
.enter().append("line")
.attr("stroke-width", function (d) {
return Math.sqrt(d.value);
});
let node = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(nodes) //graph.nodes)
.enter().append("circle")
.attr("r", 5)
.call(d3.drag()
.on("start", this.dragstarted)
.on("drag", this.dragged)
.on("end", this.dragended));
node.append("title")
.text(function (d) {
return d.id;
});
this.simulation
.nodes(nodes)
.on("tick", ticked);
this.simulation.force("link")
.links(links); //graph.links);
function ticked() {
link
.attr("x1", function (d) {
return d.source.x;
})
.attr("y1", function (d) {
return d.source.y;
})
.attr("x2", function (d) {
return d.target.x;
})
.attr("y2", function (d) {
return d.target.y;
});
node
.attr("cx", function (d) {
return d.x;
})
.attr("cy", function (d) {
return d.y;
});
}
}
}
}
</script>
with mapData looking like this :
const mapData = {
'nodes': [{
'id':String
}, and more],
'links': [{
'id':String,
'source': sourceNodeId,
'target': targetNodeId
}, and more]
}
and the vue template is an svg :
<template>
<svg class='svg'></svg>
</template>
And I got an error :
[Vue warn]: Invalid value for option "computed": expected an Object,
but got Function.
In computed() you define variables that update the DOM at runtime, calling a method there without assigning a returned value or object to a variable is wrong. You should try moving this.data_vis() into the mounted() hook instead.

Displaying text labels correctly

I'm trying to show a label on each circle of the svg and change them every time the select box changes. Something shows up, but it's unreadable and I don't know what's wrong.
Here's the js bin: http://jsbin.com/legexovicu/edit?html,output
And this is the relevant code:
var pathContainers = svg.selectAll('g.line')
.data(operacion);
pathContainers.enter().append('g')
.attr('class', 'line')
.attr("style", function(d) {
return "stroke: " + color_hash[operacion.indexOf(d)][1];
});
pathContainers.selectAll('path')
.data(function (d) { return [d]; }) // continues the data from the pathContainer
.enter().append('path')
.attr('d', d3.svg.line()
.x(function (d) { return xScale(d.x); })
.y(function (d) { return yScale(d.y); })
);
pathContainers.selectAll('text')
.data(function (d) { return d; })
.enter().append('text')
.attr('x', function (d) { return xScale(d.x) + 20; })
.attr('y', function (d) { return yScale(d.y) + 25; })
.text( function (d) { return d.name; })
.attr("text-anchor", "middle")
.attr("font-family", "arial")
.attr("font-size", "5px")
.attr("fill", "white")
.attr('background','white');
// add circles
pathContainers.selectAll('circle')
.data(function (d) { return d; })
.enter().append('circle')
.attr('cx', function (d) { return xScale(d.x); })
.attr('cy', function (d) { return yScale(d.y); })
.attr('r', 2)
.style('fill', 'white')
.attr("title", function(d) { return d.name });
If I look the generated html, I see something like this:
<text x="70" y="75" text-anchor="middle" font-family="arial" font-size="5px" fill="white" background="white">Consti</text>
But I end up getting something illegible.
Add this to your texts:
.style("stroke-width", 1);
Here is your JSBin: http://jsbin.com/lujuhupata/1/edit?html,output

d3.js multi bar does not refresh

My d3 multi bar does not refresh after data changes. If there is more bars it add it in the end of old but does not remove old ones. If there is less bars it does not add it at all. Axis changes all the time for that from new data
var bars = svg.select(".chart-group")
.selectAll(".state")
.data(data);
bars.enter().append("g")
.attr("class", "state")
.attr("transform", function (d) {
return "translate(" + x0Scale(d[KEY]) + ",0)";
});
bars.exit().remove();
bars.selectAll("rect")
.data(function (d) {
return d.ages;
})
.enter().append("rect")
.attr("width", x1Scale.rangeBand())
.attr("x", function (d) {
return x1Scale(d[SEGMENT]);
})
.attr("y", function (d) {
return yScale(d[DATA]);
})
.attr("height", function (d) {
return chartH - yScale(d[DATA]);
})
.style("fill", function (d) {
return color(d[SEGMENT]);
});
Edit:
Here is fiddle with my problem https://jsfiddle.net/wxw5zdws/
I achieve my goal when whole container is removed:
if (container) {
container.remove();
}
I think it is bad practice, there is an issue in my drawing bars method. It should use old elements and remove/add usseless/needed elements.
What is wrong with this bars?

Adding data label in D3 Line chart (for Power BI)

Whole source code can be found here.
Requirement: I need to add Data Labels to the Line chart (aka above to the circles)
Attempt: Added
selectionCircle.append("text")
.attr(function (d) { return d.x; })
.attr(function (d) { return d.y; })
Below the line
var selectionCircle = this.sMainGroupElement2.selectAll("circle").data(dataPoints, function (d) { return d.dataId; });
Tried adding my code at various places in the original code but not working.
Try adding the following code below the existing "selectionCircle.exit().remove();" line:
this.sMainGroupElement2.selectAll("text").remove();
var selectionLabel = this.sMainGroupElement2.selectAll("circleLabel").data(dataPoints, function (d) { return d.dataId; });
selectionLabel.enter()
.append("text")
.classed(".circleLabel", true)
.text(function(d) { return d.ActualOrg; })
.attr("x", function (d) { return d.x; })
.attr("y", function (d) { return d.y-sH*0.05; })
.attr("fill", "#bebebe")
.attr("style", "font-family:calibri;font-size:" + sL * 0.04 + "px")
.attr("text-anchor", "middle")
selectionLabel.exit().remove();
It not best-pratice to remove (they should be updated instead) all elements like the first line does, but it will get you started.
I'm not really knowledgeable with Power BI, but in d3.js you would just append the text nodes in the enter statement, just like you appended the circle.
So it would look something like this:
selectionCircle.enter()
.append("circle")
.classed(".circle112", true)
.attr("cx", function (d) { return d.x; })
.attr("cy", function (d) { return d.y; })
.attr("r", sH * 0.02)
.attr("fill", statusColor)
.attr("stroke", "white")
.attr("stroke-width", sH * 0.015)
.append("text")
.text('some label text can also be a function') //Change this
.attr(function (d) { return d.x; })
.attr(function (d) { return d.y; });
The .enter() method of d3 iterates through the data and is used to add new elements depending on the data.
Hope this helps.

change the style with 'selectAll' and 'select' problems

I am trying to change the style of some svg element.
when I do this:
var circleSelected = d3.select("#circleid_2");
circleSelected.style("fill", "purple");
circleSelected.style("stroke-width", 5);
circleSelected.style("stroke", "red");
the circle is changing its style.
BUT, when i do this:
var allCircles = d3.selectAll(".circle");
allCircles.forEach(function (circle) {
circle.style("fill", "green"); //function(d) { return getNodeColor(d); }
});
it does not work with the error: Object [object SVGCircleElement] has no method 'style'
and here is my 'circle' declaration (note: it has both class and id):
node.append("circle")
.attr("id", function (d) { return "circleid_" + d.id; })
.attr("class", "circle")
.attr("cx", function (d) { return 0; })
.attr("cy", function (d) { return 0; })
.attr("r", function (d) { return getNodeSize(d); })
.style("fill", function (d) { return getNodeColor(d); })
.style("stroke", function (d) { return getNodeStrokeColor(d); })
.style("stroke-width", function (d) { return getNodeStrokeWidth(d); });
What am I doing wrong here? Thanks for the help!
Try:
d3.selectAll("circle").style("fill", "green");
Or:
allCircles.style("fill", "PaleGoldenRod");
Explanation: d3.selectAll will return a selection, which can be acted upon using the functions described in this API: https://github.com/d3/d3/blob/master/API.md#selections-d3-selection
However, as soon as you do forEach, the internal variable returned each time as circle will be an actual DOM element - no longer a selection, and therefore no style function attached.

Resources