Home > d3, d3js, data visualization > D3 Fisheye Distortion for Bar Charts

D3 Fisheye Distortion for Bar Charts

February 25, 2014 Leave a comment Go to comments

Intro

Focus + context visualizations are quite useful when we want to zoom into some part of a visualization, but are unwilling to give up the “bird’s eye” view of the entire picture. In this case, we distort the part of the visual on which we want to focus, while preserving the entire view.

In D3, this task is accomplished through “fisheye distortion”. Mike Bostock has examples of usage of his fisheye plugin on his site.

The problem is this plugin does not support bar charts, where the application could also be quite useful. I believe lack of support is explained by the fact that the ordinal scale rangeBand() function does not take any parameters, which is fine for any bar chart: all you need is to split your range into equal regions. When applying a distortion, however, the chunk of the range devoted to a particular part of the input depends on the position of this particular chunk. So extending the plugin is really trivial, just need to provide a new signature for the rangeBand() function.

Here is what a finished example looks like:

bar_chart

The complete code for it, including the plugin can be found on JSFiddle.

In order to create it, I have modified an existing example by a StackOverflow user (thank you very much!).

Usage

The actual fisheye plugin spans lines 1 – 144 in the jsfiddle cited above. Cut it, save to a file.

  1. Create your ordinal scale for the bar chart using the plugin:
    var x = d3.fisheye.ordinal().rangeRoundBands([0, w - p[1] - p[3]])
    .distortion(0.9);
    
  2. Replace all calls to rangeBand() with calls to rangeBand(d.x):

    
    // Add a rect for each date.
    var rect = cause.selectAll("rect")
    .data(Object)
    .enter().append("svg:rect")
    .attr("x", function(d) { return x(d.x); })
    .attr("y", function(d) { return -y(d.y0) - y(d.y); })
    .attr("height", function(d) { return y(d.y); })
    .attr("width", function(d) {return x.rangeBand(d.x);});
    
    // Add a label per date.
    var label = svg.selectAll("text")
    .data(x.domain())
    .enter().append("svg:text")
    .attr("x", function(d) { return x(d) + x.rangeBand(d.x) / 2; })
    .attr("y", 6)
    .attr("text-anchor", "middle")
    .attr("dy", ".71em")
    .text(format);
    
  3. Add mouse interaction to your main container, to update the focus of the distortion, and redraw the affected elements:

    //respond to the mouse and distort where necessary
    svg.on("mousemove", function() {
        var mouse = d3.mouse(this);
        
        //refocus the distortion
        x.focus(mouse[0]);
        //redraw the bars
        rect
        .attr("x", function(d) { return x(d.x); })
        .attr("width", function(d) {return x.rangeBand(d.x);});
        
        //redraw the text
        label.attr("x", function(d) { return x(d) + x.rangeBand(d.x) / 2; });
    });
    

Et voilĂ !

  1. March 11, 2015 at 3:05 am

    Hi, Thanks for posting this. How does one increase the degree of distortion? for instance if I wanted an exaggerated amount of distortion I thought that increasing the distortion value defined in circular would do the trick, but that has zero effect.

    circular: function() {
    var radius = 200,
    distortion = 30, // no change if this is changed

  2. wschreuders
    March 11, 2015 at 3:06 am

    Hi There, Thanks for posting this. How does one change the amount of distortion in your example (to increase it)

    I changed the distortion value under circular but this seems to have no effect.

    circular: function() {
    var radius = 200,
    distortion = 2, //changing this does nothing.

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: