Package com.example.violin

Source Code of com.example.violin.ViolinPlot

package com.example.violin;

import com.example.awt.StippledStroke;
import com.example.math.Range;
import com.example.util.ArrayUtil;
import com.example.violin.density.GraphFunction;
import com.example.violin.density.KernelDensity;
import com.example.violin.density.kernels.Kernels;

import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.util.Collections;
import java.util.List;

/**
* @author Neil Traft
*/
public final class ViolinPlot extends JPanel {

  ////////////////////////////////////////////////////////////////////
  // Variables

  private static final int PADDING = 20;

  private final GraphFunction fn = new KernelDensity(Kernels.NORMAL, 0.8f);
  private final Rectangle area = new Rectangle();

  private float[] values = new float[0];
  private int[] yPoints = new int[0];
  private int[] leftPoints = new int[0];
  private int[] rightPoints = new int[0];
  private Range range;
  private float min;
  private float max;
  private float q1;
  private float q3;
  private float median;
  private int minPx;
  private int maxPx;
  private int q1Px;
  private int q3Px;
  private int medianPx;
  private int boxLeft;
  private int boxRight;
  private int midWidth;

  ////////////////////////////////////////////////////////////////////
  // Public

  public final void setValues(float[] values) {
    if (!SwingUtilities.isEventDispatchThread()) throw new RuntimeException();
    if (values == null) throw new NullPointerException();
    updateValues(values);
    computeStats();
  }

  @Override
  public final void setBounds(int x, int y, int width, int height) {
    super.setBounds(x, y, width, height);
    SwingUtilities.calculateInnerArea(this, area);
    computeStats();
  }

  ////////////////////////////////////////////////////////////////////
  // Drawing

  @Override
  protected final void paintComponent(Graphics graphics) {
//    long start = System.currentTimeMillis();

    Graphics2D g = (Graphics2D) graphics;
    g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

    g.setColor(Color.WHITE);
    g.fillRect(area.x, area.y, area.width, area.height);

    g.setColor(Color.BLACK);
//    Stroke thin = g.getStroke();
//    g.setStroke(new BasicStroke(1.5f));
    g.drawPolyline(leftPoints, yPoints, yPoints.length);
    g.drawPolyline(rightPoints, yPoints, yPoints.length);
//    g.setStroke(thin);

    g.drawLine(boxLeft, minPx, boxRight, minPx);
    g.drawLine(boxLeft, maxPx, boxRight, maxPx);

    Stroke orig = g.getStroke();
    g.setStroke(new StippledStroke());
    g.drawLine(midWidth, minPx, midWidth, q1Px);
    g.drawLine(midWidth, q3Px, midWidth, maxPx);
    g.setStroke(orig);

    g.setColor(Color.BLUE);
    g.drawRect(boxLeft, q1Px, boxRight - boxLeft, q3Px - q1Px);
    g.drawLine(boxLeft, medianPx, boxRight, medianPx);

//    System.err.printf("Drawing took %dms%n", System.currentTimeMillis() - start);
  }

  ////////////////////////////////////////////////////////////////////
  // Statistics

  private void updateValues(float[] newVals) {
//    long start = System.currentTimeMillis();

    List<Float> sorted = ArrayUtil.listOf(newVals);
    Collections.sort(sorted);
    values = ArrayUtil.toArray(sorted);

    min = values[0];
    max = values[values.length - 1];
    range = new Range(min, max).expandBy(1);

    q1 = values[(int) (values.length * .25)];
    q3 = values[(int) (values.length * .75)];

    float mid = values.length / 2f;
    int mid1 = (int) mid;
    int mid2 = mid1 + 1;
    if (mid == mid1) {
      median = (values[mid1] + values[mid2]) / 2;
    } else {
      median = values[mid2];
    }

//    System.err.printf("Sorting took %dms%n", System.currentTimeMillis() - start);
  }

  private void computeStats() {
//    long start = System.currentTimeMillis();

    int totaly = area.height;
    yPoints = new int[totaly];
    leftPoints = new int[totaly];
    rightPoints = new int[totaly];
    if (totaly == 0) {
      boxLeft = boxRight = 0;
      minPx = maxPx = q1Px = q3Px = medianPx = 0;
      return;
    }

    int totalx = area.width / 2 - PADDING;
    int startx = area.x;
    int starty = area.y;
    midWidth = area.width / 2 + startx;
    int halfLineWidth = (int) (totalx * 0.30);
    boxLeft = midWidth - halfLineWidth;
    boxRight = midWidth + halfLineWidth;

    Range viewRange = new Range(starty, starty+totaly);
    minPx = (int) range.scaleTo(min, viewRange);
    maxPx = (int) range.scaleTo(max, viewRange);
    q1Px = (int) range.scaleTo(q1, viewRange);
    q3Px = (int) range.scaleTo(q3, viewRange);
    medianPx = (int) range.scaleTo(median, viewRange);

    fn.compute(totaly, totalx, range, values);
    float[] yValues = fn.yValues();
    float yRange = fn.yRange();

    for (int i = 0; i < totaly; i++) {
      yPoints[i] = i + starty;

      float xpos = yValues[i] / yRange * totalx;
      leftPoints[i] = (int) (midWidth - xpos);
      rightPoints[i] = (int) (midWidth + xpos);
    }

//    System.err.printf("Computation took %dms%n", System.currentTimeMillis() - start);
  }

}
TOP

Related Classes of com.example.violin.ViolinPlot

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.