Search code examples
d3.jsscaleinterpolation

How do I create a new scale() function in d3.js? I would like to create a cumulative distribution function


How do I create my own scale() function in d3?

I am trying to replace the nice linear scale in d3 d3.scale.linear() with a different function that I would like to create myself. My new scale would be based on a cumulative distribution function, so that the median value would appear in the center of the x axis, and a value that was two standard deviations from the median would appear twice as far from the center of the x axis as something that was one standard deviation from the mean.

Here is a link to my jsfiddle page: http://jsfiddle.net/tbcholla/kR2PS/3/ (I would appreciate any other comments you might have about my code as well!)

right now I have:

var x = d3.scale.linear()
.range([0, width])
.domain(d3.extent([0, data.length]));    

I've seen scale.pow() and scale.log(). Now I'd like to create a new function! Thanks! EDIT: I found the function scale.quantile(), which might hold the solution for me. My related question: Plotting a line graph with scale.quantile()


Solution

  • This is an example how we can add new functionality in d3.scale.liner(). For null values my function returns null (d3.scale.liner() returns 0 in this case). The primary approach is to wrap the original scale and all his methods.

    I didn't test this function for all cases. But for basic functionality it's working. Unfortunately I didn't found easier way to do it :(

    /**
     * d3.scale.linear() retrun 0 for null value
     * I need to get null in this case
     * This is a wrapper for d3.scale.linear()
     */
    _getLinearScaleWithNull: function() {
        var alternativeScale = function(origLineScale) {
            var origScale = origLineScale ? origLineScale : d3.scale.linear();
    
            function scale(x) {
                if (x === null) return null; //this is the implementation of new behaviour
                return origScale(x);
            }
    
            scale.domain = function(x) {
                if (!arguments.length) return origScale.domain();
                origScale.domain(x);
                return scale;
            }
    
            scale.range = function(x) {
                if (!arguments.length) return origScale.range();
                origScale.range(x);
                return scale;
            }
    
            scale.copy = function() {
                return alternativeScale(origScale.copy());
            }
    
            scale.invert = function(x) {
                return origScale.invert(x);
            }
    
            scale.nice = function(m) {
                origScale = origScale.nice(m);
                return scale;
            }
    
            scale.ticks = function(m) {
                return origScale.ticks(m);
            };
    
    
            scale.tickFormat = function(m, Format) {
                return origScale.tickFormat(m, Format);
            }
    
            return scale;
        }
    
        return alternativeScale();
    },