How to build a 2d density chart with React and D3.
2d density chart
A 2D density chart is a graphical representation of data that uses color to show the concentration of data points in a given area. It shows the combined distribution of two quantitative variables. 2D density charts are often used in statistical analysis and data mining to identify trends, patterns, and correlations in the data.
In this tutorial, we will use the d3.js and React libraries to build a 2D density chart. It starts by describing how the data should be organized and how to initialize the Density2d component. It then explains how to prepare the data and compute bins. Once this is done, it shows how to render the shapes and suggests a few variations. 🙇♂️.
A 2d density chart is basically a variation of the scatterplot, useful when the amount of data points is huge. As a result, it shares the same data structure.
The data is an array of object. For each object, at least 2 properties are required: x and y. The value of x is the position of the datapoint on the horizontal axis. The value of y is linked with the vertical axis.
const data = [
+How to build a 2d density chart with React and D3.
2d density chart
A 2D density chart is a graphical representation of data that uses color to show the concentration of data points in a given area. It shows the combined distribution of two quantitative variables. 2D density charts are often used in statistical analysis and data mining to identify trends, patterns, and correlations in the data.
In this tutorial, we will use the d3.js and React libraries to build a 2D density chart. It starts by describing how the data should be organized and how to initialize the Density2d component. It then explains how to prepare the data and compute bins. Once this is done, it shows how to render the shapes and suggests a few variations. 🙇♂️.
A 2d density chart is basically a variation of the scatterplot, useful when the amount of data points is huge. As a result, it shares the same data structure.
The data is an array of object. For each object, at least 2 properties are required: x and y. The value of x is the position of the datapoint on the horizontal axis. The value of y is linked with the vertical axis.
const data = [
{
x: 2,
y: 4
@@ -78,4 +78,4 @@
}
I'm in the process of writing a complete blog post on the topic. Subscribe to the project to know when it's ready.
2D Density inspiration
If you're looking for inspiration to create your next 2D Density, note that dataviz-inspiration.com showcases many examples. Definitely the best place to get ... inspiration!
dataviz-inspiration.com showcases hundreds of stunning dataviz projects. Have a look to get some ideas on how to make your 2D Density looks good!
The hexbin representation above is just one member of a family of graphics allowing to study the combined distribution of two quantitative variables. You can read more about the existing variations in the data to viz project.
To put it in a nutshell, 2d histogram, Gaussian KDE, 2d density and Contour charts are the most common variations. It is of course possible to build them all using react and d3.js.
Here is an example with a contounr chart based on the same dataset than the previous example.
Contour chart made with React and D3.js.
ToDomake the contour chart above looks better
ToDoadd examples for 2d histograms and other variations
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data with gmail.com. You can also subscribe to the newsletter to know when I publish more content!
\ No newline at end of file
diff --git a/404.html b/404.html
index 7ba9bea7..364a09ea 100644
--- a/404.html
+++ b/404.html
@@ -1,4 +1,4 @@
-How to build a scatter plot with React and D3.
Oh No! (404)
It looks like the place you are looking for does not exist 🙈
The countries with the highest vulnerability to climate change have the lowest CO2 emissions
All countries sorted by their vulnerability and readiness to climate change. The size shows the CO2 emission per person in that country.
Reproduction of a chart originally published by Data Wrapper using react and d3.js.
Contact
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data with gmail.com. You can also subscribe to the newsletter to know when I publish more content!
+How to build a scatter plot with React and D3.
Oh No! (404)
It looks like the place you are looking for does not exist 🙈
The countries with the highest vulnerability to climate change have the lowest CO2 emissions
All countries sorted by their vulnerability and readiness to climate change. The size shows the CO2 emission per person in that country.
Reproduction of a chart originally published by Data Wrapper using react and d3.js.
Contact
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data with gmail.com. You can also subscribe to the newsletter to know when I publish more content!
\ No newline at end of file
diff --git a/_next/static/chunks/pages/course/scales/linear-scale-744385fc0fee6ab5.js b/_next/static/chunks/pages/course/scales/linear-scale-2b562f6b76eefd20.js
similarity index 99%
rename from _next/static/chunks/pages/course/scales/linear-scale-744385fc0fee6ab5.js
rename to _next/static/chunks/pages/course/scales/linear-scale-2b562f6b76eefd20.js
index 5d369d9a..da010542 100644
--- a/_next/static/chunks/pages/course/scales/linear-scale-744385fc0fee6ab5.js
+++ b/_next/static/chunks/pages/course/scales/linear-scale-2b562f6b76eefd20.js
@@ -1 +1 @@
-(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1535],{81936:function(e,s,i){(window.__NEXT_P=window.__NEXT_P||[]).push(["/course/scales/linear-scale",function(){return i(70438)}])},88578:function(e,s,i){"use strict";i.d(s,{X:function(){return r}});var n=i(85893);i(67294);let r=e=>{let{vizName:s,height:i="500px",fileToOpen:r}=e;return console.log("rerendeeeerrrrr"),(0,n.jsx)("iframe",{src:"https://codesandbox.io/embed/github/holtzy/react-graph-gallery/tree/main/viz/"+s+"?fontsize=14&hidenavigation=1&theme=dark&expanddevtools=0&view=split"+(r?"&module=/".concat(r):""),style:{width:"100%",height:i,border:"solid",borderWidth:2,borderRadius:"4px",overflow:"hidden"},allow:"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking",sandbox:"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"})}},13400:function(e,s,i){"use strict";i.d(s,{q:function(){return h}});var n=i(85893),r=i(22725),t=i(88578),a=i(8117),l=i(5),o=i(41664),c=i.n(o),d=i(77522);let h=e=>{let{exercise:s}=e,i=(0,n.jsx)(t.X,{vizName:s.practiceSandbox,height:"500px",fileToOpen:s.fileToOpen}),o=(0,n.jsx)(t.X,{vizName:s.solutionSandbox,height:"500px",fileToOpen:s.fileToOpen});return(0,n.jsxs)("div",{children:[(0,n.jsxs)("div",{className:"grid grid-cols-2 gap-4 pt-4",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)(a.C,{children:"To Do"}),(0,n.jsx)("div",{className:"mt-4",children:s.toDo})]}),(0,n.jsxs)("div",{children:[(0,n.jsx)(a.C,{children:"Why it matters"}),(0,n.jsx)("div",{className:"mt-4 pl-4",children:s.whyItMatters})]})]}),(0,n.jsxs)(r.mQ,{defaultValue:"practice",className:"relative",children:[(0,n.jsx)("div",{className:"flex justify-center items-center",children:(0,n.jsxs)(r.dr,{children:[(0,n.jsx)(r.SP,{value:"practice",children:"Practice"}),(0,n.jsx)(r.SP,{value:"solution",children:"Solution"})]})}),(0,n.jsxs)(r.nU,{value:"practice",children:[(0,n.jsx)("div",{className:"my-4",children:i}),(0,n.jsx)("div",{className:"absolute right-0",children:(0,n.jsx)(c(),{className:(0,l.d)({size:"sm",variant:"destructive"}),href:"/sandbox?vizName="+s.practiceSandbox,target:"_blank",children:"Show full screen"})})]}),(0,n.jsxs)(r.nU,{value:"solution",children:[(0,n.jsx)("div",{className:"my-4",children:o}),(0,n.jsx)("div",{className:"absolute right-0",children:(0,n.jsx)(c(),{className:(0,d.cn)((0,l.d)({size:"sm",variant:"destructive"}),"no-underline"),href:"/sandbox?vizName="+s.solutionSandbox,target:"_blank",children:"Show full screen"})})]})]})]})}},22725:function(e,s,i){"use strict";i.d(s,{SP:function(){return c},dr:function(){return o},mQ:function(){return l},nU:function(){return d}});var n=i(85893),r=i(67294),t=i(60434),a=i(77522);let l=t.fC,o=r.forwardRef((e,s)=>{let{className:i,...r}=e;return(0,n.jsx)(t.aV,{ref:s,className:(0,a.cn)("inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",i),...r})});o.displayName=t.aV.displayName;let c=r.forwardRef((e,s)=>{let{className:i,...r}=e;return(0,n.jsx)(t.xz,{ref:s,className:(0,a.cn)("inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",i),...r})});c.displayName=t.xz.displayName;let d=r.forwardRef((e,s)=>{let{className:i,...r}=e;return(0,n.jsx)(t.VY,{ref:s,className:(0,a.cn)("mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",i),...r})});d.displayName=t.VY.displayName},70438:function(e,s,i){"use strict";i.r(s),i.d(s,{default:function(){return u}});var n=i(85893);i(67294);var r=i(43710),t=i(41843),a=i(11236),l=i(41664),o=i.n(l),c=i(45023),d=i(3572),h=i(47498),x=i(13400);function u(){let e=a.Y.find(e=>"/course/scales/linear-scale"===e.link);return e?(0,n.jsxs)(t.p,{title:e.name,seoDescription:"",nextTocItem:a.Y.find(e=>"/course/scales/other-scale-types"===e.link),previousTocItem:a.Y.find(e=>"/course/scales/introduction"===e.link),children:[(0,n.jsx)(r.Z,{title:e.name,lessonStatus:e.status,readTime:e.readTime,selectedLesson:e,description:(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)("p",{children:["The previous lesson described the concept of"," ",(0,n.jsx)(o(),{href:"/course/scales/introduction",children:"scale"})," in data visualization. Scales allow, for instance, to translate a value in our dataset to a position on the screen."]}),(0,n.jsxs)("p",{children:["Now, let's study the most common scale type and its d3.js implementation: the ",(0,n.jsx)("b",{children:"linear"})," scale and its"," ",(0,n.jsx)("code",{children:"scaleLinear()"})," function."]})]})}),(0,n.jsx)(c.M,{}),(0,n.jsxs)("h2",{children:["The ",(0,n.jsx)("code",{children:"scaleLinear()"})," function"]}),(0,n.jsxs)("p",{children:["The ",(0,n.jsx)("code",{children:"scaleLinear()"})," function is part of the"," ",(0,n.jsx)("a",{href:"https://github.com/d3/d3-scale",children:"d3-scale"})," module of d3.js."]}),(0,n.jsxs)("p",{children:["It expects 2 inputs: a ",(0,n.jsx)("b",{children:"domain"})," and a ",(0,n.jsx)("b",{children:"range"}),"."]}),(0,n.jsx)("h3",{className:"mt-2 text-md",children:"\uD83C\uDFE0 Domain"}),(0,n.jsxs)("p",{children:["Usually an array of length 2. It provides the ",(0,n.jsx)("code",{children:"min"})," and the"," ",(0,n.jsx)("code",{children:"max"})," of the values we have in the dataset."]}),(0,n.jsx)("h3",{className:"mt-2 text-md",children:"\uD83D\uDCCF Range"}),(0,n.jsxs)("p",{children:["Usually an array of length 2. It provides the start and the end of the positions we are targeting ",(0,n.jsx)("b",{children:"in pixel"}),"."]}),(0,n.jsx)("p",{children:(0,n.jsx)("br",{})}),(0,n.jsxs)("p",{children:["The output is a ",(0,n.jsx)("b",{children:"function"})," that takes a single argument. You provide a value from the domain, and it returns the corresponding value from the range."]}),(0,n.jsx)("p",{children:"Let's create a scale to address the issue with the green circles above!"}),(0,n.jsx)(d.d,{code:"\nimport {scaleLinear} from d3\n\nconst scale = scaleLinear()\n .domain([0, 100])\n .range([0, 500]);\n\nconsole.log( scale(82) )\n// 240\n\n "}),(0,n.jsx)("h2",{children:"Dealing with the Y Axis"}),(0,n.jsx)("p",{children:"By now, working with the X scale should feel intuitive."}),(0,n.jsxs)("p",{children:["However, the Y axis behaves a bit differently. Typically, when a value is ",(0,n.jsx)("b",{children:"high"}),", we expect the corresponding data point to be"," ",(0,n.jsx)("b",{children:"near the top"})," of the SVG area. Conversely, a value close to 0 should appear near the bottom."]}),(0,n.jsxs)("p",{children:["This means the Y scale is essentially inverted! Luckily, we can handle this easily by ",(0,n.jsx)("b",{children:"reversing the order"})," of the range array."]}),(0,n.jsx)("p",{children:"Take a close look at the code below:"}),(0,n.jsx)(d.d,{code:"\nconst yScale = d3.scaleLinear()\n .domain([0, 100])\n .range([300, 0]); // Array is inverted! Smallest value will return 300px = bottom of the svg area\n\nconsole.log(yScale(0)) // 300\nconsole.log(yScale(100)) // 0\n"}),(0,n.jsx)("h2",{children:"Exercices"}),(0,n.jsx)(h.v,{localStorageId:e.link,exercises:[{title:(0,n.jsx)("span",{children:"Control bar size with a scale"}),content:(0,n.jsx)(x.q,{exercise:j[0]})},{title:(0,n.jsx)("span",{children:"Three Bars!"}),content:(0,n.jsx)(x.q,{exercise:j[1]})},{title:(0,n.jsx)("span",{children:"Reverse direction"}),content:(0,n.jsx)(x.q,{exercise:j[2]})},{title:(0,n.jsx)("span",{children:"Mirror barplot"}),content:(0,n.jsx)(x.q,{exercise:j[3]})}]}),(0,n.jsx)("h2",{children:"Wouch! \uD83D\uDE05"}),(0,n.jsx)("p",{children:"That was challenging!"}),(0,n.jsx)("p",{children:"Scales are a core concept in D3.js data visualization, which is why we needed so many exercises!"}),(0,n.jsx)("p",{children:"You've mastered the most important part, but we're not done with scales just yet. Let's explore a few other useful scale types!"})]}):null}let j=[{whyItMatters:(0,n.jsx)(n.Fragment,{children:(0,n.jsx)("p",{children:"Now that you know what a scale is, time to write your first scale!"})}),toDo:(0,n.jsxs)("ul",{children:[(0,n.jsx)("li",{children:"Create a barplot with 1 bar only."}),(0,n.jsx)("li",{children:"The SVG area is 500px wide. Your dataset goes from 0 to 100."}),(0,n.jsx)("li",{children:"Draw a horizontal bar that goes from the very left, and has a length that represents a value of 82 in the dataset."})]}),practiceSandbox:"exercise/linearScaleBarSizePractice",solutionSandbox:"exercise/linearScaleBarSizeSolution"},{whyItMatters:(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)("p",{children:"Once a scale is available, everything you draw on your screen will go through it to determine positions!"}),(0,n.jsx)("p",{children:"Also, see how convenient scales are when it comes to adding margins!"})]}),toDo:(0,n.jsxs)("ul",{children:[(0,n.jsx)("li",{children:"Now create 3 bars."}),(0,n.jsx)("li",{children:"Vertical positions are written manually"}),(0,n.jsxs)("li",{children:["Widths must represent the value ",(0,n.jsx)("code",{children:"34"}),", ",(0,n.jsx)("code",{children:"53"})," and"," ",(0,n.jsx)("code",{children:"82"})]}),(0,n.jsxs)("li",{children:["⚠️ You must leave a ",(0,n.jsx)("b",{children:"margin"})," of 20px on the left hand side."]})]}),practiceSandbox:"exercise/linearScaleThreeBarsPractice",solutionSandbox:"exercise/linearScaleThreeBarsSolution"},{whyItMatters:(0,n.jsx)(n.Fragment,{children:(0,n.jsx)("p",{children:"Scales are very useful to reverse the direction of drawing"})}),toDo:(0,n.jsxs)("ul",{children:[(0,n.jsxs)("li",{children:["Let's draw one single bar that represents the value ",(0,n.jsx)("code",{children:"82"})]}),(0,n.jsx)("li",{children:"But this time, the bar must go from the right to the left."}),(0,n.jsxs)("li",{children:["Hint: reverse the ",(0,n.jsx)("code",{children:"range"})," array!"]})]}),practiceSandbox:"exercise/linearScaleReversePractice",solutionSandbox:"exercise/linearScaleReverseSolution"},{whyItMatters:(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)("p",{children:["The logic behind each functions of the ",(0,n.jsx)("code",{children:"d3-shape"})," module is the same."]}),(0,n.jsx)("p",{children:"If you have a good understanding of d3.line(), you're on the right way to build any other chart type!"})]}),toDo:(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)("p",{children:"Let's create a mirror histogram!! The mirror histogram looks like this:"}),(0,n.jsxs)("ul",{children:[(0,n.jsx)("li",{children:"Create 2 scales!"}),(0,n.jsxs)("li",{children:["Values are ",(0,n.jsx)("code",{children:"23"}),", ",(0,n.jsx)("code",{children:"55"}),", ",(0,n.jsx)("code",{children:"87"})," on the left, and ",(0,n.jsx)("code",{children:"12"}),", ",(0,n.jsx)("code",{children:"43"}),", ",(0,n.jsx)("code",{children:"98"})," on the right"]})]})]}),practiceSandbox:"exercise/linearScaleMirrorPractice",solutionSandbox:"exercise/linearScaleMirrorSolution"}]}},function(e){e.O(0,[2343,7754,7823,9484,8190,3710,4969,9774,2888,179],function(){return e(e.s=81936)}),_N_E=e.O()}]);
\ No newline at end of file
+(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1535],{81936:function(e,s,i){(window.__NEXT_P=window.__NEXT_P||[]).push(["/course/scales/linear-scale",function(){return i(70438)}])},88578:function(e,s,i){"use strict";i.d(s,{X:function(){return r}});var n=i(85893);i(67294);let r=e=>{let{vizName:s,height:i="500px",fileToOpen:r}=e;return console.log("rerendeeeerrrrr"),(0,n.jsx)("iframe",{src:"https://codesandbox.io/embed/github/holtzy/react-graph-gallery/tree/main/viz/"+s+"?fontsize=14&hidenavigation=1&theme=dark&expanddevtools=0&view=split"+(r?"&module=/".concat(r):""),style:{width:"100%",height:i,border:"solid",borderWidth:2,borderRadius:"4px",overflow:"hidden"},allow:"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking",sandbox:"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"})}},13400:function(e,s,i){"use strict";i.d(s,{q:function(){return h}});var n=i(85893),r=i(22725),t=i(88578),a=i(8117),l=i(5),o=i(41664),c=i.n(o),d=i(77522);let h=e=>{let{exercise:s}=e,i=(0,n.jsx)(t.X,{vizName:s.practiceSandbox,height:"500px",fileToOpen:s.fileToOpen}),o=(0,n.jsx)(t.X,{vizName:s.solutionSandbox,height:"500px",fileToOpen:s.fileToOpen});return(0,n.jsxs)("div",{children:[(0,n.jsxs)("div",{className:"grid grid-cols-2 gap-4 pt-4",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)(a.C,{children:"To Do"}),(0,n.jsx)("div",{className:"mt-4",children:s.toDo})]}),(0,n.jsxs)("div",{children:[(0,n.jsx)(a.C,{children:"Why it matters"}),(0,n.jsx)("div",{className:"mt-4 pl-4",children:s.whyItMatters})]})]}),(0,n.jsxs)(r.mQ,{defaultValue:"practice",className:"relative",children:[(0,n.jsx)("div",{className:"flex justify-center items-center",children:(0,n.jsxs)(r.dr,{children:[(0,n.jsx)(r.SP,{value:"practice",children:"Practice"}),(0,n.jsx)(r.SP,{value:"solution",children:"Solution"})]})}),(0,n.jsxs)(r.nU,{value:"practice",children:[(0,n.jsx)("div",{className:"my-4",children:i}),(0,n.jsx)("div",{className:"absolute right-0",children:(0,n.jsx)(c(),{className:(0,l.d)({size:"sm",variant:"destructive"}),href:"/sandbox?vizName="+s.practiceSandbox,target:"_blank",children:"Show full screen"})})]}),(0,n.jsxs)(r.nU,{value:"solution",children:[(0,n.jsx)("div",{className:"my-4",children:o}),(0,n.jsx)("div",{className:"absolute right-0",children:(0,n.jsx)(c(),{className:(0,d.cn)((0,l.d)({size:"sm",variant:"destructive"}),"no-underline"),href:"/sandbox?vizName="+s.solutionSandbox,target:"_blank",children:"Show full screen"})})]})]})]})}},22725:function(e,s,i){"use strict";i.d(s,{SP:function(){return c},dr:function(){return o},mQ:function(){return l},nU:function(){return d}});var n=i(85893),r=i(67294),t=i(60434),a=i(77522);let l=t.fC,o=r.forwardRef((e,s)=>{let{className:i,...r}=e;return(0,n.jsx)(t.aV,{ref:s,className:(0,a.cn)("inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",i),...r})});o.displayName=t.aV.displayName;let c=r.forwardRef((e,s)=>{let{className:i,...r}=e;return(0,n.jsx)(t.xz,{ref:s,className:(0,a.cn)("inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",i),...r})});c.displayName=t.xz.displayName;let d=r.forwardRef((e,s)=>{let{className:i,...r}=e;return(0,n.jsx)(t.VY,{ref:s,className:(0,a.cn)("mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",i),...r})});d.displayName=t.VY.displayName},70438:function(e,s,i){"use strict";i.r(s),i.d(s,{default:function(){return u}});var n=i(85893);i(67294);var r=i(43710),t=i(41843),a=i(11236),l=i(41664),o=i.n(l),c=i(45023),d=i(3572),h=i(47498),x=i(13400);function u(){let e=a.Y.find(e=>"/course/scales/linear-scale"===e.link);return e?(0,n.jsxs)(t.p,{title:e.name,seoDescription:"",nextTocItem:a.Y.find(e=>"/course/scales/other-scale-types"===e.link),previousTocItem:a.Y.find(e=>"/course/scales/introduction"===e.link),children:[(0,n.jsx)(r.Z,{title:e.name,lessonStatus:e.status,readTime:e.readTime,selectedLesson:e,description:(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)("p",{children:["The previous lesson described the concept of"," ",(0,n.jsx)(o(),{href:"/course/scales/introduction",children:"scale"})," in data visualization. Scales allow, for instance, to translate a value in our dataset to a position on the screen."]}),(0,n.jsxs)("p",{children:["Now, let's study the most common scale type and its d3.js implementation: the ",(0,n.jsx)("b",{children:"linear"})," scale and its"," ",(0,n.jsx)("code",{children:"scaleLinear()"})," function."]})]})}),(0,n.jsx)(c.M,{}),(0,n.jsxs)("h2",{children:["The ",(0,n.jsx)("code",{children:"scaleLinear()"})," function"]}),(0,n.jsxs)("p",{children:["The ",(0,n.jsx)("code",{children:"scaleLinear()"})," function is part of the"," ",(0,n.jsx)("a",{href:"https://github.com/d3/d3-scale",children:"d3-scale"})," module of d3.js."]}),(0,n.jsxs)("p",{children:["It expects 2 inputs: a ",(0,n.jsx)("b",{children:"domain"})," and a ",(0,n.jsx)("b",{children:"range"}),"."]}),(0,n.jsx)("h3",{className:"mt-2 text-md",children:"\uD83C\uDFE0 Domain"}),(0,n.jsxs)("p",{children:["Usually an array of length 2. It provides the ",(0,n.jsx)("code",{children:"min"})," and the"," ",(0,n.jsx)("code",{children:"max"})," of the values we have in the dataset."]}),(0,n.jsx)("h3",{className:"mt-2 text-md",children:"\uD83D\uDCCF Range"}),(0,n.jsxs)("p",{children:["Usually an array of length 2. It provides the start and the end of the positions we are targeting ",(0,n.jsx)("b",{children:"in pixel"}),"."]}),(0,n.jsx)("p",{children:(0,n.jsx)("br",{})}),(0,n.jsxs)("p",{children:["The output is a ",(0,n.jsx)("b",{children:"function"})," that takes a single argument. You provide a value from the domain, and it returns the corresponding value from the range."]}),(0,n.jsx)("p",{children:"Let's create a scale to address the issue with the green circles above!"}),(0,n.jsx)(d.d,{code:"\nimport {scaleLinear} from d3\n\nconst scale = scaleLinear()\n .domain([0, 100])\n .range([0, 500]);\n\nconsole.log( scale(82) )\n// 410\n\n "}),(0,n.jsx)("h2",{children:"Dealing with the Y Axis"}),(0,n.jsx)("p",{children:"By now, working with the X scale should feel intuitive."}),(0,n.jsxs)("p",{children:["However, the Y axis behaves a bit differently. Typically, when a value is ",(0,n.jsx)("b",{children:"high"}),", we expect the corresponding data point to be"," ",(0,n.jsx)("b",{children:"near the top"})," of the SVG area. Conversely, a value close to 0 should appear near the bottom."]}),(0,n.jsxs)("p",{children:["This means the Y scale is essentially inverted! Luckily, we can handle this easily by ",(0,n.jsx)("b",{children:"reversing the order"})," of the range array."]}),(0,n.jsx)("p",{children:"Take a close look at the code below:"}),(0,n.jsx)(d.d,{code:"\nconst yScale = d3.scaleLinear()\n .domain([0, 100])\n .range([300, 0]); // Array is inverted! Smallest value will return 300px = bottom of the svg area\n\nconsole.log(yScale(0)) // 300\nconsole.log(yScale(100)) // 0\n"}),(0,n.jsx)("h2",{children:"Exercices"}),(0,n.jsx)(h.v,{localStorageId:e.link,exercises:[{title:(0,n.jsx)("span",{children:"Control bar size with a scale"}),content:(0,n.jsx)(x.q,{exercise:j[0]})},{title:(0,n.jsx)("span",{children:"Three Bars!"}),content:(0,n.jsx)(x.q,{exercise:j[1]})},{title:(0,n.jsx)("span",{children:"Reverse direction"}),content:(0,n.jsx)(x.q,{exercise:j[2]})},{title:(0,n.jsx)("span",{children:"Mirror barplot"}),content:(0,n.jsx)(x.q,{exercise:j[3]})}]}),(0,n.jsx)("h2",{children:"Wouch! \uD83D\uDE05"}),(0,n.jsx)("p",{children:"That was challenging!"}),(0,n.jsx)("p",{children:"Scales are a core concept in D3.js data visualization, which is why we needed so many exercises!"}),(0,n.jsx)("p",{children:"You've mastered the most important part, but we're not done with scales just yet. Let's explore a few other useful scale types!"})]}):null}let j=[{whyItMatters:(0,n.jsx)(n.Fragment,{children:(0,n.jsx)("p",{children:"Now that you know what a scale is, time to write your first scale!"})}),toDo:(0,n.jsxs)("ul",{children:[(0,n.jsx)("li",{children:"Create a barplot with 1 bar only."}),(0,n.jsx)("li",{children:"The SVG area is 500px wide. Your dataset goes from 0 to 100."}),(0,n.jsx)("li",{children:"Draw a horizontal bar that goes from the very left, and has a length that represents a value of 82 in the dataset."})]}),practiceSandbox:"exercise/linearScaleBarSizePractice",solutionSandbox:"exercise/linearScaleBarSizeSolution"},{whyItMatters:(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)("p",{children:"Once a scale is available, everything you draw on your screen will go through it to determine positions!"}),(0,n.jsx)("p",{children:"Also, see how convenient scales are when it comes to adding margins!"})]}),toDo:(0,n.jsxs)("ul",{children:[(0,n.jsx)("li",{children:"Now create 3 bars."}),(0,n.jsx)("li",{children:"Vertical positions are written manually"}),(0,n.jsxs)("li",{children:["Widths must represent the value ",(0,n.jsx)("code",{children:"34"}),", ",(0,n.jsx)("code",{children:"53"})," and"," ",(0,n.jsx)("code",{children:"82"})]}),(0,n.jsxs)("li",{children:["⚠️ You must leave a ",(0,n.jsx)("b",{children:"margin"})," of 20px on the left hand side."]})]}),practiceSandbox:"exercise/linearScaleThreeBarsPractice",solutionSandbox:"exercise/linearScaleThreeBarsSolution"},{whyItMatters:(0,n.jsx)(n.Fragment,{children:(0,n.jsx)("p",{children:"Scales are very useful to reverse the direction of drawing"})}),toDo:(0,n.jsxs)("ul",{children:[(0,n.jsxs)("li",{children:["Let's draw one single bar that represents the value ",(0,n.jsx)("code",{children:"82"})]}),(0,n.jsx)("li",{children:"But this time, the bar must go from the right to the left."}),(0,n.jsxs)("li",{children:["Hint: reverse the ",(0,n.jsx)("code",{children:"range"})," array!"]})]}),practiceSandbox:"exercise/linearScaleReversePractice",solutionSandbox:"exercise/linearScaleReverseSolution"},{whyItMatters:(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)("p",{children:["The logic behind each functions of the ",(0,n.jsx)("code",{children:"d3-shape"})," module is the same."]}),(0,n.jsx)("p",{children:"If you have a good understanding of d3.line(), you're on the right way to build any other chart type!"})]}),toDo:(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)("p",{children:"Let's create a mirror histogram!! The mirror histogram looks like this:"}),(0,n.jsxs)("ul",{children:[(0,n.jsx)("li",{children:"Create 2 scales!"}),(0,n.jsxs)("li",{children:["Values are ",(0,n.jsx)("code",{children:"23"}),", ",(0,n.jsx)("code",{children:"55"}),", ",(0,n.jsx)("code",{children:"87"})," on the left, and ",(0,n.jsx)("code",{children:"12"}),", ",(0,n.jsx)("code",{children:"43"}),", ",(0,n.jsx)("code",{children:"98"})," on the right"]})]})]}),practiceSandbox:"exercise/linearScaleMirrorPractice",solutionSandbox:"exercise/linearScaleMirrorSolution"}]}},function(e){e.O(0,[2343,7754,7823,9484,8190,3710,4969,9774,2888,179],function(){return e(e.s=81936)}),_N_E=e.O()}]);
\ No newline at end of file
diff --git a/_next/static/chunks/pages/course/svg/tips-and-tricks-9a34a92abbedcff1.js b/_next/static/chunks/pages/course/svg/tips-and-tricks-718819bf957d0ddb.js
similarity index 74%
rename from _next/static/chunks/pages/course/svg/tips-and-tricks-9a34a92abbedcff1.js
rename to _next/static/chunks/pages/course/svg/tips-and-tricks-718819bf957d0ddb.js
index ca9070c1..cb61067b 100644
--- a/_next/static/chunks/pages/course/svg/tips-and-tricks-9a34a92abbedcff1.js
+++ b/_next/static/chunks/pages/course/svg/tips-and-tricks-718819bf957d0ddb.js
@@ -1 +1 @@
-(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[9551],{77035:function(e,s,t){(window.__NEXT_P=window.__NEXT_P||[]).push(["/course/svg/tips-and-tricks",function(){return t(9463)}])},88578:function(e,s,t){"use strict";t.d(s,{X:function(){return n}});var r=t(85893);t(67294);let n=e=>{let{vizName:s,height:t="500px",fileToOpen:n}=e;return console.log("rerendeeeerrrrr"),(0,r.jsx)("iframe",{src:"https://codesandbox.io/embed/github/holtzy/react-graph-gallery/tree/main/viz/"+s+"?fontsize=14&hidenavigation=1&theme=dark&expanddevtools=0&view=split"+(n?"&module=/".concat(n):""),style:{width:"100%",height:t,border:"solid",borderWidth:2,borderRadius:"4px",overflow:"hidden"},allow:"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking",sandbox:"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"})}},41843:function(e,s,t){"use strict";t.d(s,{p:function(){return d}});var r=t(85893),n=t(49700),i=t(63476),a=t(17414),l=t(41664),o=t.n(l);let d=e=>{let{children:s,title:t,seoDescription:l,previousTocItem:d,nextTocItem:c}=e;return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(a.A,{title:t,seoDescription:l}),(0,r.jsx)(n.Z,{}),(0,r.jsx)("div",{className:"wrapper",children:s}),(0,r.jsxs)("div",{className:"flex justify-center items-center space-x-6 my-24 py-12 bg-muted/50",children:[d?(0,r.jsxs)(o(),{href:d.link,className:"text-gray-500 no-underline flex flex-col justify-start items-end w-96 h-32 border-r border-black p-8 hover:bg-muted ",children:[(0,r.jsx)("span",{className:"uppercase font-light text-transparent bg-gradient-to-l to-fuchsia-300 from-blue-400 bg-clip-text",children:"← Previous"}),(0,r.jsx)("p",{children:d.name})]}):(0,r.jsx)("div",{className:"w-96"}),c&&(0,r.jsxs)(o(),{href:c.link,className:"text-gray-500 no-underline flex flex-col justify-start w-96 h-32 border-l border-black p-8 hover:bg-muted ",children:[(0,r.jsx)("span",{className:"uppercase font-light text-transparent bg-gradient-to-l from-fuchsia-300 to-blue-400 bg-clip-text",children:"Next →"}),(0,r.jsx)("p",{children:c.name})]})]}),(0,r.jsx)("div",{className:"wrapper",children:(0,r.jsx)(i.Z,{})})]})}},63265:function(e,s,t){"use strict";t.d(s,{D:function(){return n}});var r=t(85893);let n=e=>{let{text:s}=e;return(0,r.jsxs)("div",{className:"hidden absolute w-60 top-1/2 -right-10 border-l text-card-foreground border-card-foreground h-28 translate-x-full -translate-y-1/2 xl:flex items-center ",children:[(0,r.jsx)("span",{className:"",children:"→"}),(0,r.jsx)("span",{className:"text-sm ml-2 opacity-70",children:s})]})}},3572:function(e,s,t){"use strict";t.d(s,{d:function(){return c}});var r=t(85893),n=t(32581),i=t(15660),a=t.n(i),l=t(67294),o=t(45993),d=t.n(o);let c=e=>{let{code:s}=e,[t,i]=(0,l.useState)(!1),o=(0,l.useRef)(null);(0,l.useEffect)(()=>{o.current&&a().highlightElement(o.current)},[o,s]);let c=(0,r.jsx)("div",{onClick:()=>{navigator.clipboard.writeText(s),i(!0)},className:d().codeChunckCopyButton,children:t?"Copied":(0,r.jsx)(n.Z,{size:14,style:{padding:0}})});return(0,r.jsxs)("div",{className:"mb-6 relative",children:[(0,r.jsx)("pre",{className:"rounded-md line-numbers",children:(0,r.jsx)("code",{ref:o,className:"language-javascript",children:s})}),(0,r.jsx)("div",{className:d().copyButtonContainer,children:c})]})}},9463:function(e,s,t){"use strict";t.r(s),t.d(s,{default:function(){return _}});var r=t(85893),n=t(67294),i=t(43710),a=t(41843),l=t(11236),o=t(88578),d=t(92882),c=t(8971),h=t(84979),p=t(13742),u=t(77522);let x=d.fC;d.ZA;let m=d.B4,f=n.forwardRef((e,s)=>{let{className:t,children:n,...i}=e;return(0,r.jsxs)(d.xz,{ref:s,className:(0,u.cn)("flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",t),...i,children:[n,(0,r.jsx)(d.JO,{asChild:!0,children:(0,r.jsx)(c.Z,{className:"h-4 w-4 opacity-50"})})]})});f.displayName=d.xz.displayName;let g=n.forwardRef((e,s)=>{let{className:t,...n}=e;return(0,r.jsx)(d.u_,{ref:s,className:(0,u.cn)("flex cursor-default items-center justify-center py-1",t),...n,children:(0,r.jsx)(h.Z,{className:"h-4 w-4"})})});g.displayName=d.u_.displayName;let j=n.forwardRef((e,s)=>{let{className:t,...n}=e;return(0,r.jsx)(d.$G,{ref:s,className:(0,u.cn)("flex cursor-default items-center justify-center py-1",t),...n,children:(0,r.jsx)(c.Z,{className:"h-4 w-4"})})});j.displayName=d.$G.displayName;let y=n.forwardRef((e,s)=>{let{className:t,children:n,position:i="popper",...a}=e;return(0,r.jsx)(d.h_,{children:(0,r.jsxs)(d.VY,{ref:s,className:(0,u.cn)("relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2","popper"===i&&"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",t),position:i,...a,children:[(0,r.jsx)(g,{}),(0,r.jsx)(d.l_,{className:(0,u.cn)("p-1","popper"===i&&"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"),children:n}),(0,r.jsx)(j,{})]})})});y.displayName=d.VY.displayName;let b=n.forwardRef((e,s)=>{let{className:t,...n}=e;return(0,r.jsx)(d.__,{ref:s,className:(0,u.cn)("py-1.5 pl-8 pr-2 text-sm font-semibold",t),...n})});b.displayName=d.__.displayName;let w=n.forwardRef((e,s)=>{let{className:t,children:n,...i}=e;return(0,r.jsxs)(d.ck,{ref:s,className:(0,u.cn)("relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",t),...i,children:[(0,r.jsx)("span",{className:"absolute left-2 flex h-3.5 w-3.5 items-center justify-center",children:(0,r.jsx)(d.wU,{children:(0,r.jsx)(p.Z,{className:"h-4 w-4"})})}),(0,r.jsx)(d.eT,{children:n})]})});w.displayName=d.ck.displayName;let v=n.forwardRef((e,s)=>{let{className:t,...n}=e;return(0,r.jsx)(d.Z0,{ref:s,className:(0,u.cn)("-mx-1 my-1 h-px bg-muted",t),...n})});v.displayName=d.Z0.displayName;var k=t(63265),N=t(49362),S=t(15148),G=t(3572);let V=["auto","baseline","before-edge","text-before-edge","middle","central","after-edge","text-after-edge","ideographic","alphabetic","hanging","mathematical","inherit"],T=["start","middle","end","inherit"];function _(){let e=l.Y.find(e=>"/course/svg/tips-and-tricks"===e.link),[s,t]=(0,n.useState)("baseline"),[d,c]=(0,n.useState)("start");return e?(0,r.jsxs)(a.p,{title:e.name,seoDescription:"",nextTocItem:l.Y.find(e=>"/course/scales/introduction"===e.link),previousTocItem:l.Y.find(e=>"/course/svg/path-element"===e.link),children:[(0,r.jsx)(i.Z,{title:e.name,lessonStatus:e.status,readTime:e.readTime,selectedLesson:e,description:(0,r.jsxs)(r.Fragment,{children:[(0,r.jsxs)("p",{children:["By now, SVG might seem straightforward, but trust me,"," ",(0,r.jsx)("b",{children:"it has its quirks"})," that can make your data visualization journey challenging."]}),(0,r.jsxs)("p",{children:["In this lesson, I'll share some tips and tricks that can"," ",(0,r.jsx)("b",{children:"save yo hours of frustration"})," — lessons I learned the hard way."]})]})}),(0,r.jsx)("h2",{children:"1️⃣ SVG Elements Don’t Have a Background Color"}),(0,r.jsxs)("p",{children:["Unlike HTML elements, SVG elements do not support background colors directly. They also do not support ",(0,r.jsx)("b",{children:"borders"}),"."]}),(0,r.jsxs)("p",{children:["If you want to create a background or add a border to your SVG, you need to draw a ",(0,r.jsx)("b",{children:"rectangle that covers the desired area"}),". CSS properties like ",(0,r.jsx)("code",{children:"background-color"})," or ",(0,r.jsx)("code",{children:"fill"})," or"," ",(0,r.jsx)("code",{children:"border"})," on the SVG element itself are not recognized and will be ignored."]}),(0,r.jsx)("p",{children:"Example:"}),(0,r.jsx)("div",{className:"full-bleed my-4 max-w-7xl mx-auto",children:(0,r.jsx)(o.X,{vizName:"exercise/SvgStackingOrderSolution"})}),(0,r.jsx)("h2",{children:"2️⃣ Text Alignment in SVG"}),(0,r.jsxs)("p",{children:["Text alignment in SVG works differently compared to HTML. You can control both horizontal and vertical alignment using the"," ",(0,r.jsx)("code",{children:"text-anchor"})," and ",(0,r.jsx)("code",{children:"alignment-baseline"})," properties, which are unique to SVG."]}),(0,r.jsx)("div",{className:"relative",children:(0,r.jsx)(k.D,{text:(0,r.jsxs)("p",{children:["Remember, in JSX, CSS properties should be camelCased (e.g.,"," ",(0,r.jsx)("code",{children:"textAnchor"})," instead of ",(0,r.jsx)("code",{children:"text-anchor"}),")."]})})}),(0,r.jsx)("p",{children:(0,r.jsx)("br",{})}),(0,r.jsx)("p",{children:"Here’s a summary of how they work:"}),(0,r.jsxs)("div",{className:"flex items-center justify-start gap-4",children:[(0,r.jsx)(N.Z,{}),(0,r.jsxs)("span",{children:[(0,r.jsx)("code",{children:"text-anchor"})," controls the horizontal alignment →"]}),(0,r.jsxs)(x,{value:d,onValueChange:e=>c(e),children:[(0,r.jsx)(f,{className:"w-[180px]",children:(0,r.jsx)(m,{children:d})}),(0,r.jsx)(y,{children:T.map((e,s)=>(0,r.jsx)(w,{value:e,children:e},s))})]})]}),(0,r.jsxs)("div",{className:"flex items-center justify-start gap-4 mt-2 mb-8",children:[(0,r.jsx)(S.Z,{}),(0,r.jsxs)("span",{children:[(0,r.jsx)("code",{children:"alignment-baseline"})," controls the vertical alignment →"]}),(0,r.jsxs)(x,{value:s,onValueChange:e=>t(e),children:[(0,r.jsx)(f,{className:"w-[180px]",children:(0,r.jsx)(m,{children:s})}),(0,r.jsx)(y,{children:V.map((e,s)=>(0,r.jsx)(w,{value:e,children:e},s))})]})]}),(0,r.jsxs)("svg",{width:"500",height:"300",children:[(0,r.jsx)("rect",{width:"100%",height:"100%",stroke:"black",fill:"none"}),(0,r.jsx)("circle",{cx:250,cy:150,r:5}),(0,r.jsx)("text",{x:250,y:150,fontSize:30,alignmentBaseline:s,textAnchor:d,children:"This is some text"})]}),(0,r.jsxs)("h2",{children:["3️⃣ Grouping Elements with ",(0,r.jsx)("code",{children:""})]}),(0,r.jsxs)("p",{children:["The ",(0,r.jsx)("code",{children:""})," element in SVG is used to group multiple elements together."]}),(0,r.jsx)("p",{children:"This is especially useful for applying transformations, styles, or events to a collection of elements as a single unit."}),(0,r.jsx)(G.d,{code:'\n\n'.trim()}),(0,r.jsx)("h2",{children:"4️⃣ Stroke, Fill, and Color: Different from HTML"}),(0,r.jsxs)("p",{children:["In SVG, the concepts of ",(0,r.jsx)("code",{children:"stroke"}),", ",(0,r.jsx)("code",{children:"fill"}),", and"," ",(0,r.jsx)("code",{children:"color"})," work differently than in standard HTML."]}),(0,r.jsxs)("p",{children:["The ",(0,r.jsx)("code",{children:"fill"})," property controls the interior color of shapes, while ",(0,r.jsx)("code",{children:"stroke"})," affects the outline. Unlike ",(0,r.jsx)("code",{children:"div"})," ","elements, SVG shapes don’t have separate properties for borders and backgrounds; instead, you use ",(0,r.jsx)("code",{children:"stroke"})," and ",(0,r.jsx)("code",{children:"fill"})," ","to control these aspects."]}),(0,r.jsxs)("p",{children:["For text elements, avoid using ",(0,r.jsx)("code",{children:"stroke"})," to outline text, as it can result in poor readability. Instead, focus on using"," ",(0,r.jsx)("code",{children:"fill"})," for color and ",(0,r.jsx)("code",{children:"text-anchor"})," for alignment."]}),(0,r.jsx)("h2",{children:"5️⃣ CSS Specificity in SVG"}),(0,r.jsx)("p",{children:"CSS specificity in SVG can be a bit more complex than in HTML. Styles applied to SVG elements can come from inline styles, internal stylesheets, or external stylesheets, and the rules of specificity still apply. However, because SVG elements are often nested and grouped, understanding which styles take precedence requires a good grasp of CSS specificity rules."}),(0,r.jsx)("h2",{children:"6️⃣ Text Wrapping"}),(0,r.jsxs)("p",{children:["In SVG, there is"," ",(0,r.jsx)("b",{children:"no built-in functionality for automatic text wrapping"})," like you would find in HTML or CSS. \uD83D\uDE31"]}),(0,r.jsx)("p",{children:"You have to manage text wrapping manually or use JavaScript libraries to handle it."}),(0,r.jsx)("p",{children:"This is very very annoying. In practice, we'll often use a HTML layer on top of the SVG layer to add text (like in tooltips) to make our life simpler."}),(0,r.jsx)("h2",{children:"7️⃣ SVG Dimensions: The Impact of “100%”"}),(0,r.jsx)("p",{children:'Setting SVG dimensions to "100%" can lead to unexpected results, especially in responsive designs. SVGs can scale based on their container, but how they scale depends on the viewBox and preserveAspectRatio attributes. Understanding these attributes is key to ensuring your SVGs display correctly across different screen sizes. For more details, refer to our module on responsiveness.'}),(0,r.jsx)("h2",{children:"8️⃣ Filters, Blur Effects, and Gradients"}),(0,r.jsxs)("p",{children:["SVG offers powerful capabilities for applying visual effects, such as filters and gradients. Filters like ",(0,r.jsx)("code",{children:"blur"}),","," ",(0,r.jsx)("code",{children:"drop-shadow"}),", and ",(0,r.jsx)("code",{children:"grayscale"})," can add depth and dimension to your graphics. Gradients allow for smooth transitions between colors, which can be applied to fills or strokes, adding richness to your visualizations."]}),(0,r.jsx)("h2",{children:"9️⃣ Stacking Order Matters"}),(0,r.jsx)("p",{children:"In SVG, elements are rendered in the order they appear in the markup, creating a natural stacking order. This means that the order of elements in your SVG code affects their visual layering. Elements later in the code will appear on top of earlier ones, so careful planning is needed when layering elements to achieve the desired visual effect."}),(0,r.jsx)("div",{className:"full-bleed my-4 max-w-7xl mx-auto",children:(0,r.jsx)(o.X,{vizName:"exercise/SvgStackingOrderSolution"})}),(0,r.jsx)("h2",{children:"\uD83D\uDD1F Dealing with Blurry SVG Elements"}),(0,r.jsxs)("p",{children:["SVG elements can sometimes appear blurry, especially when scaled. This is often due to anti-aliasing, which can smooth edges but also cause them to lose sharpness. To fix this, you can use the"," ",(0,r.jsx)("code",{children:'shape-rendering="crispEdges"'})," property to make edges appear sharper, especially for pixel-perfect designs."]})]}):null}},45993:function(e){e.exports={codeChunckCopyButton:"code-block_codeChunckCopyButton__yPrL_",copyButtonContainer:"code-block_copyButtonContainer__BrX9E"}}},function(e){e.O(0,[2343,7754,7823,2860,8190,3710,9774,2888,179],function(){return e(e.s=77035)}),_N_E=e.O()}]);
\ No newline at end of file
+(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[9551],{77035:function(e,s,t){(window.__NEXT_P=window.__NEXT_P||[]).push(["/course/svg/tips-and-tricks",function(){return t(9463)}])},88578:function(e,s,t){"use strict";t.d(s,{X:function(){return n}});var r=t(85893);t(67294);let n=e=>{let{vizName:s,height:t="500px",fileToOpen:n}=e;return console.log("rerendeeeerrrrr"),(0,r.jsx)("iframe",{src:"https://codesandbox.io/embed/github/holtzy/react-graph-gallery/tree/main/viz/"+s+"?fontsize=14&hidenavigation=1&theme=dark&expanddevtools=0&view=split"+(n?"&module=/".concat(n):""),style:{width:"100%",height:t,border:"solid",borderWidth:2,borderRadius:"4px",overflow:"hidden"},allow:"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking",sandbox:"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"})}},41843:function(e,s,t){"use strict";t.d(s,{p:function(){return d}});var r=t(85893),n=t(49700),i=t(63476),a=t(17414),l=t(41664),o=t.n(l);let d=e=>{let{children:s,title:t,seoDescription:l,previousTocItem:d,nextTocItem:c}=e;return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(a.A,{title:t,seoDescription:l}),(0,r.jsx)(n.Z,{}),(0,r.jsx)("div",{className:"wrapper",children:s}),(0,r.jsxs)("div",{className:"flex justify-center items-center space-x-6 my-24 py-12 bg-muted/50",children:[d?(0,r.jsxs)(o(),{href:d.link,className:"text-gray-500 no-underline flex flex-col justify-start items-end w-96 h-32 border-r border-black p-8 hover:bg-muted ",children:[(0,r.jsx)("span",{className:"uppercase font-light text-transparent bg-gradient-to-l to-fuchsia-300 from-blue-400 bg-clip-text",children:"← Previous"}),(0,r.jsx)("p",{children:d.name})]}):(0,r.jsx)("div",{className:"w-96"}),c&&(0,r.jsxs)(o(),{href:c.link,className:"text-gray-500 no-underline flex flex-col justify-start w-96 h-32 border-l border-black p-8 hover:bg-muted ",children:[(0,r.jsx)("span",{className:"uppercase font-light text-transparent bg-gradient-to-l from-fuchsia-300 to-blue-400 bg-clip-text",children:"Next →"}),(0,r.jsx)("p",{children:c.name})]})]}),(0,r.jsx)("div",{className:"wrapper",children:(0,r.jsx)(i.Z,{})})]})}},63265:function(e,s,t){"use strict";t.d(s,{D:function(){return n}});var r=t(85893);let n=e=>{let{text:s}=e;return(0,r.jsxs)("div",{className:"hidden absolute w-60 top-1/2 -right-10 border-l text-card-foreground border-card-foreground h-28 translate-x-full -translate-y-1/2 xl:flex items-center ",children:[(0,r.jsx)("span",{className:"",children:"→"}),(0,r.jsx)("span",{className:"text-sm ml-2 opacity-70",children:s})]})}},3572:function(e,s,t){"use strict";t.d(s,{d:function(){return c}});var r=t(85893),n=t(32581),i=t(15660),a=t.n(i),l=t(67294),o=t(45993),d=t.n(o);let c=e=>{let{code:s}=e,[t,i]=(0,l.useState)(!1),o=(0,l.useRef)(null);(0,l.useEffect)(()=>{o.current&&a().highlightElement(o.current)},[o,s]);let c=(0,r.jsx)("div",{onClick:()=>{navigator.clipboard.writeText(s),i(!0)},className:d().codeChunckCopyButton,children:t?"Copied":(0,r.jsx)(n.Z,{size:14,style:{padding:0}})});return(0,r.jsxs)("div",{className:"mb-6 relative",children:[(0,r.jsx)("pre",{className:"rounded-md line-numbers",children:(0,r.jsx)("code",{ref:o,className:"language-javascript",children:s})}),(0,r.jsx)("div",{className:d().copyButtonContainer,children:c})]})}},9463:function(e,s,t){"use strict";t.r(s),t.d(s,{default:function(){return _}});var r=t(85893),n=t(67294),i=t(43710),a=t(41843),l=t(11236),o=t(88578),d=t(92882),c=t(8971),h=t(84979),p=t(13742),u=t(77522);let x=d.fC;d.ZA;let m=d.B4,f=n.forwardRef((e,s)=>{let{className:t,children:n,...i}=e;return(0,r.jsxs)(d.xz,{ref:s,className:(0,u.cn)("flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",t),...i,children:[n,(0,r.jsx)(d.JO,{asChild:!0,children:(0,r.jsx)(c.Z,{className:"h-4 w-4 opacity-50"})})]})});f.displayName=d.xz.displayName;let g=n.forwardRef((e,s)=>{let{className:t,...n}=e;return(0,r.jsx)(d.u_,{ref:s,className:(0,u.cn)("flex cursor-default items-center justify-center py-1",t),...n,children:(0,r.jsx)(h.Z,{className:"h-4 w-4"})})});g.displayName=d.u_.displayName;let j=n.forwardRef((e,s)=>{let{className:t,...n}=e;return(0,r.jsx)(d.$G,{ref:s,className:(0,u.cn)("flex cursor-default items-center justify-center py-1",t),...n,children:(0,r.jsx)(c.Z,{className:"h-4 w-4"})})});j.displayName=d.$G.displayName;let y=n.forwardRef((e,s)=>{let{className:t,children:n,position:i="popper",...a}=e;return(0,r.jsx)(d.h_,{children:(0,r.jsxs)(d.VY,{ref:s,className:(0,u.cn)("relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2","popper"===i&&"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",t),position:i,...a,children:[(0,r.jsx)(g,{}),(0,r.jsx)(d.l_,{className:(0,u.cn)("p-1","popper"===i&&"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"),children:n}),(0,r.jsx)(j,{})]})})});y.displayName=d.VY.displayName;let b=n.forwardRef((e,s)=>{let{className:t,...n}=e;return(0,r.jsx)(d.__,{ref:s,className:(0,u.cn)("py-1.5 pl-8 pr-2 text-sm font-semibold",t),...n})});b.displayName=d.__.displayName;let w=n.forwardRef((e,s)=>{let{className:t,children:n,...i}=e;return(0,r.jsxs)(d.ck,{ref:s,className:(0,u.cn)("relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",t),...i,children:[(0,r.jsx)("span",{className:"absolute left-2 flex h-3.5 w-3.5 items-center justify-center",children:(0,r.jsx)(d.wU,{children:(0,r.jsx)(p.Z,{className:"h-4 w-4"})})}),(0,r.jsx)(d.eT,{children:n})]})});w.displayName=d.ck.displayName;let v=n.forwardRef((e,s)=>{let{className:t,...n}=e;return(0,r.jsx)(d.Z0,{ref:s,className:(0,u.cn)("-mx-1 my-1 h-px bg-muted",t),...n})});v.displayName=d.Z0.displayName;var k=t(63265),N=t(49362),S=t(15148),G=t(3572);let T=["auto","baseline","before-edge","text-before-edge","middle","central","after-edge","text-after-edge","ideographic","alphabetic","hanging","mathematical","inherit"],V=["start","middle","end","inherit"];function _(){let e=l.Y.find(e=>"/course/svg/tips-and-tricks"===e.link),[s,t]=(0,n.useState)("baseline"),[d,c]=(0,n.useState)("start");return e?(0,r.jsxs)(a.p,{title:e.name,seoDescription:"",nextTocItem:l.Y.find(e=>"/course/scales/introduction"===e.link),previousTocItem:l.Y.find(e=>"/course/svg/path-element"===e.link),children:[(0,r.jsx)(i.Z,{title:e.name,lessonStatus:e.status,readTime:e.readTime,selectedLesson:e,description:(0,r.jsxs)(r.Fragment,{children:[(0,r.jsxs)("p",{children:["By now, SVG might seem straightforward, but trust me,"," ",(0,r.jsx)("b",{children:"it has its quirks"})," that can make your data visualization journey challenging."]}),(0,r.jsxs)("p",{children:["In this lesson, I'll share some tips and tricks that can"," ",(0,r.jsx)("b",{children:"save yo hours of frustration"})," — lessons I learned the hard way."]})]})}),(0,r.jsx)("h2",{children:"1️⃣ SVG Elements Don’t Have a Background Color"}),(0,r.jsxs)("p",{children:["Unlike HTML elements, SVG elements do not support background colors directly. They also do not support ",(0,r.jsx)("b",{children:"borders"}),"."]}),(0,r.jsxs)("p",{children:["If you want to create a background or add a border to your SVG, you need to draw a ",(0,r.jsx)("b",{children:"rectangle that covers the desired area"}),". CSS properties like ",(0,r.jsx)("code",{children:"background-color"})," or ",(0,r.jsx)("code",{children:"fill"})," or"," ",(0,r.jsx)("code",{children:"border"})," on the SVG element itself are not recognized and will be ignored."]}),(0,r.jsx)("p",{children:"Example:"}),(0,r.jsx)("div",{className:"full-bleed my-4 max-w-7xl mx-auto",children:(0,r.jsx)(o.X,{vizName:"exercise/SvgStackingOrderSolution"})}),(0,r.jsx)("h2",{children:"2️⃣ Text Alignment in SVG"}),(0,r.jsxs)("p",{children:["Text alignment in SVG works differently compared to HTML. You can control both horizontal and vertical alignment using the"," ",(0,r.jsx)("code",{children:"text-anchor"})," and ",(0,r.jsx)("code",{children:"alignment-baseline"})," properties, which are unique to SVG."]}),(0,r.jsx)("div",{className:"relative",children:(0,r.jsx)(k.D,{text:(0,r.jsxs)("p",{children:["Remember, in JSX, CSS properties should be camelCased (e.g.,"," ",(0,r.jsx)("code",{children:"textAnchor"})," instead of ",(0,r.jsx)("code",{children:"text-anchor"}),")."]})})}),(0,r.jsx)("p",{children:(0,r.jsx)("br",{})}),(0,r.jsx)("p",{children:"Here’s a summary of how they work:"}),(0,r.jsxs)("div",{className:"flex items-center justify-start gap-4",children:[(0,r.jsx)(N.Z,{}),(0,r.jsxs)("span",{children:[(0,r.jsx)("code",{children:"text-anchor"})," controls the horizontal alignment →"]}),(0,r.jsxs)(x,{value:d,onValueChange:e=>c(e),children:[(0,r.jsx)(f,{className:"w-[180px]",children:(0,r.jsx)(m,{children:d})}),(0,r.jsx)(y,{children:V.map((e,s)=>(0,r.jsx)(w,{value:e,children:e},s))})]})]}),(0,r.jsxs)("div",{className:"flex items-center justify-start gap-4 mt-2 mb-8",children:[(0,r.jsx)(S.Z,{}),(0,r.jsxs)("span",{children:[(0,r.jsx)("code",{children:"alignment-baseline"})," controls the vertical alignment →"]}),(0,r.jsxs)(x,{value:s,onValueChange:e=>t(e),children:[(0,r.jsx)(f,{className:"w-[180px]",children:(0,r.jsx)(m,{children:s})}),(0,r.jsx)(y,{children:T.map((e,s)=>(0,r.jsx)(w,{value:e,children:e},s))})]})]}),(0,r.jsxs)("svg",{width:"500",height:"300",children:[(0,r.jsx)("rect",{width:"100%",height:"100%",stroke:"black",fill:"none"}),(0,r.jsx)("circle",{cx:250,cy:150,r:5}),(0,r.jsx)("text",{x:250,y:150,fontSize:30,alignmentBaseline:s,textAnchor:d,children:"This is some text"})]}),(0,r.jsxs)("h2",{children:["3️⃣ Grouping Elements with ",(0,r.jsx)("code",{children:""})]}),(0,r.jsxs)("p",{children:["The ",(0,r.jsx)("code",{children:""})," element in SVG is used to group multiple elements together."]}),(0,r.jsx)("p",{children:"This is especially useful for applying transformations, styles, or events to a collection of elements as a single unit."}),(0,r.jsx)(G.d,{code:'\n\n'.trim()}),(0,r.jsx)("h2",{children:"4️⃣ Stroke, Fill, and Color: Different from HTML"}),(0,r.jsxs)("p",{children:["In SVG, the concepts of ",(0,r.jsx)("code",{children:"stroke"}),", ",(0,r.jsx)("code",{children:"fill"}),", and"," ",(0,r.jsx)("code",{children:"color"})," work differently than in standard HTML."]}),(0,r.jsxs)("p",{children:["The ",(0,r.jsx)("code",{children:"fill"})," property controls the interior color of shapes, while ",(0,r.jsx)("code",{children:"stroke"})," affects the outline. Unlike ",(0,r.jsx)("code",{children:"div"})," ","elements, SVG shapes don’t have separate properties for borders and backgrounds; instead, you use ",(0,r.jsx)("code",{children:"stroke"})," and ",(0,r.jsx)("code",{children:"fill"})," ","to control these aspects."]}),(0,r.jsx)("p",{children:(0,r.jsx)("br",{})}),(0,r.jsxs)("blockquote",{className:"bg-fuchsia-50 py-8",children:["For text elements, avoid using ",(0,r.jsx)("code",{children:"stroke"})," to outline text, as it can result in poor readability. Instead, focus on using"," ",(0,r.jsx)("code",{children:"fill"})," for color and ",(0,r.jsx)("code",{children:"text-anchor"})," for alignment."]}),(0,r.jsx)("h2",{children:"5️⃣ Inheritance Rules"}),(0,r.jsxs)("p",{children:["In HTML, styling generally doesn’t inherit by default (e.g., a color applied to a ",(0,r.jsx)("code",{children:"div"})," doesn’t affect child elements unless they inherit it explicitly). In SVG, many properties do inherit by default, especially graphic-specific ones. For example, fill and stroke values applied to an SVG container ",(0,r.jsx)("code",{children:"g"})," (group) element will cascade down to all children unless overridden. This makes grouping styles common in SVG."]}),(0,r.jsx)("h2",{children:"6️⃣ Text Wrapping"}),(0,r.jsxs)("p",{children:["In SVG, there is"," ",(0,r.jsx)("b",{children:"no built-in functionality for automatic text wrapping"})," like you would find in HTML or CSS. \uD83D\uDE31"]}),(0,r.jsx)("p",{children:"You have to manage text wrapping manually or use JavaScript libraries to handle it."}),(0,r.jsx)("p",{children:"This is very very annoying. In practice, we'll often use a HTML layer on top of the SVG layer to add text (like in tooltips) to make our life simpler."}),(0,r.jsx)("h2",{children:"7️⃣ SVG Dimensions: The Impact of “100%”"}),(0,r.jsx)("p",{children:'Setting SVG dimensions to "100%" can lead to unexpected results, especially in responsive designs. SVGs can scale based on their container, but how they scale depends on the viewBox and preserveAspectRatio attributes. Understanding these attributes is key to ensuring your SVGs display correctly across different screen sizes. For more details, refer to our module on responsiveness.'}),(0,r.jsx)("h2",{children:"8️⃣ Filters, Blur Effects, and Gradients"}),(0,r.jsxs)("p",{children:["SVG offers powerful capabilities for applying visual effects, such as filters and gradients. Filters like ",(0,r.jsx)("code",{children:"blur"}),","," ",(0,r.jsx)("code",{children:"drop-shadow"}),", and ",(0,r.jsx)("code",{children:"grayscale"})," can add depth and dimension to your graphics. Gradients allow for smooth transitions between colors, which can be applied to fills or strokes, adding richness to your visualizations."]}),(0,r.jsx)("h2",{children:"9️⃣ Stacking Order Matters"}),(0,r.jsx)("p",{children:"In SVG, elements are rendered in the order they appear in the markup, creating a natural stacking order. This means that the order of elements in your SVG code affects their visual layering. Elements later in the code will appear on top of earlier ones, so careful planning is needed when layering elements to achieve the desired visual effect."}),(0,r.jsx)("div",{className:"full-bleed my-4 max-w-7xl mx-auto",children:(0,r.jsx)(o.X,{vizName:"exercise/SvgStackingOrderSolution"})}),(0,r.jsx)("h2",{children:"\uD83D\uDD1F Dealing with Blurry SVG Elements"}),(0,r.jsxs)("p",{children:["SVG elements can sometimes appear blurry, especially when scaled. This is often due to anti-aliasing, which can smooth edges but also cause them to lose sharpness. To fix this, you can use the"," ",(0,r.jsx)("code",{children:'shape-rendering="crispEdges"'})," property to make edges appear sharper, especially for pixel-perfect designs."]})]}):null}},45993:function(e){e.exports={codeChunckCopyButton:"code-block_codeChunckCopyButton__yPrL_",copyButtonContainer:"code-block_copyButtonContainer__BrX9E"}}},function(e){e.O(0,[2343,7754,7823,2860,8190,3710,9774,2888,179],function(){return e(e.s=77035)}),_N_E=e.O()}]);
\ No newline at end of file
diff --git a/_next/static/Qn9JDBrmHpswodUUyZzEd/_buildManifest.js b/_next/static/nDNzxM9oguhvL5k4w7ZTG/_buildManifest.js
similarity index 94%
rename from _next/static/Qn9JDBrmHpswodUUyZzEd/_buildManifest.js
rename to _next/static/nDNzxM9oguhvL5k4w7ZTG/_buildManifest.js
index 021862b5..52761644 100644
--- a/_next/static/Qn9JDBrmHpswodUUyZzEd/_buildManifest.js
+++ b/_next/static/nDNzxM9oguhvL5k4w7ZTG/_buildManifest.js
@@ -1 +1 @@
-self.__BUILD_MANIFEST=function(s,a,c,e,t,i,o,r,n,p,u,d,l,h,b,g,f,m,k,j,v,x,w,z,y,_,I,B,F,A,D){return{__rewrites:{beforeFiles:[],afterFiles:[],fallback:[]},"/":[s,"static/chunks/2718-c1b4ae8aebf23716.js",a,o,"static/chunks/pages/index-d41f25467ee6dcf3.js"],"/2d-density-plot":[s,c,t,i,a,e,o,n,r,"static/chunks/pages/2d-density-plot-8a8df282839cbf77.js"],"/404":[s,c,t,a,e,o,m,"static/css/8a734e64c19c3976.css","static/chunks/pages/404-083d849d0ce45b06.js"],"/_error":["static/chunks/pages/_error-82b79221b9ed784b.js"],"/about":[s,c,t,a,e,o,b,"static/chunks/pages/about-8505a607369c3630.js"],"/all":[s,c,a,e,o,u,k,"static/chunks/pages/all-c5ea439386fed3d0.js"],"/animation":[s,c,a,e,o,u,k,"static/chunks/pages/animation-fa9dfe1d4e131eb9.js"],"/arc-diagram":[s,c,t,i,a,e,o,n,u,h,"static/chunks/pages/arc-diagram-8c80fd0c10cfac1b.js"],"/area-plot":[s,c,t,i,a,e,o,n,r,"static/chunks/pages/area-plot-850e2af7f558eaea.js"],"/articles":[s,c,a,e,o,b,"static/chunks/pages/articles-4f71b8e4bef1386a.js"],"/barplot":[s,c,t,i,p,a,e,o,u,h,"static/chunks/pages/barplot-00f75722a80a9adb.js"],"/boxplot":[s,c,t,i,a,e,o,n,u,h,"static/chunks/pages/boxplot-27510a56d1e5db92.js"],"/bubble-map":[s,c,t,i,p,a,e,o,n,u,j,h,"static/chunks/pages/bubble-map-623301ff0f5c7875.js"],"/bubble-plot":[s,c,t,i,p,a,e,o,u,m,w,z,"static/css/ec7558f4d3e32e69.css","static/chunks/pages/bubble-plot-b5d354230244be84.js"],"/build-axis-with-react":[s,c,t,i,a,e,o,r,"static/chunks/pages/build-axis-with-react-38ba08684038bf02.js"],"/cartogram":[s,c,a,e,o,b,"static/chunks/pages/cartogram-3909805a96300cc2.js"],"/chord-diagram":[s,c,t,i,a,e,o,n,r,"static/chunks/pages/chord-diagram-157be7aad86575fb.js"],"/choropleth-map":[s,c,t,i,a,e,o,n,j,r,"static/chunks/pages/choropleth-map-07055d4a58480514.js"],"/circular-barplot":[s,c,t,i,a,e,o,n,r,"static/chunks/pages/circular-barplot-dba2b21bfe0f2586.js"],"/circular-packing":[s,c,t,i,p,a,e,o,u,h,"static/chunks/pages/circular-packing-c42dfa9a290456fc.js"],"/connected-scatter-plot":[s,c,t,i,a,e,o,n,r,"static/chunks/pages/connected-scatter-plot-8d9a8ddc1c0f3a7b.js"],"/connection-map":[s,c,t,i,a,e,o,n,j,r,"static/chunks/pages/connection-map-68a98e8e6bd1aa65.js"],"/correlogram":[s,c,t,i,a,e,o,"static/css/d54486714a313ae1.css","static/chunks/pages/correlogram-2094d57c1eb2fa41.js"],"/course/animation/dealing-with-path":[s,c,t,p,f,a,e,"static/css/56c7a0691f59768b.css","static/chunks/pages/course/animation/dealing-with-path-ef89d156bc300c89.js"],"/course/animation/enter-update-exit":[s,c,p,a,e,g,"static/chunks/pages/course/animation/enter-update-exit-59c9c6f667ced3e4.js"],"/course/animation/introduction":[s,c,t,p,a,e,v,g,"static/chunks/pages/course/animation/introduction-b6604c2146389f42.js"],"/course/animation/project":[s,c,t,p,a,e,v,g,"static/chunks/pages/course/animation/project-63faeae783f2c633.js"],"/course/animation/react-spring-for-dataviz":[s,c,i,p,l,a,e,d,"static/chunks/pages/course/animation/react-spring-for-dataviz-e01b8eea46ee56f4.js"],"/course/animation/scatterplot":[s,c,t,i,p,a,e,w,d,"static/chunks/pages/course/animation/scatterplot-5735416f3e48abb1.js"],"/course/axis/axis-variations":[s,c,a,e,g,"static/chunks/pages/course/axis/axis-variations-e8cf5bd8282a7c5f.js"],"/course/axis/axis-with-d3":[s,c,t,i,a,e,d,"static/chunks/pages/course/axis/axis-with-d3-f644056be4487108.js"],"/course/axis/bottom-axis":[s,c,t,i,l,a,e,d,"static/chunks/pages/course/axis/bottom-axis-bb532bb0bbba2e40.js"],"/course/axis/introduction":[s,c,t,a,e,g,"static/chunks/pages/course/axis/introduction-66ef24957a309b5d.js"],"/course/axis/margin-and-translation":[s,c,i,l,a,e,d,"static/chunks/pages/course/axis/margin-and-translation-e481dc8c6abf9ce8.js"],"/course/axis/project":[s,c,t,i,a,e,z,d,"static/chunks/pages/course/axis/project-3f188a1165fc56c7.js"],"/course/canvas/combining-svg-and-canvas":[s,c,t,i,a,e,d,"static/chunks/pages/course/canvas/combining-svg-and-canvas-7dfb1617ad30a20c.js"],"/course/canvas/drawing-shapes-with-canvas":[s,c,i,l,a,e,d,"static/chunks/pages/course/canvas/drawing-shapes-with-canvas-b987979bb2ffc953.js"],"/course/canvas/introduction":[s,c,t,i,a,e,d,"static/chunks/pages/course/canvas/introduction-9b7446a49771d4ce.js"],"/course/canvas/svg-path-in-canvas":[s,c,t,i,a,e,d,"static/chunks/pages/course/canvas/svg-path-in-canvas-ba361ca4364f5d2f.js"],"/course/hover-effect/css-descendant-selector":[s,c,t,i,l,a,e,u,"static/css/8666b20defb3e011.css","static/chunks/pages/course/hover-effect/css-descendant-selector-36ad6543af1f2621.js"],"/course/hover-effect/css-pseudo-class":[s,c,t,i,l,a,e,u,y,"static/css/69b5bd49186db9de.css","static/chunks/pages/course/hover-effect/css-pseudo-class-802774492109f763.js"],"/course/hover-effect/internal-state":[s,c,t,i,a,e,u,"static/css/f1e5f65ddf99e8f6.css","static/chunks/pages/course/hover-effect/internal-state-ff7118d79b1cc3cd.js"],"/course/hover-effect/introduction":[s,c,t,p,a,e,y,"static/css/0ec73f568dde8513.css","static/chunks/pages/course/hover-effect/introduction-d91fdd943b95d1ff.js"],"/course/hover-effect/link-two-graphs":[s,c,t,i,a,e,o,u,_,"static/css/c76003f718a0f9be.css","static/chunks/pages/course/hover-effect/link-two-graphs-fc8be979befb85d3.js"],"/course/hover-effect/toggle-class-in-js":[s,c,t,i,l,a,e,"static/css/f5258d81ed13d0d5.css","static/chunks/pages/course/hover-effect/toggle-class-in-js-fb21fb5b810c4b56.js"],"/course/introduction/initial-setup":[s,c,t,i,a,e,d,"static/chunks/pages/course/introduction/initial-setup-1a01dca02cbea214.js"],"/course/introduction/introduction-to-d3":[s,c,t,a,e,g,"static/chunks/pages/course/introduction/introduction-to-d3-6ded1ce234ed1b2c.js"],"/course/introduction/introduction-to-react":[s,c,a,e,g,"static/chunks/pages/course/introduction/introduction-to-react-a392c14cf58076cf.js"],"/course/introduction/js-dataviz-libraries":[s,c,i,a,e,d,"static/chunks/pages/course/introduction/js-dataviz-libraries-f7f28061427db698.js"],"/course/responsiveness/code-organization":[s,c,i,a,e,d,"static/chunks/pages/course/responsiveness/code-organization-4dee38ef916f6e9b.js"],"/course/responsiveness/common-pitfalls":[s,c,a,e,g,"static/chunks/pages/course/responsiveness/common-pitfalls-b052d1cc732e6cb4.js"],"/course/responsiveness/introduction":[s,c,t,i,a,e,d,"static/chunks/pages/course/responsiveness/introduction-638287c3a0c0f3e3.js"],"/course/responsiveness/use-dimension-hook":[s,c,i,a,e,d,"static/chunks/pages/course/responsiveness/use-dimension-hook-035fc5d826f40d64.js"],"/course/responsiveness/using-the-hook":[s,c,i,l,a,e,d,"static/chunks/pages/course/responsiveness/using-the-hook-bdd2dfdbaf2e4479.js"],"/course/scales/introduction":[s,c,i,a,e,I,d,"static/chunks/pages/course/scales/introduction-4801b90c32a802e0.js"],"/course/scales/linear-scale":[s,c,i,l,a,e,I,d,"static/chunks/pages/course/scales/linear-scale-744385fc0fee6ab5.js"],"/course/scales/other-scale-types":[s,c,t,i,l,a,e,d,"static/chunks/pages/course/scales/other-scale-types-6d076272a1d64e97.js"],"/course/scales/project":[s,c,t,i,a,e,d,"static/chunks/pages/course/scales/project-d5bc6bbb2a6c117b.js"],"/course/svg/d3-shape":[s,c,i,l,a,e,d,"static/chunks/pages/course/svg/d3-shape-6855634224ffd05f.js"],"/course/svg/introduction":[s,c,t,l,a,e,g,"static/chunks/pages/course/svg/introduction-cbc6f0c36a1a42ec.js"],"/course/svg/main-svg-elements":[s,c,i,l,a,e,d,"static/chunks/pages/course/svg/main-svg-elements-b67e94f54df7d5ea.js"],"/course/svg/path-element":[s,c,i,l,a,e,d,"static/chunks/pages/course/svg/path-element-ddeafb47c2680043.js"],"/course/svg/tips-and-tricks":[s,c,i,"static/chunks/2860-d038ef2b7795bb05.js",a,e,d,"static/chunks/pages/course/svg/tips-and-tricks-9a34a92abbedcff1.js"],"/course/tooltip/display-on-hover":[s,c,t,i,l,a,e,x,"static/css/530b699660279b3e.css","static/chunks/pages/course/tooltip/display-on-hover-e5794d0da9958032.js"],"/course/tooltip/introduction":[s,c,t,a,e,m,"static/css/b23f3515152ab10c.css","static/chunks/pages/course/tooltip/introduction-dd57bbe658e25a2e.js"],"/course/tooltip/project":[s,c,t,i,a,e,B,"static/css/e6721a776c502451.css","static/chunks/pages/course/tooltip/project-2f4d2ec670a5c6ec.js"],"/course/tooltip/templates":[s,c,t,a,e,m,x,"static/css/ec6f9e7260a78fe2.css","static/chunks/pages/course/tooltip/templates-e08fba51c8c643ca.js"],"/course/tooltip/tooltip-component":[s,c,i,l,a,e,d,"static/chunks/pages/course/tooltip/tooltip-component-be4ee12236b179e2.js"],"/cross-graph-highlight-interaction":[s,c,t,i,"static/chunks/8446-4892663fdb75b8e1.js",a,e,o,"static/css/507114ea18f6728e.css","static/chunks/pages/cross-graph-highlight-interaction-f4981236e3ce062b.js"],"/dataset-transition":[s,c,t,i,p,a,e,o,r,"static/chunks/pages/dataset-transition-04f3ac5287b70e46.js"],"/dendrogram":[s,c,t,i,a,e,o,F,r,"static/chunks/pages/dendrogram-437272f9020c7aab.js"],"/density-plot":[s,c,t,i,a,e,o,n,A,r,"static/chunks/pages/density-plot-a9c9eae2588b0c6c.js"],"/donut":[s,c,t,i,p,f,a,e,o,n,"static/css/306a1a30c14677d4.css","static/chunks/pages/donut-f6c4704c8df5ae55.js"],"/example/arc-diagram-vertical":[s,c,t,i,a,e,o,r,"static/chunks/pages/example/arc-diagram-vertical-ee4b8759645617e3.js"],"/example/barplot-data-transition-animation":[s,c,t,i,p,a,e,o,r,"static/chunks/pages/example/barplot-data-transition-animation-3b43c38cc63954f8.js"],"/example/barplot-stacked-horizontal":[s,c,t,i,a,e,o,u,h,"static/chunks/pages/example/barplot-stacked-horizontal-88e863909d739272.js"],"/example/barplot-stacked-vertical":[s,c,t,a,e,o,u,k,"static/chunks/pages/example/barplot-stacked-vertical-1383a75f05139115.js"],"/example/boxplot-horizontal":[s,c,t,i,a,e,o,r,"static/chunks/pages/example/boxplot-horizontal-ba359fa226e9e306.js"],"/example/boxplot-jitter":[s,c,t,i,a,e,o,r,"static/chunks/pages/example/boxplot-jitter-c3aa852f6add3126.js"],"/example/circle-packing-with-d3-force":[s,c,t,i,a,e,o,r,"static/chunks/pages/example/circle-packing-with-d3-force-91029646511643dc.js"],"/example/histogram-mirror":[s,c,t,i,a,e,o,r,"static/chunks/pages/example/histogram-mirror-00743c0fa7e95ca8.js"],"/example/histogram-slider-bin-size":[s,c,t,a,e,o,D,"static/css/f7129d2d0aac0f23.css","static/chunks/pages/example/histogram-slider-bin-size-4dea62a699539ada.js"],"/example/histogram-small-multiple":[s,c,t,i,a,e,o,r,"static/chunks/pages/example/histogram-small-multiple-794625c2d9f73b4e.js"],"/example/histogram-with-several-groups":[s,c,t,i,a,e,o,r,"static/chunks/pages/example/histogram-with-several-groups-df434001b3f202b7.js"],"/example/line-chart-synchronized-cursors":[s,c,t,i,p,a,e,o,r,"static/chunks/pages/example/line-chart-synchronized-cursors-4533bf55dbbfc249.js"],"/example/network-diagram-with-colored-groups":[s,c,t,i,a,e,o,r,"static/chunks/pages/example/network-diagram-with-colored-groups-87e8c79c8205e6f4.js"],"/example/population-pyramid":[t,p,"static/css/d71181803328322d.css","static/chunks/pages/example/population-pyramid-7f97eae907059157.js"],"/example/radar-chart-animation":[s,c,t,i,p,a,e,o,v,r,"static/chunks/pages/example/radar-chart-animation-43847f64fedbca97.js"],"/example/sankey-bump-chart":[s,c,t,a,e,o,b,"static/chunks/pages/example/sankey-bump-chart-e9c76dcf9dc5b58e.js"],"/example/scatterplot-basic-canvas":[s,c,t,i,a,e,o,r,"static/chunks/pages/example/scatterplot-basic-canvas-4bc535863d92c309.js"],"/example/scatterplot-tooltip-with-voronoi-for-closest-point-detection":[s,c,t,i,a,e,o,r,"static/chunks/pages/example/scatterplot-tooltip-with-voronoi-for-closest-point-detection-ca83c451932a3cb2.js"],"/example/timeseries-moving-average":[s,c,t,i,a,e,o,u,"static/css/0051346e12b181a2.css","static/chunks/pages/example/timeseries-moving-average-09c989c1f87b1ea6.js"],"/fix-canvas-blurry-dataviz":[s,c,i,a,e,o,r,"static/chunks/pages/fix-canvas-blurry-dataviz-4dec33a6dd3d0b86.js"],"/heatmap":[s,c,t,i,a,e,o,n,B,"static/css/efd490e62b6b40d6.css","static/chunks/pages/heatmap-7fae042d715abd6d.js"],"/hexbin-map":[s,c,t,i,a,e,o,n,r,"static/chunks/pages/hexbin-map-a930630d43a80673.js"],"/hierarchical-edge-bundling":[s,c,t,i,a,e,o,F,r,"static/chunks/pages/hierarchical-edge-bundling-13f282ff59e73fb9.js"],"/histogram":[s,c,t,i,p,a,e,o,n,u,D,"static/css/516fbb6bc1065354.css","static/chunks/pages/histogram-205eb50e1cb77334.js"],"/interactivity":[s,c,a,e,o,u,k,"static/chunks/pages/interactivity-54e994fb8fdc812d.js"],"/line-chart":[s,c,t,i,p,a,e,o,n,u,h,"static/chunks/pages/line-chart-c4caf24c6849ce57.js"],"/lollipop-plot":[s,c,t,i,p,a,e,o,n,u,"static/css/64f55f4f67c1b792.css","static/chunks/pages/lollipop-plot-790d82a18314bc66.js"],"/map":[s,c,t,i,a,e,o,n,j,r,"static/chunks/pages/map-62403d2e3e8e93d8.js"],"/network-chart":[s,c,t,i,a,e,o,n,u,h,"static/chunks/pages/network-chart-00db4310eaf287bd.js"],"/parallel-plot":[s,c,t,i,a,e,o,n,r,"static/chunks/pages/parallel-plot-fc5eb664e86a8c8a.js"],"/pie-plot":[s,c,t,i,p,f,a,e,o,n,"static/css/7b5f8c9d016b3f7c.css","static/chunks/pages/pie-plot-a1b092b9d7149b8b.js"],"/radar-chart":[s,c,t,i,a,e,o,n,u,h,"static/chunks/pages/radar-chart-d9c6a5e9d64ddec6.js"],"/react-d3-dataviz-course":[s,c,a,e,o,b,"static/chunks/pages/react-d3-dataviz-course-f771d9fed9984c64.js"],"/react-dataviz-animation-with-react-spring":[s,c,t,p,a,e,o,b,"static/chunks/pages/react-dataviz-animation-with-react-spring-241bf24a4a74f8f0.js"],"/ridgeline":[s,c,t,i,a,e,o,n,u,A,h,"static/chunks/pages/ridgeline-11cba4c161729478.js"],"/sandbox":["static/chunks/pages/sandbox-1ce071da1e108df4.js"],"/sankey-diagram":[s,c,t,i,a,e,o,n,r,"static/chunks/pages/sankey-diagram-6d10b62979b8ba19.js"],"/scatter-plot":[s,c,t,i,a,e,o,n,u,m,x,_,"static/css/1973cdfb43563a59.css","static/chunks/pages/scatter-plot-fdef5fee6c505ccb.js"],"/shape-morphism-for-dataviz-with-react":[s,c,t,i,p,f,a,e,o,r,"static/chunks/pages/shape-morphism-for-dataviz-with-react-e737e8b242667de2.js"],"/stacked-area-plot":[s,c,t,i,p,f,a,e,o,n,"static/css/c79e5809ea8fe7eb.css","static/chunks/pages/stacked-area-plot-0f8f8a283b797557.js"],"/stacked-barplot-with-negative-values":[s,c,t,a,e,o,b,"static/chunks/pages/stacked-barplot-with-negative-values-01f393a6847a4218.js"],"/streamchart":[s,c,t,i,p,f,a,e,o,n,"static/css/003d5c48b04543ca.css","static/chunks/pages/streamchart-f7a9d802105a768e.js"],"/subscribe":[s,c,a,e,o,b,"static/chunks/pages/subscribe-cd6b3b49e0189ed1.js"],"/timeseries":[s,c,t,i,p,a,e,o,u,h,"static/chunks/pages/timeseries-0ec0a86b7c04bf8f.js"],"/treemap":[s,c,t,i,a,e,o,"static/css/25919ae4f53719a0.css","static/chunks/pages/treemap-68194c557d023a94.js"],"/typescript-d3-axis":[s,c,t,i,a,e,o,r,"static/chunks/pages/typescript-d3-axis-4533d45cdd503e53.js"],"/violin-plot":[s,c,t,i,a,e,o,n,r,"static/chunks/pages/violin-plot-1f925576e0efd35f.js"],"/viz-from-the-future":[s,c,a,e,o,"static/css/8d4c0e152872e92c.css","static/chunks/pages/viz-from-the-future-7590f2db599d31cf.js"],"/voronoi":[s,c,t,i,a,e,o,n,u,h,"static/chunks/pages/voronoi-0969554f6c933799.js"],"/what-is-a-color":[s,c,a,e,o,b,"static/chunks/pages/what-is-a-color-2ceba4025243af3a.js"],"/wordcloud":[s,c,t,i,a,e,o,r,"static/chunks/pages/wordcloud-eca0caf76708bed1.js"],sortedPages:["/","/2d-density-plot","/404","/_app","/_error","/about","/all","/animation","/arc-diagram","/area-plot","/articles","/barplot","/boxplot","/bubble-map","/bubble-plot","/build-axis-with-react","/cartogram","/chord-diagram","/choropleth-map","/circular-barplot","/circular-packing","/connected-scatter-plot","/connection-map","/correlogram","/course/animation/dealing-with-path","/course/animation/enter-update-exit","/course/animation/introduction","/course/animation/project","/course/animation/react-spring-for-dataviz","/course/animation/scatterplot","/course/axis/axis-variations","/course/axis/axis-with-d3","/course/axis/bottom-axis","/course/axis/introduction","/course/axis/margin-and-translation","/course/axis/project","/course/canvas/combining-svg-and-canvas","/course/canvas/drawing-shapes-with-canvas","/course/canvas/introduction","/course/canvas/svg-path-in-canvas","/course/hover-effect/css-descendant-selector","/course/hover-effect/css-pseudo-class","/course/hover-effect/internal-state","/course/hover-effect/introduction","/course/hover-effect/link-two-graphs","/course/hover-effect/toggle-class-in-js","/course/introduction/initial-setup","/course/introduction/introduction-to-d3","/course/introduction/introduction-to-react","/course/introduction/js-dataviz-libraries","/course/responsiveness/code-organization","/course/responsiveness/common-pitfalls","/course/responsiveness/introduction","/course/responsiveness/use-dimension-hook","/course/responsiveness/using-the-hook","/course/scales/introduction","/course/scales/linear-scale","/course/scales/other-scale-types","/course/scales/project","/course/svg/d3-shape","/course/svg/introduction","/course/svg/main-svg-elements","/course/svg/path-element","/course/svg/tips-and-tricks","/course/tooltip/display-on-hover","/course/tooltip/introduction","/course/tooltip/project","/course/tooltip/templates","/course/tooltip/tooltip-component","/cross-graph-highlight-interaction","/dataset-transition","/dendrogram","/density-plot","/donut","/example/arc-diagram-vertical","/example/barplot-data-transition-animation","/example/barplot-stacked-horizontal","/example/barplot-stacked-vertical","/example/boxplot-horizontal","/example/boxplot-jitter","/example/circle-packing-with-d3-force","/example/histogram-mirror","/example/histogram-slider-bin-size","/example/histogram-small-multiple","/example/histogram-with-several-groups","/example/line-chart-synchronized-cursors","/example/network-diagram-with-colored-groups","/example/population-pyramid","/example/radar-chart-animation","/example/sankey-bump-chart","/example/scatterplot-basic-canvas","/example/scatterplot-tooltip-with-voronoi-for-closest-point-detection","/example/timeseries-moving-average","/fix-canvas-blurry-dataviz","/heatmap","/hexbin-map","/hierarchical-edge-bundling","/histogram","/interactivity","/line-chart","/lollipop-plot","/map","/network-chart","/parallel-plot","/pie-plot","/radar-chart","/react-d3-dataviz-course","/react-dataviz-animation-with-react-spring","/ridgeline","/sandbox","/sankey-diagram","/scatter-plot","/shape-morphism-for-dataviz-with-react","/stacked-area-plot","/stacked-barplot-with-negative-values","/streamchart","/subscribe","/timeseries","/treemap","/typescript-d3-axis","/violin-plot","/viz-from-the-future","/voronoi","/what-is-a-color","/wordcloud"]}}("static/chunks/2343-fd77427f6d276a64.js","static/chunks/8190-bc54b059aeb5396b.js","static/chunks/7754-86d7d1d8f1f2cbb4.js","static/chunks/3710-40e32244f56e9b7c.js","static/chunks/3950-38f2f386edd33f86.js","static/chunks/7823-7fe55b50301cbfb1.js","static/chunks/2594-166023395f0e3eec.js","static/css/3f9dc76f65000636.css","static/chunks/6588-a2783089ca9aec45.js","static/chunks/2719-ff70805b79da7e6d.js","static/chunks/693-fc37b082b568d0e9.js","static/css/0fa95a85e3c094ce.css","static/chunks/9484-bdf662975f6102ab.js","static/css/bf3bc3250ab9e729.css","static/css/2247407c30b587b7.css","static/css/4aaaca05e34861fe.css","static/chunks/7303-d19d970f114fd8c4.js","static/chunks/2428-70208576adca3a60.js","static/css/537902226fc25775.css","static/chunks/5450-70ab90718653e6b6.js","static/chunks/7620-4f0bd3369dc66a11.js","static/chunks/2-07cbe458739247a7.js","static/chunks/2411-ba1de7774cf99f17.js","static/chunks/4741-05bce33428fd0105.js","static/chunks/7934-43612e1419e096cd.js","static/chunks/9381-73035a3d64711aef.js","static/chunks/4969-a489b2c1a112f705.js","static/chunks/1751-b103fc296c796353.js","static/chunks/9041-4aa84b93adf8b1ac.js","static/chunks/5796-06dd83477ed03c0b.js","static/chunks/8469-8c55bcc40455636a.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();
\ No newline at end of file
+self.__BUILD_MANIFEST=function(s,a,c,e,t,i,o,r,n,p,u,d,l,h,b,f,g,m,k,j,v,x,w,z,y,_,I,B,F,A,D){return{__rewrites:{beforeFiles:[],afterFiles:[],fallback:[]},"/":[s,"static/chunks/2718-c1b4ae8aebf23716.js",a,o,"static/chunks/pages/index-d41f25467ee6dcf3.js"],"/2d-density-plot":[s,c,t,i,a,e,o,n,r,"static/chunks/pages/2d-density-plot-8a8df282839cbf77.js"],"/404":[s,c,t,a,e,o,m,"static/css/8a734e64c19c3976.css","static/chunks/pages/404-083d849d0ce45b06.js"],"/_error":["static/chunks/pages/_error-82b79221b9ed784b.js"],"/about":[s,c,t,a,e,o,b,"static/chunks/pages/about-8505a607369c3630.js"],"/all":[s,c,a,e,o,u,k,"static/chunks/pages/all-c5ea439386fed3d0.js"],"/animation":[s,c,a,e,o,u,k,"static/chunks/pages/animation-fa9dfe1d4e131eb9.js"],"/arc-diagram":[s,c,t,i,a,e,o,n,u,h,"static/chunks/pages/arc-diagram-8c80fd0c10cfac1b.js"],"/area-plot":[s,c,t,i,a,e,o,n,r,"static/chunks/pages/area-plot-850e2af7f558eaea.js"],"/articles":[s,c,a,e,o,b,"static/chunks/pages/articles-4f71b8e4bef1386a.js"],"/barplot":[s,c,t,i,p,a,e,o,u,h,"static/chunks/pages/barplot-00f75722a80a9adb.js"],"/boxplot":[s,c,t,i,a,e,o,n,u,h,"static/chunks/pages/boxplot-27510a56d1e5db92.js"],"/bubble-map":[s,c,t,i,p,a,e,o,n,u,j,h,"static/chunks/pages/bubble-map-623301ff0f5c7875.js"],"/bubble-plot":[s,c,t,i,p,a,e,o,u,m,w,z,"static/css/ec7558f4d3e32e69.css","static/chunks/pages/bubble-plot-b5d354230244be84.js"],"/build-axis-with-react":[s,c,t,i,a,e,o,r,"static/chunks/pages/build-axis-with-react-38ba08684038bf02.js"],"/cartogram":[s,c,a,e,o,b,"static/chunks/pages/cartogram-3909805a96300cc2.js"],"/chord-diagram":[s,c,t,i,a,e,o,n,r,"static/chunks/pages/chord-diagram-157be7aad86575fb.js"],"/choropleth-map":[s,c,t,i,a,e,o,n,j,r,"static/chunks/pages/choropleth-map-07055d4a58480514.js"],"/circular-barplot":[s,c,t,i,a,e,o,n,r,"static/chunks/pages/circular-barplot-dba2b21bfe0f2586.js"],"/circular-packing":[s,c,t,i,p,a,e,o,u,h,"static/chunks/pages/circular-packing-c42dfa9a290456fc.js"],"/connected-scatter-plot":[s,c,t,i,a,e,o,n,r,"static/chunks/pages/connected-scatter-plot-8d9a8ddc1c0f3a7b.js"],"/connection-map":[s,c,t,i,a,e,o,n,j,r,"static/chunks/pages/connection-map-68a98e8e6bd1aa65.js"],"/correlogram":[s,c,t,i,a,e,o,"static/css/d54486714a313ae1.css","static/chunks/pages/correlogram-2094d57c1eb2fa41.js"],"/course/animation/dealing-with-path":[s,c,t,p,g,a,e,"static/css/56c7a0691f59768b.css","static/chunks/pages/course/animation/dealing-with-path-ef89d156bc300c89.js"],"/course/animation/enter-update-exit":[s,c,p,a,e,f,"static/chunks/pages/course/animation/enter-update-exit-59c9c6f667ced3e4.js"],"/course/animation/introduction":[s,c,t,p,a,e,v,f,"static/chunks/pages/course/animation/introduction-b6604c2146389f42.js"],"/course/animation/project":[s,c,t,p,a,e,v,f,"static/chunks/pages/course/animation/project-63faeae783f2c633.js"],"/course/animation/react-spring-for-dataviz":[s,c,i,p,l,a,e,d,"static/chunks/pages/course/animation/react-spring-for-dataviz-e01b8eea46ee56f4.js"],"/course/animation/scatterplot":[s,c,t,i,p,a,e,w,d,"static/chunks/pages/course/animation/scatterplot-5735416f3e48abb1.js"],"/course/axis/axis-variations":[s,c,a,e,f,"static/chunks/pages/course/axis/axis-variations-e8cf5bd8282a7c5f.js"],"/course/axis/axis-with-d3":[s,c,t,i,a,e,d,"static/chunks/pages/course/axis/axis-with-d3-f644056be4487108.js"],"/course/axis/bottom-axis":[s,c,t,i,l,a,e,d,"static/chunks/pages/course/axis/bottom-axis-bb532bb0bbba2e40.js"],"/course/axis/introduction":[s,c,t,a,e,f,"static/chunks/pages/course/axis/introduction-66ef24957a309b5d.js"],"/course/axis/margin-and-translation":[s,c,i,l,a,e,d,"static/chunks/pages/course/axis/margin-and-translation-e481dc8c6abf9ce8.js"],"/course/axis/project":[s,c,t,i,a,e,z,d,"static/chunks/pages/course/axis/project-3f188a1165fc56c7.js"],"/course/canvas/combining-svg-and-canvas":[s,c,t,i,a,e,d,"static/chunks/pages/course/canvas/combining-svg-and-canvas-7dfb1617ad30a20c.js"],"/course/canvas/drawing-shapes-with-canvas":[s,c,i,l,a,e,d,"static/chunks/pages/course/canvas/drawing-shapes-with-canvas-b987979bb2ffc953.js"],"/course/canvas/introduction":[s,c,t,i,a,e,d,"static/chunks/pages/course/canvas/introduction-9b7446a49771d4ce.js"],"/course/canvas/svg-path-in-canvas":[s,c,t,i,a,e,d,"static/chunks/pages/course/canvas/svg-path-in-canvas-ba361ca4364f5d2f.js"],"/course/hover-effect/css-descendant-selector":[s,c,t,i,l,a,e,u,"static/css/8666b20defb3e011.css","static/chunks/pages/course/hover-effect/css-descendant-selector-36ad6543af1f2621.js"],"/course/hover-effect/css-pseudo-class":[s,c,t,i,l,a,e,u,y,"static/css/69b5bd49186db9de.css","static/chunks/pages/course/hover-effect/css-pseudo-class-802774492109f763.js"],"/course/hover-effect/internal-state":[s,c,t,i,a,e,u,"static/css/f1e5f65ddf99e8f6.css","static/chunks/pages/course/hover-effect/internal-state-ff7118d79b1cc3cd.js"],"/course/hover-effect/introduction":[s,c,t,p,a,e,y,"static/css/0ec73f568dde8513.css","static/chunks/pages/course/hover-effect/introduction-d91fdd943b95d1ff.js"],"/course/hover-effect/link-two-graphs":[s,c,t,i,a,e,o,u,_,"static/css/c76003f718a0f9be.css","static/chunks/pages/course/hover-effect/link-two-graphs-fc8be979befb85d3.js"],"/course/hover-effect/toggle-class-in-js":[s,c,t,i,l,a,e,"static/css/f5258d81ed13d0d5.css","static/chunks/pages/course/hover-effect/toggle-class-in-js-fb21fb5b810c4b56.js"],"/course/introduction/initial-setup":[s,c,t,i,a,e,d,"static/chunks/pages/course/introduction/initial-setup-1a01dca02cbea214.js"],"/course/introduction/introduction-to-d3":[s,c,t,a,e,f,"static/chunks/pages/course/introduction/introduction-to-d3-6ded1ce234ed1b2c.js"],"/course/introduction/introduction-to-react":[s,c,a,e,f,"static/chunks/pages/course/introduction/introduction-to-react-a392c14cf58076cf.js"],"/course/introduction/js-dataviz-libraries":[s,c,i,a,e,d,"static/chunks/pages/course/introduction/js-dataviz-libraries-f7f28061427db698.js"],"/course/responsiveness/code-organization":[s,c,i,a,e,d,"static/chunks/pages/course/responsiveness/code-organization-4dee38ef916f6e9b.js"],"/course/responsiveness/common-pitfalls":[s,c,a,e,f,"static/chunks/pages/course/responsiveness/common-pitfalls-b052d1cc732e6cb4.js"],"/course/responsiveness/introduction":[s,c,t,i,a,e,d,"static/chunks/pages/course/responsiveness/introduction-638287c3a0c0f3e3.js"],"/course/responsiveness/use-dimension-hook":[s,c,i,a,e,d,"static/chunks/pages/course/responsiveness/use-dimension-hook-035fc5d826f40d64.js"],"/course/responsiveness/using-the-hook":[s,c,i,l,a,e,d,"static/chunks/pages/course/responsiveness/using-the-hook-bdd2dfdbaf2e4479.js"],"/course/scales/introduction":[s,c,i,a,e,I,d,"static/chunks/pages/course/scales/introduction-4801b90c32a802e0.js"],"/course/scales/linear-scale":[s,c,i,l,a,e,I,d,"static/chunks/pages/course/scales/linear-scale-2b562f6b76eefd20.js"],"/course/scales/other-scale-types":[s,c,t,i,l,a,e,d,"static/chunks/pages/course/scales/other-scale-types-6d076272a1d64e97.js"],"/course/scales/project":[s,c,t,i,a,e,d,"static/chunks/pages/course/scales/project-d5bc6bbb2a6c117b.js"],"/course/svg/d3-shape":[s,c,i,l,a,e,d,"static/chunks/pages/course/svg/d3-shape-6855634224ffd05f.js"],"/course/svg/introduction":[s,c,t,l,a,e,f,"static/chunks/pages/course/svg/introduction-cbc6f0c36a1a42ec.js"],"/course/svg/main-svg-elements":[s,c,i,l,a,e,d,"static/chunks/pages/course/svg/main-svg-elements-b67e94f54df7d5ea.js"],"/course/svg/path-element":[s,c,i,l,a,e,d,"static/chunks/pages/course/svg/path-element-ddeafb47c2680043.js"],"/course/svg/tips-and-tricks":[s,c,i,"static/chunks/2860-d038ef2b7795bb05.js",a,e,d,"static/chunks/pages/course/svg/tips-and-tricks-718819bf957d0ddb.js"],"/course/tooltip/display-on-hover":[s,c,t,i,l,a,e,x,"static/css/530b699660279b3e.css","static/chunks/pages/course/tooltip/display-on-hover-e5794d0da9958032.js"],"/course/tooltip/introduction":[s,c,t,a,e,m,"static/css/b23f3515152ab10c.css","static/chunks/pages/course/tooltip/introduction-dd57bbe658e25a2e.js"],"/course/tooltip/project":[s,c,t,i,a,e,B,"static/css/e6721a776c502451.css","static/chunks/pages/course/tooltip/project-2f4d2ec670a5c6ec.js"],"/course/tooltip/templates":[s,c,t,a,e,m,x,"static/css/ec6f9e7260a78fe2.css","static/chunks/pages/course/tooltip/templates-e08fba51c8c643ca.js"],"/course/tooltip/tooltip-component":[s,c,i,l,a,e,d,"static/chunks/pages/course/tooltip/tooltip-component-be4ee12236b179e2.js"],"/cross-graph-highlight-interaction":[s,c,t,i,"static/chunks/8446-4892663fdb75b8e1.js",a,e,o,"static/css/507114ea18f6728e.css","static/chunks/pages/cross-graph-highlight-interaction-f4981236e3ce062b.js"],"/dataset-transition":[s,c,t,i,p,a,e,o,r,"static/chunks/pages/dataset-transition-04f3ac5287b70e46.js"],"/dendrogram":[s,c,t,i,a,e,o,F,r,"static/chunks/pages/dendrogram-437272f9020c7aab.js"],"/density-plot":[s,c,t,i,a,e,o,n,A,r,"static/chunks/pages/density-plot-a9c9eae2588b0c6c.js"],"/donut":[s,c,t,i,p,g,a,e,o,n,"static/css/306a1a30c14677d4.css","static/chunks/pages/donut-f6c4704c8df5ae55.js"],"/example/arc-diagram-vertical":[s,c,t,i,a,e,o,r,"static/chunks/pages/example/arc-diagram-vertical-ee4b8759645617e3.js"],"/example/barplot-data-transition-animation":[s,c,t,i,p,a,e,o,r,"static/chunks/pages/example/barplot-data-transition-animation-3b43c38cc63954f8.js"],"/example/barplot-stacked-horizontal":[s,c,t,i,a,e,o,u,h,"static/chunks/pages/example/barplot-stacked-horizontal-88e863909d739272.js"],"/example/barplot-stacked-vertical":[s,c,t,a,e,o,u,k,"static/chunks/pages/example/barplot-stacked-vertical-1383a75f05139115.js"],"/example/boxplot-horizontal":[s,c,t,i,a,e,o,r,"static/chunks/pages/example/boxplot-horizontal-ba359fa226e9e306.js"],"/example/boxplot-jitter":[s,c,t,i,a,e,o,r,"static/chunks/pages/example/boxplot-jitter-c3aa852f6add3126.js"],"/example/circle-packing-with-d3-force":[s,c,t,i,a,e,o,r,"static/chunks/pages/example/circle-packing-with-d3-force-91029646511643dc.js"],"/example/histogram-mirror":[s,c,t,i,a,e,o,r,"static/chunks/pages/example/histogram-mirror-00743c0fa7e95ca8.js"],"/example/histogram-slider-bin-size":[s,c,t,a,e,o,D,"static/css/f7129d2d0aac0f23.css","static/chunks/pages/example/histogram-slider-bin-size-4dea62a699539ada.js"],"/example/histogram-small-multiple":[s,c,t,i,a,e,o,r,"static/chunks/pages/example/histogram-small-multiple-794625c2d9f73b4e.js"],"/example/histogram-with-several-groups":[s,c,t,i,a,e,o,r,"static/chunks/pages/example/histogram-with-several-groups-df434001b3f202b7.js"],"/example/line-chart-synchronized-cursors":[s,c,t,i,p,a,e,o,r,"static/chunks/pages/example/line-chart-synchronized-cursors-4533bf55dbbfc249.js"],"/example/network-diagram-with-colored-groups":[s,c,t,i,a,e,o,r,"static/chunks/pages/example/network-diagram-with-colored-groups-87e8c79c8205e6f4.js"],"/example/population-pyramid":[t,p,"static/css/d71181803328322d.css","static/chunks/pages/example/population-pyramid-7f97eae907059157.js"],"/example/radar-chart-animation":[s,c,t,i,p,a,e,o,v,r,"static/chunks/pages/example/radar-chart-animation-43847f64fedbca97.js"],"/example/sankey-bump-chart":[s,c,t,a,e,o,b,"static/chunks/pages/example/sankey-bump-chart-e9c76dcf9dc5b58e.js"],"/example/scatterplot-basic-canvas":[s,c,t,i,a,e,o,r,"static/chunks/pages/example/scatterplot-basic-canvas-4bc535863d92c309.js"],"/example/scatterplot-tooltip-with-voronoi-for-closest-point-detection":[s,c,t,i,a,e,o,r,"static/chunks/pages/example/scatterplot-tooltip-with-voronoi-for-closest-point-detection-ca83c451932a3cb2.js"],"/example/timeseries-moving-average":[s,c,t,i,a,e,o,u,"static/css/0051346e12b181a2.css","static/chunks/pages/example/timeseries-moving-average-09c989c1f87b1ea6.js"],"/fix-canvas-blurry-dataviz":[s,c,i,a,e,o,r,"static/chunks/pages/fix-canvas-blurry-dataviz-4dec33a6dd3d0b86.js"],"/heatmap":[s,c,t,i,a,e,o,n,B,"static/css/efd490e62b6b40d6.css","static/chunks/pages/heatmap-7fae042d715abd6d.js"],"/hexbin-map":[s,c,t,i,a,e,o,n,r,"static/chunks/pages/hexbin-map-a930630d43a80673.js"],"/hierarchical-edge-bundling":[s,c,t,i,a,e,o,F,r,"static/chunks/pages/hierarchical-edge-bundling-13f282ff59e73fb9.js"],"/histogram":[s,c,t,i,p,a,e,o,n,u,D,"static/css/516fbb6bc1065354.css","static/chunks/pages/histogram-205eb50e1cb77334.js"],"/interactivity":[s,c,a,e,o,u,k,"static/chunks/pages/interactivity-54e994fb8fdc812d.js"],"/line-chart":[s,c,t,i,p,a,e,o,n,u,h,"static/chunks/pages/line-chart-c4caf24c6849ce57.js"],"/lollipop-plot":[s,c,t,i,p,a,e,o,n,u,"static/css/64f55f4f67c1b792.css","static/chunks/pages/lollipop-plot-790d82a18314bc66.js"],"/map":[s,c,t,i,a,e,o,n,j,r,"static/chunks/pages/map-62403d2e3e8e93d8.js"],"/network-chart":[s,c,t,i,a,e,o,n,u,h,"static/chunks/pages/network-chart-00db4310eaf287bd.js"],"/parallel-plot":[s,c,t,i,a,e,o,n,r,"static/chunks/pages/parallel-plot-fc5eb664e86a8c8a.js"],"/pie-plot":[s,c,t,i,p,g,a,e,o,n,"static/css/7b5f8c9d016b3f7c.css","static/chunks/pages/pie-plot-a1b092b9d7149b8b.js"],"/radar-chart":[s,c,t,i,a,e,o,n,u,h,"static/chunks/pages/radar-chart-d9c6a5e9d64ddec6.js"],"/react-d3-dataviz-course":[s,c,a,e,o,b,"static/chunks/pages/react-d3-dataviz-course-f771d9fed9984c64.js"],"/react-dataviz-animation-with-react-spring":[s,c,t,p,a,e,o,b,"static/chunks/pages/react-dataviz-animation-with-react-spring-241bf24a4a74f8f0.js"],"/ridgeline":[s,c,t,i,a,e,o,n,u,A,h,"static/chunks/pages/ridgeline-11cba4c161729478.js"],"/sandbox":["static/chunks/pages/sandbox-1ce071da1e108df4.js"],"/sankey-diagram":[s,c,t,i,a,e,o,n,r,"static/chunks/pages/sankey-diagram-6d10b62979b8ba19.js"],"/scatter-plot":[s,c,t,i,a,e,o,n,u,m,x,_,"static/css/1973cdfb43563a59.css","static/chunks/pages/scatter-plot-fdef5fee6c505ccb.js"],"/shape-morphism-for-dataviz-with-react":[s,c,t,i,p,g,a,e,o,r,"static/chunks/pages/shape-morphism-for-dataviz-with-react-e737e8b242667de2.js"],"/stacked-area-plot":[s,c,t,i,p,g,a,e,o,n,"static/css/c79e5809ea8fe7eb.css","static/chunks/pages/stacked-area-plot-0f8f8a283b797557.js"],"/stacked-barplot-with-negative-values":[s,c,t,a,e,o,b,"static/chunks/pages/stacked-barplot-with-negative-values-01f393a6847a4218.js"],"/streamchart":[s,c,t,i,p,g,a,e,o,n,"static/css/003d5c48b04543ca.css","static/chunks/pages/streamchart-f7a9d802105a768e.js"],"/subscribe":[s,c,a,e,o,b,"static/chunks/pages/subscribe-cd6b3b49e0189ed1.js"],"/timeseries":[s,c,t,i,p,a,e,o,u,h,"static/chunks/pages/timeseries-0ec0a86b7c04bf8f.js"],"/treemap":[s,c,t,i,a,e,o,"static/css/25919ae4f53719a0.css","static/chunks/pages/treemap-68194c557d023a94.js"],"/typescript-d3-axis":[s,c,t,i,a,e,o,r,"static/chunks/pages/typescript-d3-axis-4533d45cdd503e53.js"],"/violin-plot":[s,c,t,i,a,e,o,n,r,"static/chunks/pages/violin-plot-1f925576e0efd35f.js"],"/viz-from-the-future":[s,c,a,e,o,"static/css/8d4c0e152872e92c.css","static/chunks/pages/viz-from-the-future-7590f2db599d31cf.js"],"/voronoi":[s,c,t,i,a,e,o,n,u,h,"static/chunks/pages/voronoi-0969554f6c933799.js"],"/what-is-a-color":[s,c,a,e,o,b,"static/chunks/pages/what-is-a-color-2ceba4025243af3a.js"],"/wordcloud":[s,c,t,i,a,e,o,r,"static/chunks/pages/wordcloud-eca0caf76708bed1.js"],sortedPages:["/","/2d-density-plot","/404","/_app","/_error","/about","/all","/animation","/arc-diagram","/area-plot","/articles","/barplot","/boxplot","/bubble-map","/bubble-plot","/build-axis-with-react","/cartogram","/chord-diagram","/choropleth-map","/circular-barplot","/circular-packing","/connected-scatter-plot","/connection-map","/correlogram","/course/animation/dealing-with-path","/course/animation/enter-update-exit","/course/animation/introduction","/course/animation/project","/course/animation/react-spring-for-dataviz","/course/animation/scatterplot","/course/axis/axis-variations","/course/axis/axis-with-d3","/course/axis/bottom-axis","/course/axis/introduction","/course/axis/margin-and-translation","/course/axis/project","/course/canvas/combining-svg-and-canvas","/course/canvas/drawing-shapes-with-canvas","/course/canvas/introduction","/course/canvas/svg-path-in-canvas","/course/hover-effect/css-descendant-selector","/course/hover-effect/css-pseudo-class","/course/hover-effect/internal-state","/course/hover-effect/introduction","/course/hover-effect/link-two-graphs","/course/hover-effect/toggle-class-in-js","/course/introduction/initial-setup","/course/introduction/introduction-to-d3","/course/introduction/introduction-to-react","/course/introduction/js-dataviz-libraries","/course/responsiveness/code-organization","/course/responsiveness/common-pitfalls","/course/responsiveness/introduction","/course/responsiveness/use-dimension-hook","/course/responsiveness/using-the-hook","/course/scales/introduction","/course/scales/linear-scale","/course/scales/other-scale-types","/course/scales/project","/course/svg/d3-shape","/course/svg/introduction","/course/svg/main-svg-elements","/course/svg/path-element","/course/svg/tips-and-tricks","/course/tooltip/display-on-hover","/course/tooltip/introduction","/course/tooltip/project","/course/tooltip/templates","/course/tooltip/tooltip-component","/cross-graph-highlight-interaction","/dataset-transition","/dendrogram","/density-plot","/donut","/example/arc-diagram-vertical","/example/barplot-data-transition-animation","/example/barplot-stacked-horizontal","/example/barplot-stacked-vertical","/example/boxplot-horizontal","/example/boxplot-jitter","/example/circle-packing-with-d3-force","/example/histogram-mirror","/example/histogram-slider-bin-size","/example/histogram-small-multiple","/example/histogram-with-several-groups","/example/line-chart-synchronized-cursors","/example/network-diagram-with-colored-groups","/example/population-pyramid","/example/radar-chart-animation","/example/sankey-bump-chart","/example/scatterplot-basic-canvas","/example/scatterplot-tooltip-with-voronoi-for-closest-point-detection","/example/timeseries-moving-average","/fix-canvas-blurry-dataviz","/heatmap","/hexbin-map","/hierarchical-edge-bundling","/histogram","/interactivity","/line-chart","/lollipop-plot","/map","/network-chart","/parallel-plot","/pie-plot","/radar-chart","/react-d3-dataviz-course","/react-dataviz-animation-with-react-spring","/ridgeline","/sandbox","/sankey-diagram","/scatter-plot","/shape-morphism-for-dataviz-with-react","/stacked-area-plot","/stacked-barplot-with-negative-values","/streamchart","/subscribe","/timeseries","/treemap","/typescript-d3-axis","/violin-plot","/viz-from-the-future","/voronoi","/what-is-a-color","/wordcloud"]}}("static/chunks/2343-fd77427f6d276a64.js","static/chunks/8190-bc54b059aeb5396b.js","static/chunks/7754-86d7d1d8f1f2cbb4.js","static/chunks/3710-40e32244f56e9b7c.js","static/chunks/3950-38f2f386edd33f86.js","static/chunks/7823-7fe55b50301cbfb1.js","static/chunks/2594-166023395f0e3eec.js","static/css/3f9dc76f65000636.css","static/chunks/6588-a2783089ca9aec45.js","static/chunks/2719-ff70805b79da7e6d.js","static/chunks/693-fc37b082b568d0e9.js","static/css/0fa95a85e3c094ce.css","static/chunks/9484-bdf662975f6102ab.js","static/css/bf3bc3250ab9e729.css","static/css/2247407c30b587b7.css","static/css/4aaaca05e34861fe.css","static/chunks/7303-d19d970f114fd8c4.js","static/chunks/2428-70208576adca3a60.js","static/css/537902226fc25775.css","static/chunks/5450-70ab90718653e6b6.js","static/chunks/7620-4f0bd3369dc66a11.js","static/chunks/2-07cbe458739247a7.js","static/chunks/2411-ba1de7774cf99f17.js","static/chunks/4741-05bce33428fd0105.js","static/chunks/7934-43612e1419e096cd.js","static/chunks/9381-73035a3d64711aef.js","static/chunks/4969-a489b2c1a112f705.js","static/chunks/1751-b103fc296c796353.js","static/chunks/9041-4aa84b93adf8b1ac.js","static/chunks/5796-06dd83477ed03c0b.js","static/chunks/8469-8c55bcc40455636a.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();
\ No newline at end of file
diff --git a/_next/static/Qn9JDBrmHpswodUUyZzEd/_ssgManifest.js b/_next/static/nDNzxM9oguhvL5k4w7ZTG/_ssgManifest.js
similarity index 100%
rename from _next/static/Qn9JDBrmHpswodUUyZzEd/_ssgManifest.js
rename to _next/static/nDNzxM9oguhvL5k4w7ZTG/_ssgManifest.js
diff --git a/about.html b/about.html
index 9aad30a3..7f4119a2 100644
--- a/about.html
+++ b/about.html
@@ -1,4 +1,4 @@
-About the gallery
React + D3.js = ❤️
A love story – So simplepowerful yet so complicated
A few years ago I created the d3 graph gallery, a website showcasing hundreds of simple charts made with d3.js. It worked well! Thousands of people use it daily to learn d3. 🎉
Since then, React became the most popular framework to build user interfaces. This rose a question: how to build a chart in react? That's a complicated question with many answers. Here are the 3 most common approaches.
3 ways to draw a chart in react
→ 1️⃣ Charting libraries
There is a myriad of charting libraries offering react components for every chart type. HighChart, ReCharts, React-viz, plot, visX and so many more. Those libraries are awesome: you'll get a working chart in minutes using them.
But simplicity comes with a cost: the time you saved in the first place will be lost when you'll try to reach a high level of customization.
If you want to build something unique, you need to draw shapes one by one.
→ 2️⃣ D3 for rendering in a useEffect hook
If you're familiar with d3.js already, it's possible to use any of its examples (from a block or the gallery) by using a useEffect hook.
Basically, you can create a div in the DOM using react. You can then use the drawing methods of the d3-selection module like append or axisBottom to target this div, and add the content of the chart.
Let's apply this to draw axes:
You can use all the d3 knowlege you have in a useEffect hook to build the graph in a react context.
This works but comes with some caveats. To put it in a nutshell you now have 2 tools trying to control the DOM: react and d3. That's hard to maintain for large applications.
→ 3️⃣ D3 for maths, React for rendering
This gallery suggests using d3.js only for the math utils it provides. And to add entries to the DOM using react, like for any other UI element.
Let's say we want to build a scatterplot. The scaleLinear function of d3.js is used to build the scales. Now that we can easily know the position of a circle on the screen, we can just loop through all data items and render them as a circle svg element.
Use d3.js to compute the scales. Use React to render the circles.
Learn concepts, Get templates
This gallery is all about using the power of the d3 math utils and the react rendering engine.
The first goal is to teach the concepts. Many examples are provided for each chart type. Each one targets a specific theme like color, axis, responsiveness, hover effect, or tooltips.
The second goal is to provide templates for each viz type. Building a viz from scratch is time-consuming, so better tweak an existing example.
All graph examples come with an explanation and a code sandbox allowing you to play with the code.
I built this website with ❤️. I hope it will help you create stunning vizs in a minimum amount of time. Reach me on Twitter, contribute on github and subscribe to the newsletter to know when new chart types are published!
Contact
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data with gmail.com. You can also subscribe to the newsletter to know when I publish more content!
+About the gallery
React + D3.js = ❤️
A love story – So simplepowerful yet so complicated
A few years ago I created the d3 graph gallery, a website showcasing hundreds of simple charts made with d3.js. It worked well! Thousands of people use it daily to learn d3. 🎉
Since then, React became the most popular framework to build user interfaces. This rose a question: how to build a chart in react? That's a complicated question with many answers. Here are the 3 most common approaches.
3 ways to draw a chart in react
→ 1️⃣ Charting libraries
There is a myriad of charting libraries offering react components for every chart type. HighChart, ReCharts, React-viz, plot, visX and so many more. Those libraries are awesome: you'll get a working chart in minutes using them.
But simplicity comes with a cost: the time you saved in the first place will be lost when you'll try to reach a high level of customization.
If you want to build something unique, you need to draw shapes one by one.
→ 2️⃣ D3 for rendering in a useEffect hook
If you're familiar with d3.js already, it's possible to use any of its examples (from a block or the gallery) by using a useEffect hook.
Basically, you can create a div in the DOM using react. You can then use the drawing methods of the d3-selection module like append or axisBottom to target this div, and add the content of the chart.
Let's apply this to draw axes:
You can use all the d3 knowlege you have in a useEffect hook to build the graph in a react context.
This works but comes with some caveats. To put it in a nutshell you now have 2 tools trying to control the DOM: react and d3. That's hard to maintain for large applications.
→ 3️⃣ D3 for maths, React for rendering
This gallery suggests using d3.js only for the math utils it provides. And to add entries to the DOM using react, like for any other UI element.
Let's say we want to build a scatterplot. The scaleLinear function of d3.js is used to build the scales. Now that we can easily know the position of a circle on the screen, we can just loop through all data items and render them as a circle svg element.
Use d3.js to compute the scales. Use React to render the circles.
Learn concepts, Get templates
This gallery is all about using the power of the d3 math utils and the react rendering engine.
The first goal is to teach the concepts. Many examples are provided for each chart type. Each one targets a specific theme like color, axis, responsiveness, hover effect, or tooltips.
The second goal is to provide templates for each viz type. Building a viz from scratch is time-consuming, so better tweak an existing example.
All graph examples come with an explanation and a code sandbox allowing you to play with the code.
I built this website with ❤️. I hope it will help you create stunning vizs in a minimum amount of time. Reach me on Twitter, contribute on github and subscribe to the newsletter to know when new chart types are published!
Contact
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data with gmail.com. You can also subscribe to the newsletter to know when I publish more content!
\ No newline at end of file
diff --git a/all.html b/all.html
index aa1700b9..9bb7a8de 100644
--- a/all.html
+++ b/all.html
@@ -1,4 +1,4 @@
-All graphs
All graphs
The react graph gallery displays hundreds of graphs made with React, often with the help of d3.js. This page provides an overview of all charts showcased in this gallery.
Note that all chart types are presented on the welcome page of the gallery. It is probably a more convenient way to browse this website if you know what you are looking for!
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data with gmail.com. You can also subscribe to the newsletter to know when I publish more content!
+All graphs
All graphs
The react graph gallery displays hundreds of graphs made with React, often with the help of d3.js. This page provides an overview of all charts showcased in this gallery.
Note that all chart types are presented on the welcome page of the gallery. It is probably a more convenient way to browse this website if you know what you are looking for!
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data with gmail.com. You can also subscribe to the newsletter to know when I publish more content!
\ No newline at end of file
diff --git a/animation.html b/animation.html
index 929f9a41..abd3013c 100644
--- a/animation.html
+++ b/animation.html
@@ -1,4 +1,4 @@
-Animation
Animation
Animation is both the most challenging and the most exciting part of an interactive chart. Animation is like salt: use the right amount of it and your creation is a delight. Too much of it and it spoils the dish 🤌.
There are many ways to animate the transition between 2 chart states. Here I suggest to use react-spring in combination with react andd3.js.
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data with gmail.com. You can also subscribe to the newsletter to know when I publish more content!
+Animation
Animation
Animation is both the most challenging and the most exciting part of an interactive chart. Animation is like salt: use the right amount of it and your creation is a delight. Too much of it and it spoils the dish 🤌.
There are many ways to animate the transition between 2 chart states. Here I suggest to use react-spring in combination with react andd3.js.
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data with gmail.com. You can also subscribe to the newsletter to know when I publish more content!
\ No newline at end of file
diff --git a/arc-diagram.html b/arc-diagram.html
index d6f87b5d..2594d125 100644
--- a/arc-diagram.html
+++ b/arc-diagram.html
@@ -1,4 +1,4 @@
-How to build an Arc Diagram with React and D3.
Arc diagram
An arc diagram is a special kind of network graph. It is consituted by nodes that represent entities and by links that show relationships between entities. In arc diagrams, nodes are displayed along a single axis and links are represented with arcs.
This page is a step by step tutorial explaining how to build an Arc diagram component with React and D3.js. It comes with explanations and code sandboxes. It starts by simple concept like how to format the data and how to draw arcs in SVG, and then goes further with hover effect, tooltip and more.
Two layers of information are required to build an arc diagram: a list of nodes to build the circles and a list of links to build the arcs.
Many different data structures can be used to store such information. In this tutorial I suggest to start with the following:
export const data = {
+How to build an Arc Diagram with React and D3.
Arc diagram
An arc diagram is a special kind of network graph. It is consituted by nodes that represent entities and by links that show relationships between entities. In arc diagrams, nodes are displayed along a single axis and links are represented with arcs.
This page is a step by step tutorial explaining how to build an Arc diagram component with React and D3.js. It comes with explanations and code sandboxes. It starts by simple concept like how to format the data and how to draw arcs in SVG, and then goes further with hover effect, tooltip and more.
I'm in the process of writing a complete blog post on the topic. Subscribe to the project to know when it's ready.
Arc Diagram inspiration
If you're looking for inspiration to create your next Arc Diagram, note that dataviz-inspiration.com showcases many examples. Definitely the best place to get ... inspiration!
dataviz-inspiration.com showcases hundreds of stunning dataviz projects. Have a look to get some ideas on how to make your Arc Diagram looks good!
Once you've understood how to build a basic arc diagram with d3 and react, it opens an infinite world of customization. Here are a few examples highlighting what it is possible to do with arc diagrams.
Click on the overview below to get details and code.
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data with gmail.com. You can also subscribe to the newsletter to know when I publish more content!
\ No newline at end of file
diff --git a/area-plot.html b/area-plot.html
index 2fedded0..c679f0b8 100644
--- a/area-plot.html
+++ b/area-plot.html
@@ -1,4 +1,4 @@
-Area charts with React
Area charts
An area chart displays the evolution of one numeric variables. It is like a line chart, but with the area below the line being filled.
This section describes how to build area charts on the web with d3.js and react. It starts very basic and then explains how to add more complex features like brushing, adding hover effects and more.
The dataset required to build a line chart is usually an array where each item is an object providing the x and the y values of the data point.
Here is a minimal example:
const data = [
+Area charts with React
Area charts
An area chart displays the evolution of one numeric variables. It is like a line chart, but with the area below the line being filled.
This section describes how to build area charts on the web with d3.js and react. It starts very basic and then explains how to add more complex features like brushing, adding hover effects and more.
Both a y0 and a y1 arguments are used. They provide both the bottom and the top position of the shape for each x position.
The output areaPath can now be passed to a path resulting in the following area chart:
A very basic area chart made using react and the area() function of d3.js
Area chart inspiration
If you're looking for inspiration to create your next Area chart, note that dataviz-inspiration.com showcases many examples. Definitely the best place to get ... inspiration!
dataviz-inspiration.com showcases hundreds of stunning dataviz projects. Have a look to get some ideas on how to make your Area chart looks good!
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data with gmail.com. You can also subscribe to the newsletter to know when I publish more content!
\ No newline at end of file
diff --git a/articles.html b/articles.html
index 5f7dfe71..b4832dca 100644
--- a/articles.html
+++ b/articles.html
@@ -1,7 +1,7 @@
-How to make react and d3.js work together
Dataviz Insights with React and D3.js
While our gallery showcases a myriad of graph examples, this space is dedicated to delving into the intricacies of data visualization using React and D3.js.
From unraveling the complexities of creating stacked bar plots with negative values to envisioning futuristic visualizations, our articles aim to enlighten, inspire, and guide you through the advanced realms of dataviz.
Whether you're a seasoned developer or just starting out, these articles offer a wealth of knowledge to elevate your visualization game.
Let's embark on this enlightening journey together! 🔥
Viz components often take a width and a height properties as input. This blogposts explains how to build a wrapper around it that computes the parent's div dimension and pass it as propsRead more
Interactivity is an important part of dataviz when working in the browser. Adding a hover effect can improve the user experience by highlighting a series on the chart. Here are a couple way to implement it, always keeping performances in mind.Read more
A stacked barchart displays the values of items split in group and subgroups. It's a quite common chart type, but dealing with negative values in the dataset brings some interesting dataviz discussions.Read more
6 minutes read
Dataviz
The next articles are currently in writing mode. ⬇️
They will be released soon and you can be updated through my newsletter:
+How to make react and d3.js work together
Dataviz Insights with React and D3.js
While our gallery showcases a myriad of graph examples, this space is dedicated to delving into the intricacies of data visualization using React and D3.js.
From unraveling the complexities of creating stacked bar plots with negative values to envisioning futuristic visualizations, our articles aim to enlighten, inspire, and guide you through the advanced realms of dataviz.
Whether you're a seasoned developer or just starting out, these articles offer a wealth of knowledge to elevate your visualization game.
Let's embark on this enlightening journey together! 🔥
Viz components often take a width and a height properties as input. This blogposts explains how to build a wrapper around it that computes the parent's div dimension and pass it as propsRead more
Interactivity is an important part of dataviz when working in the browser. Adding a hover effect can improve the user experience by highlighting a series on the chart. Here are a couple way to implement it, always keeping performances in mind.Read more
A stacked barchart displays the values of items split in group and subgroups. It's a quite common chart type, but dealing with negative values in the dataset brings some interesting dataviz discussions.Read more
6 minutes read
Dataviz
The next articles are currently in writing mode. ⬇️
They will be released soon and you can be updated through my newsletter:
Using react and d3.js: The 2 strategies
React modifies the DOM. So does d3.js. It makes it notoriously hard to have them work together. This blog post describes the 2 main strategies to use d3.js in a react app, with their pros and cons.
4 minutes read
Fundamental
Axes: build them with react (and a bit of d3)
Most of the viz types need some axes to be insightful. This post explains how to build them from a d3 scale, using the tick() method of d3 to create re-usable react components.
8 minutes read
Fundamental
Axis
Graph to graph interaction
Let's say you have a choropleth map on a side, a timeseries on the other. How can you add cross-viz interactions, like hovering a country to highlight its trend on the timeseries?
10 minutes read
Interaction
Advanced
Spring animations with react spring
It's often necessary to transition between 2 ys of a graph. React-spring is here to help, allowing to use spring animations easily.
5 minutes read
Fundamental
Animation
Dataset transition
Adding a smooth transition between dataset often adds a nice touch to your viz component. Let's see how to implement it with react-spring.
5 minutes read
Animation
Shape morphism: animate the transition between 2 distincts charts
How can we build a smooth transition between a pie chart and a barplot? The flubber js library allows to interpolate shapes and react-spring can animate this interpolation.
5 minutes read
Advanced
Animation
Improve chart performance with Canvas
Rendering a chart using svg is limited in term of performace. The DOM gets to crowded and updating it ends up being slow. Using canvas is the best workaround but you need to be able to draw your svg path using it!
5 minutes read
Fundamental
Canvas
Fix the blurry canvas on Retina screens
When using canvas for your viz, the result will be blurry on retina screens if you don't scale the canvas properly. Here is why and how to implement it.
5 minutes read
Canvas
Advanced
What is a color
There are so many ways to define a color when talking with a computer. Let's take a tour and see what's the most appropriate for a dataviz point of view.
3 minutes read
Fundamental
Axis
Buiding a futuristic viz
What makes a viz look from the future. And how to implement it with d3.js and reac.
3 minutes read
Fundamental
Axis
Contact
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data with gmail.com. You can also subscribe to the newsletter to know when I publish more content!
\ No newline at end of file
diff --git a/barplot.html b/barplot.html
index 17948ea3..78a632ae 100644
--- a/barplot.html
+++ b/barplot.html
@@ -1,4 +1,4 @@
-Barplot with React
Barplot
A barplot displays a numeric value for several groups of a dataset using rectangles. This page is a step-by-step guide on how to build your own barplot for the web, using React and D3.js.
It starts with very basic concepts like data structure, scales and svg rectangle rendering. It then shows how to add interactivity to the chart with hover effects. Last but not least it explains how to build variations like the stacked barplot.
The dataset required to build a barplot is usually an array where each item is an object providing the name and the value of the group.
Here is a minimal example
const data = [
+Barplot with React
Barplot
A barplot displays a numeric value for several groups of a dataset using rectangles. This page is a step-by-step guide on how to build your own barplot for the web, using React and D3.js.
It starts with very basic concepts like data structure, scales and svg rectangle rendering. It then shows how to add interactivity to the chart with hover effects. Last but not least it explains how to build variations like the stacked barplot.
I'm in the process of writing a complete blog post on the topic. Subscribe to the project to know when it's ready.
Transition
When the dataset updates, it adds a nice touch to smoothly animate the transition. In the example below, changing the dataset will update the bar sizes and their positions on the Y axis to keep the ranking accurate.
Animation is a complicated topic in dataviz. We have to deal with updates (an element changes its features), enter (a new element appears) and exit (an element is not present anymore) patterns.
I suggest to rely on the react-spring library to help here. Please check this dedicated blogpost to get explanations about the code of this example.
Most basic barplot built with d3.js for scales, and react for rendering
Stacking
A stacked barplot is a variation of a barplot where an additional level of grouping is represented. Each bar represent the value of a group, for instance how much each my friend spent in the last month. Each bar is then subdivided, each part representing the value of a subgroup, for instance the category of expense.
D3 comes with a very handy stack() function. The 2 tutorials below explain how this function works, and how to use it to render a clean stacked barplot.
Vertical barplot
The vertical option is less common since it makes is much harder to read the labels. But if you really need it, it is just a matter of swaping the X and Y axes of the previous example.
This example will be publish soon, please subscribe below if you want to be notified.
Hover effect
This example will be publish soon, please subscribe to the newsletter if you want to be notified.
Variations
Let's go beyond the basic barcharts. Click on the overview images below to get details and code.
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data with gmail.com. You can also subscribe to the newsletter to know when I publish more content!
\ No newline at end of file
diff --git a/boxplot.html b/boxplot.html
index 58da0122..10f36e38 100644
--- a/boxplot.html
+++ b/boxplot.html
@@ -1,4 +1,4 @@
-Boxplot with React
Boxplot with React and d3.js
A boxplot summarizes the distribution of a numeric variable, often for several groups of a dataset. This page is a step-by-step guide on how to build a reusable boxplot component for the web using React and D3.js.
It starts by describing how to format the dataset and how to initialize the boxplot component. It then explains how to create a Box component that displays a single box. Finally, it shows how to render the boxplot and suggests a few variations. 🙇♂️.
The dataset used to build a boxplot is usually an array of objects. For each object, a name property provides the group name, and a value property provides the numeric value. It looks like this:
const data = [
+Boxplot with React
Boxplot with React and d3.js
A boxplot summarizes the distribution of a numeric variable, often for several groups of a dataset. This page is a step-by-step guide on how to build a reusable boxplot component for the web using React and D3.js.
It starts by describing how to format the dataset and how to initialize the boxplot component. It then explains how to create a Box component that displays a single box. Finally, it shows how to render the boxplot and suggests a few variations. 🙇♂️.
The dataset used to build a boxplot is usually an array of objects. For each object, a name property provides the group name, and a value property provides the numeric value. It looks like this:
I'm in the process of writing a complete blog post on the topic. Subscribe to the project to know when it's ready.
Boxplot inspiration
If you're looking for inspiration to create your next Boxplot, note that dataviz-inspiration.com showcases many examples. Definitely the best place to get ... inspiration!
dataviz-inspiration.com showcases hundreds of stunning dataviz projects. Have a look to get some ideas on how to make your Boxplot looks good!
Even if powerful to summarize the distribution of a numeric variable, the boxplot has flaws.
It indeed hides the underlying distribution. For instance, a low sample size or a bi-modal distribution is impossible to detect by reading the boxes only.
Jittering is a good workaround. Add all individual data points with low size, low opacity, and some random shift to the right or the left (jitter). The underlying distribution becomes instantly available.
Note that another good alternative is the violin plot, especially for a high sample size.
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data with gmail.com. You can also subscribe to the newsletter to know when I publish more content!
\ No newline at end of file
diff --git a/bubble-map.html b/bubble-map.html
index f0ba8476..2464a5e7 100644
--- a/bubble-map.html
+++ b/bubble-map.html
@@ -1,4 +1,4 @@
-How to build a bubble map component with React and D3.
Bubble Map
A bubble map uses circles of different size to represent a numeric value on a territory. It displays one bubble per geographic coordinate, or one bubble per region.
This page explains how to build bubble maps for the web using d3.js and react. Several tools can be used to display the background map as shown in the dedicated section. Circles are then computed with d3 and render using SVG or canvas elements with react.
Examples start easy and add layers of complexity progressively. You will always find explanations and code sandboxes for each step.
Two pieces of information are required to build a bubble map:
→ Geographic information
The first thing you need is the 2d coordinates of the boundaries of the regions you want to represent. If you are trying to build a world map, you need to know where the country boundaries are located 🤷♀️.
Several formats exist to store such a piece of information. When working with d3.js, the expected format is geoJSON. A geoJSON file looks pretty much like this:
{
+How to build a bubble map component with React and D3.
Bubble Map
A bubble map uses circles of different size to represent a numeric value on a territory. It displays one bubble per geographic coordinate, or one bubble per region.
This page explains how to build bubble maps for the web using d3.js and react. Several tools can be used to display the background map as shown in the dedicated section. Circles are then computed with d3 and render using SVG or canvas elements with react.
Examples start easy and add layers of complexity progressively. You will always find explanations and code sandboxes for each step.
Two pieces of information are required to build a bubble map:
→ Geographic information
The first thing you need is the 2d coordinates of the boundaries of the regions you want to represent. If you are trying to build a world map, you need to know where the country boundaries are located 🤷♀️.
Several formats exist to store such a piece of information. When working with d3.js, the expected format is geoJSON. A geoJSON file looks pretty much like this:
A bubble chart component that smoothly animates changes between datasets.
Animation in dataviz using React is a big topic. It's impossible to go in-depth here! I will publish a dedicated blog post on the topic soon. Please subscribe to the newsletter if you want to be notified.
Bubble inspiration
If you're looking for inspiration to create your next Bubble, note that dataviz-inspiration.com showcases many examples. Definitely the best place to get ... inspiration!
dataviz-inspiration.com showcases hundreds of stunning dataviz projects. Have a look to get some ideas on how to make your Bubble looks good!
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data with gmail.com. You can also subscribe to the newsletter to know when I publish more content!
\ No newline at end of file
diff --git a/bubble-plot.html b/bubble-plot.html
index 0d6c8094..b1f5a101 100644
--- a/bubble-plot.html
+++ b/bubble-plot.html
@@ -1,4 +1,4 @@
-Bubble plot with React
Bubble plot
A bubble plot is an extension of a scatterplot, where each circle has its size proportional to a numeric value. This page is a step-by-step guide on how to build your own bubble chart for the web, using React and D3.js.
This page focuses on the implementation of features that are different from the scatterplot that has its dedicated section. It describes how the dataset differs, how the circle size can be mapped to a numeric value, and how to explicit it using a legend. Last but not least it explains how to add interactivity: hover effect, tooltip, and dataset transition. 🙇♂️.
The dataset used to build a bubble plot is usually an array of objects where each object is a data point. For each object, at least 3 properties are required.
Two properties are used for the X and Y axis, the third one is used for the circle size.
Note that you can add more properties to the object. For instance, a name can be displayed in the tooltip, and a group can be used to color the bubbles.
const data = [
+Bubble plot with React
Bubble plot
A bubble plot is an extension of a scatterplot, where each circle has its size proportional to a numeric value. This page is a step-by-step guide on how to build your own bubble chart for the web, using React and D3.js.
This page focuses on the implementation of features that are different from the scatterplot that has its dedicated section. It describes how the dataset differs, how the circle size can be mapped to a numeric value, and how to explicit it using a legend. Last but not least it explains how to add interactivity: hover effect, tooltip, and dataset transition. 🙇♂️.
The dataset used to build a bubble plot is usually an array of objects where each object is a data point. For each object, at least 3 properties are required.
Two properties are used for the X and Y axis, the third one is used for the circle size.
Note that you can add more properties to the object. For instance, a name can be displayed in the tooltip, and a group can be used to color the bubbles.
A bubble chart component that smoothly animates changes between datasets.
Animation in dataviz using React is a big topic. It's impossible to go in-depth here! I will publish a dedicated blog post on the topic soon. Please subscribe to the newsletter if you want to be notified.
Real-life application
Let's apply the concepts learned above to a real-life example.
I like this scatterplot originally published on the data wrapper blog. It shows a strong correlation between vulnerability to climate change and CO2 emissions.
The chart has several features that are interesting to reproduce from a technical point of view:
Custom annotation: only a fraction of the country names are written
Hover effect: the hovered country is highlighted with a black stroke. After a short delay, countries of other groups are dimmed. Note that the effect is triggered once the mouse approaches the marker, no need to be perfectly on top.
Tooltip: highly customized and linked to the mouse position
The countries with the highest vulnerability to climate change have the lowest CO2 emissions
All countries sorted by their vulnerability and readiness to climate change. The size shows the CO2 emission per person in that country.
Reproduction of a chart originally published by Data Wrapper using react and d3.js.
Variations
Once you've understood how to build a basic bubble chart with d3 and react, it opens an infinite world of customization. Here are a few examples using the same concepts.
Click on the overview below to get details and code.
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data with gmail.com. You can also subscribe to the newsletter to know when I publish more content!
\ No newline at end of file
diff --git a/build-axis-with-react.html b/build-axis-with-react.html
index f4f9a96e..d851d0da 100644
--- a/build-axis-with-react.html
+++ b/build-axis-with-react.html
@@ -1,4 +1,4 @@
-Building graph axes with React (and d3.js)
Building graph axes with React (and d3.js)
This post explains how to build axes from d3 scales for a chart. It relies on the tick() method to compute the tick positions and use react for the rendering. The code of the BottomAxis and LeftAxiscomponents is provided, together with some reproducible examples.
This minimal example uses scaleLinear() to compute the scales, ticks() to compute tick positions and react to render the axes.
Bottom Axis
The code snippet below builds a AxisBottom component. It is very much inspired from this blogpost by Amelia Wattenberger. I've just changed a few things, notably passing a scale as input instead of a range and a domain.
The logic mainly relies on the ticks() method of a d3 scale. It takes a target number of ticks as input, find the most appropriate way to build smart ticks based on this target, and returns an array with all the tick positions.
What follows is just some svg drawings based on those tick positions.
This post explains how to build axes from d3 scales for a chart. It relies on the tick() method to compute the tick positions and use react for the rendering. The code of the BottomAxis and LeftAxiscomponents is provided, together with some reproducible examples.
This minimal example uses scaleLinear() to compute the scales, ticks() to compute tick positions and react to render the axes.
Bottom Axis
The code snippet below builds a AxisBottom component. It is very much inspired from this blogpost by Amelia Wattenberger. I've just changed a few things, notably passing a scale as input instead of a range and a domain.
The logic mainly relies on the ticks() method of a d3 scale. It takes a target number of ticks as input, find the most appropriate way to build smart ticks based on this target, and returns an array with all the tick positions.
What follows is just some svg drawings based on those tick positions.
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data with gmail.com. You can also subscribe to the newsletter to know when I publish more content!
\ No newline at end of file
diff --git a/cartogram.html b/cartogram.html
index 371dc093..a46af757 100644
--- a/cartogram.html
+++ b/cartogram.html
@@ -1,4 +1,4 @@
-How to build a cartogram with React and D3.
Cartogram
A cartogram is a map in which the geometry of regions is distorted in order to convey the information of an alternate variable.
It is possible to build a Cartogram react component thanks to a js library called topogram. This page provides step-by-step explanations on how to use the library based on a geoJson file with the help of d3.js for manipulating such a data source.
Probably uses the same as for a choropleth map or for a bubble map.
The Topogram library
As far as I can tell the best way to create a cartogram in JS is the topogram library.
However it looks like there is no easy way to install it using npm. The easiest way is probably to clone the repo and create the build, or to copy the content of the cartogram.js file.
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data with gmail.com. You can also subscribe to the newsletter to know when I publish more content!
+How to build a cartogram with React and D3.
Cartogram
A cartogram is a map in which the geometry of regions is distorted in order to convey the information of an alternate variable.
It is possible to build a Cartogram react component thanks to a js library called topogram. This page provides step-by-step explanations on how to use the library based on a geoJson file with the help of d3.js for manipulating such a data source.
Probably uses the same as for a choropleth map or for a bubble map.
The Topogram library
As far as I can tell the best way to create a cartogram in JS is the topogram library.
However it looks like there is no easy way to install it using npm. The easiest way is probably to clone the repo and create the build, or to copy the content of the cartogram.js file.
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data with gmail.com. You can also subscribe to the newsletter to know when I publish more content!
\ No newline at end of file
diff --git a/chord-diagram.html b/chord-diagram.html
index 833d2882..2b08672c 100644
--- a/chord-diagram.html
+++ b/chord-diagram.html
@@ -1,4 +1,4 @@
-How to build a chord diagram with React and D3.
Chord diagram
A chord diagram represents flows between several entities called nodes. Each node is represented by a fragment on the outer part of the circular layout. Then, arcs are drawn between each entities. The size of the arc is proportional to the importance of the flow..
Building a chord diagram with React and D3.js relies on the d3-chord module that computes the node and arc positions for us. React can then be used to draw everything in SVG. This page is a step by step tutorial with code sandboxes. It will teach you how to build a ChordDiagram component.
The dataset required to build a chord diagram is a square matrix. It has a dimension of n x n where n is the number of nodes.
In javascript, this matrix is represented as an array of n array. Each individual array also has n items. The matrix of flow has a direction: the second item of the third row gives the flow from element 2 to element 3.
Usually an additional array is provided, giving the name of each node.
Here is a minimal example of the data structure:
// matrix of flow
+How to build a chord diagram with React and D3.
Chord diagram
A chord diagram represents flows between several entities called nodes. Each node is represented by a fragment on the outer part of the circular layout. Then, arcs are drawn between each entities. The size of the arc is proportional to the importance of the flow..
Building a chord diagram with React and D3.js relies on the d3-chord module that computes the node and arc positions for us. React can then be used to draw everything in SVG. This page is a step by step tutorial with code sandboxes. It will teach you how to build a ChordDiagram component.
The dataset required to build a chord diagram is a square matrix. It has a dimension of n x n where n is the number of nodes.
In javascript, this matrix is represented as an array of n array. Each individual array also has n items. The matrix of flow has a direction: the second item of the third row gives the flow from element 2 to element 3.
Usually an additional array is provided, giving the name of each node.
I'm in the process of writing a complete blog post on the topic. Subscribe to the project to know when it's ready.
Chord Diagram inspiration
If you're looking for inspiration to create your next Chord Diagram, note that dataviz-inspiration.com showcases many examples. Definitely the best place to get ... inspiration!
dataviz-inspiration.com showcases hundreds of stunning dataviz projects. Have a look to get some ideas on how to make your Chord Diagram looks good!
I suggest 2 improvements to get a descent chord diagram:
→ Colors
Pretty straightforward to implement. You just need to create an array of colors. Then, for each item to draw the index is always available. It can be used to retrieve the color in the color array.
→ Labels
A new prop needs to be passed to the component with a list of names for the nodes. I suggest to position labels as for a donut chart but many other possibilities are available.
Connections between nodes are drawn thanks to the ribbon() function of d3.js.
ToDoAdd section on hover effect
ToDoTalk about chordDirected() and chordTranspose()
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data with gmail.com. You can also subscribe to the newsletter to know when I publish more content!
\ No newline at end of file
diff --git a/choropleth-map.html b/choropleth-map.html
index 79a87434..13892146 100644
--- a/choropleth-map.html
+++ b/choropleth-map.html
@@ -1,4 +1,4 @@
-Building Choropleth Maps with React and D3.js: A Step-by-Step Tutorial
Choropleth Map
A choropleth map displays divided geographical areas or regions that are coloured in relation to a numeric variable. It enables the study of how a variable evolves across a geographical area.
Once you understood how to draw a map background from a geoJson file, it is just a matter of coloring each region with the appropriate color. On top of this, it is advised to add a color legend and some interactivity (hover effect and tooltip).
This webpage is a tutorial coming with explanation and code sandboxes. It explains how to build interactive choropleth map with React and D3.js.
Two pieces of information are required to build a choropleth map:
→ Geographic information
The first thing you need to build a choropleth map is the 2d coordinates of the boundaries of the regions you want to represent. If you are trying to build a world map, you need to know where the country boundaries are located 🤷♀️.
Several formats exist to store such a piece of information. When working with d3.js, the expected format is geoJSON. A geoJSON file looks pretty much like this:
{
+Building Choropleth Maps with React and D3.js: A Step-by-Step Tutorial
Choropleth Map
A choropleth map displays divided geographical areas or regions that are coloured in relation to a numeric variable. It enables the study of how a variable evolves across a geographical area.
Once you understood how to draw a map background from a geoJson file, it is just a matter of coloring each region with the appropriate color. On top of this, it is advised to add a color legend and some interactivity (hover effect and tooltip).
This webpage is a tutorial coming with explanation and code sandboxes. It explains how to build interactive choropleth map with React and D3.js.
Two pieces of information are required to build a choropleth map:
→ Geographic information
The first thing you need to build a choropleth map is the 2d coordinates of the boundaries of the regions you want to represent. If you are trying to build a world map, you need to know where the country boundaries are located 🤷♀️.
Several formats exist to store such a piece of information. When working with d3.js, the expected format is geoJSON. A geoJSON file looks pretty much like this:
Then you probably want to add some ticks on top of the color graduation to make it insightful.
Fortunately, the d3 linearScale comes with a handy tick() function. Basically, calling xScale.ticks(4) will create an array with approximately 4 items, each providing everything you need to draw a smartly located tick.
Color Legend is a big topic. There is much more to say about it and I'll post a complete blog post on the topic soon. Subscribe to the gallery if interested!
ToDoHover effect section
ToDoTalk more about color scale. Hover effect linked with color scale
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data with gmail.com. You can also subscribe to the newsletter to know when I publish more content!
\ No newline at end of file
diff --git a/circular-barplot.html b/circular-barplot.html
index fcadccec..cc68169c 100644
--- a/circular-barplot.html
+++ b/circular-barplot.html
@@ -1,4 +1,4 @@
-Circular Barplot with React
Circular Barplot
A circular barplot is a variation of a barplot where bars are displayed around a circle using polar coordinates. It is a less accurate representation of the data, but provides a strong eye-catching effect.
This page describes how to deal with radial coordinates with d3.js and react to build a circular barplot. It's a step by step tutorial with several interactive sandboxes.
The dataset required to build a circular barplot is usually an array where each item is an object providing the name and the value of the group.
Here is a minimal example
const data = [
+Circular Barplot with React
Circular Barplot
A circular barplot is a variation of a barplot where bars are displayed around a circle using polar coordinates. It is a less accurate representation of the data, but provides a strong eye-catching effect.
This page describes how to deal with radial coordinates with d3.js and react to build a circular barplot. It's a step by step tutorial with several interactive sandboxes.
Not much to add. Just include the paths in a svg element. Remember that 0,0 is the center of the chart instead of being the top-left corner. So we need to apply a translate at some point.
Most basic circular barplot built with d3.js and react, using radial coordinates and path instead of rect.
That's a good start but it looks pretty much like a snail so far. Let's make it a real chart with labels and values.
Labels
It is necessary to add a text element to show the name of each bar.
We need those labels to be readable (like not written upside down). So a bit of logic is necessary to determine wether or not a label must be flipped, and how to position it properly.
To do so it is necessary to switch from radians (use for the xScale) to degrees (used for the transform property).
Please check the code below for full explanation.
Add some labels to each bar of the circular barchart to make it insightful
Circular Barplot inspiration
If you're looking for inspiration to create your next Circular Barplot, note that dataviz-inspiration.com showcases many examples. Definitely the best place to get ... inspiration!
dataviz-inspiration.com showcases hundreds of stunning dataviz projects. Have a look to get some ideas on how to make your Circular Barplot looks good!
Stacking is a process where a chart is broken up across more than one categoric variables which make up the whole.
d3 comes with some handy functions for stacking. The process is extensively described in this stacked barplot tutorial. There is nothing really different to make it circular and here is a working sandbox to discover the code.
Add some labels to each bar of the circular barchart to make it insightful
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data with gmail.com. You can also subscribe to the newsletter to know when I publish more content!
+})
→ Rendering
Not much to add. Just include the paths in a svg element. Remember that 0,0 is the center of the chart instead of being the top-left corner. So we need to apply a translate at some point.
Most basic circular barplot built with d3.js and react, using radial coordinates and path instead of rect.
That's a good start but it looks pretty much like a snail so far. Let's make it a real chart with labels and values.
Labels
It is necessary to add a text element to show the name of each bar.
We need those labels to be readable (like not written upside down). So a bit of logic is necessary to determine wether or not a label must be flipped, and how to position it properly.
To do so it is necessary to switch from radians (use for the xScale) to degrees (used for the transform property).
Please check the code below for full explanation.
Add some labels to each bar of the circular barchart to make it insightful
Circular Barplot inspiration
If you're looking for inspiration to create your next Circular Barplot, note that dataviz-inspiration.com showcases many examples. Definitely the best place to get ... inspiration!
dataviz-inspiration.com showcases hundreds of stunning dataviz projects. Have a look to get some ideas on how to make your Circular Barplot looks good!
Stacking is a process where a chart is broken up across more than one categoric variables which make up the whole.
d3 comes with some handy functions for stacking. The process is extensively described in this stacked barplot tutorial. There is nothing really different to make it circular and here is a working sandbox to discover the code.
Add some labels to each bar of the circular barchart to make it insightful
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data with gmail.com. You can also subscribe to the newsletter to know when I publish more content!
\ No newline at end of file
diff --git a/circular-packing.html b/circular-packing.html
index 5579012e..9f50d5a5 100644
--- a/circular-packing.html
+++ b/circular-packing.html
@@ -1,4 +1,4 @@
-Circular Packing chart with React
Circular Packing
A circular packing chart displays a hierarchical dataset as a set of nested circles, each circle representing a node of the data structure. Size is usually proportional to a numeric variable.
This page is a tutorial teaching how to create a circle pack chart with d3.js and React. It starts with a very basic version, adds some levels of nesting and finishes with usual customization like animating the transition between datasets.
The dataset describes a hierarchy using a recursive structure. It is similar to a dendrogram or to a treemap.
Each item in this structure is called a node, the lowest nodes of the hierarchy being called leaves. The dataset is an object that has at least 3 properties: name, value and children. Children is an array of nodes that have this structure too.
Here is a minimal example of the data structure:
const data = {
+Circular Packing chart with React
Circular Packing
A circular packing chart displays a hierarchical dataset as a set of nested circles, each circle representing a node of the data structure. Size is usually proportional to a numeric variable.
This page is a tutorial teaching how to create a circle pack chart with d3.js and React. It starts with a very basic version, adds some levels of nesting and finishes with usual customization like animating the transition between datasets.
The dataset describes a hierarchy using a recursive structure. It is similar to a dendrogram or to a treemap.
Each item in this structure is called a node, the lowest nodes of the hierarchy being called leaves. The dataset is an object that has at least 3 properties: name, value and children. Children is an array of nodes that have this structure too.
This component uses the useSpring hook of react spring to interpolate the cx, cy and r properties. Those values are passed to a special svg element (animated.circle) that does the animation.
Animating the transition between 2 similar dataset with react and d3.js (for rendering) and react spring (for animation).
Animation in dataviz using React is a big topic. It's impossible to go in depth here! I will publish a dedicated blog post on the topic soon. Please subscribe to the newsletter if you want to be notified.
ToDoBetter dataset transition where circle keep position
Variations
Once you've understood how to build a basic circular packing with d3 and react, it opens an infinite world of customization. Here are a few examples using the same concepts.
Click on the overview below to get details and code.
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data with gmail.com. You can also subscribe to the newsletter to know when I publish more content!
\ No newline at end of file
diff --git a/connected-scatter-plot.html b/connected-scatter-plot.html
index 90760d06..0b5bc23a 100644
--- a/connected-scatter-plot.html
+++ b/connected-scatter-plot.html
@@ -1,4 +1,4 @@
-Connected scatterplot with React and D3.js
Connected Scatterplot
A connected scatterplot displays the evolution of a numeric variable. Data points are represented by a dot and connected with straight line segments. A variation of the connected scatterplot allows to study the evolution of 2 numeric variables together.
This page explains how to build a connected scatterplot using react andd3.js. It is highly connected with the line chart section of the gallery but provides further information concerning connected scatterplot specific features.
The dataset required to build a connected scatterplot is the same as for a line chart. It is usually an array where each item is an object providing the x and the y values of the data point.
Here is a minimal example:
const data = [
+Connected scatterplot with React and D3.js
Connected Scatterplot
A connected scatterplot displays the evolution of a numeric variable. Data points are represented by a dot and connected with straight line segments. A variation of the connected scatterplot allows to study the evolution of 2 numeric variables together.
This page explains how to build a connected scatterplot using react andd3.js. It is highly connected with the line chart section of the gallery but provides further information concerning connected scatterplot specific features.
The dataset required to build a connected scatterplot is the same as for a line chart. It is usually an array where each item is an object providing the x and the y values of the data point.
I'm in the process of writing a complete blog post on the topic. Subscribe to the project to know when it's ready.
ToDoadd links to line chart examples
ToDoreproduce the connected scatter from the state of JS survey
Connected Scatter inspiration
If you're looking for inspiration to create your next Connected Scatter, note that dataviz-inspiration.com showcases many examples. Definitely the best place to get ... inspiration!
dataviz-inspiration.com showcases hundreds of stunning dataviz projects. Have a look to get some ideas on how to make your Connected Scatter looks good!
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data with gmail.com. You can also subscribe to the newsletter to know when I publish more content!
\ No newline at end of file
diff --git a/connection-map.html b/connection-map.html
index fc771433..c7336ad7 100644
--- a/connection-map.html
+++ b/connection-map.html
@@ -1,4 +1,4 @@
-How to build a connection map component with React and D3.
Connection Map
A connection map is a map where links between geographical positions are represented using lines or arcs. Most of the time, great circles are used.
This page explains how to build connection maps for the web using d3.js and react. Several tools can be used to display the background map as shown in the dedicated section. The path used to show the connection can then be computed thanks to the geoPath() function of d3.
Two pieces of information are required to build a connection map:
→ Geographic information
The first thing you need is the 2d coordinates of the boundaries of the regions you want to represent. If you are trying to build a world map, you need to know where the country boundaries are located 🤷♀️.
Several formats exist to store such a piece of information. When working with d3.js, the expected format is geoJSON. A geoJSON file looks pretty much like this:
{
+How to build a connection map component with React and D3.
Connection Map
A connection map is a map where links between geographical positions are represented using lines or arcs. Most of the time, great circles are used.
This page explains how to build connection maps for the web using d3.js and react. Several tools can be used to display the background map as shown in the dedicated section. The path used to show the connection can then be computed thanks to the geoPath() function of d3.
Two pieces of information are required to build a connection map:
→ Geographic information
The first thing you need is the 2d coordinates of the boundaries of the regions you want to represent. If you are trying to build a world map, you need to know where the country boundaries are located 🤷♀️.
Several formats exist to store such a piece of information. When working with d3.js, the expected format is geoJSON. A geoJSON file looks pretty much like this:
I'm in the process of writing a complete blog post on the topic. Subscribe to the project to know when it's ready.
Connection inspiration
If you're looking for inspiration to create your next Connection, note that dataviz-inspiration.com showcases many examples. Definitely the best place to get ... inspiration!
dataviz-inspiration.com showcases hundreds of stunning dataviz projects. Have a look to get some ideas on how to make your Connection looks good!
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data with gmail.com. You can also subscribe to the newsletter to know when I publish more content!
\ No newline at end of file
diff --git a/correlogram.html b/correlogram.html
index 770a0a22..fb726632 100644
--- a/correlogram.html
+++ b/correlogram.html
@@ -1,4 +1,4 @@
-Correlogram with React
Correlogram
In this blog post, we will be exploring how to build a correlogram with React and D3.js. A correlogram is a graphical representation of the correlation matrix for a given dataset. It is a useful tool for visualizing the relationships between different variables in a dataset, and can help identify potential correlations that may not be immediately obvious.
Building a correlogram with React and D3.js allows us to create a highly interactive and customizable visualization. We will be able to use React's powerful component-based approach to build our visualization, while leveraging the flexibility and power of D3.js to create a dynamic and engaging visual representation of our data.
A correlogram uses histograms to show the distribution of each numeric variable on the diagonal of the matrix. It uses scatter plots to show the relationship of each pair of variable on every other cells.
As a result, it is required to understand how to build a histogram and a scatter plot component using React and d3.js! In this post, we will just show how to leverage those reusable components to build a correlogram.
The Data
The dataset provides several numeric values for a set of data points. It can also add some categorical variables that can be added to customize the marker colors.
The suggested data structure is an array of object, where each object is a data point. It can have as many numeric properties as needed.
Here is a minimal example of the data structure:
const data = [
+Correlogram with React
Correlogram
In this blog post, we will be exploring how to build a correlogram with React and D3.js. A correlogram is a graphical representation of the correlation matrix for a given dataset. It is a useful tool for visualizing the relationships between different variables in a dataset, and can help identify potential correlations that may not be immediately obvious.
Building a correlogram with React and D3.js allows us to create a highly interactive and customizable visualization. We will be able to use React's powerful component-based approach to build our visualization, while leveraging the flexibility and power of D3.js to create a dynamic and engaging visual representation of our data.
A correlogram uses histograms to show the distribution of each numeric variable on the diagonal of the matrix. It uses scatter plots to show the relationship of each pair of variable on every other cells.
As a result, it is required to understand how to build a histogram and a scatter plot component using React and d3.js! In this post, we will just show how to leverage those reusable components to build a correlogram.
The Data
The dataset provides several numeric values for a set of data points. It can also add some categorical variables that can be added to customize the marker colors.
The suggested data structure is an array of object, where each object is a data point. It can have as many numeric properties as needed.
And voilà, a first decent correlogram for your data analysis pipeline 😊. It's not perfect yet. You probably want to give more love to axes and labels, add hover effect and tooltips. But hopefully that's a good template to get started.
A correlogram built with react and d3.js. It shows the relationship between the 4 numeric variables of the famous iris dataset.
Note: You can compare this code with the pure d3 alternative. I find it much more readable.
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data with gmail.com. You can also subscribe to the newsletter to know when I publish more content!
\ No newline at end of file
diff --git a/course/animation/dealing-with-path.html b/course/animation/dealing-with-path.html
index d7c82de4..6b8af4b6 100644
--- a/course/animation/dealing-with-path.html
+++ b/course/animation/dealing-with-path.html
@@ -1 +1 @@
-Dealing with path
Dealing with path
Thanks to the previous lessons we have a pretty solid understanding of react-spring, allowing to animate all the shapes on a graph, leading to a pretty nice bubble chart smooth transition.
There is one piece missing in the puzzle though. How are we going to deal with path, to build transitions on charts like the line chart or the streamgraph?
Wip
4 minutes read
The problem
Until now we've aanimated the transition of many features: position, size, color, text...
This is kind of straightforward! If I tell you to animate a position from 0 to 100, you understand that you just need to infer positions (numbers) between those 2 values.
Now, if the first path is M0,100 L 100,200 and that the next path is M100,150 L200, 300, it is not so obvious how to go from 1 to the other!
The good news
react spring KNOWS how to transition between paths that have the same number of points.
Click on the buttons to trigger a smooth transition between the 2 line charts.
The bad news
react spring does NOT know how to transition between 2 paths that are highly different = not the same number of points. In this case, we need to use custom interpolation and the best tool for that is flubber.
Offset typeCurve type
Try d3.js various options to offset the data and smooth shapes. See a smooth transition between options.
Even fursther, show the boxplot - violin plot transition
Transition from a pie chart to a barplot with a smooth animation using the buttons on top.
Thanks to the previous lessons we have a pretty solid understanding of react-spring, allowing to animate all the shapes on a graph, leading to a pretty nice bubble chart smooth transition.
There is one piece missing in the puzzle though. How are we going to deal with path, to build transitions on charts like the line chart or the streamgraph?
Wip
4 minutes read
The problem
Until now we've aanimated the transition of many features: position, size, color, text...
This is kind of straightforward! If I tell you to animate a position from 0 to 100, you understand that you just need to infer positions (numbers) between those 2 values.
Now, if the first path is M0,100 L 100,200 and that the next path is M100,150 L200, 300, it is not so obvious how to go from 1 to the other!
The good news
react spring KNOWS how to transition between paths that have the same number of points.
Click on the buttons to trigger a smooth transition between the 2 line charts.
The bad news
react spring does NOT know how to transition between 2 paths that are highly different = not the same number of points. In this case, we need to use custom interpolation and the best tool for that is flubber.
Offset typeCurve type
Try d3.js various options to offset the data and smooth shapes. See a smooth transition between options.
Even fursther, show the boxplot - violin plot transition
Transition from a pie chart to a barplot with a smooth animation using the buttons on top.
\ No newline at end of file
diff --git a/course/animation/enter-update-exit.html b/course/animation/enter-update-exit.html
index 4e18a159..fb1facc5 100644
--- a/course/animation/enter-update-exit.html
+++ b/course/animation/enter-update-exit.html
@@ -1 +1 @@
-Enter, Update, Exit
Enter, Update, Exit
In the previous lesson we've made our first animated scatterplot! 🎉
But it was an easy one: the same exact group were available in each dataset. Now how do we manage groups that enter for the first time, or are not available anymore?
Wip
4 minutes read
The problem
I need an example where I see a disparition and an apparition
Ok but there is a problem now: how do we deal with the data points that enter the dataset, or the one that exit?
That's the plan for the next lesson.
For the enter part, we can manage it thanks to the from property of useSpring
For the exit part, I would need to make it using another hook: useTransition
Element id
Explain what happens if the elements are not in the right order? Explain that the key of the element is important
In the previous lesson we've made our first animated scatterplot! 🎉
But it was an easy one: the same exact group were available in each dataset. Now how do we manage groups that enter for the first time, or are not available anymore?
Wip
4 minutes read
The problem
I need an example where I see a disparition and an apparition
Ok but there is a problem now: how do we deal with the data points that enter the dataset, or the one that exit?
That's the plan for the next lesson.
For the enter part, we can manage it thanks to the from property of useSpring
For the exit part, I would need to make it using another hook: useTransition
Element id
Explain what happens if the elements are not in the right order? Explain that the key of the element is important
\ No newline at end of file
diff --git a/course/animation/introduction.html b/course/animation/introduction.html
index 452081f4..daea6497 100644
--- a/course/animation/introduction.html
+++ b/course/animation/introduction.html
@@ -1 +1 @@
-Introduction
Introduction
Welcome to the world of animation! It’s exciting, but it can also get complex 😱.
In this first lesson, we’ll explore why animations can enhance data visualizations, when to use them (and when not to), and introduce the concept of spring animations.
Ready to get hands-on? We’ll dive into the code in the next lesson!
Free
4 minutes read
Why Use Animation?
Imagine you have a web app with a few charts to explore a dataset. Each chart can represent different groups within the data.
You could switch instantly between groups, but adding smooth, animated transitions gives the experience a polished, engaging feel.
Here’s an example, try clicking the buttons above the charts!
Types of Data Professionals
The field of data offers a diverse array of job titles, making it challenging to navigate without getting lost in the jargon and uncertainty about which roles to pursue. The charts below offer deeper insights into the competencies needed, salary ranges, and popularity trends for the four primary job titles.
Three charts with smooth dataset transition.
There are many advantages coming with those smooth animations!
Pros
Enhances Understanding: help viewers grasp changes over time or shifts in data by gradually showing differences, reducing cognitive load compared to abrupt changes.
Directs Attention: Animation naturally attracts attention, guiding users to focus on specific data points or trends, which can be especially useful in dashboards or interactive reports.
When used effectively, animations make applications more visually appealing, enhancing overall engagement.
❌ Yes, but
Animated transitions must be used carefully to avoid overwhelming or distracting users.
When overused or too complex, animations can create visual clutter, drawing attention away from important data or insights.
Long or intricate animations can also slow down user interactions, which can frustrate users and reduce usability.
If you're hesitant to add an animation in your app, keep this citation by Josh Comeau in mind:
Animation is like salt: too much of it spoils the dish
☯️ 2 types if animation
There are two main types of animations: CSS and spring.
→ CSS animations are simple, using keyframes to create smooth transitions for things like fades, spins, and hover effects. They’re efficient but lack flexibility for interactive or dynamic animations.
→ Spring animations, on the other hand, mimic real-world physics by adding effects like bounce and decay, making them ideal for interactive elements that respond naturally to user input.
There are 2 main ways to animate stuff on the web: CSS and spring-based animations.
Each type serves different purposes: CSS is great for simple, efficient transitions, while spring animations create dynamic, realistic movement. Think of spring physics as a secret ingredient that makes animations feel more alive.
I’d love to dive deeper into spring animations, but Josh Comeau has introduced the concept so brilliantly that it’s worth reading his explanation. If you want a better understanding of the why before tackling the how, check out his work here.
Welcome to the world of animation! It’s exciting, but it can also get complex 😱.
In this first lesson, we’ll explore why animations can enhance data visualizations, when to use them (and when not to), and introduce the concept of spring animations.
Ready to get hands-on? We’ll dive into the code in the next lesson!
Free
4 minutes read
Why Use Animation?
Imagine you have a web app with a few charts to explore a dataset. Each chart can represent different groups within the data.
You could switch instantly between groups, but adding smooth, animated transitions gives the experience a polished, engaging feel.
Here’s an example, try clicking the buttons above the charts!
Types of Data Professionals
The field of data offers a diverse array of job titles, making it challenging to navigate without getting lost in the jargon and uncertainty about which roles to pursue. The charts below offer deeper insights into the competencies needed, salary ranges, and popularity trends for the four primary job titles.
Three charts with smooth dataset transition.
There are many advantages coming with those smooth animations!
Pros
Enhances Understanding: help viewers grasp changes over time or shifts in data by gradually showing differences, reducing cognitive load compared to abrupt changes.
Directs Attention: Animation naturally attracts attention, guiding users to focus on specific data points or trends, which can be especially useful in dashboards or interactive reports.
When used effectively, animations make applications more visually appealing, enhancing overall engagement.
❌ Yes, but
Animated transitions must be used carefully to avoid overwhelming or distracting users.
When overused or too complex, animations can create visual clutter, drawing attention away from important data or insights.
Long or intricate animations can also slow down user interactions, which can frustrate users and reduce usability.
If you're hesitant to add an animation in your app, keep this citation by Josh Comeau in mind:
Animation is like salt: too much of it spoils the dish
☯️ 2 types if animation
There are two main types of animations: CSS and spring.
→ CSS animations are simple, using keyframes to create smooth transitions for things like fades, spins, and hover effects. They’re efficient but lack flexibility for interactive or dynamic animations.
→ Spring animations, on the other hand, mimic real-world physics by adding effects like bounce and decay, making them ideal for interactive elements that respond naturally to user input.
There are 2 main ways to animate stuff on the web: CSS and spring-based animations.
Each type serves different purposes: CSS is great for simple, efficient transitions, while spring animations create dynamic, realistic movement. Think of spring physics as a secret ingredient that makes animations feel more alive.
I’d love to dive deeper into spring animations, but Josh Comeau has introduced the concept so brilliantly that it’s worth reading his explanation. If you want a better understanding of the why before tackling the how, check out his work here.
\ No newline at end of file
diff --git a/course/animation/project.html b/course/animation/project.html
index 32b2d753..916c0686 100644
--- a/course/animation/project.html
+++ b/course/animation/project.html
@@ -1 +1 @@
-Project
Project
Let's apply everything we know to create a good, interactive viz!
Wip
4 minutes read
Types of Data Professionals
The field of data offers a diverse array of job titles, making it challenging to navigate without getting lost in the jargon and uncertainty about which roles to pursue. The charts below offer deeper insights into the competencies needed, salary ranges, and popularity trends for the four primary job titles.
Dive deep into the 4 main types of Data Professionals. Understand their main required competencies, their salary ranges and their popularity.
Let's apply everything we know to create a good, interactive viz!
Wip
4 minutes read
Types of Data Professionals
The field of data offers a diverse array of job titles, making it challenging to navigate without getting lost in the jargon and uncertainty about which roles to pursue. The charts below offer deeper insights into the competencies needed, salary ranges, and popularity trends for the four primary job titles.
Dive deep into the 4 main types of Data Professionals. Understand their main required competencies, their salary ranges and their popularity.
\ No newline at end of file
diff --git a/course/animation/react-spring-for-dataviz.html b/course/animation/react-spring-for-dataviz.html
index 1872e5db..851896f0 100644
--- a/course/animation/react-spring-for-dataviz.html
+++ b/course/animation/react-spring-for-dataviz.html
@@ -1,4 +1,4 @@
-Introduction to react-spring for data visualization
Introduction to react-spring for data visualization
Web animations fall into two main categories: CSS and spring-based animations.
In this lesson, we’ll explore react-spring, a popular library for creating spring-based animations in React. Let’s see how to use it to bring our graph elements to life.
Wip
4 minutes read
Animating a Circle
Let’s start with something simple for this first lesson.
Our goal is to animate a circle moving smoothly from one position to another. Here’s what the final effect will look like:
Pretty cool, right? 🙃
To achieve this, we’ll use react-spring, the most popular JavaScript library for spring-based animations.
react-spring homepage. The most famous lib for javascript animation (28k stars on github)
Full code
react-spring is incredibly powerful, but it can be a bit tricky to grasp, and I personally find its documentation a little unclear. 😞
For now, the two key features we need are the useSpring hook and the animated component.
With these two tools, we can create a Circle component that accepts a position prop. Whenever a new position value is passed, the circle smoothly transitions to its new location.
Here’s how the Circle component looks:
+Introduction to react-spring for data visualization
Introduction to react-spring for data visualization
Web animations fall into two main categories: CSS and spring-based animations.
In this lesson, we’ll explore react-spring, a popular library for creating spring-based animations in React. Let’s see how to use it to bring our graph elements to life.
Wip
4 minutes read
Animating a Circle
Let’s start with something simple for this first lesson.
Our goal is to animate a circle moving smoothly from one position to another. Here’s what the final effect will look like:
Pretty cool, right? 🙃
To achieve this, we’ll use react-spring, the most popular JavaScript library for spring-based animations.
react-spring homepage. The most famous lib for javascript animation (28k stars on github)
Full code
react-spring is incredibly powerful, but it can be a bit tricky to grasp, and I personally find its documentation a little unclear. 😞
For now, the two key features we need are the useSpring hook and the animated component.
With these two tools, we can create a Circle component that accepts a position prop. Whenever a new position value is passed, the circle smoothly transitions to its new location.
Here’s how the Circle component looks:
import { animated, useSpring } from 'react-spring';
export const Circle = ({ position }) => {
@@ -48,4 +48,4 @@
r={springProps.position.to((pos) => pos / 10)}
/>
);
-
This is called interpolation in react-spring terminology. You can learn more about it in the full documentation here.
Let’s take a look at the result!
Smooth animation where circle size is derived from X position.
Animating Text
So far, we’ve only animated numerical values—like smoothly transitioning the position from 1 to 100.
But react-spring is much more powerful than that! It can animate almost anything, including text and colors!
In the example below, watch how the number evolves progressively:
Demo: react-spring can also animate text, colors and so much more!
\ No newline at end of file
diff --git a/course/animation/scatterplot.html b/course/animation/scatterplot.html
index aa5361d7..d2c0c43a 100644
--- a/course/animation/scatterplot.html
+++ b/course/animation/scatterplot.html
@@ -1,4 +1,4 @@
-Application on a scatterplot
Application on a scatterplot
In the previous lesson, we explored animating SVG and HTML elements with react-spring.
Now, let's apply that knowledge to a real-world graph by animating the transition between two datasets on a scatterplot.
Wip
4 minutes read
Most basic example
Smooth dataset transition
How can we smoothly animate the transition between 2 datasets on a bubble chart? The chart used in this blog post can be drawn for several different years. You can use the select button on top to select the year, and the bubbles will animate to their new position.
This is possible thanks to the react spring library. Basically, instead of rendering usual circle elements, the library provides an animated.circle element, that is linked to a useSpringhook.
This is what the Circle component I use looks like:
import { useSpring, animated } from "@react-spring/web";
+Application on a scatterplot
Application on a scatterplot
In the previous lesson, we explored animating SVG and HTML elements with react-spring.
Now, let's apply that knowledge to a real-world graph by animating the transition between two datasets on a scatterplot.
Wip
4 minutes read
Most basic example
Smooth dataset transition
How can we smoothly animate the transition between 2 datasets on a bubble chart? The chart used in this blog post can be drawn for several different years. You can use the select button on top to select the year, and the bubbles will animate to their new position.
This is possible thanks to the react spring library. Basically, instead of rendering usual circle elements, the library provides an animated.circle element, that is linked to a useSpringhook.
This is what the Circle component I use looks like:
\ No newline at end of file
diff --git a/course/axis/axis-variations.html b/course/axis/axis-variations.html
index 0ac39981..89c4f6a8 100644
--- a/course/axis/axis-variations.html
+++ b/course/axis/axis-variations.html
@@ -1 +1 @@
-Axis component variations
Axis component variations
In the previous lesson we made a reusable component for the bottom axis.
This lesson suggests many variation: left axis, adding grids, dealing with titles...
Wip
4 minutes read
Gallery
Show a gallery with the various axis styles available in the gallery.
I need a first series of button: linear / ordinal / bandwidth / time / any = type of scale
Then a second series: left / bottom
Then it shows all the example in the gallery using this setup with a set of images
When user clicks on an image, it opens the sandbox so user has the code ready to copy paste.
\ No newline at end of file
diff --git a/course/axis/axis-with-d3.html b/course/axis/axis-with-d3.html
index 24135b94..1cf0a26b 100644
--- a/course/axis/axis-with-d3.html
+++ b/course/axis/axis-with-d3.html
@@ -1,4 +1,4 @@
-Alternative: use d3 helper
Alternative: use d3 helper
The previous lessons taught us how to build React axis components that can be used in any of your charts.
However, there's an alternative worth mentioning: D3 can also draw axes. Let's explore this option and see which one works best for you.
Free
4 minutes read
The d3 axis module
D3 has a whole module dedicated to drawing axes! It is called ... d3-axis 🙃
It performs essentially the same function as the AxisBottom andAxisLeft components we created in the previous lesson: taking a scale and rendering lines and ticks based on it on the screen.
A few axes made with d3.js and its d3-axis module.
😳 Did you say rendering?
We have a challenge: in a React environment where rendering is managed by React, how can we delegate part of the rendering process to D3?
This is possible using a react useEffect()!
Here is an example:
This axis is rendered using d3. The d3 necessary functions are called from a useEffect
How to Use D3 to Render Axes in a React App
Let's clarify the code from the example above.
⛳️ Using a ref
A ref acts as a pointer to a specific part of the DOM. We need to initialize a ref and assign it to the SVG element we want to manipulate with JavaScript later on.
To create the ref, use the following code:
const axesRef = useRef(null);
Next, assign the ref to the <g> element where D3 will render the axis:
<g
+Alternative: use d3 helper
Alternative: use d3 helper
The previous lessons taught us how to build React axis components that can be used in any of your charts.
However, there's an alternative worth mentioning: D3 can also draw axes. Let's explore this option and see which one works best for you.
Free
4 minutes read
The d3 axis module
D3 has a whole module dedicated to drawing axes! It is called ... d3-axis 🙃
It performs essentially the same function as the AxisBottom andAxisLeft components we created in the previous lesson: taking a scale and rendering lines and ticks based on it on the screen.
A few axes made with d3.js and its d3-axis module.
😳 Did you say rendering?
We have a challenge: in a React environment where rendering is managed by React, how can we delegate part of the rendering process to D3?
This is possible using a react useEffect()!
Here is an example:
This axis is rendered using d3. The d3 necessary functions are called from a useEffect
How to Use D3 to Render Axes in a React App
Let's clarify the code from the example above.
⛳️ Using a ref
A ref acts as a pointer to a specific part of the DOM. We need to initialize a ref and assign it to the SVG element we want to manipulate with JavaScript later on.
To create the ref, use the following code:
const axesRef = useRef(null);
Next, assign the ref to the <g> element where D3 will render the axis:
Both options have their merits, each with its own set of pros and cons. Personally, I prefer the React component approach for creating axes. Here’s why:
🎨 Styling: You can customize axis elements individually, allowing for precise styling.
🔄 Lifecycle: When using D3 to create axes, they operate outside of React's lifecycle events, making it challenging to ensure they update at the right times.
♻️ Reusability: React emphasizes the creation of reusable components. Building axes with D3 each time goes against this philosophy, which simplifies development.
🛠️ Maintainability / Readability: Other developers in your organization will likely find it easier to understand the SVG markup of the AxisBottom component compared to the D3.js functions from the d3-axis module.
\ No newline at end of file
+ .call(xAxisGenerator);
Done! 🎉
So, React or D3.js for Axes?
Both options have their merits, each with its own set of pros and cons. Personally, I prefer the React component approach for creating axes. Here’s why:
🎨 Styling: You can customize axis elements individually, allowing for precise styling.
🔄 Lifecycle: When using D3 to create axes, they operate outside of React's lifecycle events, making it challenging to ensure they update at the right times.
♻️ Reusability: React emphasizes the creation of reusable components. Building axes with D3 each time goes against this philosophy, which simplifies development.
🛠️ Maintainability / Readability: Other developers in your organization will likely find it easier to understand the SVG markup of the AxisBottom component compared to the D3.js functions from the d3-axis module.
\ No newline at end of file
diff --git a/course/axis/bottom-axis.html b/course/axis/bottom-axis.html
index 4cab7fde..7958a50b 100644
--- a/course/axis/bottom-axis.html
+++ b/course/axis/bottom-axis.html
@@ -1,4 +1,4 @@
-Build a bottom axis
Build a bottom axis
In the previous lesson, we learned how to manage margins effectively in our chart. Now, let's explore how to create a AxisBottom react component that draws a bottom axis!
Free
8 minutes read
🔍 More about scaleLinear()
In the previous lessons we talked a lot about the scaleLinear() function of d3.js.
You should perfectly understand the code below. If not, go back to the scale module of this course!
const xScale = d3.scaleLinear()
+Build a bottom axis
Build a bottom axis
In the previous lesson, we learned how to manage margins effectively in our chart. Now, let's explore how to create a AxisBottom react component that draws a bottom axis!
Free
8 minutes read
🔍 More about scaleLinear()
In the previous lessons we talked a lot about the scaleLinear() function of d3.js.
You should perfectly understand the code below. If not, go back to the scale module of this course!
\ No newline at end of file
diff --git a/course/axis/introduction.html b/course/axis/introduction.html
index 73d608e5..688a607f 100644
--- a/course/axis/introduction.html
+++ b/course/axis/introduction.html
@@ -1 +1 @@
-Introduction
Introduction
In the previous module on scales, we learned how to position SVG shapes precisely, adding meaning to the growing graph we're constructing.
Now, it's time to provide context to these shape positions. For most chart types, this is achieved using axes. Axes can be complex elements, so let's explore how to create them effectively.
Free
2 minutes read
This module explains how to build axes like the one you can see at the bottom and on the left of this chart area.
Key Terminology
To work effectively with axes in data visualization, it's important to understand the key terms highlighted on the figure below.
While left and bottom axes are the most common, they aren’t the only options. In the previous module on scales, we created a barplot with the x-axis positioned at the top.
Right-side axes can also be useful, though they’re typically associated with dual y-axis line charts—a practice generally best avoided.
Margins
You may have noticed that axes take up some space! To accommodate them, we'll need to add margins around the chart area.
Managing margins can quickly become challenging, but don’t worry—I’ll show you a simple trick to make it easy.
In the previous module on scales, we learned how to position SVG shapes precisely, adding meaning to the growing graph we're constructing.
Now, it's time to provide context to these shape positions. For most chart types, this is achieved using axes. Axes can be complex elements, so let's explore how to create them effectively.
Free
2 minutes read
This module explains how to build axes like the one you can see at the bottom and on the left of this chart area.
Key Terminology
To work effectively with axes in data visualization, it's important to understand the key terms highlighted on the figure below.
While left and bottom axes are the most common, they aren’t the only options. In the previous module on scales, we created a barplot with the x-axis positioned at the top.
Right-side axes can also be useful, though they’re typically associated with dual y-axis line charts—a practice generally best avoided.
Margins
You may have noticed that axes take up some space! To accommodate them, we'll need to add margins around the chart area.
Managing margins can quickly become challenging, but don’t worry—I’ll show you a simple trick to make it easy.
\ No newline at end of file
diff --git a/course/axis/margin-and-translation.html b/course/axis/margin-and-translation.html
index 30ea58f2..ae6fe873 100644
--- a/course/axis/margin-and-translation.html
+++ b/course/axis/margin-and-translation.html
@@ -1,4 +1,4 @@
-Margin and translation
Margin and translation
Most chart types use a bottom and a left axis.
In these cases, we need to leave space for tick labels and axis titles. Let’s look at how to implement this effectively.
Free
4 minutes read
SVG Area and Bounds Area
Imagine an SVG area with a width of 500px and a height of 300px.
The left and bottom axes aren’t displayed right at the SVG border. Instead, we add margins on all sides: left, right, bottom, and top.
The area within these margins is known as the bounds, where the chart content is positioned between the x and y axes. In our code, we’ll refer to the width and height of this bounds area as boundsWidth and boundsHeight.
Anatomy of the chart areas: some margins are set all around the SVG area. The area inside is called the Bounds.
Implementation
A chart component often starts by defining its margins. An object with 4 properties is ideal for that:
const MARGIN = {
+Margin and translation
Margin and translation
Most chart types use a bottom and a left axis.
In these cases, we need to leave space for tick labels and axis titles. Let’s look at how to implement this effectively.
Free
4 minutes read
SVG Area and Bounds Area
Imagine an SVG area with a width of 500px and a height of 300px.
The left and bottom axes aren’t displayed right at the SVG border. Instead, we add margins on all sides: left, right, bottom, and top.
The area within these margins is known as the bounds, where the chart content is positioned between the x and y axes. In our code, we’ll refer to the width and height of this bounds area as boundsWidth and boundsHeight.
Anatomy of the chart areas: some margins are set all around the SVG area. The area inside is called the Bounds.
Implementation
A chart component often starts by defining its margins. An object with 4 properties is ideal for that:
const MARGIN = {
top: 10,
right: 30,
bottom: 50,
@@ -12,4 +12,4 @@
>
// ... all shapes go here
</g>
-</svg>
What's going on here? 😱
1️⃣ The SVG area is created as usual with the svg element, along with the specified width and height.
2️⃣ The g element is used to group other SVG elements, similar to how a div works in HTML. This group represents the bounds, defined by its boundsWidth and boundsHeight dimensions!
3️⃣ The transform property is used to translate the bounds slightly to the right and down, creating space for the left and top margins!
Exercices
Drawing the Axis
Now that we’ve created space for it, it’s time to draw the axis. Let’s build some reusable components for this!
1️⃣ The SVG area is created as usual with the svg element, along with the specified width and height.
2️⃣ The g element is used to group other SVG elements, similar to how a div works in HTML. This group represents the bounds, defined by its boundsWidth and boundsHeight dimensions!
3️⃣ The transform property is used to translate the bounds slightly to the right and down, creating space for the left and top margins!
Exercices
Drawing the Axis
Now that we’ve created space for it, it’s time to draw the axis. Let’s build some reusable components for this!
\ No newline at end of file
diff --git a/course/axis/project.html b/course/axis/project.html
index c935cbbe..553b2389 100644
--- a/course/axis/project.html
+++ b/course/axis/project.html
@@ -1,4 +1,4 @@
-Project
Project
We've built a solid foundation in D3, SVG, and scales! Now, let's put that knowledge to the test by recreating a barplot inspired by The Economist.
Wip
4 minutes read
Our Objective
In this lesson, we aim to recreate a chart from The Economist with several key design elements:
Title, subtitle, and footer
Grid lines with values displayed at the top
Inline labels placed inside or outside the bars
The data
The dataset is very simple! It looks like this:
data = [
+Project
Project
We've built a solid foundation in D3, SVG, and scales! Now, let's put that knowledge to the test by recreating a barplot inspired by The Economist.
Wip
4 minutes read
Our Objective
In this lesson, we aim to recreate a chart from The Economist with several key design elements:
\ No newline at end of file
diff --git a/course/canvas/combining-svg-and-canvas.html b/course/canvas/combining-svg-and-canvas.html
index cd86b471..00f259b6 100644
--- a/course/canvas/combining-svg-and-canvas.html
+++ b/course/canvas/combining-svg-and-canvas.html
@@ -1,4 +1,4 @@
-Combining SVG and Canvas
Combining SVG and Canvas
When displaying 100,000 circles in a scatterplot, using canvas is essential for performance.
However, SVG is still ideal for axes and lighter graphical elements. Let’s explore how to combine SVG and canvas effectively!
Free
4 minutes read
🍔 Stacking Canvas and SVG
In the previous lesson, we learned how to loop through a dataset and render a circle for each item. This is very close to creating a bubble chart! 🎉
In earlier modules, we explored how to add margins around the chart area and created reusable axis components to define the x and y scales.
The great news is that we can seamlessly combine both canvas and SVG, since, at the core, they're both HTML elements!
How to overlap SVG and Canvas layers to create a bubble plot.
🔎 How your DOM will look like
Below is some pseudocode demonstrating the JSX structure of the graph component.
Essentially, your SVG and canvas elements need to be absolutely positioned (using position: absolute) to stack correctly on top of each other.
A key point to remember is that absolutely positioned elements are positioned relative to the nearest positioned ancestor. So, make sure the parent div is set to position: relative, or the positioning won’t work as expected.
+Combining SVG and Canvas
Combining SVG and Canvas
When displaying 100,000 circles in a scatterplot, using canvas is essential for performance.
However, SVG is still ideal for axes and lighter graphical elements. Let’s explore how to combine SVG and canvas effectively!
Free
4 minutes read
🍔 Stacking Canvas and SVG
In the previous lesson, we learned how to loop through a dataset and render a circle for each item. This is very close to creating a bubble chart! 🎉
In earlier modules, we explored how to add margins around the chart area and created reusable axis components to define the x and y scales.
The great news is that we can seamlessly combine both canvas and SVG, since, at the core, they're both HTML elements!
How to overlap SVG and Canvas layers to create a bubble plot.
🔎 How your DOM will look like
Below is some pseudocode demonstrating the JSX structure of the graph component.
Essentially, your SVG and canvas elements need to be absolutely positioned (using position: absolute) to stack correctly on top of each other.
A key point to remember is that absolutely positioned elements are positioned relative to the nearest positioned ancestor. So, make sure the parent div is set to position: relative, or the positioning won’t work as expected.
\ No newline at end of file
diff --git a/course/canvas/drawing-shapes-with-canvas.html b/course/canvas/drawing-shapes-with-canvas.html
index e687ffe8..c47a44d2 100644
--- a/course/canvas/drawing-shapes-with-canvas.html
+++ b/course/canvas/drawing-shapes-with-canvas.html
@@ -1,4 +1,4 @@
-Drawing shapes with canvas
Drawing shapes with canvas
Remember the SVG module where we learned how to draw various shapes on the screen? Now, we'll be doing this again, but with canvas instead—and the approach is quite different!
Let's make some circles again! 🎉
Free
4 minutes read
Let's make a circle (again)
📍 Start with a canvas element
Everything begins with the DOM. In the return statement of our graph component, rather than rendering multiple SVG elements as we did previously,
we now render just a singlecanvas element.
return (
+Drawing shapes with canvas
Drawing shapes with canvas
Remember the SVG module where we learned how to draw various shapes on the screen? Now, we'll be doing this again, but with canvas instead—and the approach is quite different!
Let's make some circles again! 🎉
Free
4 minutes read
Let's make a circle (again)
📍 Start with a canvas element
Everything begins with the DOM. In the return statement of our graph component, rather than rendering multiple SVG elements as we did previously,
This approach is called imperative programming, as opposed to declarative programming, where we define everything directly in the DOM, like we did with SVG.
Next, we’ll need to “edit” the canvas by drawing on it. To achieve this, we need a reference to the canvas element so we can target it directly. Then, we can use useEffect to write the code for drawing inside it.
// define a ref = a way to target the canvas element
const canvasRef = useRef(null);
@@ -16,4 +16,4 @@
ctx.fill();
🔵 Complete circle example
A simple circle drawn with canvas
🟪 What about rectangles?
The process is almost identical!
The only change is the canvas call inside useEffect. This time, we’ll use the rect() function as shown:
ctx.beginPath();
ctx.rect(100, 100, 80, 50); // Draw the rectangle (x, y, width, height)
ctx.fillStyle = "purple";
-ctx.fill();
And that’s it! Here’s a complete example:
A simple Rectangle drawn with canvas
🍔 Stacking Order Matters
Drawing with canvas is a bit like using a pen on paper: whatever you draw second will always appear on top of what was drawn first!
For data visualizations, we need to carefully consider the stacking order, as there’s no way to change it afterward.
Similarly, individual elements can’t be removed from the canvas. The only option is to redraw everything from scratch—which isn’t an issue since it’s very fast.
Drawing with canvas is a bit like using a pen on paper: whatever you draw second will always appear on top of what was drawn first!
For data visualizations, we need to carefully consider the stacking order, as there’s no way to change it afterward.
Similarly, individual elements can’t be removed from the canvas. The only option is to redraw everything from scratch—which isn’t an issue since it’s very fast.
\ No newline at end of file
diff --git a/course/canvas/introduction.html b/course/canvas/introduction.html
index e0dac530..27166dfd 100644
--- a/course/canvas/introduction.html
+++ b/course/canvas/introduction.html
@@ -1,3 +1,3 @@
-What is it, and why is it useful?
What is it, and why is it useful?
By now, after completing the previous modules, you’re likely able to draw almost anything on the screen— including interactive elements like tooltips, hover effects, and animations.
However, there's a significant bottleneck: performance. Let's explore canvas, a rendering engine that can help solve this issue.
Free
4 minutes read
The Problem with SVG
SVG can be slow.
If you’re working with chart types that don’t involve too many elements, like simple line or bar charts, SVG will handle them well.
But if you create a scatterplot with 100,000 data points and layer on complex animations, you’ll likely run into performance troubles.
So, why is SVG slow?
🐢 Drawing SVG is CPU-Only
SVG rendering relies entirely on the CPU, with no GPU acceleration.
This means every shape, line, or point in an SVG graphic is drawn by the CPU, which can quickly become a bottleneck. Without the benefit of GPU power, rendering large amounts of data or intricate animations can be time-consuming and sluggish.
🏋️♀️ SVG Creates a Heavy DOM
Each element you draw in SVG is added as a separate line in the DOM.
For a large number of elements, this quickly bloats the DOM, which your browser has to continuously manage and render.
Adding event listeners to each element further increases the workload, as the browser must keep track of interactions on all these individual DOM nodes. And as the DOM grows, memory usage rises as well, which can lead to even more slowdowns.
Example
Here’s a small scatterplot with a few thousand data points and a hover effect that updates an internal state.
Hover over it with your mouse. Notice the lag? See how slow it gets?
With just a few graphs like this in your app, you can quickly reach a million nodes in the DOM 🙈.
When that happens, your entire app—or even the whole browser—can start to freeze as it struggles to manage the overwhelming number of elements.
So,
If your graph has a large number of elements or requires heavy animations, it’s best to move away from SVG and choose something more performant, like canvas.
⚡️ What is canvas, and why is it fast
Canvas provides a high-performance, low-level context for drawing 2D graphics, animations, and even simple games, giving you pixel-level control for faster rendering, especially with dynamic content or large datasets.
canvas is an HTML element! You can create one by writing:
+What is it, and why is it useful?
What is it, and why is it useful?
By now, after completing the previous modules, you’re likely able to draw almost anything on the screen— including interactive elements like tooltips, hover effects, and animations.
However, there's a significant bottleneck: performance. Let's explore canvas, a rendering engine that can help solve this issue.
Free
4 minutes read
The Problem with SVG
SVG can be slow.
If you’re working with chart types that don’t involve too many elements, like simple line or bar charts, SVG will handle them well.
But if you create a scatterplot with 100,000 data points and layer on complex animations, you’ll likely run into performance troubles.
So, why is SVG slow?
🐢 Drawing SVG is CPU-Only
SVG rendering relies entirely on the CPU, with no GPU acceleration.
This means every shape, line, or point in an SVG graphic is drawn by the CPU, which can quickly become a bottleneck. Without the benefit of GPU power, rendering large amounts of data or intricate animations can be time-consuming and sluggish.
🏋️♀️ SVG Creates a Heavy DOM
Each element you draw in SVG is added as a separate line in the DOM.
For a large number of elements, this quickly bloats the DOM, which your browser has to continuously manage and render.
Adding event listeners to each element further increases the workload, as the browser must keep track of interactions on all these individual DOM nodes. And as the DOM grows, memory usage rises as well, which can lead to even more slowdowns.
Example
Here’s a small scatterplot with a few thousand data points and a hover effect that updates an internal state.
Hover over it with your mouse. Notice the lag? See how slow it gets?
With just a few graphs like this in your app, you can quickly reach a million nodes in the DOM 🙈.
When that happens, your entire app—or even the whole browser—can start to freeze as it struggles to manage the overwhelming number of elements.
So,
If your graph has a large number of elements or requires heavy animations, it’s best to move away from SVG and choose something more performant, like canvas.
⚡️ What is canvas, and why is it fast
Canvas provides a high-performance, low-level context for drawing 2D graphics, animations, and even simple games, giving you pixel-level control for faster rendering, especially with dynamic content or large datasets.
canvas is an HTML element! You can create one by writing:
<canvas width={300} height={200}/>
-
Think of it like holding a whiteboard, ready to draw on it—only lightning fast!
Not convinced?
Check the same sandbox, made in Canvas!
A scatterplot with thousands of point and a fast hover effect.
Looks fun, let’s code!
Yep, but be ready to learn from scratch—and to break a sweat!
In this module, we’ll dive into how the canvas works, how to use it effectively, and how it can solve performance issues in your web apps.
\ No newline at end of file
diff --git a/course/canvas/svg-path-in-canvas.html b/course/canvas/svg-path-in-canvas.html
index c4789c1f..9a07f1bd 100644
--- a/course/canvas/svg-path-in-canvas.html
+++ b/course/canvas/svg-path-in-canvas.html
@@ -1,4 +1,4 @@
-Using paths in Canvas
Using paths in Canvas
We've seen how powerful D3 is for transforming a dataset into an SVG path. For example, give it a radius and angle, and it can easily generate an arc path.
But how can we use this same data to draw the shape with canvas? Let’s explore.
Free
4 minutes read
Remember the area chart?
Before we start using canvas, let's remind quickly how to build an area chart with react and d3.
Everything starts with a dataset.
const data = [
+Using paths in Canvas
Using paths in Canvas
We've seen how powerful D3 is for transforming a dataset into an SVG path. For example, give it a radius and angle, and it can easily generate an arc path.
But how can we use this same data to draw the shape with canvas? Let’s explore.
Free
4 minutes read
Remember the area chart?
Before we start using canvas, let's remind quickly how to build an area chart with react and d3.
Everything starts with a dataset.
const data = [
{x:1, y: 90},
{x: 2, y: 12},
{x: 3, y: 34},
@@ -19,4 +19,4 @@
// Then in the useEffect:
const ctx = canvas.getContext('2d');
const path = new Path2D(areaPath); // Convert to Path2D
-ctx.fill(path); // Now you can fill or stroke the path
Let's see it in action on a full chart:
A minimal area chart made in canvas thanks to d3.area() and Path2D
Too easy!
That makes it a breeze!
Let's try on a donut chart to see if it works the same:
\ No newline at end of file
diff --git a/course/hover-effect/css-descendant-selector.html b/course/hover-effect/css-descendant-selector.html
index 9ba0133a..ea6cc1fb 100644
--- a/course/hover-effect/css-descendant-selector.html
+++ b/course/hover-effect/css-descendant-selector.html
@@ -1,4 +1,4 @@
-Strategy 2: CSS descendant selector
Strategy 2: CSS descendant selector
In the previous lesson, we learned how to modify a hovered graph item using the :hover CSS pseudo-class.
However, this approach has design limitations. To achieve a more effective highlighting effect, it's better to simultaneously dim the other graph items.
This can be accomplished using CSS alone, with the help of the CSS descendant selector.
Free
10 minutes read
What is a css descendant selector?
A descendant selector allows to target elements that are children of another element.
Here’s an example:
.rectangle {
+Strategy 2: CSS descendant selector
Strategy 2: CSS descendant selector
In the previous lesson, we learned how to modify a hovered graph item using the :hover CSS pseudo-class.
However, this approach has design limitations. To achieve a more effective highlighting effect, it's better to simultaneously dim the other graph items.
This can be accomplished using CSS alone, with the help of the CSS descendant selector.
Free
10 minutes read
What is a css descendant selector?
A descendant selector allows to target elements that are children of another element.
We assign a class called container to the SVG container and a class called rectangle to each rectangle in the chart.
Then we set the default rectangle opacity to 1. Using the descendant selector, you can reduce the opacity of all rectangles to 0.1 when the container is hovered.
Then, use a hover selector to set the opacity of the hovered rectangle back to 1.
Application: treemap
Strategy 2: use CSS descendant combinator to dim all markers except the one that is hovered.
Pros & Cons
Pros
Easy to implement
Improves design by making hover effects more noticeable
Excellent performance (no JS computation, minimal redrawing)
Cons
Fades all circles if the mouse enters the chart area without hovering over a specific circle. This technique works for chart where the whole svg area is covered by markers, like a treemap.
Cannot highlight circles that are obscured by other elements. (Potentially fixed using z-index).
More examples
The examples below all use this strategy to implement their hover effect.
Exercices
Note: When you use the :hover pseudo-class on an SVG area, it activates whenever the mouse enters the entire SVG rectangle.
However, if you apply :hover to a g element, it will only trigger when the mouse hovers over one of the elements within the g group!
We assign a class called container to the SVG container and a class called rectangle to each rectangle in the chart.
Then we set the default rectangle opacity to 1. Using the descendant selector, you can reduce the opacity of all rectangles to 0.1 when the container is hovered.
Then, use a hover selector to set the opacity of the hovered rectangle back to 1.
Application: treemap
Strategy 2: use CSS descendant combinator to dim all markers except the one that is hovered.
Pros & Cons
Pros
Easy to implement
Improves design by making hover effects more noticeable
Excellent performance (no JS computation, minimal redrawing)
Cons
Fades all circles if the mouse enters the chart area without hovering over a specific circle. This technique works for chart where the whole svg area is covered by markers, like a treemap.
Cannot highlight circles that are obscured by other elements. (Potentially fixed using z-index).
More examples
The examples below all use this strategy to implement their hover effect.
Exercices
Note: When you use the :hover pseudo-class on an SVG area, it activates whenever the mouse enters the entire SVG rectangle.
However, if you apply :hover to a g element, it will only trigger when the mouse hovers over one of the elements within the g group!
\ No newline at end of file
diff --git a/course/hover-effect/css-pseudo-class.html b/course/hover-effect/css-pseudo-class.html
index f22629b7..d726dcf9 100644
--- a/course/hover-effect/css-pseudo-class.html
+++ b/course/hover-effect/css-pseudo-class.html
@@ -1,4 +1,4 @@
-Strategy 1: CSS pseudo element
Strategy 1: CSS pseudo element
The simplest strategy.
Let's explore how to use a CSS pseudo-class to modify only the graph item that is being hovered over.
Free
4 minutes read
What is a pseudo class
A CSS pseudo-class is a keyword added to a CSS selector that specifies a special state of the selected element(s). You can learn more about pseudo-classes in the MDN doc.
Essentially, this means you can assign a class to each shape in a graph and change its appearance when the user hovers over it.
Here is an example:
.scatterplotCircle {
+Strategy 1: CSS pseudo element
Strategy 1: CSS pseudo element
The simplest strategy.
Let's explore how to use a CSS pseudo-class to modify only the graph item that is being hovered over.
Free
4 minutes read
What is a pseudo class
A CSS pseudo-class is a keyword added to a CSS selector that specifies a special state of the selected element(s). You can learn more about pseudo-classes in the MDN doc.
Essentially, this means you can assign a class to each shape in a graph and change its appearance when the user hovers over it.
Consider a scatterplot with multiple SVG circle elements, each assigned a .scatterplotCircle class. In the CSS file, you can set the fill-opacity to 0.3 using this class.
To change the appearance on hover, use the .scatterplotCircle:hover selector to increase the opacity to 1.
Strategy 1: use a pseudo-class to change the appearance of the hovered marker
Pros & Cons
Pros
Easy to implement
Excellent performance (no JS computation, minimal redrawing)
Cons
Poor design: non-hovered circles remain prominent, so the highlight effect is weak
If the highlight information comes as a prop, another solution is needed
More examples
The examples below all use this strategy to implement their hover effect.
Consider a scatterplot with multiple SVG circle elements, each assigned a .scatterplotCircle class. In the CSS file, you can set the fill-opacity to 0.3 using this class.
To change the appearance on hover, use the .scatterplotCircle:hover selector to increase the opacity to 1.
Strategy 1: use a pseudo-class to change the appearance of the hovered marker
Pros & Cons
Pros
Easy to implement
Excellent performance (no JS computation, minimal redrawing)
Cons
Poor design: non-hovered circles remain prominent, so the highlight effect is weak
If the highlight information comes as a prop, another solution is needed
More examples
The examples below all use this strategy to implement their hover effect.
\ No newline at end of file
diff --git a/course/hover-effect/internal-state.html b/course/hover-effect/internal-state.html
index 86ea94e7..3b5aba60 100644
--- a/course/hover-effect/internal-state.html
+++ b/course/hover-effect/internal-state.html
@@ -1,4 +1,4 @@
-Strategy 4: react internal state
Strategy 4: react internal state
We've already explored three different strategies for adding hover effects to a chart! 😳 Each relies heavily on CSS, which is ideal as it requires minimal redrawing.
However, sometimes a more traditional React approach is needed, using a central state to trigger redraws when the state updates. Let’s explore why. ⬇️
Free
12 minutes read
⚙️ Why and How
Imagine you have multiple UI components. Say, a barplot and a pie chart, both displaying numbers for the same groups.
When you hover over Group B on the barplot, you also want group B to be highlighted on the pie chart. This setup is common in dashboards.
The CSS-focused strategies we've used before won’t work here. Instead, we need a parent component that wraps both charts and manages a shared state. When one chart is hovered, it updates the shared state, which in turn updates both charts.
Anatomy of a state update, connecting 2 charts together.
Here’s a step-by-step breakdown:
1️⃣ The mouse hovers over group B on the bar plot, triggering a function thanks to onMouseEnter
2️⃣ This function calls setHoverGroup, updating the global state in the parent component.
3️⃣ hoveredGroup, the global state, is passed to the pie chart as a prop.
4️⃣ When hoveredGroup updates, the pie chart re-renders, highlighting the group B slice.
Let's code!
1️⃣ Internal state
First, we need an internal state (called hoveredGroup) that stores which group is hovered hover. It can also be null if there is nothing hovered!
Then, the onMouseOver attribute of each rectangle can call this setter function!
<svg>
+Strategy 4: react internal state
Strategy 4: react internal state
We've already explored three different strategies for adding hover effects to a chart! 😳 Each relies heavily on CSS, which is ideal as it requires minimal redrawing.
However, sometimes a more traditional React approach is needed, using a central state to trigger redraws when the state updates. Let’s explore why. ⬇️
Free
12 minutes read
⚙️ Why and How
Imagine you have multiple UI components. Say, a barplot and a pie chart, both displaying numbers for the same groups.
When you hover over Group B on the barplot, you also want group B to be highlighted on the pie chart. This setup is common in dashboards.
The CSS-focused strategies we've used before won’t work here. Instead, we need a parent component that wraps both charts and manages a shared state. When one chart is hovered, it updates the shared state, which in turn updates both charts.
Anatomy of a state update, connecting 2 charts together.
Here’s a step-by-step breakdown:
1️⃣ The mouse hovers over group B on the bar plot, triggering a function thanks to onMouseEnter
2️⃣ This function calls setHoverGroup, updating the global state in the parent component.
3️⃣ hoveredGroup, the global state, is passed to the pie chart as a prop.
4️⃣ When hoveredGroup updates, the pie chart re-renders, highlighting the group B slice.
Let's code!
1️⃣ Internal state
First, we need an internal state (called hoveredGroup) that stores which group is hovered hover. It can also be null if there is nothing hovered!
Here’s a preview of this strategy in action. Hover over one graph, and watch the corresponding section in the other graph highlight as well:
Two graphs inter-connected thanks to a hover effect
Pros & Cons
Pros
Enables synchronization across multiple UI components, allowing hover effects, tooltips, and text highlights to update together. Highly versatile.
Provides flexibility for hover effects by using JavaScript animations, for instance, with react-spring.
Cons
Performance 🚨🚨🚨: Redrawing all elements on each hover event can significantly impact performance, especially with many elements, such as thousands of circles.
More examples
The examples below all use this strategy to implement their hover effect.
Exercise
Open a new sandbox, and build the barplot + pie chart example above from scratch!
Remember, this strategy can have performance drawbacks! We'll cover a workaround using Canvas later in this course.
Here’s a preview of this strategy in action. Hover over one graph, and watch the corresponding section in the other graph highlight as well:
Two graphs inter-connected thanks to a hover effect
Pros & Cons
Pros
Enables synchronization across multiple UI components, allowing hover effects, tooltips, and text highlights to update together. Highly versatile.
Provides flexibility for hover effects by using JavaScript animations, for instance, with react-spring.
Cons
Performance 🚨🚨🚨: Redrawing all elements on each hover event can significantly impact performance, especially with many elements, such as thousands of circles.
More examples
The examples below all use this strategy to implement their hover effect.
Exercise
Open a new sandbox, and build the barplot + pie chart example above from scratch!
Remember, this strategy can have performance drawbacks! We'll cover a workaround using Canvas later in this course.
\ No newline at end of file
diff --git a/course/hover-effect/introduction.html b/course/hover-effect/introduction.html
index 1b3f3b01..72394d61 100644
--- a/course/hover-effect/introduction.html
+++ b/course/hover-effect/introduction.html
@@ -1 +1 @@
-What is it?
What is it?
In the previous modules, you learned how to create a wide variety of static charts. 👏
However, interactivity is essential web applications. Adding hover effects significantly enhances the user experience by highlighting specific series on the chart.
In this module, we'll explore several strategies for implementing hover effects using both CSS and React. Before diving into the code, let's ensure we have a clear understanding of what hover effects are.
Free
3 minutes read
Definition
A hover effect is a visual change that occurs when a user moves their cursor over a specific element on a webpage.
→
Technically speaking, tooltip are also a hover effect. But we will talk about them in a dedicated section.
When implementing a hover effect, you should be careful about:
Design: hover effect is visually appealing and enhances the user experience. It is consistent with the overall design of your application and does not distract or confuse the user.
Performance: hover effect is fast: no lag or delay. It does not significantly impact the performance of your application, especially when dealing with large datasets or complex viz.
Three Types of Hover Effects
In my opinion, there are three main types of hover effects: those that only modify the hovered graph item, those that modify other graph markers, and those that affect other related elements in the user interface.
Click the button below to see examples of all three types:
Observe this graph: when you hover over a circle, its style changes slightly!
While this isn't the most dramatic visual effect, it is very easy to implement using a single CSS pseudo-element.
We'll learn how to implement this in the next lesson.
Let's code
Enough theory.
Let's dive into the simplest hover effect you can create: just a few lines of CSS using pseudo-elements.
In the previous modules, you learned how to create a wide variety of static charts. 👏
However, interactivity is essential web applications. Adding hover effects significantly enhances the user experience by highlighting specific series on the chart.
In this module, we'll explore several strategies for implementing hover effects using both CSS and React. Before diving into the code, let's ensure we have a clear understanding of what hover effects are.
Free
3 minutes read
Definition
A hover effect is a visual change that occurs when a user moves their cursor over a specific element on a webpage.
→
Technically speaking, tooltip are also a hover effect. But we will talk about them in a dedicated section.
When implementing a hover effect, you should be careful about:
Design: hover effect is visually appealing and enhances the user experience. It is consistent with the overall design of your application and does not distract or confuse the user.
Performance: hover effect is fast: no lag or delay. It does not significantly impact the performance of your application, especially when dealing with large datasets or complex viz.
Three Types of Hover Effects
In my opinion, there are three main types of hover effects: those that only modify the hovered graph item, those that modify other graph markers, and those that affect other related elements in the user interface.
Click the button below to see examples of all three types:
Observe this graph: when you hover over a circle, its style changes slightly!
While this isn't the most dramatic visual effect, it is very easy to implement using a single CSS pseudo-element.
We'll learn how to implement this in the next lesson.
Let's code
Enough theory.
Let's dive into the simplest hover effect you can create: just a few lines of CSS using pseudo-elements.
\ No newline at end of file
diff --git a/course/hover-effect/link-two-graphs.html b/course/hover-effect/link-two-graphs.html
index 728f7ba4..f956df6a 100644
--- a/course/hover-effect/link-two-graphs.html
+++ b/course/hover-effect/link-two-graphs.html
@@ -1,4 +1,4 @@
-Hover interaction on a chart with React
Hover interaction on a chart with React
Interactivity is crucial in data visualization, especially for web applications. Adding hover effects enhances user experience by highlighting specific series on the chart.
This post suggests a few strategies to implement hover effects using css and react.
Note: this article does not talk about tooltips that has its dedicated section.
4️⃣ Internal state & event listener
Add onMouseEnter event listener to all circle
Set an internal state
Trigger a redraw of all circles with conditional state.
As for the tooltip example above, everything starts with an internal state (called hoveredGroup) that stores which circle is hovered hover.
Now, this state needs to be updated when a user hovers over the circle. setHoveredGroup can be passed as a callback to the onMouseOver attribute of each circle.
On top of this, some specific css classes can be attributed to circles depending on the circle that is hovered hover. In the example above, a class called dimmed is added to circles that must disappear.
To put it in a nutshell, the circles are created as follows:
const allShapes = data.map((d, i) => {
+Hover interaction on a chart with React
Hover interaction on a chart with React
Interactivity is crucial in data visualization, especially for web applications. Adding hover effects enhances user experience by highlighting specific series on the chart.
This post suggests a few strategies to implement hover effects using css and react.
Note: this article does not talk about tooltips that has its dedicated section.
4️⃣ Internal state & event listener
Add onMouseEnter event listener to all circle
Set an internal state
Trigger a redraw of all circles with conditional state.
As for the tooltip example above, everything starts with an internal state (called hoveredGroup) that stores which circle is hovered hover.
Now, this state needs to be updated when a user hovers over the circle. setHoveredGroup can be passed as a callback to the onMouseOver attribute of each circle.
On top of this, some specific css classes can be attributed to circles depending on the circle that is hovered hover. In the example above, a class called dimmed is added to circles that must disappear.
To put it in a nutshell, the circles are created as follows:
const allShapes = data.map((d, i) => {
const className = // class if the circle depends on the hover state
hoveredGroup && d.group !== hoveredGroup
? styles.scatterplotCircle + " " + styles.dimmed
@@ -20,4 +20,4 @@
});
Last but not least, some css needs to be added to customize the circle depending on if they are in default, .dimmed or :hover mode.
Note that the filter: saturate(0) is a good way to dim unwanted circles. Also, playing with transition-delay and transition-duration adds to animate the transition is a nice touch you should consider. Check the code below the example to see the full css.
TODO.
Pros
Allows to sync the hover effect with other UI updates. The hovered state can be used to update any other react components in the application. Like tooltip or another graph.
Using javascript to trigger the animation can give more flexibility to customize the hover effect, using react-spring for instance.
Cons
Performance 🚨. Here we are redrawing all the circles each time a hover effect is hovered. This can be dramatic if you have thousands of circles!
4️⃣ Canvas
Using the useDimensions hook described above is pretty straight-forward. You first need to create a ref using the react useRef()function:
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data with gmail.com. You can also subscribe to the newsletter to know when I publish more content!
\ No newline at end of file
diff --git a/course/hover-effect/toggle-class-in-js.html b/course/hover-effect/toggle-class-in-js.html
index 6e838f6a..70694c7b 100644
--- a/course/hover-effect/toggle-class-in-js.html
+++ b/course/hover-effect/toggle-class-in-js.html
@@ -1,4 +1,4 @@
-Strategy 3: toggle css classes
Strategy 3: toggle css classes
In the previous lesson, we explored how to dim elements that are not being hovered over using a CSS-only approach.
However, there are times when using JavaScript can provide more precise control over the hover effect. A handy technique is to toggle classes with JavaScript. Let’s take a look at how to do this.
Free
14 minutes read
🔘 Toggle Class in JavaScript
1️⃣ Create a ref
We’ve discussed the useRef React hook a few times now.
This hook allows us to target specific elements in the DOM and manipulate them with JavaScript.
// Define a ref for the graph container
+Strategy 3: toggle css classes
Strategy 3: toggle css classes
In the previous lesson, we explored how to dim elements that are not being hovered over using a CSS-only approach.
However, there are times when using JavaScript can provide more precise control over the hover effect. A handy technique is to toggle classes with JavaScript. Let’s take a look at how to do this.
Free
14 minutes read
🔘 Toggle Class in JavaScript
1️⃣ Create a ref
We’ve discussed the useRef React hook a few times now.
This hook allows us to target specific elements in the DOM and manipulate them with JavaScript.
// Define a ref for the graph container
const containerRef = useRef();
// Attach this ref to an element in the DOM
@@ -27,4 +27,4 @@
.container.hasHighlight .slice {
opacity: 0.2;
}
-
🍩 Application: Donut Chart with Hover Effect
A donut chart is a variation of the more well-known pie chart. It is easy to create using the pie() function from D3.js.
The following example demonstrates the technique described earlier. When a slice is hovered over, a class is added to the SVG container, resulting in a CSS change for all the other slices.
A donut chart with hover interaction using the class toggle strategy.
Pros & Cons
Pros
Fine control over interactions via JavaScript
Performance-friendly: no re-rendering required
Cons
Doesn't align with React’s central state management approach, which can make managing state more challenging.
More examples
The examples below all use this strategy to implement their hover effect.
Check the legend on the left hand side: it uses class toggle for its hover effect!
A donut chart is a variation of the more well-known pie chart. It is easy to create using the pie() function from D3.js.
The following example demonstrates the technique described earlier. When a slice is hovered over, a class is added to the SVG container, resulting in a CSS change for all the other slices.
A donut chart with hover interaction using the class toggle strategy.
Pros & Cons
Pros
Fine control over interactions via JavaScript
Performance-friendly: no re-rendering required
Cons
Doesn't align with React’s central state management approach, which can make managing state more challenging.
More examples
The examples below all use this strategy to implement their hover effect.
Check the legend on the left hand side: it uses class toggle for its hover effect!
\ No newline at end of file
diff --git a/course/introduction/initial-setup.html b/course/introduction/initial-setup.html
index abce0e67..9815f0c9 100644
--- a/course/introduction/initial-setup.html
+++ b/course/introduction/initial-setup.html
@@ -1,7 +1,7 @@
-Initial setup
Initial setup
Creating graphs in a React environment using D3.js can be quite complex.
Here’s a list of tools I highly recommend to simplify your journey in building a dataviz web application. 🔧
Free
4 minutes read
1️⃣ React: Use a Framework
React is a JavaScript library, not a framework.
Several frameworks are built on top of it to manage common requirements such as routing, static page generation, server-side rendering, and more.
Personally, I'm a huge fan of Next.js, but other options like Gatsby, Remix, or even sticking with Create React App are excellent choices as well!
List of next.js features that will make your life easier. Source.
2️⃣ D3.js: Load What You Need
D3.js is not a monolithic library but a collection of around 30 discrete modules.
You don’t need to install and load the entire D3.js library for your work; it's likely that you'll only use a fraction of its capabilities.
For example, if you need to work with scales, you can simply install the d3-scale module using npm install d3-scale and utilize only the functions you require from it!
+Initial setup
Initial setup
Creating graphs in a React environment using D3.js can be quite complex.
Here’s a list of tools I highly recommend to simplify your journey in building a dataviz web application. 🔧
Free
4 minutes read
1️⃣ React: Use a Framework
React is a JavaScript library, not a framework.
Several frameworks are built on top of it to manage common requirements such as routing, static page generation, server-side rendering, and more.
Personally, I'm a huge fan of Next.js, but other options like Gatsby, Remix, or even sticking with Create React App are excellent choices as well!
List of next.js features that will make your life easier. Source.
2️⃣ D3.js: Load What You Need
D3.js is not a monolithic library but a collection of around 30 discrete modules.
You don’t need to install and load the entire D3.js library for your work; it's likely that you'll only use a fraction of its capabilities.
For example, if you need to work with scales, you can simply install the d3-scale module using npm install d3-scale and utilize only the functions you require from it!
// import the scaleLinear function from the d3-scale module
import { scaleLinear } from "d3";
// Use it in your code
cons xScale = scaleLinear()
-
3️⃣ Typescript: your best friend
TypeScript is like a special version of JavaScript that helps you write better code by letting you add labels to your variables. These labels, or "types," tell you what kind of data you're working with, like number or string.
This way, if you make a mistake, TypeScript can help you catch it before you run your program, making it easier to fix problems and build bigger projects!
I strongly advise to learn and use typescript. I'll use it in this course, but you do not have to if you do not want to.
D3.js & Typescript
Fortunately, DefinitelyTyped provides the types of all d3.js functions and objects! So you can install all the types we'll need with:
If you like those tools too, check out my boilerplate! This repository is a minimal project with all the tools mentioned in this lesson already installed. Just clone it, run npm run dev, and you’ll have a working environment that looks like this right away:
Overview of my dataviz project boilerplate. Use next.js + d3 + tailwind + typescript + shadcn/UI in 2 minutes. .
✌️ No Worries!
Don’t want to install any of those tools? No worries!
All the lessons in this course feature interactive sandboxes, allowing you to learn and experiment without ever leaving this website!
Here is an example with a basic barplot you can edit by clicking on the "see code" button:
Most basic barplot built with d3.js for scales, and react for rendering
Now, let’s start creating some dataviz magic on that screen, shall we?
TypeScript is like a special version of JavaScript that helps you write better code by letting you add labels to your variables. These labels, or "types," tell you what kind of data you're working with, like number or string.
This way, if you make a mistake, TypeScript can help you catch it before you run your program, making it easier to fix problems and build bigger projects!
I strongly advise to learn and use typescript. I'll use it in this course, but you do not have to if you do not want to.
D3.js & Typescript
Fortunately, DefinitelyTyped provides the types of all d3.js functions and objects! So you can install all the types we'll need with:
If you like those tools too, check out my boilerplate! This repository is a minimal project with all the tools mentioned in this lesson already installed. Just clone it, run npm run dev, and you’ll have a working environment that looks like this right away:
Overview of my dataviz project boilerplate. Use next.js + d3 + tailwind + typescript + shadcn/UI in 2 minutes. .
✌️ No Worries!
Don’t want to install any of those tools? No worries!
All the lessons in this course feature interactive sandboxes, allowing you to learn and experiment without ever leaving this website!
Here is an example with a basic barplot you can edit by clicking on the "see code" button:
Most basic barplot built with d3.js for scales, and react for rendering
Now, let’s start creating some dataviz magic on that screen, shall we?
\ No newline at end of file
diff --git a/course/introduction/introduction-to-d3.html b/course/introduction/introduction-to-d3.html
index 56c131a3..4e12f1b3 100644
--- a/course/introduction/introduction-to-d3.html
+++ b/course/introduction/introduction-to-d3.html
@@ -1 +1 @@
-What is d3
What is d3
D3.js is a powerful JavaScript library that offers a wide range of functions for creating dynamic graphs and visualizations.
Its popularity is immense; you’ll find it hard to encounter a web-based graph that doesn’t leverage D3 in some capacity. Let’s explore why it’s become such an essential tool.
It is this kind of graph, where rectangles are used to represent hierarchical data, with size proportional to a value:
A basic treemap made with React and D3.js
Drawing rectangles with React and some divs is simple. But how do you calculate the coordinates to ensure each rectangle's area matches its corresponding value? 🙈
That's exactly what the treemap() function in d3.js does for you.
And that's why we need d3!
Note: the React Graph Gallery has a whole section on treemaps! But do not try to understand the code for now!
❌ Not a Charting library
It's important to understand that D3 is not a charting library.
A charting library would offer a ready-made Scatterplot component where you pass some properties, and it renders the chart for you.
D3 doesn’t do that. It provides utility functions to help you create your scatterplot, but it won’t build it for you.
D3.js website screenshot.
That's why d3 is ideal for "bespoke" dataviz. It requires more effort but gives you complete control for any customization.
🗡️ Only a fraction
D3.js offers a wide range of functions, which can be grouped into two main categories:
📐 Math functions
These include functions like treemap() mentioned earlier. They return numbers, positions, colors, or text, but don’t interact with the DOM.
✍️ Rendering functions
Functions that modify the DOM, like append, which can add elements (e.g., a circle) to an SVG.
Here’s the good news: in a React environment, we only need D3's math functions, since all the rendering will be handled by React and its JSX!
D3.js is a powerful JavaScript library that offers a wide range of functions for creating dynamic graphs and visualizations.
Its popularity is immense; you’ll find it hard to encounter a web-based graph that doesn’t leverage D3 in some capacity. Let’s explore why it’s become such an essential tool.
It is this kind of graph, where rectangles are used to represent hierarchical data, with size proportional to a value:
A basic treemap made with React and D3.js
Drawing rectangles with React and some divs is simple. But how do you calculate the coordinates to ensure each rectangle's area matches its corresponding value? 🙈
That's exactly what the treemap() function in d3.js does for you.
And that's why we need d3!
Note: the React Graph Gallery has a whole section on treemaps! But do not try to understand the code for now!
❌ Not a Charting library
It's important to understand that D3 is not a charting library.
A charting library would offer a ready-made Scatterplot component where you pass some properties, and it renders the chart for you.
D3 doesn’t do that. It provides utility functions to help you create your scatterplot, but it won’t build it for you.
D3.js website screenshot.
That's why d3 is ideal for "bespoke" dataviz. It requires more effort but gives you complete control for any customization.
🗡️ Only a fraction
D3.js offers a wide range of functions, which can be grouped into two main categories:
📐 Math functions
These include functions like treemap() mentioned earlier. They return numbers, positions, colors, or text, but don’t interact with the DOM.
✍️ Rendering functions
Functions that modify the DOM, like append, which can add elements (e.g., a circle) to an SVG.
Here’s the good news: in a React environment, we only need D3's math functions, since all the rendering will be handled by React and its JSX!
\ No newline at end of file
diff --git a/course/introduction/introduction-to-react.html b/course/introduction/introduction-to-react.html
index e92d424e..eea6dd93 100644
--- a/course/introduction/introduction-to-react.html
+++ b/course/introduction/introduction-to-react.html
@@ -1 +1 @@
-What is react
What is react
React is a JavaScript library used for creating dynamic and interactive user interfaces through reusable components. Developed by Facebook, it simplifies the process of managing application state and updating the user interface efficiently.
This lesson will offer a concise overview of React and its key features.
Free
4 minutes read
Why React?
React was introduced in 2013, transforming the landscape of web development.
Prior to its component-based architecture, building web applications was complex and cumbersome.
If you make charts for the web and don't know react, you're missing out!
This is particularly evident in applications that involve data visualization. The ability to create reusable components, like a Scatterplot component, that can be utilized throughout your app, is a game-changer for your development process.
If you're building a data visualization application, React offers everything you need:
Robust state management, perfectly suited for dynamic data.
A component-driven approach, ideal for creating interactive visualizations.
Extensive community support and comprehensive documentation.
Expected knowledge
This course focuses on Data Visualization using React.
We won’t cover the basics of React, as that’s a vast topic deserving its own dedicated course! For a solid introduction, check out this intro by Codecademy.
Basically, you should just be able to understand what's happening in this sandbox:
That's it, no need to be a React expert.
Even seasoned developers will find valuable insights here: creating visualizations with React and D3 involves specialized knowledge that differs significantly from typical UI development.
Lastly, you don’t need prior experience with D3 to get started! We’ll use it sparingly and provide a thorough explanation of how it works.
🤔Alternatives
While React is a leading choice for building user interfaces, there are notable alternatives, primarily Vue and Angular. Additionally, Svelte has gained considerable traction within the data visualization community.
However, React's popularity is significantly larger, as illustrated in the graph below from npmtrends.
For further insights, you can explore a variety of metrics on this repository. It's clear to me that React has established itself as the de-facto library for creating user interfaces and is here to stay.
Evolution of the number of downloads for React (green), Angular, Vue and Svelte
React is a JavaScript library used for creating dynamic and interactive user interfaces through reusable components. Developed by Facebook, it simplifies the process of managing application state and updating the user interface efficiently.
This lesson will offer a concise overview of React and its key features.
Free
4 minutes read
Why React?
React was introduced in 2013, transforming the landscape of web development.
Prior to its component-based architecture, building web applications was complex and cumbersome.
If you make charts for the web and don't know react, you're missing out!
This is particularly evident in applications that involve data visualization. The ability to create reusable components, like a Scatterplot component, that can be utilized throughout your app, is a game-changer for your development process.
If you're building a data visualization application, React offers everything you need:
Robust state management, perfectly suited for dynamic data.
A component-driven approach, ideal for creating interactive visualizations.
Extensive community support and comprehensive documentation.
Expected knowledge
This course focuses on Data Visualization using React.
We won’t cover the basics of React, as that’s a vast topic deserving its own dedicated course! For a solid introduction, check out this intro by Codecademy.
Basically, you should just be able to understand what's happening in this sandbox:
That's it, no need to be a React expert.
Even seasoned developers will find valuable insights here: creating visualizations with React and D3 involves specialized knowledge that differs significantly from typical UI development.
Lastly, you don’t need prior experience with D3 to get started! We’ll use it sparingly and provide a thorough explanation of how it works.
🤔Alternatives
While React is a leading choice for building user interfaces, there are notable alternatives, primarily Vue and Angular. Additionally, Svelte has gained considerable traction within the data visualization community.
However, React's popularity is significantly larger, as illustrated in the graph below from npmtrends.
For further insights, you can explore a variety of metrics on this repository. It's clear to me that React has established itself as the de-facto library for creating user interfaces and is here to stay.
Evolution of the number of downloads for React (green), Angular, Vue and Svelte
\ No newline at end of file
diff --git a/course/introduction/js-dataviz-libraries.html b/course/introduction/js-dataviz-libraries.html
index 7ac5124e..9505a03e 100644
--- a/course/introduction/js-dataviz-libraries.html
+++ b/course/introduction/js-dataviz-libraries.html
@@ -1,7 +1,7 @@
-Chart libraries: don't
Chart libraries: don't
When creating a chart, your first instinct is usually to reach for a JavaScript library. While that’s a great starting point, it often leads to unnecessary complications.
Let’s explore why. 🤓
Free
4 minutes read
In a hurry
You're building an impressive app and need to add a barplot. You'll need rectangles, axes, labels, a title, and maybe even a tooltip—all responsive and well-designed.
The good news?
There are plenty of JavaScript dataviz libraries that can handle this perfectly 🔥:
List of the biggest javascript libraries for data visualization
Let's try with Nivo (I used it for a client recently 🙃).
All you have to do is to npm install the lib, import it ResponsiveBar component and use it with the 3 required arguments: data, keys and indexBy.
+Chart libraries: don't
Chart libraries: don't
When creating a chart, your first instinct is usually to reach for a JavaScript library. While that’s a great starting point, it often leads to unnecessary complications.
Let’s explore why. 🤓
Free
4 minutes read
In a hurry
You're building an impressive app and need to add a barplot. You'll need rectangles, axes, labels, a title, and maybe even a tooltip—all responsive and well-designed.
The good news?
There are plenty of JavaScript dataviz libraries that can handle this perfectly 🔥:
List of the biggest javascript libraries for data visualization
Let's try with Nivo (I used it for a client recently 🙃).
All you have to do is to npm install the lib, import it ResponsiveBar component and use it with the 3 required arguments: data, keys and indexBy.
// Import lib
import { ResponsiveBar } from '@nivo/bar';
// Make a barchart
<ResponsiveBar data={data} keys={['value']} indexBy="country"/>
-
Just like that, you’ve created a fantastic barplot! Time to celebrate 🎉.
A basic barplot made using the Nivo library in 3 minutes.
Yes, But...
The excitement fades, and it’s time to elevate your chart to the next level. Here’s a list of common tweaks you’ll likely need:
📊 Chart type
The user actually needs a diverging bar chart, with individual data points overlayed.
🎨 Design
Enhanced colors, labels on top, subtle arrows, custom gridlines, and a unique font.
🎮 Interactivity
Smooth hover effect to highlight specific groups which also triggers a change on a minimap elsewhere in the app. Oh, and clicking on text should also highlight certain dots/rectangles.
Essentially, you’re aiming for something like this:
→
I made this app to win a dataviz competition: the Pacific Dataviz Challenge
Interactive barplot made to win a dataviz challenge. Check it out.
Now, you're in trouble!
Some of the features listed above can be achieved with a dataviz library, but they will require endless tweaks beyond what the library is designed to do.
Others simply aren’t possible, meaning you’ll have to convince the product manager to let them go. 😞
JavaScript libraries are great for quick visualizations, but their limitations will stop you from winning a dataviz challenge or meeting your PM's complex needs.
To take data visualization seriously, you should move away from those JavaScript libraries and switch to D3.js.
Let’s explore what D3.js is and how it stands apart. ➡️
Just like that, you’ve created a fantastic barplot! Time to celebrate 🎉.
A basic barplot made using the Nivo library in 3 minutes.
Yes, But...
The excitement fades, and it’s time to elevate your chart to the next level. Here’s a list of common tweaks you’ll likely need:
📊 Chart type
The user actually needs a diverging bar chart, with individual data points overlayed.
🎨 Design
Enhanced colors, labels on top, subtle arrows, custom gridlines, and a unique font.
🎮 Interactivity
Smooth hover effect to highlight specific groups which also triggers a change on a minimap elsewhere in the app. Oh, and clicking on text should also highlight certain dots/rectangles.
Essentially, you’re aiming for something like this:
→
I made this app to win a dataviz competition: the Pacific Dataviz Challenge
Interactive barplot made to win a dataviz challenge. Check it out.
Now, you're in trouble!
Some of the features listed above can be achieved with a dataviz library, but they will require endless tweaks beyond what the library is designed to do.
Others simply aren’t possible, meaning you’ll have to convince the product manager to let them go. 😞
JavaScript libraries are great for quick visualizations, but their limitations will stop you from winning a dataviz challenge or meeting your PM's complex needs.
To take data visualization seriously, you should move away from those JavaScript libraries and switch to D3.js.
Let’s explore what D3.js is and how it stands apart. ➡️
\ No newline at end of file
diff --git a/course/responsiveness/code-organization.html b/course/responsiveness/code-organization.html
index e83567c6..5c3f4029 100644
--- a/course/responsiveness/code-organization.html
+++ b/course/responsiveness/code-organization.html
@@ -1,4 +1,4 @@
-Best Practices for Code Organization
Best Practices for Code Organization
Let's create a confortable working environment: let's use Next.js.
Wip
4 minutes read
🎁 Wrapper component
I like to create a "wrapper" component that manages the responsiveness and pass all the other props to the viz component, plus width and height.
If you already have a dataviz component and just want to make it responsive, this template should be useful to you:
type ResponsiveDensityChartProps = {
+Best Practices for Code Organization
Best Practices for Code Organization
Let's create a confortable working environment: let's use Next.js.
Wip
4 minutes read
🎁 Wrapper component
I like to create a "wrapper" component that manages the responsiveness and pass all the other props to the viz component, plus width and height.
If you already have a dataviz component and just want to make it responsive, this template should be useful to you:
type ResponsiveDensityChartProps = {
data: number[];
};
@@ -28,4 +28,4 @@
// Non responsive component
const DensityChart = ({ width, height, data }: DensityChartProps) => {
//... dataviz code goes here
-}
\ No newline at end of file
diff --git a/course/responsiveness/common-pitfalls.html b/course/responsiveness/common-pitfalls.html
index 5d575b58..f91f1c7c 100644
--- a/course/responsiveness/common-pitfalls.html
+++ b/course/responsiveness/common-pitfalls.html
@@ -1 +1 @@
-Common Pitfalls and How to Avoid Them
Common Pitfalls and How to Avoid Them
Let's create a confortable working environment: let's use Next.js.
Wip
4 minutes read
🐞 Caveats
Here are some potential caveats to consider when using the useDimensions hook:
1️⃣ Container Needs Dimensions
In HTML, not all <div> elements have dimensions by default. If a <div> lacks dimensions, the useDimensions hook won't be able to measure it!
An inline <div> cannot have width and height.
By default, a <div> has no height. Its width is 100%, but its height is determined by its content. This means that without content, the <div> will have no height.
2️⃣ Performance
When the graph dimensions change, ensure that you only recompute what is necessary within the visualization component. useMemo and useCallback are valuable tools for optimizing performance.
3️⃣ Design
A graph is not merely a piece of text; its aspect ratio significantly affects its appearance. A wide graph might look great, while a narrower version may not. Sometimes, adapting the chart type based on window size is the best approach.
4️⃣ Zero Dimensions
Be cautious with the useDimensions hook. When your app first loads, the reference dimensions might be null or zero. Ensure your code handles this scenario properly to avoid errors.
\ No newline at end of file
+Common Pitfalls and How to Avoid Them
Common Pitfalls and How to Avoid Them
Let's create a confortable working environment: let's use Next.js.
Wip
4 minutes read
🐞 Caveats
Here are some potential caveats to consider when using the useDimensions hook:
1️⃣ Container Needs Dimensions
In HTML, not all <div> elements have dimensions by default. If a <div> lacks dimensions, the useDimensions hook won't be able to measure it!
An inline <div> cannot have width and height.
By default, a <div> has no height. Its width is 100%, but its height is determined by its content. This means that without content, the <div> will have no height.
2️⃣ Performance
When the graph dimensions change, ensure that you only recompute what is necessary within the visualization component. useMemo and useCallback are valuable tools for optimizing performance.
3️⃣ Design
A graph is not merely a piece of text; its aspect ratio significantly affects its appearance. A wide graph might look great, while a narrower version may not. Sometimes, adapting the chart type based on window size is the best approach.
4️⃣ Zero Dimensions
Be cautious with the useDimensions hook. When your app first loads, the reference dimensions might be null or zero. Ensure your code handles this scenario properly to avoid errors.
\ No newline at end of file
diff --git a/course/responsiveness/introduction.html b/course/responsiveness/introduction.html
index a7e0dc44..b3b57cd6 100644
--- a/course/responsiveness/introduction.html
+++ b/course/responsiveness/introduction.html
@@ -1,4 +1,4 @@
-Introduction to responsiveness
Introduction to responsiveness
To build a graph, you need to know the width and height of the SVG area.
However, we often don't know the exact dimensions we need for our visualizations; we just want them to fit their container.
This module explains how to make a chart responsive. It provides the code for a hook that detects changes in a div's dimensions and explains how to inject its returned values into a visualization component.
Free
4 minutes read
What is responsiveness?
Responsiveness refers to the ability of a data visualization (such as charts, graphs, or dashboards) to adapt and display correctly across different devices and screen sizes.
This ensures that users have an optimal viewing experience whether they are accessing the visualizations on a desktop, tablet, or mobile device
This density chart is responsive! Resize your window to see how the graph fits its container.
Responsiveness is a key aspect of web development. This module specifically focuses on making charts responsive. It won't cover general topics like CSS, Flexbox, Grid, or other concepts related to overall website responsiveness.
Design Considerations
A graph can appear visually appealing when its width exceeds its height, but it may lose its effectiveness if shrunk too much. In some cases, using a completely different chart type on smaller screens, removing a chart, or flipping it may be necessary.
This course offers technical guidelines on making graphs responsive. It focuses on the "how" rather than the "what," providing you with the tools to achieve your desired outcomes.
😢 Unresponsive chart
When building a chart with JavaScript, knowing its dimensions — width and height — is essential. These dimensions are needed to compute scales, draw axes, and determine where to place shapes.
Consequently, a visualization component always expects width and heightproperties.
Consider a simple density plot, for example. The code looks like this:
import * as d3 from "d3";
+Introduction to responsiveness
Introduction to responsiveness
To build a graph, you need to know the width and height of the SVG area.
However, we often don't know the exact dimensions we need for our visualizations; we just want them to fit their container.
This module explains how to make a chart responsive. It provides the code for a hook that detects changes in a div's dimensions and explains how to inject its returned values into a visualization component.
Free
4 minutes read
What is responsiveness?
Responsiveness refers to the ability of a data visualization (such as charts, graphs, or dashboards) to adapt and display correctly across different devices and screen sizes.
This ensures that users have an optimal viewing experience whether they are accessing the visualizations on a desktop, tablet, or mobile device
This density chart is responsive! Resize your window to see how the graph fits its container.
Responsiveness is a key aspect of web development. This module specifically focuses on making charts responsive. It won't cover general topics like CSS, Flexbox, Grid, or other concepts related to overall website responsiveness.
Design Considerations
A graph can appear visually appealing when its width exceeds its height, but it may lose its effectiveness if shrunk too much. In some cases, using a completely different chart type on smaller screens, removing a chart, or flipping it may be necessary.
This course offers technical guidelines on making graphs responsive. It focuses on the "how" rather than the "what," providing you with the tools to achieve your desired outcomes.
😢 Unresponsive chart
When building a chart with JavaScript, knowing its dimensions — width and height — is essential. These dimensions are needed to compute scales, draw axes, and determine where to place shapes.
Consequently, a visualization component always expects width and heightproperties.
Consider a simple density plot, for example. The code looks like this:
import * as d3 from "d3";
type DensityProps = {
width: number; // 🙁 not responsive!
@@ -17,4 +17,4 @@
</svg>
</div>
);
-};
Let's Code
Let's assume we have a div that is responsive and takes the full width of an app.
How can we draw a chart inside this div that also takes up the entire space and remains responsive?
\ No newline at end of file
diff --git a/course/responsiveness/use-dimension-hook.html b/course/responsiveness/use-dimension-hook.html
index 6c2b56bb..265f676c 100644
--- a/course/responsiveness/use-dimension-hook.html
+++ b/course/responsiveness/use-dimension-hook.html
@@ -1,4 +1,4 @@
-Creating a useDimensions Hook
Creating a useDimensions Hook
The visualization component is going to be wrapped in a responsive div. We need a way to retrieve this container's dimensions.
To achieve this, let's create a hook called useDimensions.
Free
4 minutes read
What is a hook
A hook is a special function that lets you use state and other React features in functional components, as explained in the documentation.
That's exactly what we need! A function that we can reuse in all our chart components and that manages its internal state.
🎣 Hook to get the container dimensions
That's how the hook looks like:
import { useEffect, useLayoutEffect, useState } from "react";
+Creating a useDimensions Hook
Creating a useDimensions Hook
The visualization component is going to be wrapped in a responsive div. We need a way to retrieve this container's dimensions.
To achieve this, let's create a hook called useDimensions.
Free
4 minutes read
What is a hook
A hook is a special function that lets you use state and other React features in functional components, as explained in the documentation.
That's exactly what we need! A function that we can reuse in all our chart components and that manages its internal state.
🎣 Hook to get the container dimensions
That's how the hook looks like:
import { useEffect, useLayoutEffect, useState } from "react";
// Hook to retrieve the dimensions of a div.
// react-graph-gallery.com
@@ -27,4 +27,4 @@
}, []);
return dimensions;
-}
This hook is essentially a function that checks the offsetWidth and offsetHeight of a provided ref.
An event listener for the resize event is added to the window to ensure the dimensions are updated when the window size changes.
I do not want to go too much in depth on how it works. More importantly, let's see how to use it!
\ No newline at end of file
diff --git a/course/responsiveness/using-the-hook.html b/course/responsiveness/using-the-hook.html
index af8cc8a5..d8f87c7b 100644
--- a/course/responsiveness/using-the-hook.html
+++ b/course/responsiveness/using-the-hook.html
@@ -1,7 +1,7 @@
-Integrating the Hook with Your Graph
Integrating the Hook with Your Graph
Our use-dimensions hook monitors changes in a div's dimensions and returns those values. Now, let’s use this hook to feed the dimensions directly into our graph!
Free
4 minutes read
1️⃣ Create a Ref
Begin by creating a ref with the React useRef() function.
A ref lets you directly target and interact with a specific HTML element in your app’s DOM. Remember, we covered this concept in the module on D3.js axes.
const chartRef = useRef(null);
Finally, pass the chartRef to the container you want to monitor.
return(
+Integrating the Hook with Your Graph
Integrating the Hook with Your Graph
Our use-dimensions hook monitors changes in a div's dimensions and returns those values. Now, let’s use this hook to feed the dimensions directly into our graph!
Free
4 minutes read
1️⃣ Create a Ref
Begin by creating a ref with the React useRef() function.
A ref lets you directly target and interact with a specific HTML element in your app’s DOM. Remember, we covered this concept in the module on D3.js axes.
const chartRef = useRef(null);
Finally, pass the chartRef to the container you want to monitor.
\ No newline at end of file
diff --git a/course/scales/introduction.html b/course/scales/introduction.html
index 78f5c9d6..4bae0127 100644
--- a/course/scales/introduction.html
+++ b/course/scales/introduction.html
@@ -1,5 +1,5 @@
-Introduction to scales
Introduction to scales
Building a graph requires to transform a dimension (a numeric variable in your dataset) in a position in pixels. This is done using a fundamental dataviz concept called scale.
Before implementing it in the next lesson, let's describe a bit what this crucial concept of dataviz is.
Free
4 minutes read
Test your intuition
Let's test your intuition with the following exercise.
1️⃣ You have a SVG area with a width of 500px.
2️⃣ You can place circles anywhere along this area horizontally.
3️⃣ You have a dataset with 5 values: 0, 50, 60, 82, 100
→ How do you position your circles to represent this dataset? Drag the circles below following your intuition:
Note: the number in each circle represents its value in the dataset.
How it actually works
The obvious part:
→ For a value of 0, the circle should be placed at the extreme left of the SVG. This corresponds to cx = 0px.
→ For the highest value in the dataset, 100, the circle should be positioned at the extreme right of the SVG. This corresponds to cx = width (i.e., 500px).
→ For a value of 50, which is the midpoint of our dataset, the circle should be positioned at the center of the SVG. This corresponds to cx = width / 2 (i.e., 250px).
The math part:
For a value of 82, which is not an exact midpoint, you need to calculate the position proportionally.
The position can be calculated as:
// Linear scale equation
+Introduction to scales
Introduction to scales
Building a graph requires to transform a dimension (a numeric variable in your dataset) in a position in pixels. This is done using a fundamental dataviz concept called scale.
Before implementing it in the next lesson, let's describe a bit what this crucial concept of dataviz is.
Free
4 minutes read
Test your intuition
Let's test your intuition with the following exercise.
1️⃣ You have a SVG area with a width of 500px.
2️⃣ You can place circles anywhere along this area horizontally.
3️⃣ You have a dataset with 5 values: 0, 50, 60, 82, 100
→ How do you position your circles to represent this dataset? Drag the circles below following your intuition:
Note: the number in each circle represents its value in the dataset.
How it actually works
The obvious part:
→ For a value of 0, the circle should be placed at the extreme left of the SVG. This corresponds to cx = 0px.
→ For the highest value in the dataset, 100, the circle should be positioned at the extreme right of the SVG. This corresponds to cx = width (i.e., 500px).
→ For a value of 50, which is the midpoint of our dataset, the circle should be positioned at the center of the SVG. This corresponds to cx = width / 2 (i.e., 250px).
The math part:
For a value of 82, which is not an exact midpoint, you need to calculate the position proportionally.
Manually calculating positions for each data point would be incredibly tedious for every graph you create.
Fortunately, d3.js provides a function called scaleLinear() that handles this task for you. In the next lesson, we'll explore how it works and simplifies your data visualization process.
Manually calculating positions for each data point would be incredibly tedious for every graph you create.
Fortunately, d3.js provides a function called scaleLinear() that handles this task for you. In the next lesson, we'll explore how it works and simplifies your data visualization process.
\ No newline at end of file
diff --git a/course/scales/linear-scale.html b/course/scales/linear-scale.html
index f54f6765..69f1356f 100644
--- a/course/scales/linear-scale.html
+++ b/course/scales/linear-scale.html
@@ -1,4 +1,4 @@
-Linear Scales
Linear Scales
The previous lesson described the concept of scale in data visualization. Scales allow, for instance, to translate a value in our dataset to a position on the screen.
Now, let's study the most common scale type and its d3.js implementation: the linear scale and its scaleLinear() function.
Free
4 minutes read
The scaleLinear() function
The scaleLinear() function is part of the d3-scale module of d3.js.
It expects 2 inputs: a domain and a range.
🏠 Domain
Usually an array of length 2. It provides the min and the max of the values we have in the dataset.
📏 Range
Usually an array of length 2. It provides the start and the end of the positions we are targeting in pixel.
The output is a function that takes a single argument. You provide a value from the domain, and it returns the corresponding value from the range.
Let's create a scale to address the issue with the green circles above!
+Linear Scales
Linear Scales
The previous lesson described the concept of scale in data visualization. Scales allow, for instance, to translate a value in our dataset to a position on the screen.
Now, let's study the most common scale type and its d3.js implementation: the linear scale and its scaleLinear() function.
Free
4 minutes read
The scaleLinear() function
The scaleLinear() function is part of the d3-scale module of d3.js.
It expects 2 inputs: a domain and a range.
🏠 Domain
Usually an array of length 2. It provides the min and the max of the values we have in the dataset.
📏 Range
Usually an array of length 2. It provides the start and the end of the positions we are targeting in pixel.
The output is a function that takes a single argument. You provide a value from the domain, and it returns the corresponding value from the range.
Let's create a scale to address the issue with the green circles above!
By now, working with the X scale should feel intuitive.
However, the Y axis behaves a bit differently. Typically, when a value is high, we expect the corresponding data point to be near the top of the SVG area. Conversely, a value close to 0 should appear near the bottom.
This means the Y scale is essentially inverted! Luckily, we can handle this easily by reversing the order of the range array.
\ No newline at end of file
diff --git a/course/scales/other-scale-types.html b/course/scales/other-scale-types.html
index d326eae4..a815bbe8 100644
--- a/course/scales/other-scale-types.html
+++ b/course/scales/other-scale-types.html
@@ -1,4 +1,4 @@
-Other scale types
Other scale types
While scaleLinear is one of the most commonly used D3 scales, other scale types are essential for creating even basic charts.
Let's explore scaleBand, scaleOrdinal, and other indispensable functions!
Free
4 minutes read
scaleBand() to create... bands 🙂
scaleBand() is ideal for categorical variables as it allocates equal space for each category, ensuring that every discrete value is uniformly represented on the axis.
Example
You want to create a horizontal bar chart with 3 bars in a figure that is 240 pixels high. You want to dedicate 33% of the total height for white space: this is the padding between bars.
You'll end up with the dimensions outlined below:
All the numbers produced by the scaleBand() function.
You can easily compute these values using the scaleBand() function!
→
There are many ways to control the padding. The official doc explains very well!
The domain is an array that lists the groups.
The range is a two-element array that specifies the pixel positions where the shapes will be drawn.
The optional padding method is expressed as a fraction of the band width.
const yScale = d3.scaleBand()
+Other scale types
Other scale types
While scaleLinear is one of the most commonly used D3 scales, other scale types are essential for creating even basic charts.
Let's explore scaleBand, scaleOrdinal, and other indispensable functions!
Free
4 minutes read
scaleBand() to create... bands 🙂
scaleBand() is ideal for categorical variables as it allocates equal space for each category, ensuring that every discrete value is uniformly represented on the axis.
Example
You want to create a horizontal bar chart with 3 bars in a figure that is 240 pixels high. You want to dedicate 33% of the total height for white space: this is the padding between bars.
You'll end up with the dimensions outlined below:
All the numbers produced by the scaleBand() function.
You can easily compute these values using the scaleBand() function!
→
There are many ways to control the padding. The official doc explains very well!
The domain is an array that lists the groups.
The range is a two-element array that specifies the pixel positions where the shapes will be drawn.
The optional padding method is expressed as a fraction of the band width.
Now that this scale is available, let's use it to get all the positions we need! Note that the yScale function we now have returns the start of the corresponding band:
// Top of each bar:
@@ -12,4 +12,4 @@
.range(["red", "green", "blue"]) // I want to assign 3 colors to them
colorScale("a") // --> red!
-colorScale("b") // --> green
More Scale Types to Explore!
The d3-scale module includes 13 different types of scales.
However, they all follow the same core pattern. Rather than covering each one individually now, we'll explore them throughout the course as they come up.
By now, you should have a solid understanding of how scales work.
While I don’t recommend it, you can always check out the full list of scale types in the official documentation if you're curious!
Exercices
It's taking shape! 🎉
You've now mastered two fundamental concepts of dataviz with React and D3: SVG and Scales. This means we're ready to build actual graphs!
In the next lesson, you'll dive into a hands-on exercise where we recreate a real-world chart using everything you've learned so far.
\ No newline at end of file
+colorScale("b") // --> green
More Scale Types to Explore!
The d3-scale module includes 13 different types of scales.
However, they all follow the same core pattern. Rather than covering each one individually now, we'll explore them throughout the course as they come up.
By now, you should have a solid understanding of how scales work.
While I don’t recommend it, you can always check out the full list of scale types in the official documentation if you're curious!
Exercices
It's taking shape! 🎉
You've now mastered two fundamental concepts of dataviz with React and D3: SVG and Scales. This means we're ready to build actual graphs!
In the next lesson, you'll dive into a hands-on exercise where we recreate a real-world chart using everything you've learned so far.
\ No newline at end of file
diff --git a/course/scales/project.html b/course/scales/project.html
index 5b5e0ff8..a550ac3e 100644
--- a/course/scales/project.html
+++ b/course/scales/project.html
@@ -1,4 +1,4 @@
-Project
Project
We've built a solid foundation in D3, SVG, and scales! Now, let's put that knowledge to the test by recreating a barplot inspired by The Economist.
Free
4 minutes read
Our Objective
In this lesson, we aim to recreate a chart from The Economist with several key design elements:
Title, subtitle, and footer
Grid lines with values displayed at the top
Inline labels placed inside or outside the bars
Escape artists Number of laboratory-acquired infections, 1970-2021
Sources: Laboratory-Acquired Infection Database; American Biological Safety Association The Economist
The data
The dataset is very simple! It looks like this:
export const data = [
+Project
Project
We've built a solid foundation in D3, SVG, and scales! Now, let's put that knowledge to the test by recreating a barplot inspired by The Economist.
Free
4 minutes read
Our Objective
In this lesson, we aim to recreate a chart from The Economist with several key design elements:
Title, subtitle, and footer
Grid lines with values displayed at the top
Inline labels placed inside or outside the bars
Escape artists Number of laboratory-acquired infections, 1970-2021
Sources: Laboratory-Acquired Infection Database; American Biological Safety Association The Economist
\ No newline at end of file
diff --git a/course/svg/d3-shape.html b/course/svg/d3-shape.html
index 11df29d5..28f5508e 100644
--- a/course/svg/d3-shape.html
+++ b/course/svg/d3-shape.html
@@ -1,4 +1,4 @@
-Building shapes with d3
Building shapes with d3
Some shapes can be quite complex—like rings, slices, paths, polygons, and curves. Manually creating the d attribute for these shapes would be a nightmare!
Fortunately, D3 provides a module called d3-shape specifically for handling all these shapes. Let’s explore how it can simplify our work.
Free
4 minutes read
Building the line you need
In the previous lesson we introduced the path element, and showed that a line chart is basically rendered this way:
<svg height="300" width="400">
+Building shapes with d3
Building shapes with d3
Some shapes can be quite complex—like rings, slices, paths, polygons, and curves. Manually creating the d attribute for these shapes would be a nightmare!
Fortunately, D3 provides a module called d3-shape specifically for handling all these shapes. Let’s explore how it can simplify our work.
Free
4 minutes read
Building the line you need
In the previous lesson we introduced the path element, and showed that a line chart is basically rendered this way:
<svg height="300" width="400">
<path
d="M0 105 L100 200 L200 200 L300 20 L350 120"
fill="none"
@@ -14,4 +14,4 @@
// Use the function, providing it the 2 paramters
multiply(4, 6))
-// 24
But that's how d3.js works, and I promise you will soon be used to it!
Other helpers
The d3.line() function is one of the most versatile in d3, enabling the creation of key chart types like line charts, lollipop plots, and even radar charts.
However, you can’t use it to create a donut chart! For that, you’ll need to draw arcs, and d3 provides a specific helper for this: d3.arc().
The d3-shape module includes 15 functions in total. Here's a diagram that highlights the most important ones, which can help you build about 80% of chart types!
Main functions of the d3-shape module
Describing each of these functions in detail one by one would be tedious. Instead, we’ll introduce them gradually throughout the course.
What’s crucial to remember is that they all share a common structure: path generators, method chaining, and accessor functions are key concepts you'll need to fully grasp.
But that's how d3.js works, and I promise you will soon be used to it!
Other helpers
The d3.line() function is one of the most versatile in d3, enabling the creation of key chart types like line charts, lollipop plots, and even radar charts.
However, you can’t use it to create a donut chart! For that, you’ll need to draw arcs, and d3 provides a specific helper for this: d3.arc().
The d3-shape module includes 15 functions in total. Here's a diagram that highlights the most important ones, which can help you build about 80% of chart types!
Main functions of the d3-shape module
Describing each of these functions in detail one by one would be tedious. Instead, we’ll introduce them gradually throughout the course.
What’s crucial to remember is that they all share a common structure: path generators, method chaining, and accessor functions are key concepts you'll need to fully grasp.
\ No newline at end of file
diff --git a/course/svg/introduction.html b/course/svg/introduction.html
index 018b3cc6..28ac2f1a 100644
--- a/course/svg/introduction.html
+++ b/course/svg/introduction.html
@@ -1 +1 @@
-Introduction to svg
Introduction to svg
At its core, a graph is just a bunch of shapes such as circles, rectangles, and lines displayed on a screen. Using standard HTML elements to draw these shapes would be cumbersome and limiting.
Fortunately, there's a more efficient solution: SVG. SVG is a versatile and widely-used technology that allows us to draw shapes in the browser with precision and ease.
In this module, we'll explore how SVG works and how it can be harnessed to create dynamic and insightful data visualizations.
Free
4 minutes read
What is SVG
Scalable Vector Graphics (SVG) is an XML-based format for vector graphics. Unlike raster graphics which are made up of pixels, SVG uses vector data (points, lines, and curves) to create images. This means SVG images are resolution-independent and can scale up or down without losing quality.
Anatomy of a React app with a graph built in a svg area.
Most simple example
Here is a very simple react app that uses SVG to render a circle:
A react component called SvgCircle is defined in a file called SvgCircle.tsx.
It renders an SVG area thank to a <svg> HTML element. It has some width and height
In this SVG area, a <circle> is drawn. cx and cy set the position of the circle. r its radius.
Awesome! 🔆
With just a few more circles like this, we'll have a complete scatterplot!
Note: The coordinate system of SVG starts at the top-left corner, where the origin point (0,0) is located.
Coordinates are upside down 🙃
SVG uses a coordinate system where the origin (0, 0) is at the top-left corner of the canvas.
As you move right, the x values increase, just like you'd expect. But here's the catch: the y values increase as you move down instead of up, which is different from typical Cartesian coordinates.
So, it's like the coordinate system is upside down for the y axis.
SVG coordinates are upside-down: 0,0 is at the top left!
Benefits
Pros
Scalability: SVG images maintain their quality at any size, making them ideal for responsive design. Whether viewed on a small mobile screen or a large desktop monitor, SVG graphics look crisp and clear.
Interactivity: SVG elements can be styled and animated using CSS and JavaScript, allowing for dynamic and interactive graphics. This makes SVG a powerful tool for creating engaging data visualizations.
Accessibility: Text within SVG is searchable and accessible by screen readers. This enhances the accessibility of web content, making it more usable for people with disabilities.
Usability: SVG elements are easy to manipulate, allowing you to create complex shapes from simple ones with ease.
Limitations
Cons
SVG has performance limitations, especially when used for data visualization.
→
💡 DOM = Document Object Model. It is basically list that shows all the elements of a webpage and how they're arranged.
SVG graphs are defined in the DOM. Each SVG element increases the number of DOM nodes. If you create a scatterplot with 1 million circles, it will make the make the DOM very heavy.
As a result, the browser may become slow and unresponsive due to the increased workload of rendering and managing numerous SVG elements. This can lead to performance bottlenecks, particularly on devices with limited processing power or memory.
At its core, a graph is just a bunch of shapes such as circles, rectangles, and lines displayed on a screen. Using standard HTML elements to draw these shapes would be cumbersome and limiting.
Fortunately, there's a more efficient solution: SVG. SVG is a versatile and widely-used technology that allows us to draw shapes in the browser with precision and ease.
In this module, we'll explore how SVG works and how it can be harnessed to create dynamic and insightful data visualizations.
Free
4 minutes read
What is SVG
Scalable Vector Graphics (SVG) is an XML-based format for vector graphics. Unlike raster graphics which are made up of pixels, SVG uses vector data (points, lines, and curves) to create images. This means SVG images are resolution-independent and can scale up or down without losing quality.
Anatomy of a React app with a graph built in a svg area.
Most simple example
Here is a very simple react app that uses SVG to render a circle:
A react component called SvgCircle is defined in a file called SvgCircle.tsx.
It renders an SVG area thank to a <svg> HTML element. It has some width and height
In this SVG area, a <circle> is drawn. cx and cy set the position of the circle. r its radius.
Awesome! 🔆
With just a few more circles like this, we'll have a complete scatterplot!
Note: The coordinate system of SVG starts at the top-left corner, where the origin point (0,0) is located.
Coordinates are upside down 🙃
SVG uses a coordinate system where the origin (0, 0) is at the top-left corner of the canvas.
As you move right, the x values increase, just like you'd expect. But here's the catch: the y values increase as you move down instead of up, which is different from typical Cartesian coordinates.
So, it's like the coordinate system is upside down for the y axis.
SVG coordinates are upside-down: 0,0 is at the top left!
Benefits
Pros
Scalability: SVG images maintain their quality at any size, making them ideal for responsive design. Whether viewed on a small mobile screen or a large desktop monitor, SVG graphics look crisp and clear.
Interactivity: SVG elements can be styled and animated using CSS and JavaScript, allowing for dynamic and interactive graphics. This makes SVG a powerful tool for creating engaging data visualizations.
Accessibility: Text within SVG is searchable and accessible by screen readers. This enhances the accessibility of web content, making it more usable for people with disabilities.
Usability: SVG elements are easy to manipulate, allowing you to create complex shapes from simple ones with ease.
Limitations
Cons
SVG has performance limitations, especially when used for data visualization.
→
💡 DOM = Document Object Model. It is basically list that shows all the elements of a webpage and how they're arranged.
SVG graphs are defined in the DOM. Each SVG element increases the number of DOM nodes. If you create a scatterplot with 1 million circles, it will make the make the DOM very heavy.
As a result, the browser may become slow and unresponsive due to the increased workload of rendering and managing numerous SVG elements. This can lead to performance bottlenecks, particularly on devices with limited processing power or memory.
\ No newline at end of file
diff --git a/course/svg/main-svg-elements.html b/course/svg/main-svg-elements.html
index 80c2e0c7..28377e50 100644
--- a/course/svg/main-svg-elements.html
+++ b/course/svg/main-svg-elements.html
@@ -1 +1 @@
-Main SVG elements
Main SVG elements
In the previous lesson, we learned about SVG and how to draw a circle with it.
To create comprehensive graphs, we'll also need other shapes such as rectangles, text, and lines. Let's explore how to create these as well.
Free
4 minutes read
Rectangle
SVG rectangles are created using the <rect> element, which requires the position and size attributes. The x and y attributes specify the coordinates of the top-left corner, while width and height determine the size of the rectangle.
For example, this code will draw a blue rectangle with the top-left corner at (10,10) and dimensions of 80x50.
Here is an interactive example so that you can play a bit with lines and understand how they work.
Text
SVG text is created using the <text> element, which requires coordinates to specify where the text should be placed. The x and y attributes define the position of the starting point of the text.
For example, this code will display the text "Hello, SVG!" at the coordinates (50,50).
Here is an interactive example so that you can experiment with text and understand how it works.
Circle
We talked about them already, but remember that SVG circles are created using the <circle> element, which requires the center coordinates and radius as attributes.
The cx and cy attributes specify the center point, while the r attribute determines the radius of the circle.
For example, this code will draw a red circle with a center at (50,50) and a radius of 40.
<circle cx="50" cy="50" r="40" fill="red" />
Here is an interactive example so that you can experiment with circles and understand how they work.
In the previous lesson, we learned about SVG and how to draw a circle with it.
To create comprehensive graphs, we'll also need other shapes such as rectangles, text, and lines. Let's explore how to create these as well.
Free
4 minutes read
Rectangle
SVG rectangles are created using the <rect> element, which requires the position and size attributes. The x and y attributes specify the coordinates of the top-left corner, while width and height determine the size of the rectangle.
For example, this code will draw a blue rectangle with the top-left corner at (10,10) and dimensions of 80x50.
Here is an interactive example so that you can play a bit with lines and understand how they work.
Text
SVG text is created using the <text> element, which requires coordinates to specify where the text should be placed. The x and y attributes define the position of the starting point of the text.
For example, this code will display the text "Hello, SVG!" at the coordinates (50,50).
Here is an interactive example so that you can experiment with text and understand how it works.
Circle
We talked about them already, but remember that SVG circles are created using the <circle> element, which requires the center coordinates and radius as attributes.
The cx and cy attributes specify the center point, while the r attribute determines the radius of the circle.
For example, this code will draw a red circle with a center at (50,50) and a radius of 40.
<circle cx="50" cy="50" r="40" fill="red" />
Here is an interactive example so that you can experiment with circles and understand how they work.
\ No newline at end of file
diff --git a/course/svg/path-element.html b/course/svg/path-element.html
index 6453256b..aeabec5d 100644
--- a/course/svg/path-element.html
+++ b/course/svg/path-element.html
@@ -1,7 +1,7 @@
-The path element
The path element
In this lesson, we'll dive into one of the most versatile and powerful elements in SVG: the <path> element.
The <path> element allows you to create complex shapes and lines that go beyond the basic geometric shapes. It is essential to build some graph types like an area chart or a line chart.
Free
4 minutes read
Most basic example
The <path> element allows to draw literally any shape in the SVG area.
You provide it with a series of drawing commands that will make straight or curved lines, resulting in your final shape.
Let's check a basic example:
<svg height="300" width="400">
+The path element
The path element
In this lesson, we'll dive into one of the most versatile and powerful elements in SVG: the <path> element.
The <path> element allows you to create complex shapes and lines that go beyond the basic geometric shapes. It is essential to build some graph types like an area chart or a line chart.
Free
4 minutes read
Most basic example
The <path> element allows to draw literally any shape in the SVG area.
You provide it with a series of drawing commands that will make straight or curved lines, resulting in your final shape.
As you can see the <path> element expect a required d attribute. This attribute defines the shape of the path. Let's discover its syntax.
Understanding the d Attribute
The d attribute defines the shape and outline of the path by specifying a series of drawing commands.
Each command consists of a letter that represents the type of drawing action (such as M for Move To) followed by one or more numbers that define the coordinates or control points.
Here is a breakdown of the svg path above:
→
Remember that the coordinate system starts from the top left in svg!
M0 105: moves the starting point of the path to coordinates 0, 105. (M stands for move to)
L100 200: draws a straight line from the current point (0, 105) to the point (100, 200). (L stands for line to)
200 200: draws a new straight line from the current point to the point (200, 200).
Now, experiment with some changes in the sandbox below to get a better understanding of how it works:
Not only lines!
The path element can create a wide variety of shapes, including the most complex ones.
Two particularly useful features are the Bézier curve (C) and the arc curve (A). Check how they work with those 2 diagrams:
Ok, that's definitely not easy to grasp.
In the sandbox below, try to play with the numbers, and see what happens.
Exercises
The good news 🎁
You won’t have to manually write the d attribute yourself. 🎉
While it’s helpful to understand its role, in practice, you’ll rely on d3.js helper functions to generate paths for you.
These functions are all part of a d3 module called d3-shape. They follow a consistent pattern: taking your data and converting it into the appropriate path d string.
The d3-shape module provides functions that generate SVG paths from a dataset. It’s a core component of d3.js!
The d3-shape module is one of the most useful in d3.js! 💙
As you can see the <path> element expect a required d attribute. This attribute defines the shape of the path. Let's discover its syntax.
Understanding the d Attribute
The d attribute defines the shape and outline of the path by specifying a series of drawing commands.
Each command consists of a letter that represents the type of drawing action (such as M for Move To) followed by one or more numbers that define the coordinates or control points.
Here is a breakdown of the svg path above:
→
Remember that the coordinate system starts from the top left in svg!
M0 105: moves the starting point of the path to coordinates 0, 105. (M stands for move to)
L100 200: draws a straight line from the current point (0, 105) to the point (100, 200). (L stands for line to)
200 200: draws a new straight line from the current point to the point (200, 200).
Now, experiment with some changes in the sandbox below to get a better understanding of how it works:
Not only lines!
The path element can create a wide variety of shapes, including the most complex ones.
Two particularly useful features are the Bézier curve (C) and the arc curve (A). Check how they work with those 2 diagrams:
Ok, that's definitely not easy to grasp.
In the sandbox below, try to play with the numbers, and see what happens.
Exercises
The good news 🎁
You won’t have to manually write the d attribute yourself. 🎉
While it’s helpful to understand its role, in practice, you’ll rely on d3.js helper functions to generate paths for you.
These functions are all part of a d3 module called d3-shape. They follow a consistent pattern: taking your data and converting it into the appropriate path d string.
The d3-shape module provides functions that generate SVG paths from a dataset. It’s a core component of d3.js!
The d3-shape module is one of the most useful in d3.js! 💙
\ No newline at end of file
diff --git a/course/svg/tips-and-tricks.html b/course/svg/tips-and-tricks.html
index 1f73b935..62f4c505 100644
--- a/course/svg/tips-and-tricks.html
+++ b/course/svg/tips-and-tricks.html
@@ -1,7 +1,7 @@
-SVG tips & tricks
SVG tips & tricks
By now, SVG might seem straightforward, but trust me, it has its quirks that can make your data visualization journey challenging.
In this lesson, I'll share some tips and tricks that can save yo hours of frustration — lessons I learned the hard way.
Wip
4 minutes read
1️⃣ SVG Elements Don’t Have a Background Color
Unlike HTML elements, SVG elements do not support background colors directly. They also do not support borders.
If you want to create a background or add a border to your SVG, you need to draw a rectangle that covers the desired area. CSS properties like background-color or fill or border on the SVG element itself are not recognized and will be ignored.
Example:
2️⃣ Text Alignment in SVG
Text alignment in SVG works differently compared to HTML. You can control both horizontal and vertical alignment using the text-anchor and alignment-baseline properties, which are unique to SVG.
→
Remember, in JSX, CSS properties should be camelCased (e.g., textAnchor instead of text-anchor).
Here’s a summary of how they work:
text-anchor controls the horizontal alignment →
alignment-baseline controls the vertical alignment →
3️⃣ Grouping Elements with <g>
The <g> element in SVG is used to group multiple elements together.
This is especially useful for applying transformations, styles, or events to a collection of elements as a single unit.
By now, SVG might seem straightforward, but trust me, it has its quirks that can make your data visualization journey challenging.
In this lesson, I'll share some tips and tricks that can save yo hours of frustration — lessons I learned the hard way.
Wip
4 minutes read
1️⃣ SVG Elements Don’t Have a Background Color
Unlike HTML elements, SVG elements do not support background colors directly. They also do not support borders.
If you want to create a background or add a border to your SVG, you need to draw a rectangle that covers the desired area. CSS properties like background-color or fill or border on the SVG element itself are not recognized and will be ignored.
Example:
2️⃣ Text Alignment in SVG
Text alignment in SVG works differently compared to HTML. You can control both horizontal and vertical alignment using the text-anchor and alignment-baseline properties, which are unique to SVG.
→
Remember, in JSX, CSS properties should be camelCased (e.g., textAnchor instead of text-anchor).
Here’s a summary of how they work:
text-anchor controls the horizontal alignment →
alignment-baseline controls the vertical alignment →
3️⃣ Grouping Elements with <g>
The <g> element in SVG is used to group multiple elements together.
This is especially useful for applying transformations, styles, or events to a collection of elements as a single unit.
In SVG, the concepts of stroke, fill, and color work differently than in standard HTML.
The fill property controls the interior color of shapes, while stroke affects the outline. Unlike div elements, SVG shapes don’t have separate properties for borders and backgrounds; instead, you use stroke and fill to control these aspects.
For text elements, avoid using stroke to outline text, as it can result in poor readability. Instead, focus on using fill for color and text-anchor for alignment.
5️⃣ CSS Specificity in SVG
CSS specificity in SVG can be a bit more complex than in HTML. Styles applied to SVG elements can come from inline styles, internal stylesheets, or external stylesheets, and the rules of specificity still apply. However, because SVG elements are often nested and grouped, understanding which styles take precedence requires a good grasp of CSS specificity rules.
6️⃣ Text Wrapping
In SVG, there is no built-in functionality for automatic text wrapping like you would find in HTML or CSS. 😱
You have to manage text wrapping manually or use JavaScript libraries to handle it.
This is very very annoying. In practice, we'll often use a HTML layer on top of the SVG layer to add text (like in tooltips) to make our life simpler.
7️⃣ SVG Dimensions: The Impact of “100%”
Setting SVG dimensions to "100%" can lead to unexpected results, especially in responsive designs. SVGs can scale based on their container, but how they scale depends on the viewBox and preserveAspectRatio attributes. Understanding these attributes is key to ensuring your SVGs display correctly across different screen sizes. For more details, refer to our module on responsiveness.
8️⃣ Filters, Blur Effects, and Gradients
SVG offers powerful capabilities for applying visual effects, such as filters and gradients. Filters like blur, drop-shadow, and grayscale can add depth and dimension to your graphics. Gradients allow for smooth transitions between colors, which can be applied to fills or strokes, adding richness to your visualizations.
9️⃣ Stacking Order Matters
In SVG, elements are rendered in the order they appear in the markup, creating a natural stacking order. This means that the order of elements in your SVG code affects their visual layering. Elements later in the code will appear on top of earlier ones, so careful planning is needed when layering elements to achieve the desired visual effect.
🔟 Dealing with Blurry SVG Elements
SVG elements can sometimes appear blurry, especially when scaled. This is often due to anti-aliasing, which can smooth edges but also cause them to lose sharpness. To fix this, you can use the shape-rendering="crispEdges" property to make edges appear sharper, especially for pixel-perfect designs.
In SVG, the concepts of stroke, fill, and color work differently than in standard HTML.
The fill property controls the interior color of shapes, while stroke affects the outline. Unlike div elements, SVG shapes don’t have separate properties for borders and backgrounds; instead, you use stroke and fill to control these aspects.
For text elements, avoid using stroke to outline text, as it can result in poor readability. Instead, focus on using fill for color and text-anchor for alignment.
5️⃣ Inheritance Rules
In HTML, styling generally doesn’t inherit by default (e.g., a color applied to a div doesn’t affect child elements unless they inherit it explicitly). In SVG, many properties do inherit by default, especially graphic-specific ones. For example, fill and stroke values applied to an SVG container g (group) element will cascade down to all children unless overridden. This makes grouping styles common in SVG.
6️⃣ Text Wrapping
In SVG, there is no built-in functionality for automatic text wrapping like you would find in HTML or CSS. 😱
You have to manage text wrapping manually or use JavaScript libraries to handle it.
This is very very annoying. In practice, we'll often use a HTML layer on top of the SVG layer to add text (like in tooltips) to make our life simpler.
7️⃣ SVG Dimensions: The Impact of “100%”
Setting SVG dimensions to "100%" can lead to unexpected results, especially in responsive designs. SVGs can scale based on their container, but how they scale depends on the viewBox and preserveAspectRatio attributes. Understanding these attributes is key to ensuring your SVGs display correctly across different screen sizes. For more details, refer to our module on responsiveness.
8️⃣ Filters, Blur Effects, and Gradients
SVG offers powerful capabilities for applying visual effects, such as filters and gradients. Filters like blur, drop-shadow, and grayscale can add depth and dimension to your graphics. Gradients allow for smooth transitions between colors, which can be applied to fills or strokes, adding richness to your visualizations.
9️⃣ Stacking Order Matters
In SVG, elements are rendered in the order they appear in the markup, creating a natural stacking order. This means that the order of elements in your SVG code affects their visual layering. Elements later in the code will appear on top of earlier ones, so careful planning is needed when layering elements to achieve the desired visual effect.
🔟 Dealing with Blurry SVG Elements
SVG elements can sometimes appear blurry, especially when scaled. This is often due to anti-aliasing, which can smooth edges but also cause them to lose sharpness. To fix this, you can use the shape-rendering="crispEdges" property to make edges appear sharper, especially for pixel-perfect designs.
\ No newline at end of file
diff --git a/course/tooltip/display-on-hover.html b/course/tooltip/display-on-hover.html
index e22ea4b8..6c4cd588 100644
--- a/course/tooltip/display-on-hover.html
+++ b/course/tooltip/display-on-hover.html
@@ -1,4 +1,4 @@
-Display on hover
Display on hover
In the previous lesson, we learned how to create a Tooltip component, position it correctly, and design its API.
Now, let’s make it appear only on hover!
Free
4 minutes read
1️⃣ Internal State
The first thing we need is an internal state, created with the useState hook.
This state can be null when nothing is hovered. If the user hovers over a graph marker, its value becomes an object of type InteractionData, storing everything we need to know about the marker!
// Initialize an internal state
+Display on hover
Display on hover
In the previous lesson, we learned how to create a Tooltip component, position it correctly, and design its API.
Now, let’s make it appear only on hover!
Free
4 minutes read
1️⃣ Internal State
The first thing we need is an internal state, created with the useState hook.
This state can be null when nothing is hovered. If the user hovers over a graph marker, its value becomes an object of type InteractionData, storing everything we need to know about the marker!
// Initialize an internal state
const [interactionData, setInteractionData] = useState<InteractionData | null>(null);
2️⃣ Updating the State on Hover
The setInteractionData function allows us to update this state. We can use it to update interactionData whenever a graph marker is hovered over!
For example, if the marker is a circle, as in a scatterplot, the code might look like this:
<circle
r={8}
@@ -14,4 +14,4 @@
onMouseLeave={() => setInteractionData(null)} // When the user stops hovering, reset the interactionData to null
/>
-
3️⃣ Conditionally Render the Tooltip
The Tooltip component takes interactionData (the internal state) as a prop.
If interactionData is null, the component returns nothing, so the tooltip appears only when interactionData has a value—i.e., when the user hovers over a marker.
Don’t forget to add pointerEvents: "none" to the div that wraps the Tooltip component! Otherwise, the onMouseEnter() event on SVG elements won’t be triggered.
Scatterplot minimal example
Let's apply what we learnt on a scatterplot, creating a minimal tooltip:
Scatterplot with tooltip. Hover over a circle to get the corresponding country name.
The Tooltip component takes interactionData (the internal state) as a prop.
If interactionData is null, the component returns nothing, so the tooltip appears only when interactionData has a value—i.e., when the user hovers over a marker.
Don’t forget to add pointerEvents: "none" to the div that wraps the Tooltip component! Otherwise, the onMouseEnter() event on SVG elements won’t be triggered.
Scatterplot minimal example
Let's apply what we learnt on a scatterplot, creating a minimal tooltip:
Scatterplot with tooltip. Hover over a circle to get the corresponding country name.
\ No newline at end of file
diff --git a/course/tooltip/introduction.html b/course/tooltip/introduction.html
index ab2ae7ca..cbf7054c 100644
--- a/course/tooltip/introduction.html
+++ b/course/tooltip/introduction.html
@@ -1 +1 @@
-Introduction
Introduction
One of the most frustrating experiences in visual design is seeing a graph element on the screen but missing crucial details about it—even though that information exists!
This module will end that frustration by showing you how to create reusable tooltip components. Let’s dive in.
Free
3 minutes read
🤔 Tooltip: Why?
The graph below is a scatterplot originally published by Datawrapper. It shows a strong negative correlation between vulnerability to climate change and CO₂ emissions 😔.
The graph looks good, and the message is clear.
But while a few countries are labeled on the chart, isn’t it frustrating not to know which country each data point represents?
In my opinion, it definitely is!
This is where tooltips come into play. Try hovering over a square: an informative tooltip with everything you need to know will appear.
The countries with the highest vulnerability to climate change have the lowest CO2 emissions
All countries sorted by their vulnerability and readiness to climate change. The size shows the CO2 emission per person in that country.
Reproduction of a chart originally published by Data Wrapper using react and d3.js.
Design consideration
A few stuff to keep in mind to create a good tooltip:
⚡️ Fast, but not too fast
Tooltips should appear quickly upon hovering, but not so fast that they flicker with small mouse movements
💧 Show only crucial information
Do not overwhelm the user with a ton of information. Pick only what's truly informative. Tooltip are not always necessary, if it's just to remind the marker value, do not build a tooltip.
📍 Positionning
Tooltips should appear near the cursor without obstructing the view of other data points. They should reposition based on available screen space.
👨🦽 Accessibility
Tooltips should be accessible for all users, including those navigating via keyboard.
👯 Consistency
consistent formatting and style across all tooltips within the chart and within the application. Make tooltip style fits marker style.
Tooltip: How?
The tooltip isn’t built in SVG, but in HTML.
Formatting text in SVG can be cumbersome, and HTML offers useful CSS features like borders and shadows that are perfect for tooltips.
The strategy is straightforward: place a div on top of the SVG area with matching dimensions. This div will host the tooltip React component, rendering HTML directly inside it.
Anatomy of a Graph with an SVG area and an overlaying tooltip layer
Now, we have two tasks ahead:
1️⃣ Create a Tooltip component that displays the information.
2️⃣ Ensure the tooltip appears only when the user hovers over a graph element.
One of the most frustrating experiences in visual design is seeing a graph element on the screen but missing crucial details about it—even though that information exists!
This module will end that frustration by showing you how to create reusable tooltip components. Let’s dive in.
Free
3 minutes read
🤔 Tooltip: Why?
The graph below is a scatterplot originally published by Datawrapper. It shows a strong negative correlation between vulnerability to climate change and CO₂ emissions 😔.
The graph looks good, and the message is clear.
But while a few countries are labeled on the chart, isn’t it frustrating not to know which country each data point represents?
In my opinion, it definitely is!
This is where tooltips come into play. Try hovering over a square: an informative tooltip with everything you need to know will appear.
The countries with the highest vulnerability to climate change have the lowest CO2 emissions
All countries sorted by their vulnerability and readiness to climate change. The size shows the CO2 emission per person in that country.
Reproduction of a chart originally published by Data Wrapper using react and d3.js.
Design consideration
A few stuff to keep in mind to create a good tooltip:
⚡️ Fast, but not too fast
Tooltips should appear quickly upon hovering, but not so fast that they flicker with small mouse movements
💧 Show only crucial information
Do not overwhelm the user with a ton of information. Pick only what's truly informative. Tooltip are not always necessary, if it's just to remind the marker value, do not build a tooltip.
📍 Positionning
Tooltips should appear near the cursor without obstructing the view of other data points. They should reposition based on available screen space.
👨🦽 Accessibility
Tooltips should be accessible for all users, including those navigating via keyboard.
👯 Consistency
consistent formatting and style across all tooltips within the chart and within the application. Make tooltip style fits marker style.
Tooltip: How?
The tooltip isn’t built in SVG, but in HTML.
Formatting text in SVG can be cumbersome, and HTML offers useful CSS features like borders and shadows that are perfect for tooltips.
The strategy is straightforward: place a div on top of the SVG area with matching dimensions. This div will host the tooltip React component, rendering HTML directly inside it.
Anatomy of a Graph with an SVG area and an overlaying tooltip layer
Now, we have two tasks ahead:
1️⃣ Create a Tooltip component that displays the information.
2️⃣ Ensure the tooltip appears only when the user hovers over a graph element.
\ No newline at end of file
diff --git a/course/tooltip/project.html b/course/tooltip/project.html
index e544d96d..b2839ed1 100644
--- a/course/tooltip/project.html
+++ b/course/tooltip/project.html
@@ -1,4 +1,4 @@
-Project
Project
We’ve covered a lot in the previous modules! 🎉 Now, let’s put it all together by recreating one of the most famous heatmaps. This exercise will include features like hover effects, tooltips, responsiveness, color scales, and more.
Free
4 minutes read
📍 Our Objective
In this lesson, our goal is to recreate a famous heatmap that illustrates the impact of vaccination on measles infection rates.
This heatmap includes several great features:
Clear, intuitive color scale
Legend
Tooltip
Hover effect
Project
Project
We’ve covered a lot in the previous modules! 🎉 Now, let’s put it all together by recreating one of the most famous heatmaps. This exercise will include features like hover effects, tooltips, responsiveness, color scales, and more.
Free
4 minutes read
📍 Our Objective
In this lesson, our goal is to recreate a famous heatmap that illustrates the impact of vaccination on measles infection rates.
This heatmap includes several great features:
Clear, intuitive color scale
Legend
Tooltip
Hover effect
The Data
The dataset is straightforward!
It’s an array where each item represents a cell. The x value is the year, mapped to the X-axis. The y value is the US state, mapped to the Y-axis. Finally, the value is used to determine the cell color.
const data = [
{
x: 1928,
@@ -35,4 +35,4 @@
.domain(THRESHOLDS.map((t) => t * max))
.range(COLORS);
🦄 Color legend
Take a few seconds to think about how you would build it. Also, did you notice that a little arrow appears on the legend when a cell is hovered over?
Once you have a good idea, read and use the code of the legend componenthere.