@Override
  protected void prepareData() {
    allQuartiles.clear();
    this.globalMin = Double.POSITIVE_INFINITY;
    this.globalMax = Double.NEGATIVE_INFINITY;

    if (columns != null) {
      int totalCount = 0;
      for (int i = 0; i < this.dataTable.getNumberOfColumns(); i++) {
        if (columns[i]) {
          totalCount++;
        }
      }

      for (int i = 0; i < this.dataTable.getNumberOfColumns(); i++) {
        if (columns[i]) {
          Quartile quartile = Quartile.calculateQuartile(this.dataTable, i);
          quartile.setColor(getColorProvider().getPointColor((double) i / (double) totalCount));
          allQuartiles.add(quartile);
          this.globalMin = MathFunctions.robustMin(this.globalMin, quartile.getMin());
          this.globalMax = MathFunctions.robustMax(this.globalMax, quartile.getMax());
        }
      }
    }
  }
 public ColorizedBubbleRenderer(double[] colors) {
   super(XYBubbleRenderer.SCALE_ON_RANGE_AXIS);
   this.minColor = Double.POSITIVE_INFINITY;
   this.maxColor = Double.NEGATIVE_INFINITY;
   for (double c : colors) {
     minColor = MathFunctions.robustMin(minColor, c);
     maxColor = MathFunctions.robustMax(maxColor, c);
   }
   this.colors = colors;
 }
  @Override
  public AttributeWeights calculateWeights(ExampleSet exampleSet) throws OperatorException {
    Attributes attributes = exampleSet.getAttributes();
    Attribute labelAttribute = attributes.getLabel();
    boolean useSquaredCorrelation = getParameterAsBoolean(PARAMETER_SQUARED_CORRELATION);

    AttributeWeights weights = new AttributeWeights(exampleSet);
    getProgress().setTotal(attributes.size());
    int progressCounter = 0;
    int exampleSetSize = exampleSet.size();
    int exampleCounter = 0;
    for (Attribute attribute : attributes) {
      double correlation =
          MathFunctions.correlation(exampleSet, labelAttribute, attribute, useSquaredCorrelation);
      weights.setWeight(attribute.getName(), Math.abs(correlation));
      progressCounter++;
      exampleCounter += exampleSetSize;
      if (exampleCounter > PROGRESS_UPDATE_STEPS) {
        exampleCounter = 0;
        getProgress().setCompleted(progressCounter);
      }
    }

    return weights;
  }
  /** Calculates the mutual information for both attributes. */
  @Override
  public double getMatrixValue(
      ExampleSet exampleSet, Attribute firstAttribute, Attribute secondAttribute) {
    // init
    double[] firstProbabilites = new double[firstAttribute.getMapping().size()];
    double[] secondProbabilites = new double[secondAttribute.getMapping().size()];
    double[][] jointProbabilities =
        new double[firstAttribute.getMapping().size()][secondAttribute.getMapping().size()];
    double firstCounter = 0.0d;
    double secondCounter = 0.0d;
    double firstSecondCounter = 0.0d;

    // count values
    for (Example example : exampleSet) {
      double firstValue = example.getValue(firstAttribute);
      if (!Double.isNaN(firstValue)) {
        firstProbabilites[(int) firstValue]++;
        firstCounter++;
      }
      double secondValue = example.getValue(secondAttribute);
      if (!Double.isNaN(secondValue)) {
        secondProbabilites[(int) secondValue]++;
        secondCounter++;
      }
      if (!Double.isNaN(firstValue) && !Double.isNaN(secondValue)) {
        jointProbabilities[(int) firstValue][(int) secondValue]++;
        firstSecondCounter++;
      }
    }

    // transform to probabilities
    for (int i = 0; i < firstProbabilites.length; i++) {
      firstProbabilites[i] /= firstCounter;
    }
    for (int i = 0; i < secondProbabilites.length; i++) {
      secondProbabilites[i] /= secondCounter;
    }
    for (int i = 0; i < jointProbabilities.length; i++) {
      for (int j = 0; j < jointProbabilities[i].length; j++) {
        jointProbabilities[i][j] /= firstSecondCounter;
      }
    }

    double firstEntropy = 0.0d;
    for (int i = 0; i < firstProbabilites.length; i++) {
      if (firstProbabilites[i] > 0.0d)
        firstEntropy += firstProbabilites[i] * MathFunctions.ld(firstProbabilites[i]);
    }
    firstEntropy *= -1;

    double secondEntropy = 0.0d;
    for (int i = 0; i < secondProbabilites.length; i++) {
      if (secondProbabilites[i] > 0.0d)
        secondEntropy += secondProbabilites[i] * MathFunctions.ld(secondProbabilites[i]);
    }
    secondEntropy *= -1;

    double jointEntropy = 0.0d;
    for (int i = 0; i < jointProbabilities.length; i++) {
      for (int j = 0; j < jointProbabilities[i].length; j++) {
        if (jointProbabilities[i][j] > 0.0d)
          jointEntropy += jointProbabilities[i][j] * MathFunctions.ld(jointProbabilities[i][j]);
      }
    }
    jointEntropy *= -1;

    return firstEntropy + secondEntropy - jointEntropy;
  }