<commit_before>var d3 = window.d3 || require('d3');
var px = require('../javascripts/modules/caravel.js');
var wrapSvgText = require('../javascripts/modules/utils.js').wrapSvgText;

require('./sunburst.css');

// Modified from http://bl.ocks.org/kerryrodden/7090426
function sunburstVis(slice) {
  var container = d3.select(slice.selector);

  var render = function () {
    // vars with shared scope within this function
    var margin = { top: 10, right: 5, bottom: 10, left: 5 };
    var containerWidth   = slice.width();
    var containerHeight  = slice.height();
    var breadcrumbHeight = containerHeight * 0.085;
    var visWidth         = containerWidth - margin.left - margin.right;
    var visHeight        = containerHeight - margin.top - margin.bottom - breadcrumbHeight;
    var radius           = Math.min(visWidth, visHeight) / 2;
    var colorByCategory  = true; // color by category if primary/secondary metrics match

    var maxBreadcrumbs, breadcrumbDims, // set based on data
        totalSize, // total size of all segments; set after loading the data.
        colorScale,
        breadcrumbs, vis, arcs, gMiddleText; // dom handles

    // Helper + path gen functions
    var partition = d3.layout.partition()
      .size([2 * Math.PI, radius * radius])
      .value(function (d) { return d.m1; });

    var arc = d3.svg.arc()
      .startAngle(function (d) {
        return d.x;
      })
      .endAngle(function (d) {
        return d.x + d.dx;
      })
      .innerRadius(function (d) {
        return Math.sqrt(d.y);
      })
      .outerRadius(function (d) {
        return Math.sqrt(d.y + d.dy);
      });

    var formatNum = d3.format(".3s");
    var formatPerc = d3.format(".3p");

    container.select("svg").remove();

    var svg = container.append("svg:svg")
      .attr("width", containerWidth)
      .attr("height", containerHeight);

    d3.json(slice.jsonEndpoint(), function (error, rawData) {
      if (error !== null) {
        slice.error(error.responseText);
        return '';
      }

      createBreadcrumbs(rawData);
      createVisualization(rawData);

      slice.done(rawData);
    });

    function createBreadcrumbs(rawData) {
      var firstRowData = rawData.data[0];
      maxBreadcrumbs = (firstRowData.length - 2) + 1; // -2 bc row contains 2x metrics, +extra for %label and buffer

      breadcrumbDims = {
        width: visWidth / maxBreadcrumbs,
        height: breadcrumbHeight *0.8, // more margin
        spacing: 3,
        tipTailWidth: 10
      };

      breadcrumbs = svg.append("svg:g")
        .attr("class", "breadcrumbs")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

      breadcrumbs.append("svg:text")
        .attr("class", "end-label");
    }

    // Main function to draw and set up the visualization, once we have the data.
    function createVisualization(rawData) {
      var tree = buildHierarchy(rawData.data);

      vis = svg.append("svg:g")
        .attr("class", "sunburst-vis")
        .attr("transform", "translate(" + (margin.left + (visWidth / 2)) + "," + (margin.top + breadcrumbHeight + (visHeight / 2)) + ")")
        .on("mouseleave", mouseleave);

      arcs = vis.append("svg:g")
        .attr("id", "arcs");

      gMiddleText = vis.append("svg:g")
        .attr("class", "center-label");

      // Bounding circle underneath the sunburst, to make it easier to detect
      // when the mouse leaves the parent g.
      arcs.append("svg:circle")
        .attr("r", radius)
        .style("opacity", 0);

      // For efficiency, filter nodes to keep only those large enough to see.
      var nodes = partition.nodes(tree)
        .filter(function (d) {
          return (d.dx > 0.005); // 0.005 radians = 0.29 degrees
        });

      var ext;

      if (rawData.form_data.metric !== rawData.form_data.secondary_metric) {
        colorByCategory = false;

        ext = d3.extent(nodes, function (d) {
          return d.m2 / d.m1;
        });

        colorScale = d3.scale.linear()
          .domain([ext[0], ext[0] + ((ext[1] - ext[0]) / 2), ext[1]])
          .range(["#00D1C1", "white", "#FFB400"]);
      }

      var path = arcs.data([tree]).selectAll("path")
        .data(nodes)
       .enter().append("svg:path")
        .attr("display", function (d) {
          return d.depth ? null : "none";
        })
        .attr("d", arc)
        .attr("fill-rule", "evenodd")
        .style("fill", function (d) {
          return colorByCategory ? px.color.category21(d.name) : colorScale(d.m2 / d.m1);
        })
        .style("opacity", 1)
        .on("mouseenter", mouseenter);

      // Get total size of the tree = value of root node from partition.
      totalSize = path.node().__data__.value;
    }

    // Fade all but the current sequence, and show it in the breadcrumb trail.
    function mouseenter(d) {

      var sequenceArray = getAncestors(d);
      var parentOfD = sequenceArray[sequenceArray.length - 2] || null;

      var absolutePercentage = (d.m1 / totalSize).toPrecision(3);
      var conditionalPercentage = parentOfD ? (d.m1 / parentOfD.m1).toPrecision(3) : null;

      var absolutePercString = formatPerc(absolutePercentage);
      var conditionalPercString = parentOfD ? formatPerc(conditionalPercentage) : "";

      var yOffsets = ["-25", "7", "35", "60"]; // 3 levels of text if inner-most level, 4 otherwise
      var offsetIndex = 0;

      // If metrics match, assume we are coloring by category
      var metricsMatch = Math.abs(d.m1 - d.m2) < 0.00001;

      gMiddleText.selectAll("*").remove();

      gMiddleText.append("text")
        .attr("class", "path-abs-percent")
        .attr("y", yOffsets[offsetIndex++])
        .text(absolutePercString + " of total");

      if (conditionalPercString) {
        gMiddleText.append("text")
          .attr("class", "path-cond-percent")
          .attr("y", yOffsets[offsetIndex++])
          .text(conditionalPercString + " of previous");
      }

      gMiddleText.append("text")
        .attr("class", "path-metrics")
        .attr("y", yOffsets[offsetIndex++])
        .text("m1: " + formatNum(d.m1) + (metricsMatch ? "" : ", m2: " + formatNum(d.m2)));

      gMiddleText.append("text")
        .attr("class", "path-ratio")
        .attr("y", yOffsets[offsetIndex++])
        .text((metricsMatch ? "" : ("m2/m1: " + formatPerc(d.m2 / d.m1))) );<commit_msg>change 'of previous' to 'of parent'<commit_after>var d3 = window.d3 || require('d3');
var px = require('../javascripts/modules/caravel.js');
var wrapSvgText = require('../javascripts/modules/utils.js').wrapSvgText;

require('./sunburst.css');

// Modified from http://bl.ocks.org/kerryrodden/7090426
function sunburstVis(slice) {
  var container = d3.select(slice.selector);

  var render = function () {
    // vars with shared scope within this function
    var margin = { top: 10, right: 5, bottom: 10, left: 5 };
    var containerWidth   = slice.width();
    var containerHeight  = slice.height();
    var breadcrumbHeight = containerHeight * 0.085;
    var visWidth         = containerWidth - margin.left - margin.right;
    var visHeight        = containerHeight - margin.top - margin.bottom - breadcrumbHeight;
    var radius           = Math.min(visWidth, visHeight) / 2;
    var colorByCategory  = true; // color by category if primary/secondary metrics match

    var maxBreadcrumbs, breadcrumbDims, // set based on data
        totalSize, // total size of all segments; set after loading the data.
        colorScale,
        breadcrumbs, vis, arcs, gMiddleText; // dom handles

    // Helper + path gen functions
    var partition = d3.layout.partition()
      .size([2 * Math.PI, radius * radius])
      .value(function (d) { return d.m1; });

    var arc = d3.svg.arc()
      .startAngle(function (d) {
        return d.x;
      })
      .endAngle(function (d) {
        return d.x + d.dx;
      })
      .innerRadius(function (d) {
        return Math.sqrt(d.y);
      })
      .outerRadius(function (d) {
        return Math.sqrt(d.y + d.dy);
      });

    var formatNum = d3.format(".3s");
    var formatPerc = d3.format(".3p");

    container.select("svg").remove();

    var svg = container.append("svg:svg")
      .attr("width", containerWidth)
      .attr("height", containerHeight);

    d3.json(slice.jsonEndpoint(), function (error, rawData) {
      if (error !== null) {
        slice.error(error.responseText);
        return '';
      }

      createBreadcrumbs(rawData);
      createVisualization(rawData);

      slice.done(rawData);
    });

    function createBreadcrumbs(rawData) {
      var firstRowData = rawData.data[0];
      maxBreadcrumbs = (firstRowData.length - 2) + 1; // -2 bc row contains 2x metrics, +extra for %label and buffer

      breadcrumbDims = {
        width: visWidth / maxBreadcrumbs,
        height: breadcrumbHeight *0.8, // more margin
        spacing: 3,
        tipTailWidth: 10
      };

      breadcrumbs = svg.append("svg:g")
        .attr("class", "breadcrumbs")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

      breadcrumbs.append("svg:text")
        .attr("class", "end-label");
    }

    // Main function to draw and set up the visualization, once we have the data.
    function createVisualization(rawData) {
      var tree = buildHierarchy(rawData.data);

      vis = svg.append("svg:g")
        .attr("class", "sunburst-vis")
        .attr("transform", "translate(" + (margin.left + (visWidth / 2)) + "," + (margin.top + breadcrumbHeight + (visHeight / 2)) + ")")
        .on("mouseleave", mouseleave);

      arcs = vis.append("svg:g")
        .attr("id", "arcs");

      gMiddleText = vis.append("svg:g")
        .attr("class", "center-label");

      // Bounding circle underneath the sunburst, to make it easier to detect
      // when the mouse leaves the parent g.
      arcs.append("svg:circle")
        .attr("r", radius)
        .style("opacity", 0);

      // For efficiency, filter nodes to keep only those large enough to see.
      var nodes = partition.nodes(tree)
        .filter(function (d) {
          return (d.dx > 0.005); // 0.005 radians = 0.29 degrees
        });

      var ext;

      if (rawData.form_data.metric !== rawData.form_data.secondary_metric) {
        colorByCategory = false;

        ext = d3.extent(nodes, function (d) {
          return d.m2 / d.m1;
        });

        colorScale = d3.scale.linear()
          .domain([ext[0], ext[0] + ((ext[1] - ext[0]) / 2), ext[1]])
          .range(["#00D1C1", "white", "#FFB400"]);
      }

      var path = arcs.data([tree]).selectAll("path")
        .data(nodes)
       .enter().append("svg:path")
        .attr("display", function (d) {
          return d.depth ? null : "none";
        })
        .attr("d", arc)
        .attr("fill-rule", "evenodd")
        .style("fill", function (d) {
          return colorByCategory ? px.color.category21(d.name) : colorScale(d.m2 / d.m1);
        })
        .style("opacity", 1)
        .on("mouseenter", mouseenter);

      // Get total size of the tree = value of root node from partition.
      totalSize = path.node().__data__.value;
    }

    // Fade all but the current sequence, and show it in the breadcrumb trail.
    function mouseenter(d) {

      var sequenceArray = getAncestors(d);
      var parentOfD = sequenceArray[sequenceArray.length - 2] || null;

      var absolutePercentage = (d.m1 / totalSize).toPrecision(3);
      var conditionalPercentage = parentOfD ? (d.m1 / parentOfD.m1).toPrecision(3) : null;

      var absolutePercString = formatPerc(absolutePercentage);
      var conditionalPercString = parentOfD ? formatPerc(conditionalPercentage) : "";

      var yOffsets = ["-25", "7", "35", "60"]; // 3 levels of text if inner-most level, 4 otherwise
      var offsetIndex = 0;

      // If metrics match, assume we are coloring by category
      var metricsMatch = Math.abs(d.m1 - d.m2) < 0.00001;

      gMiddleText.selectAll("*").remove();

      gMiddleText.append("text")
        .attr("class", "path-abs-percent")
        .attr("y", yOffsets[offsetIndex++])
        .text(absolutePercString + " of total");

      if (conditionalPercString) {
        gMiddleText.append("text")
          .attr("class", "path-cond-percent")
          .attr("y", yOffsets[offsetIndex++])
          .text(conditionalPercString + " of parent");
      }

      gMiddleText.append("text")
        .attr("class", "path-metrics")
        .attr("y", yOffsets[offsetIndex++])
        .text("m1: " + formatNum(d.m1) + (metricsMatch ? "" : ", m2: " + formatNum(d.m2)));

      gMiddleText.append("text")
        .attr("class", "path-ratio")
        .attr("y", yOffsets[offsetIndex++])
        .text((metricsMatch ? "" : ("m2/m1: " + formatPerc(d.m2 / d.m1))) );
{'fraction_non_alphanumeric': 0.15331664580725907, 'fraction_numerical': 0.017052565707133916, 'mean_word_length': 2.423942153186931, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, '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': '4140255', 'n_tokens_mistral': 4196, 'n_tokens_neox': 3995, 'n_words': 949}