Draw line chart on top of area chart - javascript

I am building a chart using D3js v5.12.0.
I have already done the area chart that has the variable year in X axis and variable earth_footprint on Y axis.
The data is in this link: https://raw.githubusercontent.com/cvrnogueira/CODWorkData/master/database/final_data_set.json
I wish to draw a line chart on the top of the area chart. This line chart should have the variable year in X axis and pop_total on the Y axis.
pop_total is another variable that is on the data.
But I can't manage how to, I saw some tutorials of how to draw a line in bar chart, but when I adapt to my code that is a area chart it does not work.
Thanks in advance
CSS
#area-chart {
text-align: center;
margin-top: 40px;
}
.selection {
fill: none;
}
HTLM
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div id="area-chart"></div>
</body>
</html>
JS
var url = "http://raw.githubusercontent.com/cvrnogueira/CODWorkData/master/database/final_data_set.json";
d3.json(url)
.then(function(data) {
data = data.filter(dataPoint => dataPoint.country_code == 'BRA');
data = data.filter(element => element.hasOwnProperty("earth_footprint"));
const heightValue = 300;
const widthValue = 600;
// Create SVG and padding for the chart
const svg = d3
.select("#area-chart")
.append("svg")
.attr("viewBox", `0 0 ${widthValue} ${heightValue}`)
;
const strokeWidth = 1.5;
const margin = { top: 0, bottom: 20, left: 30, right: 20 };
const chart = svg.append("g").attr("transform", `translate(${margin.left},0)`);
const width = 600 - margin.left - margin.right - (strokeWidth * 2);
const height = 300 - margin.top - margin.bottom;
const grp = chart
.append("g")
.attr("transform", `translate(-${margin.left - strokeWidth},-${margin.top})`);
// Create scales
const yScale = d3
.scaleLinear()
.range([height, 0])
.domain([0, d3.max(data, dataPoint => dataPoint.earth_footprint)]);
const xScale = d3
.scaleLinear()
.range([0, width])
.domain(d3.extent(data, dataPoint => dataPoint.year));
const area = d3
.area()
.x(dataPoint => xScale(dataPoint.year))
.y0(height)
.y1(dataPoint => yScale(dataPoint.earth_footprint));
// Add area
grp
.append("path")
.attr("transform", `translate(${margin.left},0)`)
.datum(data)
.style("fill", "lightblue")
.attr("stroke", "steelblue")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", strokeWidth)
.attr("d", area);
// Add the X Axis
chart
.append("g")
.attr("transform", `translate(0,${height})`)
.call(d3.axisBottom(xScale).ticks(data.length));
// Add the Y Axis
chart
.append("g")
.attr("transform", `translate(0, 0)`)
.call(d3.axisLeft(yScale));
chart.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 Earths");
chart.append("text")
.attr("transform",
"translate(" + (width/2) + " ," +
(height + margin.top + 20) + ")")
.style("text-anchor", "middle")
.text("Year");
});

For showing that line you need a line generator:
const line = d3.area()
.x(dataPoint => xScale(dataPoint.year))
.y(dataPoint => yScale(dataPoint.pop_total));
However, your yScale gets the maximum of earth_footprint, and the pop_total values would be way out of scale. So, you'll need another scale for that line generator:
const yScale2 = d3.scaleLinear()
.range([height, 0])
.domain([0, d3.max(data, dataPoint => dataPoint.pop_total)]);
After that, just append the path:
grp.append("path")
.attr("d", line);
The biggest problem now is that you have two visual encodings (the area and the line) which have different scales. Therefore, you'll need an additional axis for the line. I'll leave that work to you.
Here is the resulting code:
var url = "https://raw.githubusercontent.com/cvrnogueira/CODWorkData/master/database/final_data_set.json";
d3.json(url)
.then(function(data) {
data = data.filter(dataPoint => dataPoint.country_code == 'BRA');
data = data.filter(element => element.hasOwnProperty("earth_footprint"));
const heightValue = 300;
const widthValue = 600;
// Create SVG and padding for the chart
const svg = d3
.select("#area-chart")
.append("svg")
.attr("viewBox", `0 0 ${widthValue} ${heightValue}`);
const strokeWidth = 1.5;
const margin = {
top: 0,
bottom: 20,
left: 30,
right: 20
};
const chart = svg.append("g").attr("transform", `translate(${margin.left},0)`);
const width = 600 - margin.left - margin.right - (strokeWidth * 2);
const height = 300 - margin.top - margin.bottom;
const grp = chart
.append("g")
.attr("transform", `translate(-${margin.left - strokeWidth},-${margin.top})`);
// Create scales
const yScale = d3
.scaleLinear()
.range([height, 0])
.domain([0, d3.max(data, dataPoint => dataPoint.earth_footprint)]);
const yScale2 = d3
.scaleLinear()
.range([height, 0])
.domain([0, d3.max(data, dataPoint => dataPoint.pop_total)]);
const xScale = d3
.scaleLinear()
.range([0, width])
.domain(d3.extent(data, dataPoint => dataPoint.year));
const area = d3
.area()
.x(dataPoint => xScale(dataPoint.year))
.y0(height)
.y1(dataPoint => yScale(dataPoint.earth_footprint));
const line = d3.area()
.x(dataPoint => xScale(dataPoint.year))
.y(dataPoint => yScale2(dataPoint.pop_total));
// Add area
grp
.append("path")
.attr("transform", `translate(${margin.left},0)`)
.datum(data)
.style("fill", "lightblue")
.attr("stroke", "steelblue")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", strokeWidth)
.attr("d", area);
grp
.append("path")
.attr("transform", `translate(${margin.left},0)`)
.datum(data)
.style("fill", "none")
.attr("stroke", "red")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", strokeWidth)
.attr("d", line);
// Add the X Axis
chart
.append("g")
.attr("transform", `translate(0,${height})`)
.call(d3.axisBottom(xScale).ticks(data.length));
// Add the Y Axis
chart
.append("g")
.attr("transform", `translate(0, 0)`)
.call(d3.axisLeft(yScale));
chart.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 Earths");
chart.append("text")
.attr("transform",
"translate(" + (width / 2) + " ," +
(height + margin.top + 20) + ")")
.style("text-anchor", "middle")
.text("Year");
});
#area-chart {
text-align: center;
margin-top: 40px;
}
.selection {
fill: none;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<script src="https://d3js.org/d3.v5.min.js"></script>
<title>JS Bin</title>
</head>
<body>
<div id="area-chart"></div>
</body>
</html>

Related

d3 graph duplicates on the DOM when data source changes

I am trying to create a line graph with D3. The data source will be updated on the user actions.
<svg class="line-chart"></svg>
DataSource.watch("pdg2", (data) => {
function drawChart(data) {
var svgWidth = 800, svgHeight = 400;
var margin = { top: 20, right: 20, bottom: 30, left: 50 };
var width = svgWidth - margin.left - margin.right;
var height = svgHeight - margin.top - margin.bottom;
var svg = d3.select('svg')
.attr("width", svgWidth)
.attr("height", svgHeight);
var g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var x = d3.scaleTime()
.rangeRound([0, width]);
var y = d3.scaleLinear()
.rangeRound([height, 0]);
var line = d3.line()
.x(function(d) { return x(d.date)})
.y(function(d) { return y(d.value)})
x.domain(d3.extent(data, function(d) { return d.date }));
y.domain(d3.extent(data, function(d) { return d.value }));
g.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.select(".domain")
.remove();
g.append("g")
.call(d3.axisLeft(y))
.append("text")
.attr("fill", "#000")
.attr("transform", "rotate(-90)")
.attr("y", -45)
.attr("dy", "0.71em")
.attr("text-anchor", "end")
.text("ALLOC_GAS_VOL_MMCF");
g.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", 1.5)
.attr("d", line);
}
drawChart(data);
});
When the data source changes, it duplicates the same graph on the previous one. I was wondering if there is a way to check axes before its pushed to the graph?
Thanks
Just add the line at start of function drawChart. It will remove all the elements inside svg.
d3.selectAll("svg > *").remove();
I have shown you where you need to write.
function drawChart(data) {
d3.selectAll("svg > *").remove();

How to create left axis with variable tick interval in tick values and has same distance between tick value

I am creating left axis and the current output is like this.
.
The problem is there is a gap between tick values but i want uniform gap between two tick values as here.
Here is the Code example.
svg.append("g")
.attr("class", "axisLeft")
.call(d3.axisLeft(y1).tickValues(y1TickValues).tickSizeOuter(0).tickFormat(d3.format("d")))
.selectAll('text')
.style('text-anchor', 'end');
What you're asking for is impossible. The reason is simple: a linear scale is a continuous scale. That is, it deals with a continuous (non-discrete) quantitative variable.
The only way for you to guarantee that the distance between the ticks is rigorously the same is using an ordinal scale, but those scales deal with qualitative (categorical) variables. Not what you want.
However, there is a hack: using a log scale. In this case, since your domain crosses zero, well use a symlog scale (avoiding the log of zero, which in math is not a real number), available on D3 v5 (not v4, the version you're using). By using a symlog scale with constant(100)...
var y1 = d3.scaleSymlog()
.constant(100)
.domain([0,2000]).range([height,0]);
... we get something similar (but not exactly like) to what you asked:
Here is the updated code:
(function(window){
var graphData = [1699, 725, 1149, 868, 304, 1844, 745, 1846, 1423, 1739, 823, 1404, 226, 1603, 389, 517, 1452, 1842, 930, 547, 1072, 828, 733, 632];
var timeArr = [];
for (var i=0;i<24;i++) {
timeArr.push(i);
}
function trans(key){
return key;
}
drawEditGraph();
function drawEditGraph() {
var dataGraph = { timeArr:timeArr, graphData:graphData};
function make_x_gridlines() {
return d3.axisBottom(x).tickSize(height).tickValues(xTicks)
.ticks(10)
}
var margin = {top: 35, right: 50, bottom: 30, left: 50},
width = $(window).width() - margin.left - margin.right,
height = $(window).height() - margin.top - margin.bottom;
var svgHeight = height + 40;
var x = d3.scaleLinear().range([0, width]);
var tickValues= [0,4,8,12,16,20,24];
var y1TickValues = [20,50,75,100,150,200,300,400,500,750,1000,1500,2000]
x.domain([0,23]);
var y1 = d3.scaleSymlog()
.constant(100)
.domain([0,2000]).range([height,0]);
var xTicks = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]
var valueline2 = d3.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y1(d.open); });
var svg = d3.select("#graphDiv").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", svgHeight + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
var data = [];
for (var i=0;i<dataGraph.timeArr.length;i++){
var obj = {};
obj.date = dataGraph.timeArr[i];
obj.open = dataGraph.graphData[i];
data.push(obj)
}
svg.append("g")
.attr("class", "grid")
.attr("transform", "translate(0,"+(height)+")")
.call(make_x_gridlines()
.tickSize(-width)
.tickSizeOuter(0)
.tickFormat("")
)
svg.append("path")
.data([data])
.attr("class", "line")
.attr("d", valueline2);
// Add the X Axis
svg.append("g")
.attr("class", "axisBottom")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x).tickValues(xTicks).tickFormat(function(d,i){
if (d<10)
return "0"+d;
return d;
}));
// Add the Y Axis
svg.append("g")
.attr("class", "axisLeft")
.call(d3.axisLeft(y1).tickValues(y1TickValues).tickSizeOuter(0).tickFormat(d3.format("d")))
.selectAll('text')
.style('text-anchor', 'end');
//Add title
svg.append("text")
.attr("text-anchor", "center")
.attr("x", (width/2) - 25)
.attr("y", height + 35 )
.attr("fill", "#8E8E8E")
.attr("font-size", "12")
.text(trans("Time"));
// Y0 axis label:
svg.append("text")
.attr("text-anchor", "end")
.attr("transform", "rotate(0)")
.attr("y", -23)
.attr("x", 5)
.attr("font-size", "12")
.attr("fill", "#725100")
.text(trans("Colour"));
svg.append("text")
.attr("text-anchor", "end")
.attr("transform", "rotate(0)")
.attr("y", -8)
.attr("x", 5)
.attr("font-size", "12")
.attr("fill", "#725100")
.text("("+trans("K") + ")");
}
}(window));
.line {
fill: none;
stroke: #FFC841 ;
stroke-width: 2px;
}
.axisSteelBlue text{
fill: #FFC841;
}
.axisRed text{
fill: #5BCBD4;
}
.grid line {
stroke: lightgrey;
stroke-opacity: 0.7;
shape-rendering: crispEdges;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="description" content="Graph Demo">
<meta name="viewport" content="width=device-width">
<title>Graph Demo</title>
<script src="https://code.jquery.com/jquery-2.1.4.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.9.2/d3.min.js"></script>
</head>
<body>
<div id="graphDiv">
</div>
</body>
</html>

How can I add labels inside the points in a scatterplot?

I am trying to add state abbreviations within a scatterplot like so:
Here's a snippet of the CSV file I am working with:
id abbr healthcare poverty
1 AL 13.9 19.3
2 AK 15 11.2
3 AZ 14.4 18.2
4 AR 16.3 18.9
5 CA 14.8 16.4
6 CO 12.8 12
7 CT 8.7 10.8
8 DE 8.7 12.5
Here's my JavaScript code:
// #TODO: YOUR CODE HERE!
var svgWidth = 750;
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})`);
// 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", "rgb(117, 145, 197)")
.attr("opacity", "0.5");
// Add state labels to the points
var circleLabels = circlesGroup.selectAll("text").data(censusData).enter().append("text");
circleLabels
.attr("x", function(d) { return d.poverty; })
.attr("y", function(d) { return d.healthcare; })
.text(function(d) { return d.abbr; })
.attr("font-family", "sans-serif")
.attr("font-size", "5px")
.attr("fill", "white");
// 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")
.style("text-anchor", "middle")
.text("Lacks Healthcare (%)");
chartGroup.append("text")
.attr("transform", `translate(${width / 2}, ${height + margin.top + 30})`)
.attr("class", "axisText")
.style("text-anchor", "middle")
.text("In Poverty (%)");
// Initialize tooltip
var toolTip = d3.tip()
.attr("class", "tooltip")
.offset([80, -60])
.html(function(d) {
return `${d.state}<br>Poverty: ${d.poverty}<br>Healthcare: ${d.healthcare}<br>`;
});
// Create tooltip in the chart
chartGroup.call(toolTip);
// Create event listeners to display and hide the tooltip
circlesGroup.on("mouseover", function(data) {
toolTip.show(data, this);
})
// onmouseout event
.on("mouseout", function(data, index) {
toolTip.hide(data);
});
});
I attempted to add them in the circleLabels part of the code but to no avail.
Can anyone tell me what I am doing wrong in this part:
// Add state labels to the points
var circleLabels = circlesGroup.selectAll("text").data(censusData).enter().append("text");
circleLabels
.attr("x", function(d) { return d.poverty; })
.attr("y", function(d) { return d.healthcare; })
.text(function(d) { return d.abbr; })
.attr("font-family", "sans-serif")
.attr("font-size", "5px")
.attr("fill", "white");
Any suggestions or changes are welcome.
You have three problems:
circlesGroup is a circles' selection. You cannot append <text> elements to <circle> elements. Therefore, change it to chartGroup:
var circleLabels = chartGroup.selectAll("text")//etc...
and that brings us to the second problem:
There are text elements in that selection. So, to avoid binding data to existing elements (which reduces the size of the enter selection), use selectAll(null:
var circleLabels = chartGroup.selectAll(null)//etc...
to read more about selectAll(null), read my Q/A pair here: Selecting null: what is the reason behind 'selectAll(null)' in D3.js?
You are not using the scales for positioning the texts.
Finally, use text-anchor: middle for entering the texts.
Here is your code with those changes:
var csv = `id,abbr,healthcare,poverty
1,AL,13.9,19.3
2,AK,15,11.2,
3,AZ,14.4,18.2
4,AR,16.3,18.9
5,CA,14.8,16.4
6,CO,12.8,12
7,CT,8.7,10.8
8,DE,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");
var circleLabels = chartGroup.selectAll(null).data(censusData).enter().append("text");
circleLabels
.attr("x", function(d) {
return xLinearScale(d.poverty);
})
.attr("y", function(d) {
return yLinearScale(d.healthcare);
})
.text(function(d) {
return d.abbr;
})
.attr("font-family", "sans-serif")
.attr("font-size", "10px")
.attr("text-anchor", "middle")
.attr("fill", "white");
// 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>

Multiple simple graphs on one page d3.js

I am using d3.js and i am trying to display more than one graphs in the same page. Though the d3.js code is same.The one chart is from Measurements.csv and the other from m1.csv.
<!DOCTYPE html>
<svg width="1000" height="500"></svg>
<style> /* set the CSS */
.grid line {
stroke: aquamarine;
stroke-opacity: 0.7;
shape-rendering: crispEdges;
}
.grid path {
stroke-width: 1;
}
</style>
<style>
body {
background-color: SlateGrey;
}
</style>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
// set the dimensions and margins of the graph
var svg2 = d3.select("svg"),
margin = {top: 0, right: 0, bottom: 90, left: 50},
width = 950 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
g = svg2.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var x = d3.scaleLinear()
.rangeRound([0, width]);
var y = d3.scaleLinear()
.rangeRound([height, 0]);
// gridlines in x axis function
function make_x_gridlines() {
return d3.axisBottom(x)
.ticks(5)
}
// gridlines in y axis function
function make_y_gridlines() {
return d3.axisLeft(y)
.ticks(5)
}
var line = d3.line()
.x(function(d) { return x(d.frequency); })
.y(function(d) { return y(d.output); });
d3.csv("Measurements.csv", function(d) {
d.frequency = +d.frequency;
d.output = +d.output;
return d;
}, function(error, data) {
if (error) throw error;
x.domain(d3.extent(data, function(d) { return d.frequency; }));
y.domain(d3.extent(data, function(d) { return d.output; }));
g.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.append("text")
.attr("fill", "#000")
.attr("y", 10)
.attr("dx", "0.71em")
.attr("text-anchor", "end")
.text("Frequency");
g.append("g")
.call(d3.axisLeft(y))
.append("text")
.attr("fill", "#000")
.attr("transform", "rotate(-90)")
.attr("y", 9)
.attr("dy", "0.71em")
.attr("text-anchor", "end")
.text("Mixer");
g.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "aquamarine")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", 4)
.attr("d", line);
// add the X gridlines
svg2.append("g")
.attr("class", "grid")
.attr("transform", "translate(0," + height + ")")
.call(make_x_gridlines()
.tickSize(-height)
.tickFormat("")
)
// add the Y gridlines
svg2.append("g")
.attr("class", "grid")
.call(make_y_gridlines()
.tickSize(-width)
.tickFormat("")
)
});
// set the dimensions and margins of the graph
var svg3 = d3.select("svg"),
margin = {top: 0, right: 0, bottom: 90, left: 50},
width = 950 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
g = svg2.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var x = d3.scaleLinear()
.rangeRound([0, width]);
var y = d3.scaleLinear()
.rangeRound([height, 0]);
// gridlines in x axis function
function make_x_gridlines() {
return d3.axisBottom(x)
.ticks(5)
}
// gridlines in y axis function
function make_y_gridlines() {
return d3.axisLeft(y)
.ticks(5)
}
var line = d3.line()
.x(function(d) { return x(d.frequency); })
.y(function(d) { return y(d.output); });
d3.csv("m1.csv", function(d) {
d.frequency = +d.frequency;
d.output = +d.output;
return d;
}, function(error, data) {
if (error) throw error;
x.domain(d3.extent(data, function(d) { return d.frequency; }));
y.domain(d3.extent(data, function(d) { return d.output; }));
g.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.append("text")
.attr("fill", "#000")
.attr("y", 10)
.attr("dx", "0.71em")
.attr("text-anchor", "end")
.text("Frequency");
g.append("g")
.call(d3.axisLeft(y))
.append("text")
.attr("fill", "#000")
.attr("transform", "rotate(-90)")
.attr("y", 9)
.attr("dy", "0.71em")
.attr("text-anchor", "end")
.text("Mixer");
g.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "aquamarine")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", 4)
.attr("d", line);
// add the X gridlines
svg3.append("g")
.attr("class", "grid")
.attr("transform", "translate(0," + height + ")")
.call(make_x_gridlines()
.tickSize(-height)
.tickFormat("")
)
// add the Y gridlines
svg3.append("g")
.attr("class", "grid")
.call(make_y_gridlines()
.tickSize(-width)
.tickFormat("")
)
});
</script>
I found that have to use different variable name to hold svgs such as svg1, svg2.. etc..but the one chart is laying on the other.How to resolve this?here is the chart on the other!
Just changing this...
var svg = d3.select("svg")
... for this...
var svg2 = d3.select("svg")
... won't make any difference: the variable name is different, but the selection is the same: they are both selecting the same SVG.
Since you are not appending an SVG, but selecting an existing one, set two SVGs, each one with a unique ID....
<svg id="svg1" width="1000" height="500"></svg>
<svg id="svg2" width="1000" height="500"></svg>
... and select them accordingly:
var svg1 = d3.select("#svg1")
var svg2 = d3.select("#svg2")
PS: I'm addressing only the selection issue. For avoiding duplicated code (since you said that the code is the same), wrap the whole code in a function with two parameters: the ID of the selected SVG and the path of the CSV file. Then, you just need to call that function twice, with different arguments.

Aligning two graphs(Pie and Bar) side by side :: d3 js

I am a little new to D3 js.I need to align two graphs (bar and pie) side by side which will be displayed on a dashboard.When I use individual .html files for bar and pie charts,they work perfectly but the charts are getting overlapped when I combine them into a single .html file.
I have tried changing different parameters related to "svg" and corresponding x and y axes but to no avail.
There are two csv files(pie-data.csv,bar-data.csv) from where data will be picked.
Below is my code ::
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.arc text {
font: 10px sans-serif;
text-anchor: middle;
}
.arc path {
stroke: #fff;
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var width = 500,
height = 500,
radius = Math.min(width, height) / 2;
var color = d3.scale.ordinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var arc = d3.svg.arc()
.outerRadius(radius - 10)
.innerRadius(0);
var labelArc = d3.svg.arc()
.outerRadius(radius - 40)
.innerRadius(radius - 40);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.ticket_count; });
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
d3.csv("pie-data.csv", type, function(error, data) {
if (error) throw error;
var g = svg.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arc)
.style("fill", function(d) { return color(d.data.ticket_meter); });
g.append("text")
.attr("transform", function(d) { return "translate(" + labelArc.centroid(d) + ")"; })
.attr("dy", ".35em")
.text(function(d) { return d.data.ticket_meter; });
});
function type(d) {
d.ticket_count = +d.ticket_count;
return d;
}
////////////////////////////////////////////////
var margin = {top: 20, right: 20, bottom: 70, left: 40},
width = 150 - margin.left - margin.right,
height = 300 - 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(10);
var svg = d3.select("body").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 + ")");
d3.csv("bar-data.csv", function(error, data) {
data.forEach(function(d) {
d.issue_status = d.issue_status;
d.issue_count = +d.issue_count;
});
x.domain(data.map(function(d) { return d.issue_status; }));
y.domain([0, d3.max(data, function(d) { return d.issue_count; })]);
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")
svg.selectAll("bar")
.data(data)
.enter().append("rect")
.style("fill", "steelblue")
.attr("x", function(d) { return x(d.issue_status); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.issue_count); })
.attr("height", function(d) { return height - y(d.issue_count); });
});
</script>
</body>
</html>
Please suggest any pointers so that alignment can be done.Thanks in advance.
You are using the same variable twice:
var svg = d3.select("body").append("svg");
(and, besides that one, you are repeating some other variables that should be unique)
Appending the SVGs to the "body" is not the correct way, because when you append an SVG to the body the SVG is put at the end of the page, and you'll not be able to position them side by side.
A solution would be creating one div for each chart, with IDs #chart1 and #chart2 for instance, and then creating two variables:
var svg1 = d3.select("#chart1").append("svg");
And
var svg2 = d3.select("#chart2").append("svg");
Don't forget to change all other variables accordingly.
After the changes, use CSS to align the two divs side by side.

Categories

Resources