drawEntropyLine()

in code/decision-tree/js/EntropyBubble.js [377:492]


  drawEntropyLine() {
    const self = this;
    // loop and create permutations of samples for self.numCirclesPerGroup
    let permutations = [];
    let data = [];

    for (let i = 0; i <= self.numCirclesPerGroup; ++i) {
      let j = self.numCirclesPerGroup - i;
      // add i positive cases
      let positiveSamples = new Array(j).fill("positive");
      // append j negative cases
      let negativeSamples = new Array(i).fill("negative");

      let permutation = positiveSamples.concat(negativeSamples);
      // append to permutations array
      permutations.push(permutation);
      // create data for plot
      data.push({
        entropy: entropy(permutation),
        x: prob(permutation),
      });
    }

    // Create entropy plot
    const padding = 50;

    const areaGradient = this.svg
      .append("defs")
      .append("linearGradient")
      .attr("id", "areaGradient")
      .attr("x1", "0%")
      .attr("y1", "0%")
      .attr("x2", "0%")
      .attr("y2", "100%");

    areaGradient
      .append("stop")
      .attr("offset", "0%")
      .attr("stop-color", "rgb(188, 111, 177)")
      .attr("stop-opacity", 0.76);
    areaGradient
      .append("stop")
      .attr("offset", "100%")
      .attr("stop-color", "white")
      .attr("stop-opacity", 0);

    this.xScale = scaleLinear()
      .domain([0, 1])
      .range([this.positionXScale(2), this.positionXScale(8)]);
    // .range([padding, this.WIDTH - padding])6

    this.yScale = scaleLinear()
      .domain([0, 1])
      .range([this.HEIGHT - padding, padding * 3]);

    // add axes
    // x
    this.entroypG
      .append("g")
      .attr("id", "entropy-x-axis")
      .attr("transform", `translate(${0}, ${this.HEIGHT - padding})`)
      .call(
        axisBottom(this.xScale)
          .tickFormat((x) => `${format(".0%")(x)}`)
          .ticks(5)
      );
    // y
    this.entroypG
      .append("g")
      .attr("id", "entropy-y-axis")
      .attr("transform", `translate(${self.positionXScale(2)}, 0)`)
      .call(
        axisLeft(this.yScale)
          .tickSize(-self.positionXScale(9) + self.positionXScale(3))
          .tickSizeOuter(0)
          .ticks(4)
      );
    // draw line
    this.entroypG
      .append("path")
      .datum(data)
      .style("fill", "url(#areaGradient)")
      .attr("stroke", "rgb(188, 111, 177)")
      .attr("stroke-width", 6)
      .attr(
        "d",
        line()
          .x((d) => this.xScale(d.x))
          .y((d) => this.yScale(d.entropy))
      );

    // // add title
    this.entroypG
      .append("text")
      .attr("class", "entropy-x-axis")
      .text(`Proportion of Positive Class`)
      .attr("x", this.WIDTH / 2)
      .attr("y", this.HEIGHT - padding + 40)
      .attr("text-anchor", "middle");

    this.entroypG
      .append("text")
      .text(mmobile ? "Negative" : "Negative Class")
      .attr("x", self.positionXScale(0))
      .attr("y", self.positionYScale(4))
      .attr("text-anchor", "middle")
      .attr("class", "entropy-class-label");

    this.entroypG
      .append("text")
      .text(mmobile ? "Positive" : "Positive Class")
      .attr("x", self.positionXScale(10))
      .attr("y", self.positionYScale(4))
      .attr("text-anchor", "middle")
      .attr("class", "entropy-class-label");
  }