I have included my R code and my D3JS code. I’m trying to create a normal distribution in R-Studio, and using D3 to visualize the results, the R code is as follows, and was created to be replicable. I want the MouseMove code to show the Y-axis value on MouseMove, but currently it’s not working. Any tips is appreciated.
Happy Thanksgiving!
library(r2d3)
# Generate standard normal distribution data
set.seed(123)
df <- rnorm(n = 10000, mean = 0, sd = 1)
# Bin the data to create a histogram
binned_df <- hist(df, plot = FALSE, breaks = 770)
# Convert the binned data to a data frame
df <- data.frame(mid = binned_df$mids, count = binned_df$counts)
rm(list=setdiff(ls(), "df")) # Clear enviroment
# Use r2d3 to pass the data to D3.js
r2d3(data = df, script = "~/Desktop/D3Test.js")
The D3 code is:
// D3 code to create an interactive histogram with varying shades of blue, tooltips, and bar height display on mouseover
r2d3.onRender(function(data, svg, width, height) {
// Set margins
var margin = { top: 20, right: 20, bottom: 30, left: 40 },
width = width - margin.left - margin.right,
height = height - margin.top - margin.bottom;
// Set the scales
var x = d3
.scaleLinear()
.rangeRound([0, width])
.domain(d3.extent(data, function(d) {
return d.mid;
}));
var y = d3
.scaleLinear()
.rangeRound([height, 0])
.domain([0, d3.max(data, function(d) {
return d.count;
})]);
// Append the svg object to the body of the page
var g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Define a color scale for varying shades of blue
var colorScale = d3.scaleSequential(d3.interpolateBlues)
.domain([0, d3.max(data, function(d) {
return d.count;
})]);
// Create a tooltip
var tooltip = d3.select("body")
.append("div")
.attr("class", "tooltip")
.style("opacity", 0);
// Add the bars
g.selectAll(".bar")
.data(data)
.enter()
.append("rect")
.attr("class", "bar")
.attr("x", function(d) {
return x(d.mid);
})
.attr("y", function(d) {
return y(d.count);
})
.attr("width", 10) // fixed width for each bar
.attr("height", function(d) {
return height - y(d.count);
})
.style("fill", function(d) {
return colorScale(d.count); // Vary shades of blue based on count
})
.on("mouseover", mouseover)
.on("mousemove", mousemove) // Updated mousemove function
.on("mouseout", mouseout);
// Tooltip functions
function mouseover(d) {
tooltip
.style("opacity", 1);
d3.select(this)
.style("stroke", "black")
.style("opacity", 1);
}
/////////////////////////////////////////////////////////////////////////////
function mousemove(d) {
const tooltipContent = `Value: ${d.count}<br>Mid: ${d.mid}`;
tooltip
.html(tooltipContent)
.style("left", (d3.event.pageX + 10) + "px") // Adjust the left offset as needed
.style("top", (d3.event.pageY - 28) + "px"); // Adjust the top offset as needed
// Add text for bar height at the top of the bar
const barHeightText = g.selectAll(".bar-height-text").data([d]);
barHeightText
.enter()
.append("text")
.attr("class", "bar-height-text")
.attr("x", x(d.mid) + 5) // Adjust the positioning as needed
.attr("y", y(d.count) - 5) // Adjust the positioning as needed
.text(`Height: ${d.count}`)
.style("fill", "black");
barHeightText
.merge(barHeightText) // Update existing text
.text(`Height: ${d.count}`);
}
/////////////////////////////////////////////////////////////////////////////
function mouseout(d) {
tooltip
.style("opacity", 0);
d3.select(this)
.style("stroke", "none")
.style("opacity", 0.7);
}
// Add the x-axis
g.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// Add the y-axis
g.append("g").call(d3.axisLeft(y));
// Append text labels and arrows to the x-axis
var xAxis = g.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
xAxis.append("text")
.attr("x", width)
.attr("y", 30) // Adjust the y-coordinate for vertical positioning
.attr("text-anchor", "end")
.text("More Conservative");
xAxis.append("text")
.attr("x", 0)
.attr("y", 30) // Adjust the y-coordinate for vertical positioning
.attr("text-anchor", "start")
.text("More Liberal");
// Append arrows (optional)
var arrowSize = 10;
xAxis.append("polygon")
.attr("points", "0,0 " + arrowSize + ",0 " + arrowSize / 2 + "," + arrowSize)
.attr("transform", "translate(0, " + (arrowSize + 25) + ")")
.style("fill", "black"); // Adjust arrow styling as needed
xAxis.append("polygon")
.attr("points", "0,0 -" + arrowSize + ",0 -" + arrowSize / 2 + "," + arrowSize)
.attr("transform", "translate(" + width + ", " + (arrowSize + 25) + ")")
.style("fill", "black"); // Adjust arrow styling as needed
});