I am trying to build a scatterplot by loading data from a .csv file. My scatterplot is trying to show Poverty (x-axis) vs. Healthcare (y-axis) for each state.
Here's a snippet of the CSV file:
id state healthcare poverty
1 Alabama 13.9 19.3
2 Alaska 11.2 11.4
3 Arizona 14.4 18.2
4 Arkansas 16.3 18.9
5 California 14.8 16.4
6 Colorado 12.8 12
7 Connecticut 8.7 10.8
8 Delaware 8.7 12.5
Here's my javascript code:
var svgWidth = 960;
var svgHeight = 500;
var margin = {
top: 20,
right: 40,
bottom: 60,
left: 100
};
var width = svgWidth - margin.left - margin.right;
var height = svgHeight - margin.top - margin.bottom;
// Create an SVG wrapper, append an SVG group that will hold our chart and shift the latter by left and top margins
var svg = d3.select("#scatter")
.append("svg")
.attr("width", width)
.attr("height", height);
var chartGroup = svg.append("g")
.attr("transform", `translate(${margin.left}, ${margin.top})`);
// Import Data
d3.csv("data.csv").then(function(censusData) {
// Parse Data & Cast as numbers
censusData.forEach(function(data) {
data.healthcare = +data.healthcare;
data.poverty = +data.poverty;
});
// Create scale functions
var xLinearScale = d3.scaleLinear()
.domain(d3.extent(censusData, d => d.poverty))
.range([0, width]);
var yLinearScale = d3.scaleLinear()
.domain([0, d3.max(censusData, d => d.healthcare)])
.range([height, 0]);
// Create axis functions
var bottomAxis = d3.axisBottom(xLinearScale);
var leftAxis = d3.axisLeft(yLinearScale);
// Append axes to the chart
chartGroup.append("g")
.attr("transform", `translate(0, ${height})`)
.call(bottomAxis);
chartGroup.append("g")
.call(leftAxis);
// Create circles
var circlesGroup = chartGroup.selectAll("Circle")
.data(censusData)
.enter()
.append("circle")
.attr("cx", d => xLinearScale(d.poverty))
.attr("cy", d => yLinearScale(d.healthcare))
.attr("r", "15")
.attr("fill", "blue")
.attr("opacity", "0.5");
// Create axes labels
chartGroup.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left + 40)
.attr("x", 0 - (height / 2))
.attr("dy", "1em")
.attr("class", "axisText")
.text("Lacks Healthcare (%)");
chartGroup.append("text")
.attr("transform", `translate(${width / 2}, ${height + margin.top + 30})`)
.attr("class", "axisText")
.text("In Poverty (%)");
});
And here's the accompanying HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>D3Times</title>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49"
crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy"
crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO"
crossorigin="anonymous">
<link rel="stylesheet" href="assets/css/style.css">
<link rel="stylesheet" href="assets/css/d3Style.css">
</head>
<body>
<div class="container">
<div class="row">
<div class="col-xs-12 col-md-12">
<h1>D3Times</h1>
</div>
</div>
<div class="row">
<div class="col-xs-12 col-md-9">
<div id="scatter">
<!-- We append our chart here. -->
</div>
</div>
</div>
</div>
<!-- Footer-->
<div id="footer">
<p>The Coding Boot Camp©2016</p>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.5.0/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-tip/0.9.1/d3-tip.js"></script>
<script type="text/javascript" src="assets/js/app.js"></script>
</body>
</html>
When I run the code, here's the scatterplot I get:
Why isn't the X-axis displaying? Can anyone help with this?
Any help is greatly appreciated! Thanks in advance.
P.S: To run the code, I have to go into my project folder and run
python -m http.server
This hosts the page at localhost:8000 in the web browser.
You're using the famous margin convention to create your dataviz:
However, for this to work, you have to set the SVG size using the total width and height...
var svgWidth = 960;
var svgHeight = 500;
...not the ones computed after removing the margins:
var width = svgWidth - margin.left - margin.right;
var height = svgHeight - margin.top - margin.bottom;
Therefore, it should be:
var svg = d3.select("#scatter")
.append("svg")
.attr("width", svgWidth)
.attr("height", svgHeight);
Here is your updated code:
var csv = `id,state,healthcare,poverty
1,Alabama,13.9,19.3
2,Alaska,15,11.2,11.4
3,Arizona,14.4,18.2
4,Arkansas,16.3,18.9
5,California,14.8,16.4
6,Colorado,12.8,12
7,Connecticut,8.7,10.8
8,Delaware,8.7,12.5`;
const censusData = d3.csvParse(csv)
var svgWidth = 960;
var svgHeight = 500;
var margin = {
top: 20,
right: 40,
bottom: 60,
left: 100
};
var width = svgWidth - margin.left - margin.right;
var height = svgHeight - margin.top - margin.bottom;
// Create an SVG wrapper, append an SVG group that will hold our chart and shift the latter by left and top margins
var svg = d3.select("#scatter")
.append("svg")
.attr("width", svgWidth)
.attr("height", svgHeight);
var chartGroup = svg.append("g")
.attr("transform", `translate(${margin.left}, ${margin.top})`);
// Parse Data & Cast as numbers
censusData.forEach(function(data) {
data.healthcare = +data.healthcare;
data.poverty = +data.poverty;
});
// Create scale functions
var xLinearScale = d3.scaleLinear()
.domain(d3.extent(censusData, d => d.poverty))
.range([0, width]);
var yLinearScale = d3.scaleLinear()
.domain([0, d3.max(censusData, d => d.healthcare)])
.range([height, 0]);
// Create axis functions
var bottomAxis = d3.axisBottom(xLinearScale);
var leftAxis = d3.axisLeft(yLinearScale);
// Append axes to the chart
chartGroup.append("g")
.attr("transform", `translate(0, ${height})`)
.call(bottomAxis);
chartGroup.append("g")
.call(leftAxis);
// Create circles
var circlesGroup = chartGroup.selectAll("Circle")
.data(censusData)
.enter()
.append("circle")
.attr("cx", d => xLinearScale(d.poverty))
.attr("cy", d => yLinearScale(d.healthcare))
.attr("r", "15")
.attr("fill", "blue")
.attr("opacity", "0.5");
// Create axes labels
chartGroup.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left + 40)
.attr("x", 0 - (height / 2))
.attr("dy", "1em")
.attr("class", "axisText")
.text("Lacks Healthcare (%)");
chartGroup.append("text")
.attr("transform", `translate(${width / 2}, ${height + margin.top + 30})`)
.attr("class", "axisText")
.text("In Poverty (%)");
<head>
<meta charset="UTF-8">
<title>D3Times</title>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<link rel="stylesheet" href="assets/css/style.css">
<link rel="stylesheet" href="assets/css/d3Style.css">
</head>
<body>
<div class="container">
<div class="row">
<div class="col-xs-12 col-md-12">
<h1>D3Times</h1>
</div>
</div>
<div class="row">
<div class="col-xs-12 col-md-9">
<div id="scatter">
<!-- We append our chart here. -->
</div>
</div>
</div>
</div>
<!-- Footer-->
<div id="footer">
<p>The Coding Boot Camp©2016</p>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.5.0/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-tip/0.9.1/d3-tip.js"></script>
<script type="text/javascript" src="assets/js/app.js"></script>
</body>
Related
I'm having some difficulty getting d3 to render a geoAlbersUsa projection from topoJson data. I'm showing a blank screen, but no errors returned. The geoJson data seems to be coming through fine, but it's not rendering the path for some reason. Any help would be greatly appreciated!
Here's the relevant code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<script src="https://d3js.org/d3.v6.min.js"></script>
<script src="https://unpkg.com/topojson-client#3"></script>
</head>
<body>
<script>
const width = 1000;
const height = 600;
const projection = d3.geoAlbersUsa()
.translate([width / 2, height / 2])
.scale(800);
const path = d3.geoPath(projection);
const svg = d3.select("body")
.append("svg")
.attr("height", height)
.attr("width", width)
.style("display", "block")
.style("margin", "auto");
d3.json("https://d3js.org/us-10m.v1.json").then(data => {
svg.selectAll(".states")
.data(topojson.feature(data, data.objects.states).features)
.attr("d", path)
.style("fill", "none")
.attr("class", "states")
.style("stroke", "black")
.style("stroke-width", "2px")
});
</script>
</body>
</html>
You need to join with an element:
.data(topojson.feature(data, data.objects.states).features)
.join("path") // here
.attr("d", path)
.style("fill", "none")
.attr("class", "states")
.style("stroke", "black")
.style("stroke-width", "2px")
I am learning D3, i am trying to create a bar chart , But i couldn't find where the issue is but my bar chart is not being displayed in svg.
Below is my code , a html file,js file and my csv data
This is to create bar graph.
I have no clue what is it that I am missing.
I can see the svg area in the browser but not the graph.
index.html
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="description" content="">
<title>Gapminder Clone</title>
<!-- Bootstrap -->
<link rel="stylesheet" href="css/bootstrap.min.css">
<!-- Custom styling -->
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<nav class="navbar navbar-default">
<div class="container">
</div>
</nav>
<!-- Bootstrap grid setup -->
<div class="container">
<div class="row">
<div id="chart-area"></div>
</div>
</div>
<!-- External JS libraries -->
<script src="js/jquery.min.js"></script>
<script src="js/bootstrap.min.js"></script>-->
<script src="js/d3.min.js"></script>
<script src="js/main.js"></script>
</body>
</html>
main.js
------------------
/*
* main.js
* Mastering Data Visualization with D3.js
* 2.5 - Activity: Adding SVGs to the screen
*/
document.addEventListener('DOMContentLoaded', function(e) {
var data=d3.csv("expenditure.csv").then(function(data){
data.forEach(function(d){
d.Budget= +d.Budget;
d.Year= +d.Year;
})
});
var margin= {
top:30,
bottom:30,
right:30,
left:30
};
var width = 800-margin.left-margin.right;
var height = 300-margin.top-margin.bottom;
var x = d3.scaleLinear()
.domain([2000,90000])
.range([0,width]);
var y = d3.scaleLinear()
.domain([0,8])
.range([0,height]);
var svg = d3.select("#chart-area")
.append("svg")
.attr("width", 700 + margin.left + margin.right)
.attr("height", 200 + margin.top + margin.bottom)
.attr("transform", "translate(" + margin.left +
", " + margin.top + ")");
var rects = svg.selectAll("rect").data(data);
rects.enter().append("rect")
.attr("x",0)
.attr("y",function(d,i) {
return y(i);
})
.attr("width",function(d){
if(d.Country=="France"){
return x(d.Budget);
}else {
return x(d.Budget);
}
})
.attr("height",function(d,i) {
return y(1)-8;
})
.attr("fill",function(d){
if(d.Country=="Australia")
{
return "yellow";
}else if(d.Country=="Canada"){
return "green";
}else if(d.Country=="Brazil"){
return "Orange";
}else {
return "blue";
}
})
rects.enter().append("text")
//.classed("bar-label",true)
.attr("x",function(d,i) {
return x(d.Budget);
})
.attr("dx",3)
.attr("y",function(d,i) {
return y(i);
})
.attr("dy",function(d,i) {
return y(1)/1.5-5;
})
.text(function(d,i) {
return d.Budget;
})
});
Expenditure.csv
-------------------------------
Country,Year,Budget
Australia,1990,6704
Australia,2014,25784
Brazil,1990,9236
Brazil,2014,32660
Canada,1990,11415
Canada,2014,17854
France,1990,42590
France,2014,63614
You have a typo in your code.
In the main.js file, on line 11:
var data=d3.csv("expenditure.csv").then(function(data){
data.forEach(function(d){
d.Budget= +d.Budget;
d.Year= +d.Year;
//})
});
You should take the }) brakets where commented and put them at the end of the file. After that it works perfectly.
How can I hide and show an svg element using transition?
I try this code:
<div id="bubble"></div>
<div id="buttonHide"><button>Hide</button></div>
<div id="buttonShow"><button>Show</button></div>
d3.select("#bubble")
.append("svg")
.append("g")
.append("circle")
.attr("class", "bubble")
.attr("transform", "translate(100, 100)")
.attr("r", 50)
.attr("fill", "black");
d3.select("#buttonHide").on("click", function() {
d3.select(".bubble").transition().attr('visibility', 'hidden').duration(1000);
});
d3.select("#buttonShow").on("click", function() {
d3.select(".bubble").transition().attr('visibility', 'visible').duration(1000);
});
d3.select("#bubble")
.append("svg")
.append("g")
.append("circle")
.attr("class", "bubble")
.attr("transform", "translate(100, 100)")
.attr("r", 50)
.attr("fill", "black");
d3.select("#buttonHide").on("click", function() {
d3.select(".bubble").transition().duration(1000).attr('visibility', 'hidden');
});
d3.select("#buttonShow").on("click", function() {
d3.select(".bubble").transition().duration(1000).attr('visibility', 'visible');
});
<html lang='en'>
<head>
<meta charset='utf-8'>
<script src='https://d3js.org/d3.v5.js' charset='utf-8'></script>
</head>
<body>
<div id="bubble"></div>
<div id="buttonHide"><button>Hide</button></div>
<div id="buttonShow"><button>Show</button></div>
</body>
</html>
But transition doesn't work.
You could play with the opacity style instead of switching the visibility attribute:
d3.select("#bubble")
.append("svg")
.append("g")
.append("circle")
.attr("class", "bubble")
.attr("transform", "translate(100, 100)")
.attr("r", 50)
.attr("fill", "black")
.style("opacity", 1);
d3.select("#buttonHide").on("click", function() {
d3.select(".bubble").transition().duration(1000).style("opacity", 0);
});
d3.select("#buttonShow").on("click", function() {
d3.select(".bubble").transition().duration(1000).style("opacity", 1);
});
<html lang='en'>
<head>
<meta charset='utf-8'>
<script src='https://d3js.org/d3.v5.js' charset='utf-8'></script>
</head>
<body>
<div id="bubble"></div>
<div id="buttonHide"><button>Hide</button></div>
<div id="buttonShow"><button>Show</button></div>
</body>
</html>
This way, the transition will be applied on the opacity, which will transition from 0 to 1 (unhide) or from 1 to 0 (hide).
To set the opacity:
d3.select(".bubble").transition().duration(1000).style("opacity", 1);
The transition is in fact expecting a change which can be interpolated between two values. This is the case for the opacity (all the way between 0 and 1), whereas the visibility attribute is a simple switch (on/off).
I am trying to animate the attached code without success. I want the axis and path smoothly to shift in between the addition of new data points. The transition time should be deltaT. I hope someone could help me! (I got it working but only as long as the graph was not responsive, see attached js snippet)
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Transfer setup rpi1 interface</title>
<meta name="viewport" content="width=device-width" />
<link rel="stylesheet" type="text/css" href="style.css">
<script type="text/javascript" src="jquery-1.11.3.min.js"></script>
<script src="jquery.flot.min.js"></script>
<script src="jquery.flot.time.js"></script>
<script src="//d3js.org/d3.v3.js" charset="utf-8"></script>
<script type="text/javascript" src="main.js"></script>
</head>
<body>
<div class="content">
<header>
<h1>Transfer Setup Rpi1</h1>
</header>
<div class="main">
<h2>Control</h2>
<fieldset>
<legend>Temperature</legend>
<div id="widthReader">
<table id="cssTable">
<tr>
<td>
<table id="cssTable">
<td><label for="toggleFan">Fan</label></td>
<td>
<input id="toggleFan" class="cmn-toggle cmn-toggle-round" type="checkbox">
<label for="toggleFan"></label>
</td>
</table>
</td>
<td>
</td>
<td>
<label>Speed:</label> <input type="text"
id="fanSpeed" name="fanSpeed" value="">
</td>
</tr>
<tr>
<td>
<table id="cssTable">
<td><label for="toggleHeater">Heater</label></td>
<td>
<input id="toggleHeater" class="cmn-toggle cmn-toggle-round" type="checkbox">
<label for="toggleHeater"></label>
</td>
</table>
</td>
<td>
</td>
<td>
<label>Setpoint:</label> <input type="text"
id="heaterTemp" name="heaterTemp" value="">
</td>
</tr>
</table>
</div>
</fieldset>
<button id="buttonSave">Save Settings</button>
<h2>Dashboard</h2>
<fieldset>
<legend>Chart</legend>
<label>Current Temperature:</label> <label id="heater_temperature"> </label><label>°C</label>
<div id="chart"></div>
</fieldset>
</div>
</div>
</body>
</html>
main.js:
var deltaT = 2500; //temperature update intervall
var Chart = (function(window,d3) {
var svg, data, x, y, xAxis, yAxis, dim, chartWrapper, line, path, margin = {}, width, height, locator, textsize, xlabeloff, ylabeloff, xtickpadding, ytickpadding, xtickdistance, ytickdistance;
var breakPoint = 400; //for rendering smaller fonts on mobile devices wiht small screen widths
var n = 10,//(4)*60,//length of recording
duration = deltaT,//duration of deltat in msec
now = new Date(Date.now() - duration),
count = 0,
data = Array.apply(null, new Array(n)).map(Number.prototype.valueOf,20);
//called once the data is loaded
function init() {
//initialize scales
x = d3.time.scale()
.domain([now - (n+1) * duration, now ])
.range([0, width]);
y = d3.scale.linear()
.domain([0, (1.1*d3.max(data))])
.range([height, 0]);
line = d3.svg.line()
.interpolate("basis")
.x(function (d, i) { return x(now - ((n-1) - i) * duration); })
.y(function (d, i) { return y(d); });
//initialize axis
x.axis = d3.svg.axis().scale(x).orient("top");
y.axis = d3.svg.axis().scale(y).orient("right");
x.axisT = d3.svg.axis().scale(x).orient("bottom").tickFormat("");
y.axisR = d3.svg.axis().scale(y).orient("left").tickFormat("");
//initialize svg
svg = d3.select('#chart')
.append('svg')
.style('pointer-events', 'none');
chartWrapper = svg
.append('g')
.style('pointer-events', 'all');
//cliping mask needed because trace updates and thus moves
clipMask = chartWrapper.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect");
path = chartWrapper.append('g').attr("clip-path", "url(#clip)").append('path').datum(data).classed('line', true);
xAxis = chartWrapper.append('g')
.attr("class", "x axis")
.call(x.axis);
xAxisT = chartWrapper.append('g')
.attr("class", "x axis")
.call(x.axisT);
yAxis = chartWrapper.append('g')
.attr("class", "y axis")
.call(y.axis);
yAxisR = chartWrapper.append('g')
.attr("class", "y axis")
.call(y.axisR);
yLabel = chartWrapper.append("text")
.attr("class", "y label")
//.attr("transform", "rotate(-90)")
.style("text-anchor", "middle")
.text("Temperature (°C)");
xLabel = chartWrapper.append("text")
.attr("class", "x label")
.attr("text-anchor", "middle")
.text("Time (h:min)");
chartWrapper.on('mousemove', onMouseMove)
.on("mouseover", function() { locator.style("display", null); })
.on("mouseout", function() { locator.style("display", "none"); });
//add locator
locator = chartWrapper.append('g')
.attr("class", "focus");
//.style("display", "none");
locator.append('circle')
.attr('r', 4);
locator.append("text")
.attr("x", 0)
.style("text-anchor", "middle")
.attr("dy", "-8");
touchScale = d3.time.scale()
.domain([now - (n+1) * duration, now ]);
//render the chart
render();
}
function render() {
//get dimensions based on window size
updateDimensions();
clipMask.attr("width", width)
.attr("height", height);
//update x and y scales to new dimensions
x.range([0, width]);
y.range([height, 0]);
touchScale.range([0,width]).clamp(true);
//update svg elements to new dimensions
svg
.attr('width', width + margin.right + margin.left)
.attr('height', height + margin.top + margin.bottom);
chartWrapper
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
xLabel.attr("y", height + xlabeloff )
.attr("x", ((width/2) ) );
yLabel.attr("y", - ylabeloff )
.attr("x", (margin.top - height / 2) )
.attr("transform", "rotate(-90)");
//update the axis and line
x.axis.scale(x).tickPadding(xtickpadding);
x.axisT.scale(x);
y.axis.scale(y).tickPadding(ytickpadding);
y.axisR.scale(y);
x.axis.ticks(Math.max(width/xtickdistance, 2));
y.axis.ticks(Math.max(height/ytickdistance, 2));
x.axisT.ticks(Math.max(width/xtickdistance, 2));
y.axisR.ticks(Math.max(height/ytickdistance, 2));
xAxis.attr('transform', 'translate(0,' + height + ')').call(x.axis);
xAxisT.call(x.axisT);
yAxis.call(y.axis);
yAxisR.call(y.axisR).attr('transform', 'translate(' +width +' ,0)');
path.attr('d', line);
updateTextStyle();
}
function updateTextStyle() {
winWidth = document.getElementById("widthReader").offsetWidth;
textsize = winWidth < breakPoint ? "48%" : "80%";
//scale text size
chartWrapper.selectAll("text").style("font-size", textsize);
yAxis.call(y.axis).selectAll(".tick text").style("text-anchor", "end");
}
function updateDimensions(winWidth) {
winWidth = document.getElementById("widthReader").offsetWidth;
margin.top = winWidth < breakPoint ? 4 :10;
margin.right = winWidth < breakPoint ? 4 : 10;
margin.left = winWidth < breakPoint ? 26 : 48;
margin.bottom = winWidth < breakPoint ? 22: 40;
xlabeloff = winWidth < breakPoint ? 21 : 38;
ylabeloff = winWidth < breakPoint ? 20 : 36;
xtickpadding = winWidth < breakPoint ? "-17" : "-24";
ytickpadding = winWidth < breakPoint ? "-10" : "-12";
xtickdistance = winWidth < breakPoint ? 50 : 80;
ytickdistance = winWidth < breakPoint ? 15 : 35;
width = winWidth - margin.left - margin.right;
height = .54 * width;
}
function onMouseMove() {
var x0 = x.invert(d3.mouse(this)[0]),
y0 = y.invert(d3.mouse(this)[1]);
locator.attr("transform", "translate(" + d3.mouse(this)[0] + "," + d3.mouse(this)[1] + ")");
locator.select("text").text(y0);
}
function tick() {
// update the domains
now = new Date();
touchScale.domain([now - (n-1) * duration, now ]);
x.domain([now - (n-1) * duration, now ]);
y.domain([0, (1.1*d3.max(data))]);
// push a new data point onto the back
data.push(Number($('#heater_temperature').text()));
path.attr("d", line)
.attr("transform", null);
// slide the x-axis left, rescale the y-axis
xAxisT.call(x.axisT);
xAxis.call(x.axis);
yAxis.call(y.axis);
yAxisR.call(y.axisR);
// redraw the line and slide line left
path.attr("transform", "translate(" + (x(now - (n+0) * duration) ) + " ,0)");
// pop the old data point off the front
data.shift();
updateTextStyle();
};
return {
render : render,
tick : tick,
init : init
}
})(window,d3);
$(document).ready(function() {
// Start deltaT timer to call RESTful endpoint
setInterval(function() {
$('#heater_temperature').text(Math.random()*220);
Chart.tick();
}, deltaT);
});
$(window).load(function() { //is done after document ready
window.addEventListener('resize', Chart.render);
Chart.init();
Chart.render();
});
style.css
.x.label
{
fill: #555;
}
.y.label
{
fill: #555;
}
.axis path,
.axis line {
stroke-width: 1px;
fill: none;
stroke: #ccc;
}
.axis text {
fill: #555;
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 1px;
}
woking js:
var transition = d3.select({}).transition()
.duration(deltaT)
.ease("linear");
function tick() {
transition = transition.each(function () {
// update the domains
now = new Date();
x.domain([now - (n-1) * duration, now ]);
y.domain([0, (1.1*d3.max(data))]);
// push a new data point onto the back
data.push(Number($('#heater_temperature').text()));
// slide the x-axis left, rescale the y-axis
xAxisT.call(x.axisT);
xAxisB.call(x.axisB);
yAxisL.call(y.axisL);
yAxisR.call(y.axisR);
// redraw the line, and slide it to the left
path.attr("d", line)
.attr("transform", " translate( " + margin.left + " ," + margin.top+" )");
// slide the line left
path.transition()
.attr("transform", "translate(" + (x(now - (n+0) * duration) + margin.left) + " ," + margin.top+ ")");
// pop the old data point off the front
data.shift();
});
}
I got it working... The problem was that i started using d3.v3 instead of d3.v2. Here is what I changed:
function tick() {
d3.transition().ease("linear").duration(deltaT-100).each(function() {
// update the domains
now = new Date(Date.now());
markerScale.domain([now - (n-2) * duration, now ]);
xScale.domain([now - (n-2) * duration, now ]);
yScale.domain([0, (1.1*d3.max(data))]);
// slide the x-axis left, rescale the y-axis
xAxisContT.transition().call(xAxisT);
xAxisCont.transition().call(xAxis);
yAxisCont.transition().call(yAxis);
yAxisContR.transition().call(yAxisR);
plot.attr("transform", null);
// push a new data point onto the back
data.push( Number($('#heater_temperature').text()) );
path.attr("d", line);
marker.data(data)
.attr("cx", xValue)
.attr("cy", yValue)
.attr("transform", null);
// redraw the line and slide plot left
plot.transition()
.attr("transform", "translate(" + (xScale(now - (n-1) * duration) ) + " ,0)");
// pop the old data point off the front
data.shift();
updateTextStyle();
});
}
So I just started using d3 chart and reactjs.
I have successfully implemented the charts with different json files but now the prob is all the charts are in one div. I want to separate them so I could use a heading to each chart but what happens is:
For example:
In my code:
<h1> Chart A </h1>
<BarYearChart sourceUrl="data/data1.json"/> //first chart
<h1> Chart B </h1>
<BarYearChart sourceUrl="data/data2.json"/> //second chart
<h1> Chart C </h1>
<BarYearChart sourceUrl="data/data3.json"/> //third chart
What's actually rendered on my browser:
<h1> Chart A </h1>
<div class="baryearChart>
<svg> Chart 1
<svg> Chart 2
<svg> Chart 3
</div>
<h1> Chart B </h1>
<h1> Chart C </h1>
Anyone knows a way to do this? I would really appreciate your help. Thanks!
Here's my chart
render: function() {
return (
<div className="baryearChart" style={baryearContainer}>
</div>
);
}
});
var svg = d3.select(".baryearChart").insert("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
Then the reactjs page where I called it to display 3 same charts but with diff json files.
<div className="tile-body">
<h2 className="chart-title" style={{borderBottom:'1.5px solid #aaaaaa',paddingBottom:'10px'}}> DPWH </h2>
<BarYearChart sourceUrl="data/effectiveness--all--dpwh.json" id="chart1"/>
<h2 className="chart-title" style={{borderBottom:'1.5px solid #aaaaaa',paddingBottom:'10px'}}> DA </h2>
<BarYearChart sourceUrl="data/effectiveness--all--da.json" id="chart2"/>
<h2 className="chart-title" style={{borderBottom:'1.5px solid #aaaaaa',paddingBottom:'10px'}}> DSWD </h2>
<BarYearChart sourceUrl="data/effectiveness--all--dswd.json" id="chart3"/>
<h6 style={{float:'right',fontSize:'14px',fontStyle:'italic'}}> *of Contracts procured through public bidding </h6>
</div>
d3.select() always returns the first element matching the query, so it will give you the first instance of the div with class "baryearChart".
Instead you could try something like:
let node = React.findDOMNode(this);
d3.select(node).insert("svg")
// etc...
This will insert the SVG into the main node of this specific React component instance. In React 0.14, use ReactDOM.findDOMNode(this).
Thank you so much for your response. Thanks to my boss, I figure out already how it works. So what I did was I assigned specific IDs to every chart I call in my page.
In my chart.js
var BarYearChart = module.exports = React.createClass({
chart: null,
onWindowResize: function() {
//this.chart.update();
},
componentDidMount: function() {
this.chart = new d3BarYearChart(this.props.sourceUrl, this.props.div_id);
},
componentWillUnmount: function() {
window.removeEventListener('resize', this.onWindowResize);
},
componentDidUpdate: function(/*prevProps, prevState*/) {
// this.chart.setData(this.props);
},
render: function() {
return (
<div className="baryearChart" id={"barChart_" + this.props.div_id} style={baryearContainer}>
</div>
);
}
});
var d3BarYearChart = function(sourceUrl, div_id) {
// Var declaration.
var margin = {top: 20, right: 20, bottom: 30, left: 60},
width = 800 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .05);
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(6);
var svg = d3.select("#barChart_" + div_id).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 + ")");
Then in my index page
<div className="tile-body">
<h2 className="chart-title" style={{borderBottom:'1.5px solid #aaaaaa',paddingBottom:'10px'}}> DPWH </h2>
<BarYearChart sourceUrl="data/effectiveness--all--dpwh.json" div_id="chart1"/>
<h2 className="chart-title" style={{borderBottom:'1.5px solid #aaaaaa',paddingBottom:'10px'}}> DA </h2>
<BarYearChart sourceUrl="data/effectiveness--all--da.json" div_id="chart2"/>
<h2 className="chart-title" style={{borderBottom:'1.5px solid #aaaaaa',paddingBottom:'10px'}}> DSWD </h2>
<BarYearChart sourceUrl="data/effectiveness--all--dswd.json" div_id="chart3"/>
<h6 style={{float:'right',fontSize:'14px',fontStyle:'italic'}}> *of Contracts procured through public bidding </h6>
</div>
This removed the trouble of appending my svg on the same div. Now I could have each barchart have their own divs so I could put other elements in between them like headings. :)