I'm new to d3.js implementation. Need some help d3.js heatmap
I have a Requirement :
A heat map which shows the difference between each record. based on records Severity and Probability types:
Desired Image :
Data:
In the Above output picture , You can see the circles :
Assume those as records being displayed on a graph .
Code for that starts after Comment " //Add dots or circles " .
Record data example :
{
"group":"Likely",
"variable":"Significant",
"value":79,
"record":"Retention of environmental safety records",
"color":"red"
}
Data for those records are in variable "dots" You can find in the code below. In that I have 3 records . But 2 circles are overlapping .
I have worked on a Heatmap Design .
Combining :
Heatmap : https://www.d3-graph-gallery.com/graph/heatmap_style.html
Connected scatter plot : https://www.d3-graph-gallery.com/graph/connectedscatter_tooltip.html
For now , I have just updated the data :
I have 2 Issues :
Overlapping dots issue
Tooltip not showing after Updating to svg
Detail:
1. Overlapping dots issue
Data for those records are in variable "dots" You can find in the code below. In that I have 3 records . But 2 circles are overlapping .
The desired Output is something like this : Circles should not be Overlapped .
If two records with same data , It should display 2 records. I need help in implenting that . Any suggestion is appreciated .
** 2. ToolTip Issue :**
I had an Issue with Tooltip (It was working with div tag ) previously it was as shown below :
Due to Some requirement i had to go with svg tag in the Html rather than Div tag . since This has to be implemented in Lwc in Salesforce.
Html Updated from div to Svg as shown below :
After Updating ,
Entire Heatmap is working except the Tooltip part .
Updated the Tooltip part to Svg as shown below :
Now the Tooltip is not working .
code :
<!-- Code from d3-graph-gallery.com -->
<!DOCTYPE html>
<meta charset="utf-8">
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v5.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz">
<svg
class="d3"
width={svgWidth}
height={svgHeight}
lwc:dom="manual"
></svg></div>
<!-- Load color palettes -->
<script>
// set the dimensions and margins of the graph
var margin = {top: 80, right: 25, bottom: 30, left: 100},
width = 550 - margin.left - margin.right,
height = 450 - margin.top - margin.bottom;
// append the svg object to the body of the page
var svg = d3.select(this.template.querySelector('svg.d3'))
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
//Read the data
var data = [{"group":"Rare","variable":"Insignificant","value":45,"color":"purple"},{"group":"Rare","variable":"Minimal","value":95,"color":"purple"},{"group":"Rare","variable":"Moderate","value":22,"color":"green"},{"group":"Rare","variable":"Significant","value":14,"color":"green"},{"group":"Rare","variable":"Catastrophic","value":59,"color":"yellow"},{"group":"Unlikely","variable":"Minimal","value":37,"color":"purple"},{"group":"Unlikely","variable":"Insignificant","value":37,"color":"purple"},{"group":"Unlikely","variable":"Moderate","value":81,"color":"green"},{"group":"Unlikely","variable":"Significant","value":79,"color":"yellow"},{"group":"Unlikely","variable":"Catastrophic","value":84,"color":"orange"},{"group":"Probable","variable":"Insignificant","value":96,"color":"purple"},{"group":"Probable","variable":"Minimal","value":37,"color":"green"},{"group":"Probable","variable":"Moderate","value":98,"color":"yellow"},{"group":"Probable","variable":"Significant","value":10,"color":"orange"},{"group":"Probable","variable":"Catastrophic","value":86,"color":"red"},{"group":"Likely","variable":"Insignificant","value":75,"color":"green"},{"group":"Likely","variable":"Minimal","value":18,"color":"yellow"},{"group":"Likely","variable":"Moderate","value":92,"color":"orange"},{"group":"Likely","variable":"Significant","value":43,"color":"red"},{"group":"Likely","variable":"Catastrophic","value":16,"color":"red"},{"group":"Almost Certain","variable":"Insignificant","value":44,"color":"green"},{"group":"Almost Certain","variable":"Minimal","value":29,"color":"yellow"},{"group":"Almost Certain","variable":"Moderate","value":58,"color":"orange"},{"group":"Almost Certain","variable":"Significant","value":55,"color":"red"},{"group":"Almost Certain","variable":"Catastrophic","value":65,"color":"red"}]; // Labels of row and columns -> unique identifier of the column called 'group' and 'variable'
var myGroups = d3.map(data, function(d){return d.group;}).keys()
var myVars = d3.map(data, function(d){return d.variable;}).keys()
// Build X scales and axis:
var x = d3.scaleBand()
.range([ 0, width ])
.domain(myGroups)
.padding(0.05);
svg.append("g")
.style("font-size", 15)
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x).tickSize(0))
.select(".domain").remove()
// Build Y scales and axis:
var y = d3.scaleBand()
.range([ height, 0 ])
.domain(myVars)
.padding(0.05);
svg.append("g")
.style("font-size", 15)
.call(d3.axisLeft(y).tickSize(0))
.select(".domain").remove()
// Build color scale
var myColor = d3.scaleSequential()
.interpolator(d3.interpolateInferno)
.domain([1,100])
// create a tooltip
var tooltip = d3.select("#my_dataviz")
.append("div")
.style("opacity", 0)
.attr("class", "tooltip")
.style("background-color", "white")
.style("border", "solid")
.style("border-width", "2px")
.style("border-radius", "5px")
.style("padding", "5px")
.style("position","fixed")
// Three function that change the tooltip when user hover / move / leave a cell
var mouseover = function(d) {
tooltip
.style("opacity", 1)
d3.select(this)
.style("stroke", "black")
.style("opacity", 1)
}
var mousemove = function(d) {
tooltip
.html("The exact value of<br>this cell is: " + d.value)
.style("left", (d3.mouse(this)[0]+70) + "px")
.style("top", (d3.mouse(this)[1]) + "px")
}
var mouseleave = function(d) {
tooltip
.style("opacity", 0)
d3.select(this)
.style("stroke", "none")
.style("opacity", 0.8)
}
// add the squares
svg.selectAll()
.data(data, function(d) {return d.group+':'+d.variable;})
.enter()
.append("rect")
.attr("x", function(d) { return x(d.group) })
.attr("y", function(d) { return y(d.variable) })
.attr("rx", 4)
.attr("ry", 4)
.attr("width", x.bandwidth() )
.attr("height", y.bandwidth() )
.style("fill", function(d) { return d.color } )
.style("stroke-width", 4)
.style("stroke", "none")
.style("opacity", 0.8)
.on("mouseover", mouseover)
.on("mousemove", mousemove)
.on("mouseleave", mouseleave)
// Three function that change the tooltip when user hover / move / leave a cell
var mouseover1 = function(d) {
tooltip
.style("opacity", 1)
d3.select(this)
.style("stroke", "black")
.style("opacity", 1)
}
var mousemove1 = function(d) {
tooltip
.html("4. " + d.record)
.style("left", (d3.mouse(this)[0]+90) + "px")
.style("top", (d3.mouse(this)[1]) + "px")
}
var mouseleave1 = function(d) {
tooltip
.style("opacity", 0)
d3.select(this)
.style("stroke", "none")
.style("opacity", 0.8)
}
//Add dots or circles
var dots =
[{"group":"Likely","variable":"Significant","value":79,"record":"Retention of environmental safety records","color":"red"},
{"group":"Unlikely","variable":"Minimal","value":84,"record":"Risk of Fines from European Union GDPR due to data breach","color":"orange"},
{"group":"Unlikely","variable":"Minimal","value":84,"record":"Risk Management Case record","color":"green"}];
// Add the points
svg
.append("g")
.selectAll("dot")
.data(dots)
.enter()
.append("circle")
.attr("class", "myCircle")
.attr("cx", function(d) { return x(d.group) + x.bandwidth()/2 } )
.attr("cy", function(d) { return y(d.variable)+ y.bandwidth()/2 } )
.attr("r", 8)
.attr("stroke", "#69b3a2")
.attr("stroke-width", 3)
.attr("fill", function(d) { return d.color })
.on("mouseover", mouseover1)
.on("mousemove", mousemove1)
.on("mouseleave", mouseleave1)
//})
// Add title to graph
svg.append("text")
.attr("x", 0)
.attr("y", -50)
.attr("text-anchor", "left")
.style("font-size", "22px")
.text("A heatmap");
// Add subtitle to graph
svg.append("text")
.attr("x", 0)
.attr("y", -20)
.attr("text-anchor", "left")
.style("font-size", "14px")
.style("fill", "grey")
.style("max-width", 400)
.text("A short description of the take-away message of this chart.");
</script>
Output (Updated) :
Can someone help me in resolving these issues.
I need to display the multiple dots inside the same squares, each dot as a seperate element . when you hover over it It should display the record it represents.
Any suggestion is appreciated . Thankyou
Give your tooltip a position of fixed:
.style("position","fixed")
This will allow the top and left attributes to impact its positioning.
To make the dots appear within the boxes, change your cx attribute to:
.attr("cx", function(d) { return x(d.group) + x.bandwidth()/2 } )
That should center the dots within each box.
To give the dots their own positioning, the dots need to have their own y and x scales. Just make sure it has the same width and height.
Do you have another dataset for this? If not, I wonder if a different scale would give you the outcome you are looking for.
I have some data with 2 attributes: colour and value
I use the D3 enter selection to create circle elements, and append them to the body of the page. Their fill colour is determined by the "colour" attribute.
Then, I append text elements to the page. The text contents are determined by the "value" attribute.
Here is what I am working with:
// Set up svg element
var svg = d3.select("body")
.append("svg")
.attr("width", 300)
.attr("height", 300)
.style("background", "lightblue");
var dataset = [
{"colour":"red", "value":"First set of text"},
{"colour":"green", "value":"Second attempt"},
{"colour":"blue", "value":"Third and final!"}
];
// Create circles from the data
// On mouseover, give them a border (remove on mouseout)
svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("r", 40)
.attr("cy", function(d, i) { return i*80 + 40; })
.attr("cx", 50)
.style("fill", function(d) {return d.colour;})
// HERE
// Can I somehow show and hide the text component that is
// associated with this circle when the circle is hovered, rather
// than the text itself?
.on("mouseover", function(d) {
d3.select(this).style("stroke", "black")
.style("stroke-width", 2)
})
.on("mouseout", function(d) {d3.select(this).style("stroke", "none")});
// Now add the text for each circle
// Same thing with mouseover and mouseout
svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.attr("text-anchor", "middle")
.attr("y", function(d, i) { return i*80 + 40; })
.attr("x", 50)
.style("opacity", 0)
.on("mouseover", function(d) {d3.select(this).style("opacity", 1)})
.on("mouseout", function(d) {d3.select(this).style("opacity", 0)})
.text(function(d) { return d.value;});
I would like for the text to be hidden, until the associated circle is hovered over. How can I connect the text element with a particular circle, so that I can toggle whether the text is shown by hovering over the circle?
This fiddle below is an outline of what I am trying to do, and what I have got so far. I have the text showing up only when hovered, but not when the circle is hovered.
https://jsfiddle.net/aj4zpn6z/
There are several ways for achieving this. Since both circles and texts use the same dataset, my solution uses filter.
First, let's name the variables for the texts and circles:
var circles = svg.selectAll("circle")
//etc...
var texts = svg.selectAll("text")
//etc...
Then, inside the circles mouseover function, we filter the texts that have the same colour attribute:
.on("mouseover", function(d){
d3.select(this).style("stroke", "black").style("stroke-width", 2);
var tempTexts = texts.filter(function(e){
return e.colour === d.colour
});
tempTexts.style("opacity", 1);
});
This is your updated fiddle: https://jsfiddle.net/wxh95e9u/
I've got the following scatter plot usind d3.js http://gkalliatakis.github.io./
and now I want to add tootltip of time (value of x axis) every time the mouse is over a triangle. I read lots of examples:
http://bl.ocks.org/weiglemc/6185069
but I was not able to modify them for my project.
Any thoughts?
I've modified your code to incorporate the tooltip from your example link. The keys are this:
1.) Append the div tooltip to your html body (note, your html was malformed, it didn't have a body, I added those tags):
var tooltip = d3.select('body')
.append('div')
.attr('class', 'tooltip')
.style("opacity", 0);
2.) On mouseover/mouseout of your points update the div's html and show/hide the tooltip:
svg.selectAll(".point")
.data(session_data)
.enter()
.append("path")
.on("mouseover", function(d, i) { // show it and update html
d3.select('.tooltip')
tooltip.transition()
.duration(200)
.style("opacity", .9);
tooltip.html(d.x)
.style("left", (d3.event.pageX + 5) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d, i) {
tooltip.transition()
.duration(500)
.style("opacity", 0);
})
.attr("class", "point")
...
Working example here.
I have been struggling past 2 days to achieve below requirements.
Circle is behaving in abnormal and indeterminate way.
Requirements
1.Text should come inside the circle when circle is full hovered.
2.When circle is hovered and you take mouse cursor on text,the circle and text should not flicker.
3.Invisible circle should come back to its previous radius.
Here is the code
d3.select("#outerG")
.insert("g", "#invisibleG").attr("class", "maincircles").append("circle")
.attr("cx",120)
.attr("cy", 120)
.attr("r", 30)
.attr("class", "circle")
.style('fill', '#19b2e8');
d3.select("#invisibleG").append("g")
.attr("class","invisibleCircle")
.append("circle")
.attr("cx",120)
.attr("cy",120)
.attr("r",30)
.attr("class","inviCircle")
.style('fill-opacity', '0')
.attr("prevRadius",30)
.attr("xcoords",120)
.attr("ycoords",120)
.on("mouseover",function(){
var r=d3.select(this).attr("r");
d3.select(this).style('fill','#19b2e8')
.style('fill-opacity','1')
.transition()
.duration(1000)
.attr("r",50);
var prevRadius=d3.select(this).attr("prevRadius");
var xcoord= d3.select(this).attr("xcoords");//to centre text
var ycoord= d3.select(this).attr("ycoords");//to centre text
d3.select(this.parentNode).append("text")
.transition()
.duration(1000)
.text("Hello")
.attr("x",120)
.attr("y",120)
.style("font-family","sans-serif")
.style("font-size","20px")
.style("text-anchor","middle");
})
.on("mouseout",function(){
d3.select(this.parentNode).select("text").remove();
//d3.select(this).interrupt();
var r=d3.select(this).attr("prevRadius");
d3.select(this)
.transition()
.duration(1000)
.attr("r",r).attr("stroke-width",0)
.style('fill-opacity','0');
});
here is the HTML
<svg width="300" height="300">
<g id="outerG">
<g id="invisibleG"></g>
</g>
</svg>
Check fiddle http://jsfiddle.net/razC9/5/
Problem is that text is messing up mouse events on mouseover and solution is to add this css
svg text {
pointer-events: none;
}
Here is how it looks like now - http://jsfiddle.net/razC9/7/
Based on your requirements, here is a working fiddle. It is done with 1 circle, instead of two, drying up the code some. EDIT: Timing set to flash text once radius is fully expanded:
http://jsfiddle.net/razC9/42/
Key snippet:
.on("mouseover", function(){
d3.select(this)
.transition().attr("r", 50).duration(750)
.style("fill", "#19b2e8")
.style('fill-opacity','1');
d3.select("#outerG") .append("text")
.transition().delay(750)
.attr("class", "text")
.text("Hello")
.attr("x", 100)
.attr("y", 120)
.attr("fill", "black");
})
.on("mouseout", function(){
d3.select(this)
.transition().attr("r", 20)
.style("fill", "#19b2e8");
d3.select("#outerG").select(".text").remove();
});