Hacker News new | ask | show | jobs
by mhale 2922 days ago
I worked on a project that required some pretty standard line charts, but with the addition of an overlaid set of horizontal "benchmark" lines -- and some callouts. After struggling (and failing) to get what we wanted out of two different off-the-shelf graphing libraries (one of which was built on top of D3), we finally bit the bullet and just built the charts we wanted in D3 "from scratch". Once I wrapped my head around the model, it was such a pleasant experience. D3 is soooo nice and well thought out. You mayneed to level up in SVG, but it is so freeing to be able to bind data and display it basically any way you want. In hindsight, I wish we started with D3 from the beginning and I would not hesitate to pick it up for even simple charts again. It really is worth climbing the learning curve, which isn't as big and scary as it appears at first sight.
8 comments

I had a project with the same requirements and settled on echarts[0] (version 2 at the time, now on 4). Its adoption was, at that time, very diminished due to everything being in Chinese. Its base graphics library, zrender[1], still suffers this issue. Were it to become more introduced to westerners, it could take the place of d3 for many of these use cases since its API is much easier to grok. Granted it's all canvas, but most uses don't care how it's rendered.

Edit: well, browsing zrender's source, I see svg logic too

0 - https://github.com/apache/incubator-echarts

1 - https://github.com/ecomfe/zrender

I could not agree more with you. So many folks here seem to be missing the actual utility of D3 and why it still remains relevant and useful in todays JS/Web landscape.

If you need standard stuff, there are plenty of awesome plotting libraries that utilize D3 on the back-end while abstracting the complexity away from you. Some even try to give you some amount of flexibility and composability to customize them, but they are always going to have limitations compared to the raw power and flexibility you have if you roll your own D3 visualization.

You can't have it both ways, and that's something a lot of people don't seem to understand. If you're absolutely sure that a visualization library can support all your requirements, then it is absolutely the easier way to go about doing things. But you just have to be really sure that your requirements aren't going to change past the limitations of the visualization library of choice.

How much extra work would it have been, percentage-wise, to write the whole thing from scratch? What features did D3 give you for free?
D3 gives you a diff algorithm for free. That handles adding new items to your visualization, updating existing ones, and removing them. You implement the enter, exit, and update (update may have been deprecated). That makes it easy to take your data and handle changes. It will handle animations in a very easy way for each of those cases as well.

In data visualization, creating a scale based on the domain of your data (the range of your data) is annoying. This is handled for you by utility libraries in d3. It also can draw the line ticks of the scale without issues.

Also placing labels is not too easy. D3 does that nicely.

The truth is you can do all of that yourself, but if I were to try it, I would go over the d3 utilities first just to see how complicated some of the visual aspects you haven’t thought of but will need are.

The drawing part of d3 (SVG, canvas) are not so hard to do on your own, but the way d3 isolates the context of what you are coding is very helpful. I’ve only run through the examples and read the d3 book as well as several other charting books, but I don’t use d3 on a day to day.

But let’s go over a more realistic example. In one of my books, the author writes about simple line charts and displaying the quartiles (made by standard deviations) of the data. None of my charting libraries handle that. Rolling my own would be very time consuming. Doing this in d3 would be more feasible than the alernatives.

Not OP, but a someone who uses D3 every day, it gives you (almost) total freedom. You can decide where to put your x and y axes, legends, labels, etc. You can decide how data determines not just how something appears on the screen (like a bar chart of y height) but how the underlying data determines its classes and styling, etc.

D3 is awe-inspiring in its scope, and learning to use it has a steep learning curve. But for anything beyond trivial use cases the freedom it affords you is worth the effort.

I must be missing something, this doesn't answer the question at all. Literally everything you said is true for just building the graph in JS/SVG. What does D3 give on top of that?
Maybe this will help, it creates an SVG graphic by default.

Consider how much JS you'd have to write to even start creating all the frameworks to build in native SVG structures... a lot.

I created html graphs with tables in the late 90s, made Flash graphs in 2000s, upgrades to numerous JS based charting libraries after this, building custom graphs the whole way.

I had looked at D3 so many times over the years when it first showed up online. But it "looked" complicated, no obvious "chart" library, etc...

Finally, when I tried D3, I was like "why the f didn't I start with this?"

Maybe I'm missing something, but it's literally impossible to achieve something with D3 that you can't achieve with JS+SVG, since D3 is a JS library that emits SVG. The question is how much work you can afford to do. You can always roll your own. But you're going to have to a lot of fussing around with things like figuring out where to put tick marks or grid lines, maybe you need to parse some CSV, or figure out how to label dates. There are also things like Voronoi diagrams which are, if not tricky, at least tedious and annoying to implement yourself. And then there's simple statistical operations like making histograms or calculating medians or other quantiles that, well, you can always implement those yourself.

Basically, D3.js strikes a good balance between ease of use and expressive power, that leans pretty far towards expressive power, while still being far, far less work than rolling your own.

If you do it yourself in straight JS, you'll very quickly start building the common tools of D3: various scaling mechanisms mapping the domain to the pixels, data binding against a set of DOM elements, converting an array of data values to the co-ordinates for the d attribute of an SVG path, etc.

Somewhere else someone described D3 as a hammer, and that's a good analogy, because if you don't start with a hammer, it's the first tool you'll make for yourself when you need to pound nails.

D3 particularly excels at graph animations and data transforms (as might be helpful to facilitate graphing). Its one of the most comprehensive graphing libraries around. Well written code that uses it looks like pure elegance. Its amazing how much functionality you can get out of so little code. It does take some time and a solid understanding of javascript and scope.
I think this article does a great job breaking down the d3 API and answers your question in detail “D3 is not a Data Visualization Library” @Elijah_Meeks https://medium.com/@Elijah_Meeks/d3-is-not-a-data-visualizat...
It's an API for building custom charts. It's a huge step up from having to fully 'roll your own'. If you have to do any kind of vis that isn't available in the various off the shelf libraries, you can put it together with D3 easier than you could if you fully DIY a solution. It's well thought out but you have to use it for that to be more obvious. This book (by the D3 author) got me started, it's worth the hassle of learning [0].

[0] http://alignedleft.com/work/d3-book

The creator of D3 is Mike Bostock. That book is by Scott Murray.
Oh, ain't I silly!
So d3 is actually a _set_ of libraries, of various kind, most of which happen to be useful for data visualisation. Through its richness, there's a good chance that at least _some_ of those libraries will fit your use case well enough. There's nothing stopping you from not using it, and in fact my most recent work was with Canvas, and the only thing I used was d3-scale, which aids mapping datasets into number ranges and selecting ticks.

In another case I might not care about it, but use d3-selection, a mechanism for creating a data-driven DOM tree — but it's pretty clear that you can achieve similar mechanics with React.

Importantly, you don't have to pull the whole thing into your dependencies just because you use a bit of it, and it's light on own dependencies. So just using a small subset of functionality is "cheap."

Just browse through a basic tutorial of D3 and you understand how much niceness it gives :)
It gives you a well defined set of primitives to work with. It's also a well established library, so there are a number of good resources on it (and it's seems to be mostly bug free).
Any beginner resources you'd recommend for someone looking to get started with D3 and beginner coding experience?
Go to https://beta.observablehq.com and dive in: just start forking other people’s examples and fiddling and looking up stuff in the docs or asking for help whenever you get stuck.
do you have any recommendation on resources on d3 for beginners? Personally I find d3.js very challenging, there is tons of example out there and simple tutorials, but I don't think there are tutorials that bridge those harder examples for beginners.
d3 has a lot of really useful libraries baked in. You can even use them independently and roll your own svg using its components as utilities. I find this super helpful when using d3 as a whole isn't really a good option (as part of a React/React-Native app for example).

Such as: https://github.com/d3/d3-shape

https://github.com/d3/d3-scale

Doing it from scratch without the help of utilities like these would be much harder.

A couple examples:

var line = d3.line() .x(function(d) { return x(d.date); }) .y(function(d) { return y(d.value); }) .curve(d3.curveCatmullRom.alpha(0.5));

line(data); // gives you svg path

and

var color = d3.scaleLinear().domain([10, 100]).range(["brown", "steelblue"]);

color(20); // "#9a3439" color(50); // "#7b5167"

That's not really a fair comparison. Just because something is "baked in" doesn't mean you can't get similar functionality from other libraries in a more ala-carte fashion.
It is a la cart here. Look at those two repos as examples.
it is alacart and baked in at the same time! This article breaks down the API in graleater detail. https://medium.com/@Elijah_Meeks/d3-is-not-a-data-visualizat...

All of the functionality in d3 is split up into smaller modules that can be required independently.

The last thing I did in D3 probably would have taken several times more effort with raw SVG and JS, I expect. I couldn't find a higher level graphing library that would let me do what I really wanted at all (a custom radial graph that had fairly complex user interaction), and D3 was a perfect sweet spot I think.

It gives you a whole lot of helper functions that really speed things up, data binding, animations, transitions, etc.

what you described is an outlier.

For the vast majority of data visualizations that are of the standard type, d3 is a not a scalable way to do it. The lack of high level abstractions means developers can't be as productive can be, and the code base implemented for one svg visualization is likely not usable for another, unless you put abstraction wrappers around it, which is basically nvd3, or other d3 wrapper libraries..

Yeah, but then you just end up making another charting library which is less flexible and limited by the constraints forced by your abstractions. There is a fundamental reason why D3 has remained relevant for so long in an ever-changing JS/Web landscape.

If you want reusability, build your abstractions or use a charting library, but recognize that this will in-turn limit the flexibility of your reusable code.

You can't have your cake and eat it too. It's the very reason why D3 is still so relevant today.

you basically re-iterated what I said... the d3 wrapper libraries are likely sufficient for 85% of the use cases out there. For the others, you either do everything in D3, or you extend those wrapper libraries to give you what you need.
Not exactly. "Extend those wrapper libraries" is not at all trivial or easy because when the wrapper library / charting library creates abstractions, it also places some limitations on the overall customizability. So when the wrapper or charting lib isn't cutting it, trying to shoe-horn the feature you need is not always easy and usually involves ugly hacks that reduce the overall simplicity of the code if you had just rolled your own D3 implementation from scratch.
The difference is between tweaking the wrapper library or write everything from the ground up because one can not deal with tweaking the wrapper library.

Pros and Cons with both approaches no doubt.

I had a similar experience, off the shelf didn't do what the customer wanted, so I delved into D3, which to be fair has the strangest API on first glance.

After learning how it works, and more importantly why, it's more obvious why it's useful. It's a chart building toolkit, not a chart builder, and you can dream up all sorts of interesting things with it.

The upside is that the author has a huge library of examples you can build from [0]. It's a great tool!

[0] https://github.com/d3/d3/wiki/gallery

I find that Google Charts is great when I need simple charts:

https://developers.google.com/chart/

High quality, very good browser support, good docs, and well-maintained. There are wrappers out there for React/Vue/whatever too

Would it possible at all for you to write up how you did that? Would help me and perhaps a lot of others as well.
How do you recommend leveling up in SVG?
Thank this example: https://bl.ocks.org/mbostock/e3f4376d54e02d5d43ae32a7cf0e6aa...

...

  svg.insert("g", "g")
      .attr("fill", "none")
      .attr("stroke", "steelblue")
      .attr("stroke-linejoin", "round")
    .selectAll("path")
...

You might assume that g, fill, or stroke might be d3 terminology but it's really SVG! A quick Google of "svg g" will get you to https://developer.mozilla.org/en-US/docs/Web/SVG/Element/g

It blew my mind open, hope to share the same.

To my untrained eye that looks like css had a baby with js and the baby is an svg.
SVG is tied closely to CSS, so you can go in your CSS and create a style for your D3 graphs and do things like:

    .chartline { stroke-width: 3px; color: red; }
D3 has some convenience functions in JS for creating SVG, but you don't have to use them, you could write SVG just like HTML, it will look more like this in the DOM:

    <g fill="none" stroke="steelblue" stroke-linejoin="round">
      ...
    </g>
Gratuitous self-link, but I wrote this article about the SVG basics, what's useful to learn, and how it's different from HTML: https://macwright.org/2013/06/25/just-enough-svg.html