D3.js - A Practical Introduction

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi in this video we'll have a look at d3.js I will explain what d3.js is why it's pretty nice to use it and what we can do with that now to learn all about that in this video we're going to build a very simple first chart with DeFreitas and we'll get there step by step to understand what it is how it works and how you can use it so let's start with a very important basic question what exactly is d3.js d3.js is a library for manipulating documents based on data this is a nice sentence you can find in their official documentation on their official web page as well what does it mean though well there are two important parts in this sentence it's a library for manipulating documents so is it like jQuery maybe because jQuery if you know that it used to be very popular in the past jQuery also is a JavaScript library for in the end manipulating documents so manipulating the Dom and that is what documents here means it typically means HTML documents so is it like jQuery well we have to consider that second part here based on data that's the interesting part but what does this mean well the fridge is allows you to manipulate documents so it allows you to manipulate your HTML page your Dom but it has this strong connection to data and in the end it allows you to for example automatically render or re render HTML and SVG elements on your page based on data you make d3.js aware of so you can basically you could say connect elements on your page to data and then for example render multiple divs for multiple data points in your data or update the Dom when your data changes now that might still be relatively abstract will therefore of course have a more detailed look at this and see concrete examples but in a nutshell this is what d3.js is all about and this is how the free J's code looks like you can for example reach out to a div on your page select it maybe select all paragraphs in there for the moment you see there are no paragraphs in there but you'll see how this code works throughout this video then connect some data and that is a key part connecting data and then define what should happen if that data is can but for the first time or if new data was added and for example a render extra paragraph elements with some text inside of them for death data now that might still be very abstract so let's maybe just dive right in and write some code now for that we first of all need to add d3.js to our project and for that we can simply grab that link we find on the official page d3.js org and then simply dive into a HTML document which you have here I created a brand new one a pretty empty one just with a base skeleton and add this import before you have your script code so here I have to defer ejs import and here i have an import to my own app.js file where I'm going to write my own code here so now with that d3.js is added now we can write D free J's code or we can work with it and why don't we get started with this example here so that we can understand what happens here for that well first of all add a div here on this HTML page so instead of the body an empty div just like this and now an apt Reyes we can use d3 this is available because of our import here that unlocks a global d3 object which is now available and you can console.log do you free if you're not sure or if you want to see what's inside of that here if I open my console this is what it prints so this is this d3.js object full of helper methods and useful functionalities and one key thing we can do with d3 here is we can call the Select method on it now select does what the name implies it allows you to select an element in your Dom you have select to select a single element and select all to select multiple elements because with the free Jas and that's one of its key features and strong powers you can actually select multiple elements at the same time and manipulate them all at the same time and that is also another difference to jquery where something like this is not the main focus at least with the free j/s it is a core focus and it is very easy nonetheless here I just want to select a div and for that we can pass in a string with div inside of it and what you have here in the end doesn't have to be a attack you can have any valid CSS selector in here so CSS class name would also be possible if you add a dot at the beginning or by ID with the hash symbol but I want to select by a tag and therefore div selects the first div element which it finds on the page so now we get hold of that now we can do something which might look strange at first I call select all on this and by calling it on the selected div I effectively would now want to select elements inside of the div the interesting thing of course is that this div is empty so there is nothing to select inside of it well stick with me for now it will make more sense in a second let's select let's say all paragraph elements in there and as I said I'm fully aware that at the moment there are no paragraph elements but let's nonetheless select all elements in there and what this gives us is again a selection so select just like select all gives you a selection and all selections you can always call the same methods for example here we could again call select all to select all elements in all those paragraphs which we selected now since we don't even have paragraphs here at the moment I don't want us like anything else instead now comes something important on a selection we can call data in the end to bind this selection to that data and data here typically is an array for example here 1 2 3 but it could also be an array full of JavaScript objects or full of strings so now all paragraphs inside of the div are bound to this data to this array now of course there are no paragraphs but now come something interesting we can also bind elements which don't exist yet to data so that we automatically generate them when that data is there so once we set up this binding and we do that by now calling enter on our data which in the end creates an new selection which is basically a difference between the paragraphs with data that were rendered before and that should now be rendered because of this data binding so you can basically read this as select the div select all paragraphs in there then bind data to that paragraph and then tell me which paragraphs are missing and of course at the beginning since we have no paragraphs in there we get free missing paragraphs because we got free data points here free elements in that array and we're saying please give me all the missing elements all the missing paragraphs to which this data is found so enter now Andy and holds information about these free missing elements these free missing data points and on this selection we can now call append to append a new paragraph for every missing paragraph so this will now in the end add the missing paragraphs to this div this is very strange when you read it for the first time and when you hear it for the first time but this is something you just have to get used to and then it makes a lot of sense once you always keep in mind that the free jeaious is all about binding data to elements and then rendering these elements as they are required so now we're saying give me all the missing elements and for every missing element you render do add such a paragraph and that's by the way important just to select elements and add new Dom nodes just for that we wouldn't need d3.js we could use jQuery or just the native Dom api's which are pretty good at this right now but to have this data binding and make sure that we react to changes in data and so on for this we need C free J's because now this simple code snippet will render three new paragraphs in that div one for every data point here just with this code and if we would want to do something like this with native Dom code and so on this would take a bit more code especially when we then later also see how we can change that data and automatically update what's in the DOM so now I'm not done though I want to set some text in all those paragraphs and we don't do this with a pend but instead now with a text method which basically takes this selection so this paragraph which is created multiple times and for every created paragraph it will now set the text inside of that so it will add a text note inside of the paragraph element and text ever takes some static text like hello or if you want also a function where you get access to the data for this specific paragraph element that was rendered three elements are rendered one for each data point so here data gives you access to each data point for each paragraph and then for example here I can just return data in this function to basically say the paragraph which is rendered for the first data point should output one as text the second paragraph because the data point value is two should output to the third one because it's data point value is free should output free with all of that if we save that and we reload here we see one Q free being rendered here now this might not be the most exciting web app you've ever seen but this hopefully gives you a first idea of how D free jeaious works now typically though you don't necessarily use d3.js to just render some text but you can use it for that and this is really important to me because often when people hear d3.js they think of it as a charting library as a library that makes it easy to render charts now the thing is indeed you can use the free J's to render charts and as you can see by these examples here it's a pretty common use case but d3.js is not limited to that it's a general library for manipulating documents you can render anything with it text numbers charts shapes whatever you want it's not limited to charts if you just need charts our libraries like chart J s might be the better choice because those are heavily focused on charts and probably make that easy then the free j/s with the free jsut got more power you can build up a chart from scratch you can find unit to your requirements and you can do more than that but of course that also means that you need to do more work now with that said however let's see how we can render a basic chart if we want you to do that let's start with some dummy data now this would be data which you in reality might be fetching from some server or from a file but here it's just some hard-coded data so that we have some data to output let's say every data node has an ID has a value and let's say we're working with some sales data here so maybe we have a region but this is totally up to you I'm just coming up with some fictional data here so there we might have us a and then we got our other three data points and you could add more data points of course and let's say here we have India we got China and because I'm from Germany we also got Germany here but you can add more data if you want to now this is the data which we let's say wanna output in a bar chart so a simple bar chart is what you want to render therefore of course we're not going to render a bunch of paragraphs here but some other data nonetheless before we completely remove that if we just swap the dummy data down here for the dummy data constant I defined up here you will see that here in this function we can now access for example data reaching and if we save this and I reload here you see the regions being output here so that's just to show you how easy it is to render notes element Dom no it's based on data still that's not the main thing we want to do here instead inside of that div let's say we want to render this bar chart for this first of all I'll select the div and I actually want to change its style and that is also something you can do with d3.js you can set the attributes and specifically also the CSS classes or the inline styles of Dom elements for example the inline Styles can be set with the style method the CSS classes could be attached with the clast method but I'll go for the style method and on that div let's say I want to set a border to one pixel solid and red and if I do that we see nothing or we see this year but we don't see a real box or anything like that because this div is missing things like a width and a height now you can set everything with CSS as you're used to I'm just using d3.js here to show you how it works but let me also show you how we could add a class here with the class method I could add my container CSS class and now if I add a basic inline style here let's say just like that and of course you could always use a CSS file but if I use that here and I didn't have in my container selector and I give this a width of let's say 250 pixels and a height of 200 pixels you will see that now I get an error simply because clost actually takes the second argument which defines whether that class should be added or not and here I want to add it so I set this to true you have this two arguments set up so that you could change this dynamically and toggle a class for example but with true this works and now we have this nice container now in there I wanna render my bar chart that's the idea so to do that to render the bar chart here we need to again select the div and work with it we need to render elements inside of the div so first of all I'll store that selection here in a container constant so that we can always just refer to container and work with that style Dave here now to add some elements here we want to select all the nodes which we eventually want to add and that could be for example more divs and then bind some data to that now one important note though if you select all divs here in the container by default this would select the container as well because that awls is a div and it will include that selection on which you call all now to rule that out we could select for example by a CSS class like bar and make sure that the elements we are about to render half that CSS class later now we can find our dummy data here with the data method and now again call enter to find out which data wasn't rendered yet and when this app first loads of course nothing was rendered so this will be a full selection full of four data points which should be rendered so then we can append a new div here for every missing element and on every div I want to add the bar class here so that later we can select Vitus so this will now give me access to all my bars so all the bars in the bar chart at the moment of course not much is happening but we are rendering a bunch of divs if I reload we don't see anything but if we inspect this here you'll see instead of the diff there are four bar deaths being rendered now in order to make sure that we do is see them I will add a nice styling here since they have the bar class we can target this alternatively we could of course also set Styles here with the style method but all you CSS styles and give every bar let's say a background color of 5 - 1 7 5 1 or actually maybe a little more in this area so it's a nice purple color so 7 - 0 5 7 0 is the color I'm using here now I'll not set the width and the height here though instead I'll do this here in app jeaious with JavaScript for this we can use the actor method or also the style method actor would allow us to set the width attribute directly on the element style allows us to set the width style which all the works and I want to set the width style and later we want to dynamically adjust the width based on the value so that the bars are not equally sized but respect the different values but for the moment I'll just set the width to let's say armed 100 and fifty pixels and not the wif sorry the wif should be let's say we have a total container with of 250 since we have four data points let's maybe go with fifty pixels and the height should now be let's say 150 pixels and with that if I reload you see this bar here pretty large but the reason for that is that these are all the different divs just below each other they're not rendered side-by-side they're rendered below each other now of course I want to have them next to each other horizontally and to achieve this of course here in the container we could set display to flex and justify content space around and if I now reload all these bars are sitting next to each other just because of the diferencia saz styling now of course this is not a realistic bar chart though because all the bars have the same height and we typically might want to adjust this based on the actual data point for example China should have the the tallest bar Germany should have the smallest so to achieve this we need to set the height here dynamically and not hard-coded that the cool thing is just as with the text earlier where you could pass in a hard-coded value or a function to get access to the data this Dom node is bound to you can do the same for basically all other methods you have here including the style method the value which is wanted here can be a hard-coded one or you pass in a function that gets access to the data point that is responsible for rendering this concrete div so therefore this function will be called once for each stiff and therefore in total four times once for every data point so this is the value for the data point for which a new div is being rendered and we get access to that data and now we could simply take that value let's say times 15 something like this and use this as a width so that we use data dot value data is the entire object and we have a value here that's why we use data dot value times free at times 15 sorry like this plus pixels so Plus this to convert it to a string and add pixel because we still need a string here as a value and that string should contain a valid CSS value with that if we now save this you see bars of different height now that's where we can make the next step d3.js is great for document manipulations and something like this is fairly easy to achieve as you can tell that's not a lot of code these are just 19 lines and six lines of that are just our dummy data but d3.js is not limited to HTML and if we switch to SVG we are way more flexible when it comes to rendering content and to laying it out correctly and why are we more flexible with SVG because with SVG if we're rendering a SVG element and then content in that element we actually can work in a coordinate system which gives us a more fine-grained control over where in the coordinate system which elements should be positioned and we don't have to use CSS layout concepts like flexbox to position elements instead we can use data to position elements in that coordinate system and that's closer to what we do in charts anyways they use coordinate systems they use x and y axis so that's why you typically use SVG when you want a render charts or charts data so for dad and index.html I will switch from div to SVG here so that we have an SVG element here which is still a regular HTML element but well we use SVG under the hood then and here therefore we select SVG and here we don't render a div but a rect let's say a rectangle this is also a valid SVG element which we can use inside of a SVG node we can still give this a CSS class this doesn't change and we can still set the width and the height however we shouldn't do this with style instead with a true and then you all don't need to provide a string here with pixel instead you can just insert a number and it will automatically be treated as pixels you if we do that we get a slightly different result than before we do see a bar but it seems like all bars are are on top of each other and they're not laid out horizontally and they also lost the color we do see the different rectangles being rendered though and they have the right class well the color is missing because SVG elements rectangles and so on are not styled with background color but with fill fill is simply how you set the background color the fill color of SVG elements we also see that flexbox has no effect here and therefore we can remove it there is a more elegant way of laying things out with d3.js anyways and whilst I'm here already I'll actually set up order of one pixel solid and that same purple I have down there on the container like this and that of course means that in app tray as we can't get rid of this style assignment which was just there for demo purposes anyways so if that they have the right color but they're still not laid out correctly and that's happening because of this coordinate system now unlike with regular HTML elements and CSS which we then use to lay elements out in SVG we use that internal coordinate system which exists in that SVG container here and currently we're not assigning any positions to any of the rectangles in there therefore they all have the same position and that by default is the top-left corner that's by the way important the coordinate system in the SVG element starts in the top-left corner not at the bottom left what we're typically used to from charts but in the top left that's why here these rectangles sit all in the top left border and actually sit on top of each other because they all have that point top left corner on top of each other therefore and that's what I said d3.js gives us a nicer way of laying things out because instead of styling this with CSS which means that we have to control margin and spacing and positions in CSS it would be nicer if we could lay everything out here and we don't have to do this with CSS fools where we manually have to calculate things like to hide and width and maybe the positioning but instead if we could let the free j/s calculate this for us because after all that is one of the reasons why we use d free J s it's great for working with data and for helping us bring that data to the screen and indeed it also helps us with calculating positions of elements and so on so that for example if we have four data points and we want to render four bars next to each other the free J's helps us render things nicely positioned next to each other now for that we need to bring in an extra package though you can search for d3.js scale because d3.js is a modular library d3.js itself which we already imported just has all the core functionalities so this package here then if you need functionalities that for example help you with scaling and with deriving positions of elements you need to bring in the additional d3 scale package which depends on the free J's but adds extra functionalities to add it you can simply grab such a link here D free scale V freemen in my case and add this in your index.html file after the D free J's import before your apt is import and we can also add the Fourier to make sure that this is not getting executed too early and that this all executes in order here so back to App jeaious now here we should be able to set up a scaling function which essentially is a function that helps us calculate positions of different data points that are related to each other for that we add a new constant and we can name it x scale and that should give us a function that allows us to calculate the position on the x-axis and we call d3 scale band to basically give us an ordinal scale so basically a scale where every item should have the same width there also are other scales and we will need another scale for the height for example but when it comes to the width all bars should have the same width and scale band basically gives us a uniform distribution where all items have the same width now in order to let d3 calculate the width of every item we need to let d3 know how much space is available we did it by chaining a method here on the result of scale band and that's the range round method this basically tells the free J's which space is available and it wants an array which has a from Q value so from 0 Q the entire width you have available for example now we're working with a container here for our chart and that container has a width of 250 pixels so here we have 250 as an upper bound and this in the end let's do free J's figure out how much space every item should have now we also call another method on the result of this and that is padding which allows us to define a percentage padding between the items and I'll set this to 0.1 for essentially just a tiny bit of padding between the different bars with that we have the X scale now we also want a Y scale which allows us to calculate the height of the data points dynamically for that we call the freeze scale linear and by the way scale band and scale linear are methods which are only available because of this D free scale import so scale linear allows us to now calculate the right value the right height for example for the different data points taking into account different values for the value property so now unlike scale band this will not give us the same width for every data point or the same height instead it will give us different values now actually to be entirely correct both scale band and scale linear will not give us a width and a height but instead they give us functions that allow us to translate a value cue another number to be precise they will give us information about the X and the y-axis of where elements should be positioned and for that it is important to understand that with the D free scale package we basically give the free information about these two axes so x and y and D free will then be able to position elements along those axes and with scale band and scale linear we create functions that will allow us to generate positions and sizes within that coordinate system D free will be aware of sounds very abstract we'll see it in action but that is what the scale methods here in the end will do and what the idea behind them is and now here on scale linear we want to call domain and what domain does is it basically allows us to specify which min and Max value we want to be able to map into our chart in this case so we enter an array here and now we're going to render this value and the smallest possible value we theoretically could have is 0 so basically the x act should cross the y-axis at zero this is the smallest value we want to have on the y-axis so to say and the biggest value let's say is 15 so that we have some empty space above China in this case we could go for 12 but then the bar of China would go all the top to our chart so to have a little bit of empty space at the top let's use 15-year so in the end domain is our way of letting d3 know about the min and Max values it has to deal with so we let it know about the range of values it should be able to map into its internal coordinate system which later is rendered to the screen and here I'm saying my values are between 0 and 15 please position my values which in reality are between 6 and 12 inside of a system that has room for values down to 0 and up to 15 because if you look at a chart anywhere doesn't matter which kind of chart typically of course the smallest value on the y axis is not the smallest value rendered in a chart but it typically is 0 and the biggest value on the y axis typically is not the biggest value in the chart but instead a value above that biggest value so that there is a little bit of extra free space at the top but that's in the end what we're setting up here and then on that we can call their range method so not range frown but just range and here feed in the actual available space in pixels and there we of course have a height of 200 pixels and the important thing is that you start with the max value so with 200 and go all the way to zeros to the bottom now we have to start with the bigger value here 200 as a first value because the coordinate system d3.js has in mind so which it kind of uses behind the scenes to then later generate our positions and sizes that coordinate system starts in the top left corner so the position x0 y0 is in the top left not in the bottom left as it typically is in our course systems so because of that for the x-axis it is left right there we use a range where we start at zero and go up to our biggest value but for the y-axis since we start at the top and go to the bottom and not the other way around as we are used to we have to switch those two values and the biggest value comes first and then we go to the smallest value so if that we set up X scale and Y scale and both are now simply objects and all the functions which we can use to calculate concrete values for a width and height based on the data point that is being rendered we can use it down there when we render our bars on every bar instead of having a hard-coded with we can call X scale dot bandwidth as a function like this all lowercase since every bar has the same width we don't need to pass in any data specific value instead this will just give us well an equal value for every bar and in the end it does that by taking the available width and dividing it by the number of data points we have taking into account some extra padding now for the height it's a bit different there we want to keep that anonymous function but we're going to use something from the data now to translate it into actual height and pixels that takes into account the available range but also our theoretical min and Max values here and to do that we just call Y scale here as a function and we pass in data dot value as a well value and this will translate it into an actual value that's being rendered if we now reload we see something but it looks like all the bars are now simply stacked on top of each other and there's a good reason for that currently they all have the same width and they shouldn't have that of course because of my scaling here and certainly they shouldn't all take the total amount of with the total available width well that they all take the total amount of width is my error we also have to specify a domain here for X scale to basically let the scaling function know how many data points we have and we do that by using our dummy data here and then by calling map on this and for every data point we get out of there we can just access the region field and that basically means we have now an array full of strings which now is that array of unique data points we need here for domain so that the scaling function knows how many items we'll have in total we do that and reload now at least the width is correct they're still all on top of each other but now every bar has a width that is small enough cube theoretically fit for bars next to each other into our chart however of course they should be next to each other and not on top of each other so to ensure that we now don't just need to set the width and the height but also the X and the y attribute which we can do on SVG elements like our rectangle and we again set x and y with help of our scaling functions so here we again pass in the function so that we get access to the data point for which this rectangle was rendered and for X I want to call X scale and fit in data region because I used my regions here as my domain for the X scale so d3.js is aware of the for region names here and now by passing in our region here again it knows which data point it is for which it should position the item and it automatically will position it correctly along this available range here and we do something similar for Y there I pass in my data and I call Y scale here and pass in data dot value so that it knows where to position this on the y axis and if we now reload this looks interesting but now at least we see four different bars now why does this look interesting here it looks the way it looks like because our height is actually calculated incorrectly if we change our height here to be the maximum available height so 200 in our case here minus the calculated y scale value now it looks the way it should look like and the reason why we have to do this is simply that by default the coordinate system for D free does not start in the bottom left corner but in the top left corner so therefore everything is calculated from the top left and that means that since we start at the top and not at the bottom we calculate the actual height by taking our max height and reducing it by that calculated value here on the y scale so with that we now got a nicer bar chart here with d3.js now especially that scaling thing is definitely something you need to get used to but here practice is everything the more you work with that the more charts you build the easier it gets and in the end what you learned here about x and y scale and this code you see here that already is some code you're going to use a lot you also of course have to get up repository of the d free scale package where you can dive deeper and learn all about the different scales you have there and how to use them to understand is positioning better you can also simply manipulate those values here so as i said we start on the top left corner and the y scale function for it but simply gives us the y-axis position off this rectangle here and it takes the concrete value into account to give us the right position in relation to the other elements that are being rendered so for example here this first bar the leftmost one which is for the USA has a y-value of 66.6 six six six six and so on if we set this to zero here in the dev tools you see it's all the way at the top which basically proves the point that we will start in the top left corner x0 y0 would be exactly in the top left corner now we had x8 here because of the extra padding that was set up and that's all taken into account automatically by D free J s and we had Y is 66 and so on because of the Y position we derived based on the value now that shows you why of course have to calculate a height by deducting that from the available height because then you basically render a rectangle which has a height of 200 minus the space that should be empty because it's the space from the y-axis at the top to the beginning of the bar if we look at it from the top so this empty space here that should stay empty and that is the distance between the top which is zero and the starting point of our rectangle which is 66.6 666 ends on so Y scale and X scale if you call them those functions don't calculate widths or Heights they actually just calculate positions inside of that coordinate system d3.js uses behind the scenes and it's set up to you to translate these positions into for example a height as we're doing it here now for the width we have this bandwidth function which we can call on X scale to get this equal width for all the bars but for the height we take the position from the top and deduct this from our total height which we have available to get the height of the bar we want to have from bottom to the top so once you think about it like this this also shouldn't be too mysterious and hard to grasp now with that of course there's more you can do you could add an axis you could do other things but I'll leave it there for now was long video already I hope I at least could get you started with d3.js and explain roughly what it does and what difference is to jQuery and so on are and that it's not just for charts and I hope that this basic functionality is clear now there is just one thing which I also want to dive in before I really finish the video and that's that select all thing here which I did before I added data I mentioned that I do this even if nothing was rendered before and the reason for dad is actually that we now bound data to those bars and yes initially we have no such bars but that changes once such bars were rendered and you can see the effect of that if you actually add let's say a set timeout function down there where you set a timer of let's say two seconds to then execute this function and in there I'm going to use my bars here the bars which were rendered here and I'll set my bars to some new data which is let's say my dummy data but with the slice data I'm only going to take a part of it only the first two items let's say so that it's not the full array but half the data now if I do that I can call exit on this and exit is basically the opposite to enter enter gave me all the missing elements which were not rendered yet exit gives me all the elements that are too much that should be removed based on the new data I'm feeding in and it's not taking any elements that are too much it's looking at with which data the elements were rendered and which data is still there and just give me the elements that were rendered but for which the data is not there anymore and then we can call remove on that selection to remove all those elements from the DOM and with this if we save this and reload you will see that after two seconds the last two bars disappeared because they're not part of the rendered data anymore and this shows why we have to select bars here I'm using bars which is this constant which is this entire selection which in the end are the rendered bars but if I wouldn't select bars here this would not work if I would remove that code nothing would actually work here it wouldn't be rendered at all and the reason for that is that the free choice would not work which concrete elements even if they're not yet on the Dom will be tied to the data it's not the container that's tied to the data the elements inside of the container are connected to the data instead that's what we have to select them even if they're not there yet so that the freezer has knows which values will eventually be there because it can only tell me which data is missing or too much if it knows which data should be there so which elements it should find and if we just say hey have a look at the container well we do have one container here we then try to render more rectangles based on missing data but the container is no such rectangle so that doesn't work out that's by select all matters here
Info
Channel: Academind
Views: 123,679
Rating: undefined out of 5
Keywords: d3, d3.js, d3js, d3 tutorial, d3.js tutorial, d3js tutorial, d3 basics, d3 dom, d3 data, d3.js data, d3 data joins, d3 course, d3 chart, d3.js chart, d3js chart, d3 barchart, maximilian schwarzmueller, maximilian schwarzmuller
Id: TOJ9yjvlapY
Channel Id: undefined
Length: 44min 45sec (2685 seconds)
Published: Mon May 25 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.