A friendly reusable charts DSL for D3

Overview

D4

D4 is a friendly charting DSL for D3. The goal of D4 is to allow developers to quickly build data-driven charts with little knowledge of the internals of D3.

Quick Start


For the bleeding edge version of d4 download it directly from the github repository. If you prefer a more stable release you can install the latest released tag using a package manager like bower.

$ bower install d4
or
$ npm install d4

Once you have a local copy of d4 simply include it after d3 in your source file.

<!DOCTYPE html>
<html>
<head>
  <!-- sensible defaults for styles -->
  <link href="d4.css" rel="stylesheet" />
</head>
<body>
  ...
<script src="d3.js"></script>
<script src="d4.js"></script>
</body>
</html>
Hello World

Here is the most basic example, which uses many of the preset defaults provided by d4.

var data = [
  { x : '2010', y : 5 },
  { x : '2011', y : 15 },
  { x : '2012', y : 20 }
];
var columnChart = d4.charts.column();

d3.select('someDomElement')
  .datum(data)
  .call(columnChart);
Getting Fancy

d4 allows you to quickly build up sophisticated charts using a declarative and highly contextual API that allows you to mixin or mixout features from your chart.

var data = [
  { x : '2010', y : 5 },
  { x : '2011', y : 15 },
  { x : '2012', y : 20 }
];

// Create a column chart without a yAxis, but with a grid in the background.
var columnChart = d4.charts.column()
.mixout('yAxis')
.mixin({ 'name' : 'grid', 'feature' : d4.features.grid, 'index' : 0 })

d3.select('someDomElement')
  .datum(data)
  .call(columnChart);
Additional Examples

There are many more examples of d4 in the examples site inside the source code repository. Simply clone the repo and open the examples/ folder in your favorite web browser.

You can find a hosted version of the example site here: http://visible.io/

You can find a quick-start presentation on d4 here.

Philosophy


Many charting libraries do a poor job when it comes to separations of concerns. They attempt to be an all-in-one tool, which is at odds with how modern applications are built. Developers do not want a monolith that owns the data transformation, visual aesthetics, and interactivity. This leads to enormous libraries with huge config files, where every minutia about the chart must be decided upon beforehand. This typically means developers must first learn a specialized API in order to control even the most basic aspects of the chart. d4 believes many of these responsibilities would be better delegated to other technologies. If developers were woodworkers then d4 would be a jig, which allows complex cuts to be made in fraction of the time it would normally take.

CSS is for styling

Many charting libraries make internal decisions on visual aesthetics, which may remove control from the graphic designer, who may or may not understand JavaScript let alone a specialized charting API. Choices on visual design like the colors for data series and font sizes are best made in CSS. d4 exposes convenient hooks in the generated markup to allow visual designer to get precise control over the look and feel without needing deep knowledge of d4.

The chart does not own the data

Data is a stand-alone object, which can be relied upon by many other scripts on the page. Therefore, a charting library should not change the data object. It can make non-permanent transformations.

Context over configuration

There is a software design concept called "convention over configuration," which states that software should specify a collection of opinionated defaults for the developer. The goal of this approach is to lessen the number of obvious choices a developer must make before they are able to use the software. Instead, configuration should be saved for instances where the defaults do not apply. d4 extends this concept a bit and suggests that configuration should also be highly contextual to the object the developer needs changed. Instead of making choices in some abstract config file, developers instead use a highly declarative API to make changes directly to the object they want augment.

Terminology


d4 uses specific terms to describe the components of a chart.

Chart - The data rendered by d3 into a graphical representation.

Feature - A visual component of a chart, which helps convey meaning in the data.

Dimension - A segment of the data described by the chart.

Parser - A parser prepares the data for a chart.

Base Charts

Chart Features (Mixins)

Contributing

If you make improvements to d4, please share with others.

Fork the project on GitHub.

Make your feature addition or bug fix.

Commit with Git.

Send @heavysixer a pull request.

Inspiration

Where possible d4 follows existing d3 community best-practices. The inspiration of D4's modular and declarative structure came from Mike Bostock's article on writing reusable charts in d3. d4 also follows the general update pattern too. (mostly)

Other Projects using d4

d4-rails

Comments
  • Publish on npm

    Publish on npm

    We've completely moved our client-side dependencies from Bower to npm and use Browserify for dependency management. Browserify allows you to include npm modules on the client. It's great.

    There are ways to include Bower modules within Browserify. Debowerify works sometimes but can cause conflicts depending on what other transforms you have.

    For reference for others coming here, this is a way to get d4 workings within Browserify:

    package.json:
    
      "browser": {
        "bootstrap": "./src/javascript/vendor/bootstrap.js",
        "d4": "./src/javascript/vendor/d4.js",
      },
      "browserify": {
        "transform": [
          "browserify-shim",
          "coffeeify",
        ]
      },
      "browserify-shim": {
        "bootstrap": {
          "exports": "bootstrap",
          "depends": [
            "jquery:$"
          ]
        },
        "d4": {
          "exports": "d4",
          "depends": [
            "d3:d3"
          ]
        },
    

    Then you can require it in your modules:

    d4 = require('d4')
    

    But it's really nice to just be able to do this and be done:

    npm install d4 --save
    
    opened by jefffriesen 13
  • Cannot read property 'ordinal' of undefined

    Cannot read property 'ordinal' of undefined

    When I try to run the sample script on my machine. I get this error: d4.js:95 Uncaught Error: [d4] The scale type: "ordinal" is unrecognized. D4 only supports these scale types: time, time.utc When I log supportedScales in line 175 (function validateScale); d3.scale is undefined.

    I load d3.js first, then d4.js.

    Any idea why this happens?

    opened by gerritboogaart 12
  • Append features once, then reselect for data bind

    Append features once, then reselect for data bind

    This PR uses the handy d4.appendOnce convention for new series and axes. It then does a data bind and reselects the elements to apply attributes. This prevents features from being drawn twice. You can see, for example, in the dynamic data example, that the axes are re-appended every render. This PR fixes that, and should also make the transitions API easier to implement for column, shape, and line series.

    Note I didn't rebuild the project, just trying to keep the diff clean.

    opened by nsonnad 12
  • Missing bar in simple collumn graph

    Missing bar in simple collumn graph

    Hello. I'm using d4 and my graph missing one bar: example

    Still it's present in data model: data model

    Code:

    for(var i = window.data.length - 1; i >= 0; i --){
        graphData.push({
            x: i + 1,
            y: window.data[i].count
        });
    }
    
    var columnChart = d4.charts.column().outerWidth(900);
    d3.select('#graph').datum(graphData).call(columnChart);
    

    Any help is appreciated ;)

    opened by dnbard 12
  • Dual-axis capability on a basic chart

    Dual-axis capability on a basic chart

    I've been working on trying to figure out the best way to allow for a left axis and a right axis on different scales. (and thus series on different scales) Like this:

    apples-oranges_chartbuilder 76

    At the moment d4 provides no way to override the chart-wide scale on a feature by feature basis.

    So far I've tried the following,

    • add alt_scale to the yAxis feature's accessors with a default of null
    • change the first line of yAxis.render from scope.scale(this.y) to scope.scale(scope.alt_scale() ? scope.alt_scale() : this.y);
      • in other words: "if there is a custom scale, use that, otherwise use the default"

    but there is no way to access a custom scale (that I can see) from inside of a feature (such as lineSeries) since the accessor is called in the context of the chart not the context of the feature. (e.g. d4.functor(scope.accessors.y).bind(this))

    If you want to keep this functionality, perhaps it's better adding alt_y on the chart object instead—a clone of chart.y. Then there can be alt_y accessors on each feature and logic on when to use it in the render based on a use_alt_y accessor boolean on the feature. A similar thing could also be added to the x methods.

    Of course once there are two axes...why not three, four, etc? That type of functionality would require the chart.x and chart.y methods to return arrays of scales and features to have something like y_scale_index (defaulting to 0). It could also really mess up the API.

    What are your thoughts on how to achieve this @heavysixer?

    opened by yanofsky 10
  • Grid offset

    Grid offset

    If i create a grid for bar chat, the grid line goes throw the group. But i want to set it between the lines. How could it be done in a more elegant way?
    screen shot 2014-05-12 at 8 20 56 pm

    question 
    opened by Timopheym 9
  • Allow for a chart to be built inside of existing elements

    Allow for a chart to be built inside of existing elements

    I think it will be useful to be able to build charts inside of existing elements. I added logic to scaffoldChart that does the following.

    if the container is a svg, make a chart in that svg if the container is a g, make a chart in that g else the container is something else, append an svg and make a chart in that svg

    As a result I renamed this.svg to this.container

    opened by yanofsky 8
  • Method to change stack order of elements

    Method to change stack order of elements

    Is there a way to assign the stacking order of elements?

    So far i've had to mod the source code or call a send to back routine in an afterRender function

    opened by yanofsky 7
  • Dual-axis capability breaks when using groupedColumnSeries

    Dual-axis capability breaks when using groupedColumnSeries

    http://jsfiddle.net/q16eqjg4/

    It looks like the y attributes are correct, but their height attribute is not because it is set by the chart y()instead of the custom scale set to it.

    Possibly due to this line? https://github.com/heavysixer/d4/blob/master/src/features/grouped-column-series.js#L42

    bug 
    opened by yanofsky 6
  • Use nested axes for groups

    Use nested axes for groups

    Hello. So the more flexible and canonical way to do grouped columns/rows in d3 is to have what I'm calling "nested axes", meaning an outer axis to place the groups and an inner one to place the series within each group. See this example.

    I've refactored grouped-column-series to use this kind of implementation. This fixes https://github.com/heavysixer/d4/issues/25 and https://github.com/heavysixer/d4/issues/10, which as far as I can tell are the same issue. It also removes some hard-coding in the size and placement of the groups and such, because values are set according to the rangeBand of the outer axis. You can check against my grouped-axes branch on d4-www to see it in action. All of the grouped column/row examples work as far as I can tell.

    My naming treats x or y as the outer axis, and groups as the inner.

    I'm curious to see if you have any feedback on the stuff in scales.js and base.js, as some of the checks in there seem a bit dirty. Also, customizing the inner axis is not possible through the chart definition because it needs the rangeBand() of the outer axis to determine the range. So I've included roundBands as a customizable property of the groups scale.

    I should note as well that this is a breaking change as the groups axis key is required. It may be possible to fall back to an index, but I'm not so sure how to do that at the moment. Thanks and sorry for the long winded explanation!

    opened by nsonnad 5
  • BBox bug in firefox

    BBox bug in firefox

    In case of this bug https://bugzilla.mozilla.org/show_bug.cgi?id=612118 i recommend to replace js var axisBB = axis.node().getBBox(); to

     try {
           axisBB = node.node.getBBox();
          } catch (err) {
              axisBB = {
              x: node.clientLeft,
              y: node.clientTop,
              width: node.clientWidth,
              height: node.clientHeight
            };
         }
    

    what do you think about it?

    opened by Timopheym 4
  • docs: Fix simple typo, continious -> continuous

    docs: Fix simple typo, continious -> continuous

    There is a small typo in d4.js, d4.min.js, docs/d4-doc.md, src/charts/stacked-column.js, src/charts/stacked-row.js, src/charts/waterfall.js, test/lib/d4.js, test/tests/d4-bundle.js.

    Should read continuous rather than continious.

    opened by timgates42 0
  • wrong order punch-card data result wrong graph for punch-card example

    wrong order punch-card data result wrong graph for punch-card example

    if the order in punch-card data is not order by week,hour ,the graph is wrong. example data:

    [[0,0,0],[0,1,0],[0,2,0],[0,3,0],[0,4,0],[0,5,0],[0,6,0],[1,0,0],[1,1,0],[1,2,0],[1,3,0],[1,4,0],[1,5,0],[1,6,0],[2,0,0],[2,1,0],[2,2,0],[2,3,1],[2,4,0],[2,5,0],[2,6,0],[3,0,0],[3,1,0],[3,2,0],[3,3,3],[3,4,1],[3,5,0],[3,6,0],[4,0,0],[4,1,1],[4,2,0],[4,3,1],[4,4,0],[4,5,0],[4,6,0],[5,0,0],[5,1,0],[5,2,0],[5,3,0],[5,4,0],[5,5,0],[5,6,2],[6,0,0],[6,1,2],[6,2,0],[6,3,0],[6,4,0],[6,5,0],[6,6,0],[7,0,0],[7,1,2],[7,2,0],[7,3,0],[7,4,0],[7,5,0],[7,6,1],[8,0,0],[8,1,1],[8,2,0],[8,3,1],[8,4,0],[8,5,0],[8,6,0],[9,0,0],[9,1,6],[9,2,0],[9,3,1],[9,4,0],[9,5,1],[9,6,0],[10,0,0],[10,1,1],[10,2,0],[10,3,0],[10,4,0],[10,5,0],[10,6,0],[11,0,0],[11,1,0],[11,2,0],[11,3,0],[11,4,0],[11,5,4],[11,6,0],[12,0,0],[12,1,0],[12,2,0],[12,3,0],[12,4,0],[12,5,0],[12,6,0],[13,0,0],[13,1,0],[13,2,0],[13,3,0],[13,4,0],[13,5,0],[13,6,0],[14,0,0],[14,1,0],[14,2,0],[14,3,1],[14,4,0],[14,5,0],[14,6,0],[15,0,0],[15,1,0],[15,2,0],[15,3,0],[15,4,0],[15,5,0],[15,6,0],[16,0,0],[16,1,0],[16,2,0],[16,3,0],[16,4,0],[16,5,0],[16,6,0],[17,0,0],[17,1,0],[17,2,0],[17,3,0],[17,4,0],[17,5,1],[17,6,0],[18,0,0],[18,1,0],[18,2,0],[18,3,0],[18,4,0],[18,5,0],[18,6,0],[19,0,0],[19,1,1],[19,2,0],[19,3,0],[19,4,1],[19,5,0],[19,6,1],[20,0,0],[20,1,0],[20,2,1],[20,3,0],[20,4,0],[20,5,0],[20,6,1],[21,0,0],[21,1,0],[21,2,0],[21,3,0],[21,4,1],[21,5,0],[21,6,0],[22,0,0],[22,1,0],[22,2,0],[22,3,0],[22,4,0],[22,5,0],[22,6,0],[23,0,0],[23,1,0],[23,2,0],[23,3,0],[23,4,0],[23,5,0],[23,6,0]]
    
    opened by atom992 0
  • missing [week,hour,0] data result wrong graph for punch-card example

    missing [week,hour,0] data result wrong graph for punch-card example

    If I missing [week,hour,0] data,only provide non-zero data, such as

    [[2,3,1],[3,3,3],[3,4,1],[4,1,1],[4,3,1],[5,6,2],[6,1,2],[7,1,2],[7,6,1],[8,1,1],[8,3,1],[9,1,6],[9,3,1],[9,5,1],[10,1,1],[11,5,4],[14,3,1],[17,5,1],[19,1,1],[19,4,1],[19,6,1],[20,2,1],[20,6,1],[21,4,1]]
    

    the punchcard graph as following

    opened by atom992 0
  • d4.js:1172 Uncaught ReferenceError: d4 is not defined

    d4.js:1172 Uncaught ReferenceError: d4 is not defined

    Trying to use d4 with reactjs::

    Getting: d4.js:1172 Uncaught ReferenceError: d4 is not defined


    import React from 'react'; import ReactDOM from 'react-dom'; import ReactFauxDOM from 'react-faux-dom';

    import d3 from 'd3'; import d4 from 'd4';

    class App extends React.Component {

    render () { const data = [ {x: "For Investment", y: 13.27}, {x: "For Distribution", y: 8.66}, {x: "Outstanding Principal", y: 5.22}, {x: "Accrued Interest", y: 5} ];

    const myChart = d4.charts.column().width(500)

    const d = d3.select(ReactFauxDOM.createElement('div')) .datum(data).call(myChart);

    return d.node().toReact()
    

    } } export default App;

    opened by martinlendable 3
Releases(v0.9.7)
  • v0.9.7(Mar 29, 2016)

  • v0.9.6(Mar 10, 2016)

  • 0.9.5(Feb 26, 2016)

  • v0.9.1(Mar 7, 2015)

    Note: This is a breaking change release. All grouped column and grouped row charts will now need to specify a groups accessor to specify the grouping option. For example:

    chart.groups(function(groups){
        groups.key('salesman');
      })
      ... 
    

    A full example with the updated API can be seen here: http://visible.io/charts/grouped-column/basic.html

    Source code(tar.gz)
    Source code(zip)
  • v0.8.16(Nov 27, 2014)

  • v0.8.9(Aug 6, 2014)

    This release adds an afterRender function to all features, which can be used to modify the rendered selection directly. Check the test suite for examples.

    Source code(tar.gz)
    Source code(zip)
  • v0.8.8(Aug 5, 2014)

  • v0.8.7(Jul 28, 2014)

  • v0.8.6(Jul 23, 2014)

    This build adds new functionality to the line series labels feature which optionally enables the user to track and display the values of a line segment relative to the mouse's position.

    Source code(tar.gz)
    Source code(zip)
  • v0.8.5(Jul 16, 2014)

    This release adds the following functionality:

    • First implementation of a brush feature

    Fixes for the following issues:

    https://github.com/heavysixer/d4/issues/18 https://github.com/heavysixer/d4/issues/17

    Source code(tar.gz)
    Source code(zip)
Owner
Mark Daggett
Mark Daggett
Compose complex, data-driven visualizations from reusable charts and components with d3

d3.compose Compose rich, data-bound charts from charts (like Lines and Bars) and components (like Axis, Title, and Legend) with d3 and d3.chart. Advan

Cornerstone Systems 702 Jan 3, 2023
Smoothie Charts: smooooooth JavaScript charts for realtime streaming data

Smoothie Charts is a really small charting library designed for live streaming data. I built it to reduce the headaches I was getting from watching ch

Joe Walnes 2.2k Dec 13, 2022
A reusable charting library written in d3.js

NVD3 - A reusable D3 charting library Inspired by the work of Mike Bostock's Towards Reusable Charts, and supported by a combined effort of Novus and

Novus 7.2k Jan 3, 2023
:bar_chart: A D3-based reusable chart library

c3 c3 is a D3-based reusable chart library that enables deeper integration of charts into web applications. Follow the link for more information: http

C3.js 9.2k Jan 2, 2023
A framework for building reusable components with d3.js

Koto A framework for creating reusable charts with D3.js, written in ES6. Introduction KotoJS is HEAVILY inspired by another reusable charting framewo

KotoJS 280 Dec 23, 2022
Simple HTML5 Charts using the tag

Simple yet flexible JavaScript charting for designers & developers Documentation Currently, there are two versions of the library (2.9.4 and 3.x.x). V

Chart.js 59.4k Jan 7, 2023
Simple responsive charts

Big welcome by the Chartist Guy Checkout the documentation site at http://gionkunz.github.io/chartist-js/ Checkout this lightning talk that gives you

Gion Kunz 26 Dec 30, 2022
Simple, responsive, modern SVG Charts with zero dependencies

Frappe Charts GitHub-inspired modern, intuitive and responsive charts with zero dependencies Explore Demos » Edit at CodePen » Contents Installation U

Frappe 14.6k Jan 4, 2023
📊 A highly interactive data-driven visualization grammar for statistical charts.

English | 简体中文 G2 A highly interactive data-driven visualization grammar for statistical charts. Website • Tutorial Docs • Blog • G2Plot G2 is a visua

AntV team 11.5k Dec 30, 2022
JavaScript diagramming library for interactive flowcharts, org charts, design tools, planning tools, visual languages.

GoJS, a JavaScript Library for HTML Diagrams GoJS is a JavaScript and TypeScript library for creating and manipulating diagrams, charts, and graphs. S

Northwoods Software Corporation 6.6k Dec 30, 2022
Attractive JavaScript charts for jQuery

flot About flot is a JavaScript plotting library for engineering and scientific applications derived from Flot: http://www.flotcharts.org/ Take a look

Flot 5.9k Dec 22, 2022
Progressive pie, donut, bar and line charts

Peity Peity (sounds like deity) is a jQuery plugin that converts an element's content into a mini <svg> pie, donut, line or bar chart. Basic Usage HTM

Ben Pickles 4.2k Jan 1, 2023
Charts for Raphaël

g.Raphaël - Official charting plugin for Raphaël For more information, see: http://g.raphaeljs.com/ Changelog v0.51 Fixed issues with piechart related

Dmitry Baranovskiy 1.5k Dec 31, 2022
A plugin for the jQuery javascript library to generate small sparkline charts directly in the browser

jQuery Sparklines This jQuery plugin makes it easy to generate a number of different types of sparklines directly in the browser, using online a line

Gareth Watts 1.2k Jan 4, 2023
Awesome charts for AngularJS.

n3-line-chart v2 n3-line-chart is an easy-to-use JavaScript library for creating beautiful charts in AngularJS applications and it is built on top of

null 1.2k Dec 7, 2022
Create beautiful charts with one line of JavaScript

Chartkick.js Create beautiful charts with one line of JavaScript See it in action Supports Chart.js, Google Charts, and Highcharts Also available for

Andrew Kane 1.2k Jan 2, 2023
Ember Charts 3.5 2.3 L2 JavaScript A powerful and easy to use charting library for Ember.js

Ember Charts A charting library built with the Ember.js and d3.js frameworks. It includes time series, bar, pie, and scatter charts which are easy to

Addepar 793 Dec 7, 2022
Financial lightweight charts built with HTML5 canvas

Lightweight Charts Demos | Documentation | Discord community TradingView Lightweight Charts are one of the smallest and fastest financial HTML5 charts

TradingView, Inc. 5.8k Jan 9, 2023
Create beautiful JavaScript charts with one line of React

React Chartkick Create beautiful JavaScript charts with one line of React See it in action Supports Chart.js, Google Charts, and Highcharts Quick Star

Andrew Kane 1.2k Dec 28, 2022