block by timelyportfolio 3165657

performance charts example

Full Screen

index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>d3.js Axys Performance Chart</title>
        <script  src="//d3js.org/d3.v2.min.js?2.9.1"></script>        
        <style>
            .axis path, .axis line {
                fill: none;
                stroke: #000;
                shape-rendering: crispEdges;
            }
            .line {
                fill: none;
                stroke-width: 1.5px;
            }
        </style>
    </head>
    
    <body>
        <script>
            var perfdata = new Array();

            var margin = {top: 20, right: 60, bottom: 60, left: 60},
                width = 1000 - margin.right - margin.left,
                height = 500 - margin.top - margin.bottom;
            
            var x = d3.time.scale()
                .range([0, width - 60]);
            
            var y = d3.scale.linear()
                .range([height - 20, 0]);
        
            var duration = 1500,
                delay = 500;
            
            var color = d3.scale.category10();
            
            var svg = d3.select("body").append("svg")
                .attr("width", width + margin.right + margin.left)
                .attr("height", height + margin.top + margin.bottom)
                .append("g")
                .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
            
            var parse = d3.time.format("%m/%d/%Y").parse, format = d3.time.format("%Y"),
              perfdata = new Array();   
        
            var data = {
               "cDataSet":[      {
                     "date":"12/31/2000",
                     "portfolio":"5.31",
                     "sp500":"9.56"
                  },
                  {
                     "date":"12/31/2001",
                     "portfolio":"1.30",
                     "sp500":"6.42"
                  },
                  {
                     "date":"12/31/2002",
                     "portfolio":"-6.71",
                     "sp500":"-1.43"
                  },
                  {
                     "date":"12/31/2003",
                     "portfolio":"-8.45",
                     "sp500":"1.80"
                  },
                  {
                     "date":"12/31/2004",
                     "portfolio":"-5.68",
                     "sp500":"-0.93"
                  },
                  {
                     "date":"12/31/2005",
                     "portfolio":"-3.71",
                     "sp500":"-8.07"
                  },
                  {
                     "date":"12/31/2006",
                     "portfolio":"9.92",
                     "sp500":"-0.241"
                  },
                  {
                     "date":"12/31/2007",
                     "portfolio":"1.16",
                     "sp500":"-9.70"
                  },
                  {
                     "date":"12/31/2008",
                     "portfolio":"7.22",
                     "sp500":"9.64"
                  },
                  {
                     "date":"12/31/2009",
                     "portfolio":"-6.34",
                     "sp500":"-7.29"
                  },
                  {
                     "date":"12/31/2010",
                     "portfolio":"-8.99",
                     "sp500":"-2.66"
                  },
                  {
                     "date":"12/31/2011",
                     "portfolio":"4.36",
                     "sp500":"-2.92"
                  }
                ]
             }

        </script>
        <script>
                var inc = 0;
            
                data = data.cDataSet;
                
                var cumul = new Array();
                
                for (key in data[0]) {
                    if ( key != "date" ) {
                        cumul[key] = 1;
                        firstdate = parse(data[0].date);
                        firstdate.setFullYear(firstdate.getFullYear()-1);
                        perfdata[inc]  = { date: firstdate, perf : 0, cumul : cumul[key], symbol : key };
                        inc = inc + 1;
                   }
                }
            
                data.forEach( function(d) {
                    for (key in d) {
                        if ( key != "date" ) {
                            cumul[key] = cumul[key] * (1 + parseFloat(d[key]) / 100);
                            perfdata[inc]  = { date: parse(d.date) , perf : parseFloat(d[key]), cumul : cumul[key], symbol : key };
                            inc = inc + 1;
                        }
                    };
                });
                  
                //if we want to filter only some set of what is there
                //stocks = perfdata.filter(function(d) { return d.symbol in filter; });
                
                // Nest stock values by symbol.
                symbols = d3.nest()
                  .key(function(d) { return d.symbol; })
                  .entries(perfdata);
                
                // Parse dates and numbers. We assume values are sorted by date.
                // Also compute the maximum price per symbol, needed for the y-domain.
                //symbols.forEach(function(s) {
                //    s.values.forEach(function(d) { d.date = parse(d.date); d.price = +d.price; });
                //});
                
                // Sort by maximum price, descending.
                //symbols.sort(function(a, b) { return b.maxPrice - a.maxPrice; });
                
                // Compute the minimum and maximum date across symbols.
                x.domain([
                    d3.min(symbols, function(d) { return d.values[0].date; }),
                    d3.max(symbols, function(d) { return d.values[d.values.length - 1].date; })
                ]);
                
                var g = svg.selectAll("g")
                    .data(symbols)
                    .enter().append("g")
                        .attr("class", "symbol");  
                                
            groupedBar();

            setTimeout(clearBar, duration + delay);
            
            function clearBar() {
                svg.selectAll("text").transition()
                    .duration(duration/2)
                    .remove();
                svg.selectAll(".y.axis").transition()
                    .duration(duration/2)
                    .remove();                    
                svg.selectAll("rect").transition()
                    .duration(duration)
                    .style("fill-opacity", 1e-6)
                    .remove();            
            }            
            
            setTimeout(cumulLine, duration * 2 + delay);

            function groupedBar() {
                  x = d3.scale.ordinal()
                      .domain(symbols[0].values.map(function(d) { return d.date; }))
                      .rangeBands([0, width - 60], .1);
                
                  var x1 = d3.scale.ordinal()
                      .domain(symbols.map(function(d) { return d.key; }))
                      .rangeBands([0, x.rangeBand()]);
    
                var y0 = Math.max(Math.abs(d3.min(symbols.map(function(d) { return d3.min(d.values.map(function(d) { return d.perf; })); }))), d3.max(symbols.map(function(d) { return d3.max(d.values.map(function(d) { return d.perf; })); })));                
                y
                    .domain([-y0, y0])
                    //.domain([d3.min(symbols.map(function(d) { return d3.min(d.values.map(function(d) { return d.perf; })); })), d3.max(symbols.map(function(d) { return d3.max(d.values.map(function(d) { return d.perf; })); }))])
                    .range([height, 0])
                    .nice();
                
                var yAxis = d3.svg.axis().scale(y).orient("left");                            

                svg.selectAll(".labels")
                    .data(symbols[0].values.map(function(d) { return d.date; }))
                    .enter().append("text")
                        .attr("class", "labels")
                        .attr("text-anchor", "middle")
                        .attr("x", function(d,i) { return x(i) + x.rangeBand() / 2 ; })
                        .attr("y", height / 2 + 15)
                        .text(function(d) {return format(d) })
                        .style("fill-opacity", 1);

                
                  var g = svg.selectAll(".symbol");
                
                  var t = g.transition()
                      .duration(duration);
                      
                    //got working with lots of help but this section particularly dedicated to //stackoverflow.com/questions/10127402/bar-chart-with-negative-values
                  g.each(function(p, j) {
                    d3.select(this).selectAll("rect")
                        .data(function(d) { return d.values; })
                      .enter().append("rect")
                        .attr("x", function(d) { return x(d.date) + x1(p.key); })
                        .attr("y", function(d, i) { return y(Math.max(0, d.perf)); })                        
                        //.attr("y", function(d) { return y(d.perf); })
                        .attr("width", x1.rangeBand())
                        .attr("height", function(d, i) { return Math.abs(y(d.perf) - y(0)); })                        
                        //.attr("height", function(d) { return height - y(d.perf); })
                        .style("fill", color(p.key))
                        .style("fill-opacity", 1e-6)                    
                      .transition()
                        .duration(duration)
                        .style("fill-opacity", 1);
                      
                    d3.select(this).selectAll("text")
                        .data(function(d) { return d.values; })
                        .enter().append("text")
                            .attr("x", function(d) { return x(d.date) + x1(p.key) + x1.rangeBand() / 2 ; })
                            .attr("y", function(d, i) { return y(d.perf) ; })
                            .attr("text-anchor", "middle")                        
                            .text(function(d) { return d.perf; })
                            .style("fill-opacity", 1e-6)                    
                       .transition()
                        .duration(duration)
                        .style("fill-opacity", 1);
                  });            
                        
                    //svg.append("g")
                    //    .attr("class", "x axis")
                    //    .call(d3.svg.axis().scale(x).orient("bottom"));
                    
                    svg.append("g")
                        .attr("class", "y axis")
                        .call(yAxis);
                    //    .attr("y1", 0)
                    //    .attr("y2", height);
                
            }
            
            function cumulLine() {
                x = d3.time.scale()
                    .domain([perfdata[0].date, perfdata[perfdata.length - 1].date])
                    .range([0,width])
                    
                var y0 =  d3.max(symbols.map(function(d) { return d3.max(d.values.map(function(d) { return d.cumul; })); }));
                
                y
                  .domain([d3.min(symbols.map(function(d) { return d3.min(d.values.map(function(d) { return d.cumul; })); })), 
                          d3.max(symbols.map(function(d) { return d3.max(d.values.map(function(d) { return d.cumul; })); }))])
                  .range([height, 0])
                  .nice();
                
                var xAxis = d3.svg.axis()
                    .scale(x)
                    .ticks(d3.time.years, 1)
                    .tickSubdivide(data.length-1)
                    .tickValues([parse("12/31/1999"),parse("12/31/2011")])
                    .tickFormat(d3.time.format("%b %Y"));
                    
                var yAxis = d3.svg.axis().scale(y).orient("left");
                
                
                  // Add the x-axis.
                  svg.append("g")
                      .attr("class", "x axis")
                      .attr("transform", "translate(0," + y(1) + ")")
                      .call(xAxis);
                
                  // Add the y-axis.
                  svg.append("g")
                      .attr("class", "y axis")
                      //.attr("transform", "translate(" + width + ",0)")
                      .call(yAxis);

               var line = d3.svg.line()
                    .x(function (d) {return x(d.date);})
                    .y(function (d) {return y(d.cumul);});
                
                var g = svg.selectAll(".symbol");
                
                g.each(function(p) {
                    var thispath = d3.select(this)
                        .append("path")
                            .attr("class", "line")
                            .style("stroke", color(p.key));   

                    var k = 0, n = symbols[0].values.length;
                    
                    d3.timer( function() {
                        thispath
                            .transition()
                            .attr("d", function() { return line(p.values.slice(0, k + 1)); });
                        k = k + 1;
                        if (k == n) return true;
                    });
                    
                    d3.select(this).selectAll(".dot")
                        .data(function(d) { return d.values; })
                      .enter().append("circle")
                        .attr("class", "dot")
                        .attr("cx", line.x())
                        .attr("cy", line.y())
                        .attr("r", 3.5)
                        .style("fill", color(p.key));                    
                })
            };
               
        </script>
    </body>
</html>