I am new d3.js .I am trying to run code at this link(observablehq).For running this code, I placed that code in index.js file.
d3 = require("d3@5")
height = 500
margin = ({top: 10, right: 10, bottom: 20, left: 40})
data = Object.assign(d3.csvParse(await FileAttachment("data.csv").text(), d3.autoType), {y: "Population"})
groupKey = data.columns[0]
keys = data.columns.slice(1)
x0 = d3.scaleBand()
.domain(data.map(d => d[groupKey]))
.rangeRound([margin.left, width - margin.right])
.paddingInner(0.1)
x1 = d3.scaleBand()
.domain(keys)
.rangeRound([0, x0.bandwidth()])
.padding(0.05)
y = d3.scaleLinear()
.domain([0, d3.max(data, d => d3.max(keys, key => d[key]))]).nice()
.rangeRound([height - margin.bottom, margin.top])
color = d3.scaleOrdinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"])
xAxis = g => g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x0).tickSizeOuter(0))
.call(g => g.select(".domain").remove())
yAxis = g => 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))
legend = svg => {
const g = svg
.attr("transform", `translate(${width},0)`)
.attr("text-anchor", "end")
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.selectAll("g")
.data(color.domain().slice().reverse())
.join("g")
.attr("transform", (d, i) => `translate(0,${i * 20})`);
g.append("rect")
.attr("x", -19)
.attr("width", 19)
.attr("height", 19)
.attr("fill", color);
g.append("text")
.attr("x", -24)
.attr("y", 9.5)
.attr("dy", "0.35em")
.text(d => d);
}
chart = {
const svg = d3.select(DOM.svg(width, height));
svg.append("g")
.selectAll("g")
.data(data)
.join("g")
.attr("transform", d => `translate(${x0(d[groupKey])},0)`)
.selectAll("rect")
.data(d => keys.map(key => ({key, value: d[key]})))
.join("rect")
.attr("x", d => x1(d.key))
.attr("y", d => y(d.value))
.attr("width", x1.bandwidth())
.attr("height", d => y(0) - y(d.value))
.attr("fill", d => color(d.key));
svg.append("g")
.call(xAxis);
svg.append("g")
.call(yAxis);
svg.append("g")
.call(legend);
return svg.node();
}
After that i called index.js file from html script
<!DOCTYPE html>
<html>
<head>
<title>Visualization 2 (Multiline graph)</title>
<link rel="stylesheet" href="styles.css">
<script src="https://unpkg.com/d3@5.6.0/dist/d3.min.js"></script>
</head>
<body>
<svg width="960" height="500"></svg>
<script src="index.js"></script>
</body>
</html>
I created the data.csv file from array
State,Under 5 Years,5 to 13 Years,14 to 17 Years,18 to 24 Years,25 to 44 Years,45 to 64 Years,65 Years and Over
CA,2704659,4499890,2159981,3853788,10604510,8819342,4114496
TX,2027307,3277946,1420518,2454721,7017731,5656528,2472223
NY,1208495,2141490,1058031,1999120,5355235,5120254,2607672
FL,1140516,1938695, 925060,1607297,4782119,4746856,3187797
IL,894368,1558919,725973,1311479,3596343,3239173,1575308
PA,737462,1345341,679201,1203944,3157759,3414001,1910571
This code is not giving the required output that is this graph in vizhub.
How to get the required output. Here is vizhub link to code
Update: Code is giving me following error in vizhub
SyntaxError: Unexpected keyword 'const' (57:4)
/index.js (line 57)
53 : .attr("dy", "0.35em")
54 : .text(d => d);
55 : }
56 : chart = {
57 : const svg = d3.select(DOM.svg(width, height));
^
The first thing to notice is that the javascript running on observablehq is a different flavor of js. It needs a special library runtime to run on your browser. Thus, if you copy and paste the code to a .js .html file it won't work right away.
If you're learning d3 and enjoys Observable environment, you could easily download/embed your code on a page using the runtime.
Downloading and Embedding Notebooks
For example, fetching the notebook code from observable and the runtime from jsdelivr.
Remember, you could download the sources and host it from your own servers.
The code below renders cell chart
, the runtime makes sure all the other relevant cells are executed in order.
<div id="observablehq-758e3cb7"></div>
<script type="module">
import {Runtime, Inspector} from "https://cdn.jsdelivr.net/npm/@observablehq/runtime@4/dist/runtime.js";
import define from "https://api.observablehq.com/@d3/grouped-bar-chart.js?v=3";
const inspect = Inspector.into("#observablehq-758e3cb7");
(new Runtime).module(define, name => name === "chart" ? inspect() : undefined);
</script>
Using same approach but exposing the notebook source code, here you can see how your code is abstracted inside the function export default function notebook(runtime, observer)
then the runtime is responsible to run it, last two lines
const runtime = new Runtime();
const main = runtime.module(notebook, Inspector.into(document.body));
<script type="module">
import {Runtime, Inspector} from "https://cdn.jsdelivr.net/npm/@observablehq/runtime@4/dist/runtime.js";
// https://observablehq.com/@d3/grouped-bar-chart@81
export default function notebook(runtime, observer) {
const main = runtime.module();
const fileAttachments = new Map([["data.csv","https://static.observableusercontent.com/files/72eda648679b19ee477d3b70a598c977219672ab0c809bd42a0e15fb322894dc78dead25bd50ad1613de459d161dc6278b3add8d5f251547b393b10c4cf00a05"]]);
main.builtin("FileAttachment", runtime.fileAttachments(name => fileAttachments.get(name)));
main.variable(observer()).define(["md"], function(md){return(
md`# Grouped Bar Chart`
)});
main.variable(observer("chart")).define("chart", ["d3","DOM","width","height","data","x0","groupKey","keys","x1","y","color","xAxis","yAxis","legend"], function(d3,DOM,width,height,data,x0,groupKey,keys,x1,y,color,xAxis,yAxis,legend)
{
const svg = d3.select(DOM.svg(width, height));
svg.append("g")
.selectAll("g")
.data(data)
.join("g")
.attr("transform", d => `translate(${x0(d[groupKey])},0)`)
.selectAll("rect")
.data(d => keys.map(key => ({key, value: d[key]})))
.join("rect")
.attr("x", d => x1(d.key))
.attr("y", d => y(d.value))
.attr("width", x1.bandwidth())
.attr("height", d => y(0) - y(d.value))
.attr("fill", d => color(d.key));
svg.append("g")
.call(xAxis);
svg.append("g")
.call(yAxis);
svg.append("g")
.call(legend);
return svg.node();
}
);
main.variable(observer("legend")).define("legend", ["width","color"], function(width,color){return(
svg => {
const g = svg
.attr("transform", `translate(${width},0)`)
.attr("text-anchor", "end")
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.selectAll("g")
.data(color.domain().slice().reverse())
.join("g")
.attr("transform", (d, i) => `translate(0,${i * 20})`);
g.append("rect")
.attr("x", -19)
.attr("width", 19)
.attr("height", 19)
.attr("fill", color);
g.append("text")
.attr("x", -24)
.attr("y", 9.5)
.attr("dy", "0.35em")
.text(d => d);
}
)});
main.variable(observer("x0")).define("x0", ["d3","data","groupKey","margin","width"], function(d3,data,groupKey,margin,width){return(
d3.scaleBand()
.domain(data.map(d => d[groupKey]))
.rangeRound([margin.left, width - margin.right])
.paddingInner(0.1)
)});
main.variable(observer("x1")).define("x1", ["d3","keys","x0"], function(d3,keys,x0){return(
d3.scaleBand()
.domain(keys)
.rangeRound([0, x0.bandwidth()])
.padding(0.05)
)});
main.variable(observer("y")).define("y", ["d3","data","keys","height","margin"], function(d3,data,keys,height,margin){return(
d3.scaleLinear()
.domain([0, d3.max(data, d => d3.max(keys, key => d[key]))]).nice()
.rangeRound([height - margin.bottom, margin.top])
)});
main.variable(observer("color")).define("color", ["d3"], function(d3){return(
d3.scaleOrdinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"])
)});
main.variable(observer("xAxis")).define("xAxis", ["height","margin","d3","x0"], function(height,margin,d3,x0){return(
g => g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x0).tickSizeOuter(0))
.call(g => g.select(".domain").remove())
)});
main.variable(observer("yAxis")).define("yAxis", ["margin","d3","y","data"], function(margin,d3,y,data){return(
g => 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("data")).define("data", ["d3","FileAttachment"], async function(d3,FileAttachment){return(
Object.assign(d3.csvParse(await FileAttachment("data.csv").text(), d3.autoType), {y: "Population"})
)});
main.variable(observer("groupKey")).define("groupKey", ["data"], function(data){return(
data.columns[0]
)});
main.variable(observer("keys")).define("keys", ["data"], function(data){return(
data.columns.slice(1)
)});
main.variable(observer("margin")).define("margin", function(){return(
{top: 10, right: 10, bottom: 20, left: 40}
)});
main.variable(observer("height")).define("height", function(){return(
500
)});
main.variable(observer("d3")).define("d3", ["require"], function(require){return(
require("d3@5")
)});
return main;
}
const runtime = new Runtime();
const main = runtime.module(notebook, Inspector.into(document.body));
</script>
Now if you want to manually convert the code running on Observable to vanilla js, then you might need to look into other references,