Mouseover event for barchart in D3 - d3.js

I am having trouble creating a mouseOver event for my D3 visualization for a class. I have a bar chart I created and want to make it so when I mouse over each bar, it displays a small div with the actual values of the bar inside. I have created the barchart I want and am trying integrate a section of code from one of our earlier labs in class, where we added this hover functionality to the barchart visualization but I am just not able to get anything to work.
Here is the code for my index.html with a working graph
<!DOCTYPE html>
<meta charset="utf-8">
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>
<div style ="float:right; padding-right:300px" id="tooltip"></div>
<script>
// set the dimensions and margins of the graph
var margin = {top: 30, right: 30, bottom: 70, left: 60},
width = 460 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
.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 + ")");
// Parse the Data
d3.csv("Embiid3pt.csv", function(data) {
// X axis
var x = d3.scaleBand()
.range([ 0, width ])
.domain(data.map(function(d) { return d.player; }))
.padding(0.2);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.selectAll("text")
.attr("transform", "translate(-10,0)rotate(-45)")
.style("text-anchor", "end");
svg.append("text")
.attr("transform",
"translate(" + (width/2) + " ," +
(height + margin.top + 25) + ")")
.style("text-anchor", "middle")
.text("Player Name");
// Add Y axis
var y = d3.scaleLinear()
.domain([0, 0.7])
.range([ height, 0]);
svg.append("g")
.call(d3.axisLeft(y));
// text label for the y axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x",0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Three Point Percentage");
// Bars
svg.selectAll("mybar")
.data(data)
.enter()
.append("rect")
.attr("x", function(d) { return x(d.player); })
.attr("y", function(d) { return y(d.percentage); })
.attr("width", x.bandwidth())
.attr("height", function(d) { return height - y(d.percentage); })
.attr("fill", "#69b3a2")
})
</script>
And here is the CSV data I'm loading in:
player,percentage
Joel Embiid,0.377
Bam Adebayo,0.143
Clint Capela,0
Anthony Davis,0.26
Nikola Vucevic,0.339
Deandre Ayton,0.250
Jarrett Allen,0.189
Kristaps Porzingis,0.353
Finally, here is the section of code that we used earlier in the course to give the mouseover event to the bars of the bar chart:
let bars = chart.append('g')
.selectAll("rect")
.data(data)
.join("rect")
.attr("x", function (d) { return x(d.name); } )
.attr("y", function (d) { return y(d.value); } )
.attr("fill", function(d) { return ordinal(d.name) })
.attr("width", x.bandwidth()) //use the bandwidth returned from our X scale
.attr("height", function(d) { return height - y(+d.value); }) //full height - scaled y length
.style("opacity", 0.75)
bars //let's attach an event listener to points (all svg circles)
.on('mouseover', (event,d) => { //when mouse is over point
d3.select(event.currentTarget) //add a stroke to highlighted point
.style("stroke", "black");
d3.select('#tooltip2') // add text inside the tooltip div
.style('display', 'block') //make it visible
.html(`
<h1 class="tooltip-title">${d.name}</h1>
<div>Highway (HWY) MPG: ${d.value}</div>
`);
})
.on('mouseleave', (event) => { //when mouse isnt over point
d3.select('#tooltip2').style('display', 'none'); // hide tooltip
d3.select(event.currentTarget) //remove the stroke from point
.style("stroke", "none");
});
How do I integrate this final section of code into my index.html to get this mouseover event to work? I already created the tooltip div at the top of the index which will display the values once you mouse over.

Related

d3.js How to draw line chart with vertical x axis labels

d3.js How to draw line chart with vertical x axis labels?
My Fiddle:
https://jsfiddle.net/nitinjs/p1r49qeg/
// set the dimensions and margins of the graph
var margin = {top: 10, right: 30, bottom: 30, left: 60},
width = 460 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
.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
d3.csv("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/connectedscatter.csv",
// When reading the csv, I must format variables:
function(d){
return { date : d3.timeParse("%Y-%m-%d")(d.date), value : d.value }
},
// Now I can use this dataset:
function(data) {
// Add X axis --> it is a date format
var x = d3.scaleTime()
.domain(d3.extent(data, function(d) { return d.date; }))
.range([ 0, width ]);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// Add Y axis
var y = d3.scaleLinear()
.domain( [8000, 9200])
.range([ height, 0 ]);
svg.append("g")
.call(d3.axisLeft(y));
// Add the line
svg.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "#69b3a2")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(d) { return x(d.date) })
.y(function(d) { return y(d.value) })
)
// Add the points
svg
.append("g")
.selectAll("dot")
.data(data)
.enter()
.append("circle")
.attr("cx", function(d) { return x(d.date) } )
.attr("cy", function(d) { return y(d.value) } )
.attr("r", 5)
.attr("fill", "#69b3a2")
})
UPDATE
I have few questions,
1. how to make this graph resposive in bootstrap ie. without hardcoding width and height
2. how to update this graph on button click
3. how do I start y axis at 0 to any value e.g. 0 to 9100
Updated answer: to change the label rotation just select all text elements and apply rotate through transform attribute, and adjust the location using dx and dy, also if you notice I changed the padding bottom value in margin variable to be able to view the tick text since this will make them half visible with rotation.
...
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.5em")
.attr("transform", "rotate(-90)");
...
or a working snippet:
// set the dimensions and margins of the graph
var margin = {top: 10, right: 30, bottom: 60, left: 60},
width = 460 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom - 45;
// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
.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
d3.csv("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/connectedscatter.csv",
// When reading the csv, I must format variables:
function(d){
return { date : d3.timeParse("%Y-%m-%d")(d.date), value : d.value }
},
// Now I can use this dataset:
function(data) {
// Add X axis --> it is a date format
var x = d3.scaleTime()
.domain(d3.extent(data, function(d) { return d.date; }))
.range([ 0, width ]);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.5em")
.attr("transform", "rotate(-90)");
// Add Y axis
var y = d3.scaleLinear()
.domain( [8000, 9200])
.range([ height, 0 ]);
svg.append("g")
.call(d3.axisLeft(y))
// Add the line
svg.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "#69b3a2")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(d) { return x(d.date) })
.y(function(d) { return y(d.value) })
)
// Add the points
svg
.append("g")
.selectAll("dot")
.data(data)
.enter()
.append("circle")
.attr("cx", function(d) { return x(d.date) } )
.attr("cy", function(d) { return y(d.value) } )
.attr("r", 5)
.attr("fill", "#69b3a2")
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.js"></script>
<div id="my_dataviz"></div>
updated answer for, I added responsive to the chart and change the label of the first element in the left axis, I will leave the data update to you, also some notes there are better ways to make responsive d3 charts one of them is to use viewport attribute but I didn't test it myself, also the first the element to start from 0 I did it as a hack, I'm sure there is a better way of doing it without select and change, those are a starting point for you, I hope my change give some insights on where to look for here:
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
</head>
<body>
<div id="my_dataviz"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.js"></script>
<script>
// set the dimensions and margins of the graph
var margin = {top: 10, right: 30, bottom: 60, left: 60},
width = 1280 - margin.left - margin.right,
height = 650 - margin.top - margin.bottom - 45;
// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr('class', 'main-container')
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
//Read the data
d3.csv("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/connectedscatter.csv",
// When reading the csv, I must format variables:
function(d){
return { date : d3.timeParse("%Y-%m-%d")(d.date), value : d.value }
},
// Now I can use this dataset:
function(data) {
// Add X axis --> it is a date format
var x = d3.scaleTime()
.domain(d3.extent(data, function(d) { return d.date; }))
.range([ 0, width ]);
var axisBottom = svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
d3.selectAll('.axis-left text').filter((d, i) => { return i === 0}).text('0,000');
// Add Y axis
var y = d3.scaleLinear()
.domain( [8000, 9200])
.range([ height, 0 ]);
var axisLeft = svg.append("g")
.call(d3.axisLeft(y));
// Add the line
var line = svg.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "#69b3a2")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(d) { return x(d.date) })
.y(function(d) { return y(d.value) })
)
// Add the points
var dots = svg
.append("g")
.attr('class', 'dots')
.selectAll("dot")
.data(data)
.enter()
.append("circle")
.attr("cx", function(d) { return x(d.date) } )
.attr("cy", function(d) { return y(d.value) } )
.attr("r", 5)
.attr("fill", "#69b3a2")
function drawChart() {
// reset the width
width = parseInt(d3.select('body').style('width'), 10) - margin.left - margin.right;
height = (width * 0.45) - margin.top - margin.bottom;
d3.select("#my_dataviz svg")
.attr("height", height + margin.top + margin.bottom)
.attr("width", width + margin.left + margin.right)
d3.select('.main-container')
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
x = d3.scaleTime()
.domain(d3.extent(data, function(d) { return d.date; }))
.range([ 0, width ]);
axisBottom.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.attr('class', 'axis-bottom')
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.5em")
.attr("transform", "rotate(-90)");
// Add Y axis
y = d3.scaleLinear()
.domain( [8000, 9200])
.range([ height, 0 ]);
axisLeft.call(d3.axisLeft(y)).attr('class', 'axis-left');
//this is shiit!! there must be a better way.
d3.selectAll('.axis-left text').filter((d, i) => { return i === 0}).text('0,000');
line.datum(data)
.attr("fill", "none")
.attr("stroke", "#69b3a2")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(d) { return x(d.date) })
.y(function(d) { return y(d.value) })
);
d3.select('.dots').remove();
var dots = svg
.append("g")
.attr('class', 'dots')
.selectAll("dot")
.data(data)
.enter()
.append("circle")
.attr("cx", function(d) { return x(d.date) } )
.attr("cy", function(d) { return y(d.value) } )
.attr("r", 5)
.attr("fill", "#69b3a2");
}
// call this once to draw the chart initially
drawChart();
//////////////////////////////////////////////
// Resizing //////////////////////////////////
//////////////////////////////////////////////
// redraw chart on resize
window.addEventListener('resize', drawChart);
})
</script>
</body>
</html>

vertical bars not aligned with the x-axis label and last bar rendered outside the x-axis range - D3 js - simple bar with fixed width

I'm having challenges in setting the bar (fixed width) position aligned correctly width the x-axis label.
The bars and the x-ticks are not aligned correctly and also the last bar is rendered after the max xscale range.
Appreciate any help in fixing this issue.
Please check the sample here - https://jsfiddle.net/sjselvan/wsy5frh2/29/ - updated and fixed version
function generateChart(){
const data = [{
label: 100,
value: 10
},
{
label: 200,
value: 20
},
{
label: 300,
value: 30
},
{
label: 400,
value: 40
},
{
label: 500,
value: 50
}];
let margin = {top: 20, right: 20, bottom: 70, left: 40},
width = 600 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
const xScale = d3.scaleLinear().domain([0,500]).range([0,width]);
const yScale = d3.scaleLinear().domain([0,50]).range([height,0]);
const xAxis = d3.axisBottom(xScale);
const yAxis = d3.axisLeft(yScale);
console.log(d3.select('#chart'));
let svg = d3.select('#chart')
.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 + ")");
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-90)" );
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Value ($)");
svg.selectAll("bar")
.data(data)
.enter().append("rect")
.style("fill", "steelblue")
.attr("x", function(d) { return xScale(d.label); })
.attr("width", 15)
.attr("y", function(d) { return yScale(d.value); })
.attr("height", function(d) { return height - yScale(d.value); });
}
generateChart();
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div id="chart"></div>
You're setting the x value of the bars, which sets the left-hand edge of the bars, using the same scale as the x axis. So, it makes sense that the left-hand edge of the bar representing 100 is lined up with the 100 tick in the axis.
In order to line up the bars, you need to move them to the left by half of their width. You would need to make the bar width an even number so that the bars fit nicely.
const barWidth = 16;
svg.selectAll("bar")
.data(data)
.enter().append("rect")
.style("fill", "steelblue")
.attr("x", function(d) { return xScale(d.label) - (barWidth / 2); })
.attr("width", barWidth)
.attr("y", function(d) { return yScale(d.value); })
.attr("height", function(d) { return height - yScale(d.value); });
However, I would say that it doesn't really make sense for this chart to be a bar chart. Bars usually represent nominal (Banana, Apple, Pear), or ordinal values. Whereas your chart seems to more suit a line, or a scattergraph.
But if you do mean to use the numbers as labels, you will be better off using a band scale which will line up the bars above the labels nicely.

Text in the circle [duplicate]

This question already has answers here:
Adding text to d3 circle
(2 answers)
Closed 3 years ago.
I am writing a text element (x axis measure value) for each circle but even after showing text element in inspect in browser its not showing
I have appended the text under circle given same x and y for the circle but its coming through
!DOCTYPE html>
<meta charset="utf-8">
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>
<script>
// set the dimensions and margins of the graph
var margin = {top: 10, right: 30, bottom: 40, left: 100},
width = 460 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
.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 + ")");
// Parse the Data
d3.csv("https://raw.githubusercontent.com/holtzy/data_to_viz/master/Example_dataset/7_OneCatOneNum_header.csv", function(data) {
// sort data
data.sort(function(b, a) {
return a.Value - b.Value;
});
// Add X axis
var x = d3.scaleLinear()
.domain([0, 13000])
.range([ 0, width]);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.selectAll("text")
.attr("transform", "translate(-10,0)rotate(-45)")
.style("text-anchor", "end");
// Y axis
var y = d3.scaleBand()
.range([ 0, height ])
.domain(data.map(function(d) { return d.Country; }))
.padding(1);
svg.append("g")
.call(d3.axisLeft(y))
// Lines
svg.selectAll("myline")
.data(data)
.enter()
.append("line")
.attr("x1", x(0))
.attr("x2", x(0))
.attr("y1", function(d) { return y(d.Country); })
.attr("y2", function(d) { return y(d.Country); })
.attr("stroke", "grey")
// Circles -> start at X=0
svg.selectAll("mycircle")
.data(data)
.enter()
.append("circle")
.attr("cx", x(0) )
.attr("cy", function(d) { return y(d.Country); })
.attr("r", "7")
.style("fill", "#69b3a2")
.attr("stroke", "black")
// Change the X coordinates of line and circle
svg.selectAll("circle")
.transition()
.duration(2000)
.attr("cx", function(d) { return x(d.Value); })
svg.selectAll("line")
.transition()
.duration(2000)
.attr("x1", function(d) { return x(d.Value); })
// this is the line i have added at my end and it showing as well while i do the inspect element.
svg.selectAll("circle")
.append(Text)
.attr("x", function (d) { return x(d.Value); })
.attr("y", function (d) { return y(d.Country); })
.text(function (d) { return d.Value})
.attr("font-family", "sans-serif")
.attr("font-size", "6px")
.attr("fill", "black")
.style("text-anchor", "middle")
})
</script>
Would like to show measure value under circle so user dont have to guess the x axis. circle is at 13000 so it should show as 13 in circle divided by 1000
From what I can see there's a couple of things going on.
Firstly, instead of:
...
.append(Text)
which is trying to pass in a variable called Text to the append function, it should be:
...
.append('text')
i.e. append an svg text element.
However, this is still appending text elements to circle elements. If you look at the elements via Chrome Devtools, you can see that there will be a text element inside each circle element, which doesn't actually display anything.
Instead, the label text needs to be rendered separately from the circles using something like.
svg.selectAll("mytext")
.data(data)
.enter()
.append('text')
.attr("x", function (d) { return x(d.Value) + 10; })
.attr("y", function (d) { return y(d.Country) + 4; })
.text(function (d) { return d.Value})
.attr("font-family", "sans-serif")
.attr("font-size", "10px")
.attr("fill", "black")
.style("text-anchor", "start")
.style('opacity', 0)
.transition()
.delay(1500)
.duration(500)
.style('opacity', 1);
I've made the font a bit bigger, and adjusted the x and y values and used text-anchor: start so that now the text appears just off the right of the circles. I've also put in a transition based on opacity with a delay so that the text only appears at the end of the circles' animation.

d3 v4 x-axis long labels are half hidden

I am working on sample responsive d3 v4 bar chart, here the x-axis labels are bit long so it is not fully visible in the chart. Please check the Fiddle code: http://jsfiddle.net/NayanaDas/w13y5kts/4/
JavaScript code:
// set the dimensions and margins of the graph
var margin = {
top: 20,
right: 20,
bottom: 30,
left: 40
},
width = 550 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
// set the ranges
var x = d3.scaleBand()
.range([0, width])
.padding(0.1);
var y = d3.scaleLinear()
.range([height, 0]);
//define tooltip
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([20, 0])
.html(function(d) {
return "<strong>Sales:</strong> <span style='font-weight:normal;color:red'>" + d.sales + "</span>";
});
// append the svg object to the body of the page
// append a 'group' element to 'svg'
// moves the 'group' element to the top left margin
var svg = d3.select("#container").append("svg")
//.attr("width", width + margin.left + margin.right)
//.attr("height", height + margin.top + margin.bottom)
.attr("preserveAspectRatio", "xMinYMin meet")
.attr("viewBox", "0 0 550 300")
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")")
.call(tip);
// Add background color to the chart
svg.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", width)
.attr("height", height)
.attr("class","backbar");
// get the data
//d3.csv("sales.csv", function(error, data) {
// if (error) throw error;
var data = d3.csvParse(d3.select('#data_csv').text());
console.log(data);
// format the data
data.forEach(function(d) {
d.sales = +d.sales;
});
// Scale the range of the data in the domains
x.domain(data.map(function(d) {
return d.name;
}));
y.domain([0, d3.max(data, function(d) {
return d.sales;
})]);
// append the rectangles for the bar chart
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) {
return x(d.name);
})
.attr("width", x.bandwidth())
.attr("y", function(d) {
return y(d.sales);
})
.attr("height", function(d) {
return height - y(d.sales);
})
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
// add the x Axis
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.selectAll("text")
.style("text-anchor", "end")
.style("fill", "#000")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-50)" );
// add the y Axis
svg.append("g")
.call(d3.axisLeft(y));
// add y-axis label
svg.append("text")
.attr("text-anchor", "middle") // this makes it easy to centre the text as the transform is applied to the anchor
.attr("transform", "translate("+ (-margin.left/2) +","+(height/2)+")rotate(-90)") // text is drawn off the screen top left, move down and out and rotate
.text("Hours");
//});
$('#expandbtn').click(function (e) {
$("#container").css("height","100%");
$('#box').addClass('panel-fullscreen show');
$('#compressbtn').removeClass("hide").addClass("show");
$('#expandbtn').removeClass("show").addClass("hide");
});
$('#compressbtn').click(function (e) {
$("#container").css("height","480px");
$('#box').removeClass('panel-fullscreen');
$('#expandbtn').removeClass("hide").addClass("show");
$('#compressbtn').removeClass("show").addClass("hide");
});
I have also added two buttons, on clicking expand button the chart will be displayed in full screen mode and on clicking compress button, chart will be back in normal size. Don't know if that has affected the display of x-axis labels. How can I make the long labels view-able?
Change your svg viewBox attribuite to 0 0 550 550.
The first two values are the X and Y coordinates of the upper left corner of the displayed area, the last two are the width and height. viewBox is set only by attribute.
How it works
Also check what is preserveAspectRatio values and how they work

Tooltip for d3 v4 is not responding to the bar graph

I am hoping to make my bar changes color and display the year and value as the mouse hooves over it. I have the "mouseover, mouseout, and mousemove" but doesn't seem to work. Any help would be great. When I click on the bar, the key and value appear in the console. The values are nested. Thank you
Js:
//set the dimensions and margins of the graph
var margin = {
top: 20,
right: 20,
bottom: 30,
left: 70
},
width = 600 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom,
padding = 15;
// Fomat timeStamp to year
var dateFormat = d3.timeFormat("%Y");
//append the svg object to the body of the page
var svg = d3.select("#graph").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 + ")");
// Get the data
d3.json("https://moto.data.socrata.com/resource/jfwn-iu5d.json?
$limit=500000",
function(data) {
// Objects
data.forEach(function(data) {
data.incident_description = data.incident_description;
data.incident_datetime = dateFormat(new Date(data.incident_datetime));
});
// Nest data by year of incident
var NestbyDate = d3.nest()
.key(function(d) {
return d.incident_datetime;
})
.key(function(d) {
return d.incident_description + " " + d.incident_datetime;
})
.rollup(function(leaves) {
return d3.sum(leaves, function(d) {
return (d.incident_description)
});
})
.entries(data);
var y_domain = d3.max(NestbyDate, function(d) {
return d.values.length;
});
console.log(NestbyDate) /
NestbyDate.sort((a, b) => a.key - b.key);
// set the ranges
var x = d3.scaleBand().domain(NestbyDate.map(d =>
d.key)).range([padding, width]);
var y = d3.scaleLinear().domain([0, y_domain]).range([height,
10]);
// Add the X Axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x).ticks(6));
// Add the Y Axis
svg.append("g")
.attr("class", "axis")
.call(d3.axisLeft(y));
// Text label for the x-axis
svg.append("text")
.attr("x", width / 2)
.attr("y", height + margin.top + 7)
.style("text-anchor", "center")
.text("Day Date Format")
.text("Year");
// Text Label for y-axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x", 0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Number of crime incidents");
// Draw the bars
svg.selectAll("rect")
.data(NestbyDate)
.enter()
.append("rect")
.attr("class", "rect")
.attr("x", function(d) {
return x(d.key);
})
.attr("y", function(d) {
return y(d.values.length);
})
.attr("fill", "darkblue")
.attr("width", x.bandwidth())
.attr("height", function(d) {
return y(0) - y(d.values.length);
})
.on("mouseover", function() {
tooltip.style("display", null);
})
.on("mouseout", function() {
tooltip.style("display", "none");
})
.on("mousemove", function(d) {
console.log(d);
var xPosition = d3.mouse(this)[0] - 15;
var yPosition = d3.mouse(this)[1] - 55;
tooltip.attr("transform", "translate(" + xPosition +
"," + yPosition + ")");
tooltip.select("text").text(d.key +":" + y_domain);
});
// tooltips
var tooltip = svg.append("g")
.attr("class", "tooltip")
.style("display", "none");
tooltip.append("text")
.attr("dy", "1.2mm")
});
graph portion of html:
<div>
<h3> Number of crimes per year</h3>
<p>Below is a bar graph of the total number of crimes per year
from 2011 to 2018. The most crime incidents occur in 2017, with a total of
101,478 crimes.</p>
<div id="graph" class="responsive-plot"></div>
</div>
</div>

Resources