<commit_before>// a Bar chart
Bridle.BarChartCategorical = function () {

    var mode = "stacked";
    var margin = {
      top: 50,
      bottom: 100,
      left: 100,
      right: 100
    };
    var height = 400;
    var width = 1000;
    var xValue = function(d) {
      return d.x;
    };
    var yValue = function(d) {
      return d.y;
    };
    var nameValue = function(d) {
      return d.name;
    }
    var offset = 'zero';
    var order = 'default';
    var yScale = d3.scale.linear();
    var colors = d3.scale.category10();

    var yAxis = d3.svg.axis().scale(yScale).orient("left");
    var title = 'Chart Title';
    var yAxisTitle = 'Axis Title';
    var duration = 1000;
    var legend = Bridle.LegendBox().nameAccessor(function(d) {
      return nameValue
    });

    var xScale = d3.scale.ordinal()
    var xAxis = d3.svg.axis()
      .scale(xScale)
      .tickSize(5)
      .orient("bottom");

    // var tickFormat = d3.time.format("%Y-%m-%d");
    var xAxisFontSize = 10;
    var yAxisFontSize = 10;

    var formatterX = function (d) {
      return d;
    }
    var formatterY = d3.format(".02f");

    function toDate(e) {
      return new Date(e);
    }
    var sortByDateDesc = function(a, b) {
      return toDate(xValue(a)) > toDate(xValue(b)) ? 1 : -1;
    };
    var sortByDateAsc = function(a, b) {
      return toDate(xValue(b)) < toDate(xValue(a)) ? 1 : -1;
    };
    var dispatch = d3.dispatch('showTooltip', 'hideTooltip', "pointMouseover", "pointMouseout");

    function chart(selection) {
      selection.each(function(rawData) {
        var containerID = this;
        // preserve rawData variable (needed to control updates of legend module)
        var data = rawData.filter(function(d) {
          return !d.disabled
        })
        // //sort the data points in each layer
        // data.forEach(function(layer) {
        //   layer.values.sort(sortByDateDesc)
        // });

        // convert the data to an appropriate representation
        data = d3.layout.stack()
          .offset(offset)
          .order(order)
          .values(function(d) {
          return d.values
        })
          .x(xValue)
          .y(yValue)
        (data); // we pass the data as context

        // set up scales and axes
        xScale.domain(data[0].values.map(function(d) {
          console.log(d, xValue(d), xValue)
          return xValue(d);
        }))
          .rangeRoundBands([0, width - margin.left - margin.right], 0.1);

        // how many data points are there in each layer on average 
        var avgDataPoints = function() {
          var sumPoints = 0;
          data.forEach(function(layer) {
            sumPoints += layer.values.length;
          });
          // console.log("THIS", sumPoints, data.length, sumPoints / data.length)
          return (sumPoints / data.length);
        }

        // xAxis
        //   .tickValues(xScale.domain().filter(function(d, i) {
        //   var nthLabel = Math.ceil(200 / (width / avgDataPoints()));
        //   // console.log(nthLabel)
        //   return !(i % nthLabel);
        // }))

        var yGroupMax = d3.max(data, function(layer) {
          return d3.max(layer.values, function(d) {
            return d.y;
          });
        })

        var yStackMax = d3.max(data, function(layer) {
          return d3.max(layer.values, function(d) {
            return d.y0 + d.y;
          });
        });

        var numLayers = data.length;

        var maxLayerLength = d3.max(data, function(layer) {
          return layer.values.length
        });

        yScale.range([height - margin.top - margin.bottom, 0]);

        if (mode === "stacked") yScale.domain([0, yStackMax])
        else yScale.domain([0, yGroupMax]);


        // functions for rect attributes depending on stacked/group mode
        var xScaleMode = function(d, i, j) {
          if (mode === "stacked") return xScale(xValue(d));
          else return xScale(xValue(d)) + xScale.rangeBand() / numLayers * j;
        }
        var yScaleMode = function(d) {
          if (mode === "stacked") return yScale(d.y0 + d.y);
          else return yScale(d.y);
        }
        var heightMode = function(d) {
          if (mode === "stacked") return yScale(d.y0) - yScale(d.y0 + d.y);
          else return height - yScale(d.y) - margin.top - margin.bottom;
        }
        var widthMode = function() {
          if (mode === "stacked") return xScale.rangeBand();
          else return xScale.rangeBand() / numLayers;
        }

        // set up the scaffolding
        // note: enter only fires if data is empty
        var svg = d3.select(containerID).selectAll("svg").data([data]);
        var gEnter = svg.enter().append("svg").attr("class", "bridle").append("g");
        gEnter.append("g").attr("class", "rects");
        gEnter.append("g").attr("class", "x axis");
        gEnter.append("g").attr("class", "y axis").append("text")
          .attr("transform", "rotate(-90)")
          .attr("y", 6)
          .attr("dy", ".72em")
          .attr("class", "y axis label")
          .attr("text-anchor", "middle");
        gEnter.append("svg:text").attr("class", "chartTitle label")
          .attr("text-anchor", "middle")
          .attr("dy", "1em")
          .attr("transform", "translate(" + (width - margin.left - margin.right + 20) / 2 + "," + (-margin.top) + ")");
        gEnter.append("g")
          .attr("class", "legend")
          .attr("transform", "translate(" + (width - margin.left - margin.right + 20) + "," + 0 + ")")
          .style("font-size", "12px");

        // update the outer dimensions
        svg.attr("width", width)
          .attr("height", height)

        // update the inner dimensions
        var g = svg.select("g")
          .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

        // reasign the data to trigger points
        // specify a key function based on *name*, 
        // so that entering/exiting works properly when filters are triggered
        var gLayer = g.select('.rects').selectAll('g.layerrects')
          .data(function(d) {
          return d
        }, function(d) {
          return nameValue(d)
        })
          .classed('hover', function(d) {
          return d.hover
        })

        gLayer
        .exit()
        .transition()
        .duration(duration)
        .style('stroke-opacity', 1e-6)
        .style('fill-opacity', 1e-6)
        .remove();

        var gLayerEnter = gLayer.enter();

        // update entering rects
        var gRects = gLayerEnter.append("g").attr("class", "layerrects")
          .attr("fill", function(d, i) {
          return colors(nameValue(d));
        })
          .selectAll('g.rect')
          .data(function(d) {
          d.values.forEach(function(v) {
            v.name = nameValue(d)
          });
          return d.values
        })

        gRects.exit()
        .transition()
        .duration(duration)
        .style('stroke-opacity', 1e-6)
        .style('fill-opacity', 1e-6)        
          .remove();

        var rectsEnter = gRects.enter().append("g").attr("class", "rect");

        rectsEnter.append('rect')
          .attr("opacity", 0.1)
          .attr("x", function(d, i, j) {
          return xScaleMode(d, i, j)
        })
          .attr("y", function(d) {
          return height - margin.top - margin.bottom
        })
          .attr("width", function() {
          return widthMode();
        })
          .attr("height", 0)
          .on('mouseover', function(d, i, j) {
          dispatch.pointMouseover({
            x: xValue(d),
            y: yValue(d),
            series: d.name,
            pos: [xScale(xValue(d)), yScaleMode(d)],
            pointIndex: i,
            seriesIndex: j
          });
        })
          .on('mouseout', function(d) {
          dispatch.pointMouseout({
            // point: d,
            // series: data[d.series],
            // pointIndex: d.point,
            // seriesIndex: d.series
          });
        });

        // update the chillin rects
        g.selectAll('g.layerrects').selectAll('g.rect')
          .select("rect")
          .transition()
          .duration(duration)
          .attr("opacity", 0.9)
          .attr("y", function(d) {
          return yScaleMode(d)
        })
          .attr("height", function(d) {
          return heightMode(d)
        })
          .attr("width", function() {
          return widthMode();
        })
          .attr("x", function(d, i, j) {
          return xScaleMode(d, i, j)
        })

        // update the title
        g.select("text.chartTitle")
          .text(title)

        // update the x-axis
        g.select(".x.axis")
          .attr("transform", "translate(0," + yScale.range()[0] + ")")
          .call(xAxis)
        // .selectAll("text") 
        // .style("text-anchor", "end")
        // .attr("dx", "-.8em")
        // .attr("dy", ".15em")
        // .attr("transform", function(d) {
        //     return "rotate(-65)" 
        //     });

        // update the y-axis
        g.select(".y.axis")
        //.attr("transform", "translate(")
        .transition()
          .duration(duration)
          .attr("transform", "translate(-25,0)")

          .call(yAxis)

        g.select(".y.axis.label")
          .attr("y", -45)
          .attr("x", (-height + margin.top + margin.bottom) / 2)
          .attr("dy", ".1em")
          .text(yAxisTitle);

        // handle change from/to stacked/grouped
        d3.selectAll("input").on("change", change);

        function change() {
          console.log("mode change")
          if (this.value === "grouped") {
            mode = "grouped";
            yScale.domain([0, yGroupMax]);
            transitionGrouped();
          } else {
            mode = "stacked";
            yScale.domain([0, yStackMax]);
            transitionStacked();
          }
        }


        // transition to grouped layout
        function transitionGrouped() {
          // update the y-axis
          g.select(".y.axis")
          //.attr("transform", "translate(")
          .transition()
            .duration(duration)
            .attr("transform", "translate(-25,0)")

            .call(yAxis)

          g.selectAll('g.layerrects').selectAll('rect')
            .transition()
            .duration(500)
            .delay(function(d, i) {
            return i * 10;
          })
            .attr("x", function(d, i, j) {
            // console.log(d,i,j)
            return xScale(xValue(d)) + xScale.rangeBand() / numLayers * j;

          })
            .attr("width", xScale.rangeBand() / numLayers)
            .transition()
            .attr("y", function(d) {
            return yScale(d.y);
          })
            .attr("height", function(d) {
            return height - yScale(d.y) - margin.top - margin.bottom;
          });
        }

        //transition to stacked layout
        function transitionStacked() {

          // update the y-axis
          g.select(".y.axis")
          //.attr("transform", "translate(")
          .transition()
            .duration(duration)
            .attr("transform", "translate(-25,0)")

            .call(yAxis)

          g.selectAll('g.layerrects').selectAll('rect')
            .transition()
            .duration(500)
            .delay(function(d, i) {
            return i * 10;
          })
            .attr("y", function(d) {
            return yScale(d.y0 + d.y);
          })
            .attr("height", function(d) {
            return yScale(d.y0) - yScale(d.y0 + d.y);
          })
            .transition()
            .attr("x", function(d) {
            return xScale(xValue(d));
          })
            .attr("width", xScale.rangeBand());
        }

        // update the legend only if the data has changed
        if (legend.numData() != rawData.length) {
          // update the legend
          g.select('.legend')
            .datum(data)
            .call(legend);
        }

        // listen for click events from the legend module, 
        // filter the relevant data series
        legend.dispatch.on('legendClick', function(d, i) {
          d.disabled = !d.disabled;

          if (!data.filter(function(d) {
            return !d.disabled
          }).length) {
            data.forEach(function(d) {
              d.disabled = false;
            });
          }

          selection.call(chart)
        });

        // listen for mouseover events from legend module
        // flag 'hover' on data series
        legend.dispatch.on('legendMouseover', function(d, i) {
          d.hover = true;
          selection.call(chart)
        });

        // listen for mouseout events from legend module
        // remove 'hover' from data series
        legend.dispatch.on('legendMouseout', function(d, i) {
          d.hover = false;
          selection.call(chart)
        });

        // listen for mouseover events within this module
        // (i.e. on rectangles) and show tooltip
        dispatch.on('pointMouseover.tooltip', function(e) {
          var offset = $(containerID).offset(), // { left: 0, top: 0 }
            left = e.pos[0] + offset.left + margin.left,
            top = e.pos[1] + offset.top + margin.top;


          var content = '<h3>' + e.series + '</h3>' +
            '<p>' +
            '<span class="value">[' + formatterX(e.x) + ', ' + formatterY(e.y) + ']</span>' +
            '</p>';

          Bridle.tooltip.show([left, top], content);
        });

        // listen for mouseout events within this module
        // hide tooltip
        dispatch.on('pointMouseout.tooltip', function(e) {
          Bridle.tooltip.cleanup();
        });


      })
    }

    chart.dispatch = dispatch;

    chart.margin = function(_) {
      if (!arguments.length) return margin;
      margin = _;
      return chart;
    };

    chart.width = function(_) {
      if (!arguments.length) return width;
      width = _;
      return chart;
    };

    chart.height = function(_) {
      if (!arguments.length) return height;
      height = _;
      return chart;
    };

    chart.value = function(_) {
      if (!arguments.length) return value;
      value = _;
      return chart;
    };

    chart.label = function(_) {
      if (!arguments.length) return label;
      label = _;
      return chart;
    };

    chart.title = function(_) {
      if (!arguments.length) return title;
      title = _;
      return chart;
    };

    chart.xAxis = function(_) {
      if (!arguments.length) return xAxis;
      xAxis = _;
      return chart;
    };

    chart.yAxis = function(_) {
      if (!arguments.length) return yAxis;
      yAxis = _;
      return chart;
    };

    chart.yAxisTitle = function(_) {
      if (!arguments.length) return yAxisTitle;
      yAxisTitle = _;
      return chart;
    };

    chart.duration = function(_) {
      if (!arguments.length) return duration;
      duration = _;
      return chart;
    };

    // chart.tickFormat = function(_) {
    //   if (!arguments.length) return tickFormat;
    //   tickFormat = _;
    //   return chart;
    // };

    chart.legend = function(_) {
      if (!arguments.length) return legend;
      legend = _;
      return chart;
    };

    chart.xValue = function(_) {
      if (!arguments.length) return xValue;
      xValue = _;
      return chart;
    };

    chart.yValue = function(_) {
      if (!arguments.length) return yValue;
      yValue = _;
      return chart;
    };

    chart.nameValue = function(_) {
      if (!arguments.length) return nameValue;
      nameValue = _;
      return chart;
    };

    chart.colors = function(_) {
      if (!arguments.length) return colors;
      colors = _;
      return chart;
    };
    
    chart.mode = function(_) {
      if (!arguments.length) return mode;
      mode = _;
      return chart;
    };

    return chart;
  };
  <commit_msg>bumped up version<commit_after>// a Bar chart
Bridle.BarChartCategorical = function () {

    var mode = "stacked";
    var margin = {
      top: 50,
      bottom: 100,
      left: 100,
      right: 100
    };
    var height = 400;
    var width = 1000;
    var xValue = function(d) {
      return d.x;
    };
    var yValue = function(d) {
      return d.y;
    };
    var nameValue = function(d) {
      return d.name;
    }
    var offset = 'zero';
    var order = 'default';
    var yScale = d3.scale.linear();
    var colors = d3.scale.category10();

    var yAxis = d3.svg.axis().scale(yScale).orient("left");
    var title = 'Chart Title';
    var yAxisTitle = 'Axis Title';
    var duration = 1000;
    var legend = Bridle.LegendBox().nameAccessor(function(d) {
      return nameValue
    });

    var xScale = d3.scale.ordinal()
    var xAxis = d3.svg.axis()
      .scale(xScale)
      .tickSize(5)
      .orient("bottom");

    // var tickFormat = d3.time.format("%Y-%m-%d");
    var xAxisFontSize = 10;
    var yAxisFontSize = 10;

    var formatterX = function (d) {
      return d;
    }
    var formatterY = d3.format(".02f");

    function toDate(e) {
      return new Date(e);
    }
    var sortByDateDesc = function(a, b) {
      return toDate(xValue(a)) > toDate(xValue(b)) ? 1 : -1;
    };
    var sortByDateAsc = function(a, b) {
      return toDate(xValue(b)) < toDate(xValue(a)) ? 1 : -1;
    };
    var dispatch = d3.dispatch('showTooltip', 'hideTooltip', "pointMouseover", "pointMouseout");
 
    function chart(selection) {
      selection.each(function(rawData) {
        var containerID = this;
        // preserve rawData variable (needed to control updates of legend module)
        var data = rawData.filter(function(d) {
          return !d.disabled
        })
        // //sort the data points in each layer
        // data.forEach(function(layer) {
        //   layer.values.sort(sortByDateDesc)
        // });

        // convert the data to an appropriate representation
        data = d3.layout.stack()
          .offset(offset)
          .order(order)
          .values(function(d) {
          return d.values
        })
          .x(xValue)
          .y(yValue)
        (data); // we pass the data as context

        // set up scales and axes
        xScale.domain(data[0].values.map(function(d) {
          console.log(d, xValue(d), xValue)
          return xValue(d);
        }))
          .rangeRoundBands([0, width - margin.left - margin.right], 0.1);

        // how many data points are there in each layer on average 
        var avgDataPoints = function() {
          var sumPoints = 0;
          data.forEach(function(layer) {
            sumPoints += layer.values.length;
          });
          // console.log("THIS", sumPoints, data.length, sumPoints / data.length)
          return (sumPoints / data.length);
        }

        // xAxis
        //   .tickValues(xScale.domain().filter(function(d, i) {
        //   var nthLabel = Math.ceil(200 / (width / avgDataPoints()));
        //   // console.log(nthLabel)
        //   return !(i % nthLabel);
        // }))

        var yGroupMax = d3.max(data, function(layer) {
          return d3.max(layer.values, function(d) {
            return d.y;
          });
        })

        var yStackMax = d3.max(data, function(layer) {
          return d3.max(layer.values, function(d) {
            return d.y0 + d.y;
          });
        });

        var numLayers = data.length;

        var maxLayerLength = d3.max(data, function(layer) {
          return layer.values.length
        });

        yScale.range([height - margin.top - margin.bottom, 0]);

        if (mode === "stacked") yScale.domain([0, yStackMax])
        else yScale.domain([0, yGroupMax]);


        // functions for rect attributes depending on stacked/group mode
        var xScaleMode = function(d, i, j) {
          if (mode === "stacked") return xScale(xValue(d));
          else return xScale(xValue(d)) + xScale.rangeBand() / numLayers * j;
        }
        var yScaleMode = function(d) {
          if (mode === "stacked") return yScale(d.y0 + d.y);
          else return yScale(d.y);
        }
        var heightMode = function(d) {
          if (mode === "stacked") return yScale(d.y0) - yScale(d.y0 + d.y);
          else return height - yScale(d.y) - margin.top - margin.bottom;
        }
        var widthMode = function() {
          if (mode === "stacked") return xScale.rangeBand();
          else return xScale.rangeBand() / numLayers;
        }

        // set up the scaffolding
        // note: enter only fires if data is empty
        var svg = d3.select(containerID).selectAll("svg").data([data]);
        var gEnter = svg.enter().append("svg").attr("class", "bridle").append("g");
        gEnter.append("g").attr("class", "rects");
        gEnter.append("g").attr("class", "x axis");
        gEnter.append("g").attr("class", "y axis").append("text")
          .attr("transform", "rotate(-90)")
          .attr("y", 6)
          .attr("dy", ".72em")
          .attr("class", "y axis label")
          .attr("text-anchor", "middle");
        gEnter.append("svg:text").attr("class", "chartTitle label")
          .attr("text-anchor", "middle")
          .attr("dy", "1em")
          .attr("transform", "translate(" + (width - margin.left - margin.right + 20) / 2 + "," + (-margin.top) + ")");
        gEnter.append("g")
          .attr("class", "legend")
          .attr("transform", "translate(" + (width - margin.left - margin.right + 20) + "," + 0 + ")")
          .style("font-size", "12px");

        // update the outer dimensions
        svg.attr("width", width)
          .attr("height", height)

        // update the inner dimensions
        var g = svg.select("g")
          .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

        // reasign the data to trigger points
        // specify a key function based on *name*, 
        // so that entering/exiting works properly when filters are triggered
        var gLayer = g.select('.rects').selectAll('g.layerrects')
          .data(function(d) {
          return d
        }, function(d) {
          return nameValue(d)
        })
          .classed('hover', function(d) {
          return d.hover
        })

        gLayer
        .exit()
        .transition()
        .duration(duration)
        .style('stroke-opacity', 1e-6)
        .style('fill-opacity', 1e-6)
        .remove();

        var gLayerEnter = gLayer.enter();

        // update entering rects
        var gRects = gLayerEnter.append("g").attr("class", "layerrects")
          .attr("fill", function(d, i) {
          return colors(nameValue(d));
        })
          .selectAll('g.rect')
          .data(function(d) {
          d.values.forEach(function(v) {
            v.name = nameValue(d)
          });
          return d.values
        })

        gRects.exit()
        .transition()
        .duration(duration)
        .style('stroke-opacity', 1e-6)
        .style('fill-opacity', 1e-6)        
          .remove();

        var rectsEnter = gRects.enter().append("g").attr("class", "rect");

        rectsEnter.append('rect')
          .attr("opacity", 0.1)
          .attr("x", function(d, i, j) {
          return xScaleMode(d, i, j)
        })
          .attr("y", function(d) {
          return height - margin.top - margin.bottom
        })
          .attr("width", function() {
          return widthMode();
        })
          .attr("height", 0)
          .on('mouseover', function(d, i, j) {
          dispatch.pointMouseover({
            x: xValue(d),
            y: yValue(d),
            series: d.name,
            pos: [xScale(xValue(d)), yScaleMode(d)],
            pointIndex: i,
            seriesIndex: j
          });
        })
          .on('mouseout', function(d) {
          dispatch.pointMouseout({
            // point: d,
            // series: data[d.series],
            // pointIndex: d.point,
            // seriesIndex: d.series
          });
        });

        // update the chillin rects
        g.selectAll('g.layerrects').selectAll('g.rect')
          .select("rect")
          .transition()
          .duration(duration)
          .attr("opacity", 0.9)
          .attr("y", function(d) {
          return yScaleMode(d)
        })
          .attr("height", function(d) {
          return heightMode(d)
        })
          .attr("width", function() {
          return widthMode();
        })
          .attr("x", function(d, i, j) {
          return xScaleMode(d, i, j)
        })

        // update the title
        g.select("text.chartTitle")
          .text(title)

        // update the x-axis
        g.select(".x.axis")
          .attr("transform", "translate(0," + yScale.range()[0] + ")")
          .call(xAxis)
        // .selectAll("text") 
        // .style("text-anchor", "end")
        // .attr("dx", "-.8em")
        // .attr("dy", ".15em")
        // .attr("transform", function(d) {
        //     return "rotate(-65)" 
        //     });

        // update the y-axis
        g.select(".y.axis")
        //.attr("transform", "translate(")
        .transition()
          .duration(duration)
          .attr("transform", "translate(-25,0)")

          .call(yAxis)

        g.select(".y.axis.label")
          .attr("y", -45)
          .attr("x", (-height + margin.top + margin.bottom) / 2)
          .attr("dy", ".1em")
          .text(yAxisTitle);

        // handle change from/to stacked/grouped
        d3.selectAll("input").on("change", change);

        function change() {
          console.log("mode change")
          if (this.value === "grouped") {
            mode = "grouped";
            yScale.domain([0, yGroupMax]);
            transitionGrouped();
          } else {
            mode = "stacked";
            yScale.domain([0, yStackMax]);
            transitionStacked();
          }
        }


        // transition to grouped layout
        function transitionGrouped() {
          // update the y-axis
          g.select(".y.axis")
          //.attr("transform", "translate(")
          .transition()
            .duration(duration)
            .attr("transform", "translate(-25,0)")

            .call(yAxis)

          g.selectAll('g.layerrects').selectAll('rect')
            .transition()
            .duration(500)
            .delay(function(d, i) {
            return i * 10;
          })
            .attr("x", function(d, i, j) {
            // console.log(d,i,j)
            return xScale(xValue(d)) + xScale.rangeBand() / numLayers * j;

          })
            .attr("width", xScale.rangeBand() / numLayers)
            .transition()
            .attr("y", function(d) {
            return yScale(d.y);
          })
            .attr("height", function(d) {
            return height - yScale(d.y) - margin.top - margin.bottom;
          });
        }

        //transition to stacked layout
        function transitionStacked() {

          // update the y-axis
          g.select(".y.axis")
          //.attr("transform", "translate(")
          .transition()
            .duration(duration)
            .attr("transform", "translate(-25,0)")

            .call(yAxis)

          g.selectAll('g.layerrects').selectAll('rect')
            .transition()
            .duration(500)
            .delay(function(d, i) {
            return i * 10;
          })
            .attr("y", function(d) {
            return yScale(d.y0 + d.y);
          })
            .attr("height", function(d) {
            return yScale(d.y0) - yScale(d.y0 + d.y);
          })
            .transition()
            .attr("x", function(d) {
            return xScale(xValue(d));
          })
            .attr("width", xScale.rangeBand());
        }

        // update the legend only if the data has changed
        if (legend.numData() != rawData.length) {
          // update the legend
          g.select('.legend')
            .datum(data)
            .call(legend);
        }

        // listen for click events from the legend module, 
        // filter the relevant data series
        legend.dispatch.on('legendClick', function(d, i) {
          d.disabled = !d.disabled;

          if (!data.filter(function(d) {
            return !d.disabled
          }).length) {
            data.forEach(function(d) {
              d.disabled = false;
            });
          }

          selection.call(chart)
        });

        // listen for mouseover events from legend module
        // flag 'hover' on data series
        legend.dispatch.on('legendMouseover', function(d, i) {
          d.hover = true;
          selection.call(chart)
        });

        // listen for mouseout events from legend module
        // remove 'hover' from data series
        legend.dispatch.on('legendMouseout', function(d, i) {
          d.hover = false;
          selection.call(chart)
        });

        // listen for mouseover events within this module
        // (i.e. on rectangles) and show tooltip
        dispatch.on('pointMouseover.tooltip', function(e) {
          var offset = $(containerID).offset(), // { left: 0, top: 0 }
            left = e.pos[0] + offset.left + margin.left,
            top = e.pos[1] + offset.top + margin.top;


          var content = '<h3>' + e.series + '</h3>' +
            '<p>' +
            '<span class="value">[' + formatterX(e.x) + ', ' + formatterY(e.y) + ']</span>' +
            '</p>';

          Bridle.tooltip.show([left, top], content);
        });

        // listen for mouseout events within this module
        // hide tooltip
        dispatch.on('pointMouseout.tooltip', function(e) {
          Bridle.tooltip.cleanup();
        });


      })
    }

    chart.dispatch = dispatch;

    chart.margin = function(_) {
      if (!arguments.length) return margin;
      margin = _;
      return chart;
    };

    chart.width = function(_) {
      if (!arguments.length) return width;
      width = _;
      return chart;
    };

    chart.height = function(_) {
      if (!arguments.length) return height;
      height = _;
      return chart;
    };

    chart.value = function(_) {
      if (!arguments.length) return value;
      value = _;
      return chart;
    };

    chart.label = function(_) {
      if (!arguments.length) return label;
      label = _;
      return chart;
    };

    chart.title = function(_) {
      if (!arguments.length) return title;
      title = _;
      return chart;
    };

    chart.xAxis = function(_) {
      if (!arguments.length) return xAxis;
      xAxis = _;
      return chart;
    };

    chart.yAxis = function(_) {
      if (!arguments.length) return yAxis;
      yAxis = _;
      return chart;
    };

    chart.yAxisTitle = function(_) {
      if (!arguments.length) return yAxisTitle;
      yAxisTitle = _;
      return chart;
    };

    chart.duration = function(_) {
      if (!arguments.length) return duration;
      duration = _;
      return chart;
    };

    // chart.tickFormat = function(_) {
    //   if (!arguments.length) return tickFormat;
    //   tickFormat = _;
    //   return chart;
    // };

    chart.legend = function(_) {
      if (!arguments.length) return legend;
      legend = _;
      return chart;
    };

    chart.xValue = function(_) {
      if (!arguments.length) return xValue;
      xValue = _;
      return chart;
    };

    chart.yValue = function(_) {
      if (!arguments.length) return yValue;
      yValue = _;
      return chart;
    };

    chart.nameValue = function(_) {
      if (!arguments.length) return nameValue;
      nameValue = _;
      return chart;
    };

    chart.colors = function(_) {
      if (!arguments.length) return colors;
      colors = _;
      return chart;
    };
    
    chart.mode = function(_) {
      if (!arguments.length) return mode;
      mode = _;
      return chart;
    };

    return chart;
  };
  
{'fraction_non_alphanumeric': 0.15194490739284927, 'fraction_numerical': 0.008427407943146442, 'mean_word_length': 1.6378566688785667, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5971920', 'n_tokens_mistral': 9731, 'n_tokens_neox': 9393, 'n_words': 2088}