Why are labels/text not rendering on this d3.js scatter plot? - javascript

I've been practicing using D3.js by making a simple scatter plot with some dummy data. Unfortunately after spending an hour of googling and looking at examples, I still can't figure out why my labels are not rendering. Could someone point me in the right direction on what I'm doing wrong?
I'm assuming the text is not rendering because when I put in dummy numbers for the X and Y attributes, I still don't get the labels to render on the page.
const points = [
[1,2],
[2,4],
[3,6],
[4,8],
[5,10]
]
const w = 500
const h = 500
const maxX = d3.max(points, (d) => d[0]);
const maxY = d3.max(points, (d) => d[1]);
console.log(maxX, maxY);
const scaleX = d3.scaleLinear()
.domain([0, maxX])
.range([0, w]);
const scaleY = d3.scaleLinear()
.domain([0, maxY])
.range([0,h]);
const svg = d3.select('body')
.append('svg')
.attr('width', w)
.attr('height', h)
;
svg.selectAll("circle")
.data(points)
.enter()
.append('circle')
.attr('cx',(d) => scaleX(d[0]))
.attr('cy',(d) =>h - scaleY(d[1]))
.attr('r', 5)
.attr('fill', 'black')
// adding axae
const xAxis = d3.axisBottom(scaleX);
const yAxis = d3.axisLeft(scaleY);
svg.append("g")
.attr("transform", "translate(0," + (h -20) + ")")
.call(xAxis);
svg.append("g")
.attr("transform", "translate(" + 20 + ", 0)")
.call(yAxis);
// adding labels
svg.selectAll("text")
.data(points)
.enter()
.append("text")
.text((d) => (d[0] + "," + d[1]))
.attr("x", (d) => scaleX(d[0] + 10))
.attr("y", (d) => scaleY(d[1]))
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="style.css">
<script src="https://d3js.org/d3.v5.min.js"></script>
</head>
<body>
<script src='app.js'></script>
</body>
</html>

The code was almost correct, whenever you want to insert(enter) some nodes you must check if there is no selection corresponding to that.
As you have already rendered the axes, so there are already text nodes in my chart but i wanted to create an empty selection. Always use a unique indentifier for that
Replace // adding labels
svg.selectAll("text")
with // adding labels
svg.selectAll(".mylables")
Change x and y coordinate as below, you can tweek accordingly.
.attr("x", (d) => scaleX(d[0]) + 10)
.attr("y", (d) => h - scaleY(d[1]))
const points = [
[1, 2],
[2, 4],
[3, 6],
[4, 8],
[5, 10]
]
const w = 500
const h = 500
const maxX = d3.max(points, (d) => d[0]);
const maxY = d3.max(points, (d) => d[1]);
console.log(maxX, maxY);
const scaleX = d3.scaleLinear()
.domain([0, maxX])
.range([0, w]);
const scaleY = d3.scaleLinear()
.domain([0, maxY])
.range([0, h]);
const svg = d3.select('body')
.append('svg')
.attr('width', w)
.attr('height', h);
svg.selectAll("circle")
.data(points)
.enter()
.append('circle')
.attr('cx', (d) => scaleX(d[0]))
.attr('cy', (d) => h - scaleY(d[1]))
.attr('r', 5)
.attr('fill', 'black')
// adding axae
const xAxis = d3.axisBottom(scaleX);
const yAxis = d3.axisLeft(scaleY);
svg.append("g")
.attr("transform", "translate(0," + (h - 20) + ")")
.call(xAxis);
svg.append("g")
.attr("transform", "translate(" + 20 + ", 0)")
.call(yAxis);
// adding labels
svg.selectAll(".mylabels")
.data(points)
.enter()
.append("text")
.style('class', 'mylables')
.text((d) => {
debugger;
return (d[0] + "," + d[1])
})
.attr("x", (d) => scaleX(d[0]) + 10)
.attr("y", (d) => h - scaleY(d[1]))
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="style.css">
<script src="https://d3js.org/d3.v5.min.js"></script>
</head>
<body>
<script src='app.js'></script>
</body>
</html>

Related

D3.js--How to transition between multiple types of charts using buttons?

I am trying learn to transition between multiple charts using buttons. Here, i want to transition between bar and scatter chart (and may be add a line chart button as well). I have been able to show respective charts by the click of the button. But, i am not able to figure out how to exit one chart when the button for the other chart is clicked and vice-versa. Following is screenshot of the interactive figure that i have created. Here, we can see that both charts show together.
Following is the data (data.csv) i am using to create the interactive chart:
Below is the HTML code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Transition Scatter to Bar</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
</head>
<body>
<div id="container" class="container">
<h1>Transition from one chart to other</h1>
<div id="main" role="main">
<div class="btn-group" data-toggle="buttons-radio">
<button type="button" id="bar" class="btn btn-default">Bar</button>
<button type="button" id="scatter" class="btn btn-default">Scatter</button>
</div>
<div id="vis"></div>
</div>
</div>
<script src="d3.v6.js"></script>
<script src="transition.js"></script>
</body>
</html>
And the D3.js code:
//load data----
async function createApp(){
const dataset= await d3.csv('data.csv')
//create dimensions---
let dimensions={
width: 800,
height:600,
margins: {
left: 50,
right: 20,
top:20,
bottom: 50,
},
};
//bound dimensions
dimensions.boundedwidth=dimensions.width-
dimensions.margins.left-
dimensions.margins.right;
dimensions.boundedheight=dimensions.height-
dimensions.margins.top-
dimensions.margins.bottom;
//Draw canvas----
wrapper=d3.select("#vis")
.append("svg")
.attr("width", dimensions.width)
.attr("height", dimensions.height);
bounds=wrapper.append("g")
.style("transform", `translate(${
dimensions.margins.left
}px, ${
dimensions.margins.top
}px)`);
//create scales------
const xScatterscale= d3.scaleLinear()
.range([0, dimensions.boundedwidth])
.nice()
const yScatterscale= d3.scaleLinear()
.range([dimensions.boundedheight, 0])
.nice()
const xBarscale= d3.scaleBand()
.range([0, dimensions.boundedwidth])
.padding(0.2)
const yBarscale=d3.scaleLinear()
.range([dimensions.boundedheight, 0])
.nice()
//Draw perpherals--axes-------
//create axis generators
const xAxisgeneratorscatter= d3.axisBottom()
.scale(xScatterscale)
.ticks(8)
const yAxisgeneratorscatter= d3.axisLeft()
.scale(yScatterscale)
.ticks(9)
const xAxisgeneratorbar=d3.axisBottom()
.scale(xBarscale)
const yAxisgeneratorbar=d3.axisLeft()
.scale(yBarscale)
const xAxis= bounds.append("g")
.attr("class", "x-axis")
.style("transform", `translateY(${
dimensions.boundedheight
}px)`)
const yAxis=bounds.append("g")
.attr("class", "y-axis")
//binding data to empty request-----
const requests= bounds.append("g")
.attr("class", "request")
const chartgroups= requests.selectAll(".request")
.data(dataset)
.enter().append("g")
let duration = 750
const updateTransition = d3.transition().duration(duration)
scatterplot()
//create functions to draw data scatter plot----
function scatterplot(){
const xAccessorscatter= d=> +d.risk
const yAccessorscatter= d=> +d.return
xScatterscale.domain([0, d3.max(dataset, xAccessorscatter)+0.05])
yScatterscale.domain([0, d3.max(dataset, yAccessorscatter)+0.02])
xAxis.call(xAxisgeneratorscatter)
yAxis.call(yAxisgeneratorscatter)
const newscattergroup= chartgroups.append("circle")
.attr("cx", d=>xScatterscale(xAccessorscatter(d)))
.attr("cy", dimensions.boundedheight)
.attr("r", 0)
const scattergroups= newscattergroup.transition(updateTransition)
scattergroups
.attr("cx", d=>xScatterscale(xAccessorscatter(d)))
.attr("cy", d=>yScatterscale(yAccessorscatter(d)))
.attr("r", 5)
.attr("fill", "cornflowerblue")
}
//create functions to draw data bar plot----
function plotbar(){
const xAccessorbar = d=> d.id
const yAccessorbar = d=> +d.equity
xBarscale
.domain(dataset.map(xAccessorbar))
yBarscale
.domain([0, d3.max(dataset, yAccessorbar)+0.1])
xAxis.call(xAxisgeneratorbar)
yAxis.call(yAxisgeneratorbar)
const newbarsgroups= chartgroups.append("rect")
.attr("x", d=> xBarscale(d.id))
.attr("height", 0)
.attr("y", dimensions.boundedheight)
.attr("width", xBarscale.bandwidth())
const t= newbarsgroups
.transition()
.duration(duration)
t
.attr("x", d=> xBarscale(d.id))
.attr("y", d=> yBarscale(d.equity))
.attr("width", xBarscale.bandwidth())
.attr("height", d=>dimensions.boundedheight- yBarscale(yAccessorbar(d)))
.attr("fill", "cornflowerblue")
}
d3.select("#scatter").on("click", function () {
scatterplot()
});
d3.select("#bar").on("click", function () {
plotbar()
});
}
createApp()
I am new to d3.js and still trying to figure out the Enter, Update, Exit trinity. I have found some examples where button is has been used to transition/update bar charts with new data. However, i am struggling to figure out how to exit one chart when the other chart gets drawn and vice versa on the click of the button.
Any suggestions on how to accomplish this will be highly appreciated.
Thanks a lot!
UPDATE (WORKING CODE):
I was able to work out how to transition with help from some "Good" Samaritan. I thought i will share the working code here:
//load data----
async function createApp(){
const dataset= await d3.csv('data.csv')
console.log(dataset)
//create dimensions---
let dimensions={
width: 800,
height:600,
margins: {
left: 50,
right: 20,
top:20,
bottom: 50,
},
};
//bound dimensions
dimensions.boundedwidth=dimensions.width-
dimensions.margins.left-
dimensions.margins.right;
dimensions.boundedheight=dimensions.height-
dimensions.margins.top-
dimensions.margins.bottom;
//Draw canvas----
wrapper=d3.select("#vis")
.append("svg")
.attr("width", dimensions.width)
.attr("height", dimensions.height);
bounds=wrapper.append("g")
.style("transform", `translate(${
dimensions.margins.left
}px, ${
dimensions.margins.top
}px)`);
//create scales------
const xScatterscale= d3.scaleLinear()
.range([0, dimensions.boundedwidth])
.nice()
const yScatterscale= d3.scaleLinear()
.range([dimensions.boundedheight, 0])
.nice()
const xBarscale= d3.scaleBand()
.range([0, dimensions.boundedwidth])
.padding(0.2)
const yBarscale=d3.scaleLinear()
.range([dimensions.boundedheight, 0])
.nice()
//Draw perpherals--axes-------
//create axis generators
const xAxisgeneratorscatter= d3.axisBottom()
.scale(xScatterscale)
.ticks(8)
const yAxisgeneratorscatter= d3.axisLeft()
.scale(yScatterscale)
.ticks(9)
const xAxisgeneratorbar=d3.axisBottom()
.scale(xBarscale)
const yAxisgeneratorbar=d3.axisLeft()
.scale(yBarscale)
//creating a group element which contains all the things related to x-axis like axis and the labels
bounds.append("g")
.attr("class", "x-axis")
.style("transform", `translateY(${
dimensions.boundedheight
}px)`)
.append("text")
.attr("class", "x-axis-label")
.attr("x", dimensions.boundedwidth/2)
.attr("y", dimensions.margins.bottom-10)
.attr("fill", "black")
.style("font-size", "1.4em")
//creating a group element which contains all the things related to y-axis like axis and the labels
bounds.append("g")
.attr("class", "y-axis")
.append("text")
.attr("class", "y-axis-label")
.attr("x", -dimensions.boundedheight/2)
.attr("y", -dimensions.margins.left+10)
.attr("fill", "black")
.style("font-size", "1.4em")
.style("transform", "rotate(-90deg)")
.style("text-anchor", "middle")
//binding data to empty request-----
const requests= bounds.append("g")
.attr("class", "request")
const chartgroups= requests.selectAll(".request")
.data(dataset)
.enter().append("g")
let duration = 750
//const updateTransition = d3.transition().duration(duration)
const updateTransition = (t) => {
return t.duration(duration)
}
var previousChartType = "scatter";
scatterplot();
//create functions to draw data scatter plot----
function scatterplot(){
const xAccessorscatter= d=> +d.risk
const yAccessorscatter= d=> +d.return
xScatterscale.domain([0, d3.max(dataset, xAccessorscatter)+0.05])
yScatterscale.domain([0, d3.max(dataset, yAccessorscatter)+0.02])
const xAxis=bounds.select(".x-axis")
.transition()
.call(updateTransition)
.call(xAxisgeneratorscatter)
const xAxislabel= xAxis.select(".x-axis-label")
.transition()
.call(updateTransition)
.text("Risk")
const yAxis= bounds.select(".y-axis")
.transition()
.call(updateTransition)
.call(yAxisgeneratorscatter)
const yAxislabel= yAxis.select(".y-axis-label")
.transition()
.call(updateTransition)
.text("Return")
const newscattergroup= chartgroups.append("circle")
.attr("cx", d=>xScatterscale(xAccessorscatter(d)))
.attr("cy", dimensions.boundedheight)
.attr("r", 0)
const scattergroups= newscattergroup
.transition().duration(previousChartType === "bar" ? duration : 0)
// .call(updateTransition)
.attr("cx", d=>xScatterscale(xAccessorscatter(d)))
.attr("cy", d=>yScatterscale(yAccessorscatter(d)))
.attr("r", 5)
.attr("fill", "red")
previousChartType = "scatter";
}
//create functions to draw data bar plot----
function plotbar(){
const xAccessorbar = d=> d.id
const yAccessorbar = d=> +d.equity
xBarscale
.domain(dataset.map(xAccessorbar))
yBarscale
.domain([0, d3.max(dataset, yAccessorbar)+0.1])
const xAxis=bounds.select(".x-axis")
.transition()
.call(updateTransition)
.call(xAxisgeneratorbar)
const xAxislabel=xAxis.select(".x-axis-label")
.transition()
.call(updateTransition)
.text("id")
const yAxis=bounds.select(".y-axis")
.transition()
.call(updateTransition)
.call(yAxisgeneratorbar)
const yAxislabel=yAxis.select(".y-axis-label")
.transition()
.call(updateTransition)
.text("Equity")
const newbarsgroups= chartgroups.append("rect")
.attr("x", d=> xBarscale(d.id))
.attr("height", 0)
.attr("y", dimensions.boundedheight)
.attr("width", xBarscale.bandwidth())
const t= newbarsgroups
.transition().duration(previousChartType === "scatter" ? duration : 0)
//.call(updateTransition)
.attr("x", d=> xBarscale(d.id))
.attr("y", d=> yBarscale(d.equity))
.attr("width", xBarscale.bandwidth())
.attr("height", d=>dimensions.boundedheight- yBarscale(yAccessorbar(d)))
.attr("fill", "cornflowerblue")
const barText= chartgroups.filter(yAccessorbar)
.append("text")
.attr("x", d=>xBarscale(d.id)+(xBarscale.bandwidth())/2)
.attr("y", dimensions.boundedheight)
.transition().duration(previousChartType === "scatter" ? duration : 0)
// .call(updateTransition)
.attr("x", d=>xBarscale(d.id)+(xBarscale.bandwidth())/2)
.attr("y", d=>yBarscale(yAccessorbar(d))-5)
.text(yAccessorbar)
.style("text-anchor", "middle")
.attr("fill", "black")
.style("font-size", "12px")
.style("font-family", "sans-serif")
previousChartType = "bar";
}
d3.select("#scatter").on("click", function () {
chartgroups
.selectAll("rect")
.attr("fill-opacity", 1)
.transition()
.duration(duration)
.attr("y", dimensions.boundedheight)
.attr("height", 0)
.attr("fill-opacity", 0)
.remove();
chartgroups
.select("text")
.transition()
.duration(duration)
.attr("fill", "white")
.remove();
scatterplot()
});
d3.select("#bar").on("click", function () {
chartgroups
.selectAll("circle")
.attr("fill-opacity", 1)
.transition()
.duration(duration)
.attr("fill-opacity", 0)
.remove();
plotbar()
});
}
createApp()
Following is the working example:
https://pyarasid.github.io/D3.js-Animate_MultipleCharts_Button/

How to display two graph generated from separate code from “observablehq” on one browser window

I am new in d3.js.I downloaded two code generating graphs from site “observablehq”. Here are links to codes.
1- zoomable-area-chart
2-focus-context
I want to display both graphs in the same browser window. For this, I placed the files in the same directory. Here is html code of zoomable-area-chart
<!DOCTYPE html>
<meta charset="utf-8">
<title>Zoomable Area Chart</title>
<link rel="stylesheet" type="text/css" href="./inspector.css">
<body>
<script type="module">
import define from "./index.js";
import {Runtime, Library, Inspector} from "./runtime.js";
const runtime = new Runtime();
const main = runtime.module(define, Inspector.into(document.body));
</script>
Here is html code of focus-context
<!DOCTYPE html>
<meta charset="utf-8">
<title>Focus + Context</title>
<link rel="stylesheet" type="text/css" href="inspector1.css">
<body>
<script type="module">
import define from "./index1.js";
import {Runtime, Library, Inspector} from "./runtime1.js";
const runtime = new Runtime();
const main = runtime.module(define, Inspector.into(document.body));
</script>
I placed "Focus + Context" "script" in html file of "Zoomable Area Chart" like this
<!DOCTYPE html>
<meta charset="utf-8">
<title>Zoomable Area Chart</title>
<link rel="stylesheet" type="text/css" href="./inspector.css">
<body>
<script type="module">
import define from "./index.js";
import {Runtime, Library, Inspector} from "./runtime.js";
const runtime = new Runtime();
const main = runtime.module(define, Inspector.into(document.body));
</script>
<script type="module">
import define from "./index1.js";
import {Runtime, Library, Inspector} from "./runtime1.js";
const runtime = new Runtime();
const main = runtime.module(define, Inspector.into(document.body));
</script>
then I ran that html file using "webstorm" into browser. It is not displaying both graphs into the same browser window. It is displaying errors for the first graph and displaying the second graph
Here is js file for "Zoomable Area Chart"
// https://observablehq.com/#d3/zoomable-area-chart#212
export default function define(runtime, observer) {
const main = runtime.module();
const fileAttachments = new Map([["flights.csv",new URL("./files/1171cb24da0255c434c1ff554b4964c39c1253aa9349f2d356a25351acd3579367f92b24366ae5b6c208c9336811489c0a176cbc0cc62e31feff51e294a178fe",import.meta.url)]]);
main.builtin("FileAttachment", runtime.fileAttachments(name => fileAttachments.get(name)));
main.variable(observer()).define(["md"], function(md){return(
md`# Zoomable Area Chart
This zoomable time series area chart shows the number of flights per day. The effect of the September 11, 2001 attacks on air travel is evident.`
)});
main.variable(observer("chart")).define("chart", ["d3","margin","width","height","DOM","area","data","x","xAxis","yAxis","y"], function(d3,margin,width,height,DOM,area,data,x,xAxis,yAxis,y)
{
const zoom = d3.zoom()
.scaleExtent([1, 32])
.extent([[margin.left, 0], [width - margin.right, height]])
.translateExtent([[margin.left, -Infinity], [width - margin.right, Infinity]])
.on("zoom", zoomed);
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height]);
const clip = DOM.uid("clip");
svg.append("clipPath")
.attr("id", clip.id)
.append("rect")
.attr("x", margin.left)
.attr("y", margin.top)
.attr("width", width - margin.left - margin.right)
.attr("height", height - margin.top - margin.bottom);
const path = svg.append("path")
.attr("clip-path", clip)
.attr("fill", "steelblue")
.attr("d", area(data, x));
const gx = svg.append("g")
.call(xAxis, x);
svg.append("g")
.call(yAxis, y);
svg.call(zoom)
.transition()
.duration(750)
.call(zoom.scaleTo, 4, [x(Date.UTC(2001, 8, 1)), 0]);
function zoomed() {
const xz = d3.event.transform.rescaleX(x);
path.attr("d", area(data, xz));
gx.call(xAxis, xz);
}
return svg.node();
}
);
main.variable(observer("height")).define("height", function(){return(
500
)});
main.variable(observer("margin")).define("margin", function(){return(
{top: 20, right: 20, bottom: 30, left: 30}
)});
main.variable(observer("x")).define("x", ["d3","data","margin","width"], function(d3,data,margin,width){return(
d3.scaleUtc()
.domain(d3.extent(data, d => d.date))
.range([margin.left, width - margin.right])
)});
main.variable(observer("y")).define("y", ["d3","data","height","margin"], function(d3,data,height,margin){return(
d3.scaleLinear()
.domain([0, d3.max(data, d => d.value)]).nice()
.range([height - margin.bottom, margin.top])
)});
main.variable(observer("xAxis")).define("xAxis", ["height","margin","d3","width"], function(height,margin,d3,width){return(
(g, x) => g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x).ticks(width / 80).tickSizeOuter(0))
)});
main.variable(observer("yAxis")).define("yAxis", ["margin","d3","data"], function(margin,d3,data){return(
(g, y) => g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y).ticks(null, "s"))
.call(g => g.select(".domain").remove())
.call(g => g.select(".tick:last-of-type text").clone()
.attr("x", 3)
.attr("text-anchor", "start")
.attr("font-weight", "bold")
.text(data.y))
)});
main.variable(observer("area")).define("area", ["d3","y"], function(d3,y){return(
(data, x) => d3.area()
.curve(d3.curveStepAfter)
.x(d => x(d.date))
.y0(y(0))
.y1(d => y(d.value))
(data)
)});
main.variable(observer("data")).define("data", ["d3","FileAttachment"], async function(d3,FileAttachment){return(
Object.assign(d3.csvParse(await FileAttachment("flights.csv").text(), d3.autoType), {y: "Flights"})
)});
main.variable(observer("d3")).define("d3", ["require"], function(require){return(
require("d3#5")
)});
return main;
}
Here is js file for "Focus + Context"
// https://observablehq.com/#d3/focus-context#320
export default function define(runtime, observer) {
const main = runtime.module();
const fileAttachments = new Map([["aapl.csv",new URL("./files/de259092d525c13bd10926eaf7add45b15f2771a8b39bc541a5bba1e0206add4880eb1d876be8df469328a85243b7d813a91feb8cc4966de582dc02e5f8609b7",import.meta.url)]]);
main.builtin("FileAttachment", runtime.fileAttachments(name => fileAttachments.get(name)));
main.variable(observer()).define(["md"], function(md){return(
md`# Focus + Context
This [area chart](/#d3/area-chart) uses brushing to specify a focused area. Drag the gray region to pan, or brush to zoom. Compare to a [zoomable chart](/#d3/zoomable-area-chart). Data: [Yahoo Finance](https://finance.yahoo.com/lookup)`
)});
main.variable(observer("chart")).define("chart", ["d3","width","height","DOM","margin","data","xAxis","yAxis","area"], function(d3,width,height,DOM,margin,data,xAxis,yAxis,area)
{
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.style("display", "block");
const clipId = DOM.uid("clip");
svg.append("clipPath")
.attr("id", clipId.id)
.append("rect")
.attr("x", margin.left)
.attr("y", 0)
.attr("height", height)
.attr("width", width - margin.left - margin.right);
const gx = svg.append("g");
const gy = svg.append("g");
const path = svg.append("path")
.datum(data)
.attr("clip-path", clipId)
.attr("fill", "steelblue");
return Object.assign(svg.node(), {
update(focusX, focusY) {
gx.call(xAxis, focusX, height);
gy.call(yAxis, focusY, data.y);
path.attr("d", area(focusX, focusY));
}
});
}
);
main.variable(observer("viewof focus")).define("viewof focus", ["d3","width","focusHeight","margin","x","xAxis","data","area","y"], function(d3,width,focusHeight,margin,x,xAxis,data,area,y)
{
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, focusHeight])
.style("display", "block");
const brush = d3.brushX()
.extent([[margin.left, 0.5], [width - margin.right, focusHeight - margin.bottom + 0.5]])
.on("brush", brushed)
.on("end", brushended);
const defaultSelection = [x(d3.utcYear.offset(x.domain()[1], -1)), x.range()[1]];
svg.append("g")
.call(xAxis, x, focusHeight);
svg.append("path")
.datum(data)
.attr("fill", "steelblue")
.attr("d", area(x, y.copy().range([focusHeight - margin.bottom, 4])));
const gb = svg.append("g")
.call(brush)
.call(brush.move, defaultSelection);
function brushed() {
if (d3.event.selection) {
svg.property("value", d3.event.selection.map(x.invert, x).map(d3.utcDay.round));
svg.dispatch("input");
}
}
function brushended() {
if (!d3.event.selection) {
gb.call(brush.move, defaultSelection);
}
}
return svg.node();
}
);
main.variable(observer("focus")).define("focus", ["Generators", "viewof focus"], (G, _) => G.input(_));
main.variable(observer()).define(["focus","d3","data","chart","x","y"], function(focus,d3,data,chart,x,y)
{
const [minX, maxX] = focus;
const maxY = d3.max(data, d => minX <= d.date && d.date <= maxX ? d.value : NaN);
chart.update(x.copy().domain(focus), y.copy().domain([0, maxY]));
}
);
main.variable(observer("data")).define("data", ["d3","FileAttachment"], async function(d3,FileAttachment){return(
Object.assign(d3.csvParse(await FileAttachment("aapl.csv").text(), d3.autoType).map(({date, close}) => ({date, value: close})), {y: "↑ Close $"})
)});
main.variable(observer("area")).define("area", ["d3"], function(d3){return(
(x, y) => d3.area()
.defined(d => !isNaN(d.value))
.x(d => x(d.date))
.y0(y(0))
.y1(d => y(d.value))
)});
main.variable(observer("x")).define("x", ["d3","data","margin","width"], function(d3,data,margin,width){return(
d3.scaleUtc()
.domain(d3.extent(data, d => d.date))
.range([margin.left, width - margin.right])
)});
main.variable(observer("y")).define("y", ["d3","data","height","margin"], function(d3,data,height,margin){return(
d3.scaleLinear()
.domain([0, d3.max(data, d => d.value)])
.range([height - margin.bottom, margin.top])
)});
main.variable(observer("xAxis")).define("xAxis", ["margin","d3","width"], function(margin,d3,width){return(
(g, x, height) => g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x).ticks(width / 80).tickSizeOuter(0))
)});
main.variable(observer("yAxis")).define("yAxis", ["margin","d3"], function(margin,d3){return(
(g, y, title) => g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y))
.call(g => g.select(".domain").remove())
.call(g => g.selectAll(".title").data([title]).join("text")
.attr("class", "title")
.attr("x", -margin.left)
.attr("y", 10)
.attr("fill", "currentColor")
.attr("text-anchor", "start")
.text(title))
)});
main.variable(observer("margin")).define("margin", function(){return(
{top: 20, right: 20, bottom: 30, left: 40}
)});
main.variable(observer("height")).define("height", function(){return(
440
)});
main.variable(observer("focusHeight")).define("focusHeight", function(){return(
100
)});
main.variable(observer("d3")).define("d3", ["require"], function(require){return(
require("d3#5")
)});
return main;
}
How I can display both graphs in the same browser window correctly. You can download the complete project from this link
iframe is the tag which you can use for call other html pages into your web page
<iframe src="index1.html" height="700px" width="100%" style=" border:none;"></iframe>

How to put the state name into the Geo chart/D3.js

I met a problem that I want to put the state name on my geo chart. I tried to use others' method, but they cannot well-matched with my chart. Could you please let me know what's wrong with my code and how to improve it.Thank you in advance!
Index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="stylemap.css">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id = "chart"></div>
<script src="https://d3js.org/d3.v5.js"></script>
<script src="mainmap.js"></script>
</body>
</html>
Mainmap.js:
//weight and height
var chart_height = 600;
var chart_width = 800;
var color = d3.scaleQuantize().range([ 'rgb(255,245,240)','rgb(254,224,210)','rgb(252,187,161)',
'rgb(252,146,114)','rgb(251,106,74)','rgb(239,59,44)',
'rgb(203,24,29)','rgb(165,15,21)','rgb(103,0,13)']);
//Projection
var projection = d3.geoAlbersUsa()
.scale([chart_width])
.translate([chart_width / 2, chart_height / 2 ]);
// .translate([0, 100]);
var path = d3.geoPath(projection);
// .projection(projection);
//create svg
var svg = d3.select('#chart')
.append("svg")
.attr('width', chart_width)
.attr('height', chart_height);
// svg.append("rect")
// .attr("class", "background")
// .attr("width", width)
// .attr("height", height);
var g = svg.append("g")
.attr("transform", "translate(" + chart_width / 2 + "," + chart_height / 2 + ")")
.append("g")
.attr("id", "states");
//Data
d3.json('zombie-attacks.json').then(function(zombie_data){
color.domain([
d3.min(zombie_data, function(d){
return d.num;
}),
d3.max(zombie_data, function(d){
return d.num;
})
]);
d3.json('us.json').then(function(us_data){
us_data.features.forEach(function(us_e, us_i){
zombie_data.forEach(function(z_e,z_i){
if(us_e.properties.name !== z_e.state){
return null;
}
us_data.features[us_i].properties.num = parseFloat(z_e.num)
});
});
// console.log(us_data)
svg.selectAll('path')
.data(us_data.features)
.enter()
.append('path')
.attr('d',path)
.attr('fill', function(d){
var num = d.properties.num;
return num ? color(num) : '#ddd';
})
.text(function(d){
return d.properties.name;
})
.attr('stroke', '#fff')
.attr('stroke-width',1)
.attr("class", "country-label")
.append("text")
// .attr("transform", function(d) { console.log("d", d); return "translate(" + path.centroid(d) + ")"; })
// .text(function(d) { return d.properties.name; })
.attr("dy", function (d) {
return "0.35em";
})
.style('fill', 'black');
g.selectAll("text")
.data(us_data.features)
.enter()
.append("text")
.text(function(d){
return d.properties.name;
})
.attr("x", function(d){
return path.centroid(d)[0];
})
.attr("y", function(d){
return path.centroid(d)[1];
})
.attr("text-anchor","middle")
.attr('font-size','6pt')
.style('fill', 'green');
})
})
// Add names of the states to a map in d3.js
You're appending text and path to different parents: svg and g. This is an issue because:
var g = svg.append("g")
.attr("transform", "translate(" + chart_width / 2 + "," + chart_height / 2 + ")")
Your g, with the text has a transform that the svg doesn't. Which is why your text is pushed width/2, height/2 further than the projected paths. Just use svg.selectAll for the text.
The projection already has a translate applied to it, you can either apply the translation to the parent or to the projection, but shouldn't use both.

bar chart not coinciding with axes in d3.js

I am trying to create a bar chart in d3.js and unfortunately, the bars are not on the axes. They are appearing somewhere else. Can you please point out what I am doing wrong here.
I think it has do with the placing of axes and all but I am unable to figure it out.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="https://d3js.org/d3.v5.min.js"></script>
</head>
<body>
<div id="rer"></div>
<script>
var width = 400, height = 400;
var data1 = { 2011: 9, 2012: 12, 2013: 10, 2014: 8, 2015: 12, 2016: 20 }
data_ready = d3.entries(data1);
var barColor = '#50740a';
var svg = d3.select("#rer")
.append("svg")
.attr("width", width)
.attr("height", height);
var xscale = d3.scaleBand()
.domain(data_ready.map((function (d) { return d.key; })))
.range([0, width - 100]);
var yscale = d3.scaleLinear()
.domain([0, d3.max(data_ready, function (d) { return d.value; })])
.range([height / 2, 0]);
var x_axis = d3.axisBottom().scale(xscale);
var y_axis = d3.axisLeft().scale(yscale);
svg.append("g")
.attr("transform", "translate(100, 20)")
.call(y_axis);
var xAxisTranslate = height / 2 + 10;
svg.append("g")
.attr("transform", "translate(100, " + xAxisTranslate + ")")
.call(x_axis);
svg.selectAll(".bar")
.data(data_ready)
.enter().append("rect")
.attr('class', 'bar')
.attr("x", function (d) { return xscale(d.key); })
.attr("y", function (d) { return yscale(d.value); })
.attr("width", xscale.bandwidth())
.attr("height", function (d) { return height - yscale(d.value); })
.attr("fill", barColor)
</script>
</body>
</html>
I tried to correct it and got the graph as below. Can someone please explain the attr ( transform, translate ) thing. This seems to be the issue. I did a trial and error method to place the position of the graph. Is there a better way to do this ?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="https://d3js.org/d3.v5.min.js"></script>
</head>
<body>
<div id="rer"></div>
<script>
var width = 400,
height = 400;
var data1 = {
2011: 9,
2012: 12,
2013: 10,
2014: 8,
2015: 12,
2016: 20
}
data_ready = d3.entries(data1);
var barColor = '#50740a';
var svg = d3.select("#rer")
.append("svg")
.attr("width", width)
.attr("height", height);
var xscale = d3.scaleBand()
.domain(data_ready.map((function(d) {
return d.key;
})))
.range([0, width - 100])
.padding(0.1);
var yscale = d3.scaleLinear()
.domain([0, d3.max(data_ready, function(d) {
return d.value;
})])
.range([height / 2, 0]);
var x_axis = d3.axisBottom().scale(xscale);
var y_axis = d3.axisLeft().scale(yscale);
svg.append("g")
.attr("transform", "translate(100, 10)")
.call(y_axis);
var xAxisTranslate = height / 2 + 10;
svg.append("g")
.attr("transform", "translate(100, " + xAxisTranslate + ")")
.call(x_axis);
svg.selectAll(".bar")
.data(data_ready)
.enter().append("rect")
.attr('class', 'bar')
.attr("x", function(d) {
return xscale(d.key);
})
.attr("y", function(d) {
return yscale(d.value);
})
.attr("width", xscale.bandwidth())
.attr("height", function(d) {
return height / 2 - yscale(d.value);
})
.attr("fill", barColor)
.attr("transform", "translate(100, 10)")
</script>
</body>
</html>

d3 line chart, line not drawing

I'm trying to mimic the simple blocks example here, however I only seem to get the x and y axis to draw, no sign of the line. I'm loading data differently, via an array rather than a tsv file, though I've combed through a few times and I think everything is feeding into the scales and the line the same way. Non-working JSBin here:
<!DOCTYPE html>
<html>
<head>
<script src="https://d3js.org/d3.v4.min.js"></script>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<svg width="960" height="500"></svg>
<script>
var data = [["2014-12-31", 0.31999999999999],["2014-11-30", 2.71],["2014-10-31", -4.05],["2014-09-30", 4.22],["2014-08-31", 2.17],["2014-07-31", 5.36],["2014-06-30", 3.99],["2014-05-31", 3.52],["2014-04-30", -.46],["2014-03-31", -8.22],["2014-02-28", 5.89]]
var svg = d3.select("svg"),
margin = {top: 20, right: 20, bottom: 30, left: 50},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom,
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var parseTime = d3.timeParse("%Y-%m-%d");
var x = d3.scaleTime().rangeRound([0, width]);
var y = d3.scaleLinear().rangeRound([height, 0]);
var data = data.map(function(d){
return [parseTime(d[0]), +d[1]]
});
var line = d3.line()
.x(function(d){
return d[0];
})
.y(function(d){
return d[1];
});
x.domain(d3.extent(data, function(d) { return d[0]; }));
y.domain(d3.extent(data, function(d) { return d[1]; }));
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", 50)
.attr("dy", "0.9em")
.attr("text-anchor", "end")
.text("Price ($)");
g.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", 3)
.attr("d", line);
</script>
</body>
</html>
anything obvious that I'm doing wrong?
The issue is that you are not scaling your data to fit properly within your svg coordinate space:
var line = d3.line()
.x(function(d){
return d[0];
})
.y(function(d){
return d[1];
});
This section of code sets the plotted coordinates of your data, and you are currently using your data values as your x and y svg values without any scaling. You need to scale it according to your scale:
var line = d3.line()
.x(function(d){
console.log(x(d[0])); return x(d[0]);
})
.y(function(d){
return y(d[1]);
});
This will allow your graph to draw as intended.

Categories