📄 minihistogram.java
字号:
package sim.util.gui;import javax.swing.*;import java.awt.*;import java.awt.image.*;import java.awt.event.*;/** <p>A very simple histogram class. Displays values as different colors left to right. Tooltips pop up describing the actual buckets and their densities. <p>This class can be used to describe any one-dimensional array of doubles: just provide an array of doubles to setBuckets and it'll show them on-screen. If you change the doubles in that array, no need to call setBuckets again: as soon as a repaint occurs, MiniHistogram will update them. You can specify a color map to be more specific about which colors do what. You can also provide a set of bucket labels, one for each bucket, which get popped up in the tooltip along with the current bucket value. <p>As the class was created to describe histograms in particular, it has two functions (makeBuckets and makeBucketLabels) which do just that. Sample usage. The following values are placed into a histogram of four buckets. <tt><pre> MiniHistogram m = new MiniHistogram(); double[] d = new double[] {1, 1, 1, 1, 2, 2, 5, 1, 2, 3, 1, 2, 1, 1, 5, 4}; m.setBuckets(m.makeBuckets(d, 4, 1, 5, false)); m.setBucketLabels(m.makeBucketLabels(4, 1, 5)); </pre></tt>*/public class MiniHistogram extends JPanel { final static SimpleColorMap DEFAULT_MAP = new SimpleColorMap(0,1,Color.white,Color.blue); final static JLabel DEFAULT_SIZE_COMPARISON = new JLabel("X"); BufferedImage buffer; double[] buckets; String[] labels; ColorMap map; public MiniHistogram() { map = DEFAULT_MAP; setBuckets(new double[0]); addMouseListener(adapter); addMouseMotionListener(motionAdapter); setBackground(Color.red); } public MiniHistogram(double[] buckets, String[] labels) { this(); setBucketsAndLabels(buckets,labels); setBackground(Color.red); } public Dimension getPreferredSize() { return DEFAULT_SIZE_COMPARISON.getPreferredSize(); } public Dimension getMinimumSize() { return DEFAULT_SIZE_COMPARISON.getMinimumSize(); } /** Sets the displayed bucket array. If you change values in the provided array, then MiniHistogram will update itself appropriately on next repaint. */ public void setBuckets(double[] buckets) { if (buckets == null) buckets = new double[0]; int len = buckets.length; if (len == 0) buffer = null; else if (buffer==null || buffer.getWidth() != len) buffer = new BufferedImage(len,1,BufferedImage.TYPE_INT_ARGB); this.buckets = buckets; repaint(); } /** Sets labels for the buckets provided in setBuckets. */ public void setBucketLabels(String[] labels) { this.labels = labels; } public void setBucketsAndLabels(double[] buckets, String[] labels) { setBuckets(buckets); setBucketLabels(labels); } /** Sets the color map used to draw the buckets. */ public void setColorMap(ColorMap map) { this.map = map; } MouseMotionAdapter motionAdapter = new MouseMotionAdapter() { public void mouseMoved(MouseEvent event) { int x = (int)(event.getX() * (buckets == null ? 0 : buckets.length) / (double)(getBounds().width)); if (labels != null && x < labels.length) setToolTipText(labels[x] + "\tValue: " + buckets[x]); else if (buckets != null && buckets.length != 0) setToolTipText("Bucket: " + x + "\tValue: " + buckets[x]); else setToolTipText(null); } }; // the purpose of this adapter is to force the tooltip manager to turn on // its initial delay MouseAdapter adapter = new MouseAdapter() { int initialDelay; int dismissDelay; int reshowDelay; public void mouseEntered(MouseEvent event) { initialDelay = ToolTipManager.sharedInstance().getInitialDelay(); ToolTipManager.sharedInstance().setInitialDelay(0); dismissDelay = ToolTipManager.sharedInstance().getDismissDelay(); ToolTipManager.sharedInstance().setDismissDelay(Integer.MAX_VALUE); reshowDelay = ToolTipManager.sharedInstance().getReshowDelay(); ToolTipManager.sharedInstance().setReshowDelay(0); } public void mouseExited(MouseEvent event) { ToolTipManager.sharedInstance().setInitialDelay(initialDelay); ToolTipManager.sharedInstance().setDismissDelay(dismissDelay); ToolTipManager.sharedInstance().setReshowDelay(reshowDelay); } }; public synchronized void paintComponent(final Graphics graphics) { if (map==null) return; int len = 0; if (buckets != null) len = buckets.length; if (len==0) return; // don't bother drawing Rectangle bounds = getBounds(); int height = bounds.height - 2; if (height <= 0) return; // make locals final ColorMap map = this.map; final BufferedImage buffer = this.buffer; // find maxbucket, minbucket double maxbucket = buckets[0]; double minbucket = buckets[0]; for(int i=1;i<len;i++) { if (buckets[i] < minbucket) minbucket = buckets[i]; if (buckets[i] > maxbucket) maxbucket = buckets[i]; } if (maxbucket==minbucket) { graphics.fillRect(0,0,bounds.width,height); return; } for(int i=0;i<len;i++) { int x0 = bounds.width / len * i; int x1 = bounds.width / len * (i+1); int y0 = 0; int y1; if (buckets[i]==Double.POSITIVE_INFINITY) y1 = height; else if (buckets[i]!=buckets[i]) y1 = 0; // it's NaN else y1 = (int)(height * ((buckets[i] - minbucket) / (double)(maxbucket-minbucket))); // flip the y's y0 = height - y0; y1 = height - y1; graphics.fillRect(x0+1,y1+1,x1-x0+1,y0-y1 + 1); } } /** Generates a set of <i>numBuckets</i> bucket labels appropriate for use in a histogram. The values <i>numBuckets</i>, <i>min</i>, and <i>max</i> should be the same values you had provided to makeBuckets(...). Pass the resulting array into the setBuckets(...) function.*/ public static String[] makeBucketLabels(int numBuckets, double min, double max, boolean logScale) { String[] s = new String[numBuckets]; if (min>max) {double tmp = min; min = max; max = tmp;} // duh, stupid user else if (min==max) { s[0] = "["+min+"..."+max+"]"; for(int x=1;x<s.length;x++) s[x] = ""; return s;} // duh, stupider user else if (logScale) { min = Math.log(min); max = Math.log(max); for(int x=0;x<s.length;x++) s[x] = "[" + Math.exp((x/(double)numBuckets)*(max-min) + min) + "..." + Math.exp(((x+1)/(double)numBuckets)*(max-min) + min) + (x==s.length-1 ? "]" : ")"); } else for(int x=0;x<s.length;x++) s[x] = "[" + ((x/(double)numBuckets)*(max-min) + min) + "..." + (((x+1)/(double)numBuckets)*(max-min) + min) + (x==s.length-1 ? "]" : ")"); return s; } /** Generates a set of <i>numBuckets</i> buckets describing a histogram over the provided values in <i>vals</i>. <i>min</i> and <i>max</i> describe the ends of the histogram, inclusive: values outside those ranges are discarded. You can tell the histogram to bucket based on a log scale if you like (min and max are computed prior to log)), and in this case all values less than 0 are discarded as well. Pass the resulting array into the setBuckets(...) function. */ public static double[] makeBuckets(double[] vals, int numBuckets, double min, double max, boolean logScale) { if (logScale) { min = Math.log(min); max = Math.log(max); } double[] b = new double[numBuckets]; if (vals == null || numBuckets == 0) return b; // duh, stupid user if (min>max) {double tmp = min; min = max; max = tmp;} // duh, stupid user else if (min==max) { b[0] += vals.length; return b; } // duh, stupider user int count = 0; for(int x=0;x<vals.length;x++) { double v = vals[x]; if (logScale) { if (v<0) continue; v = Math.log(v); } if (v < min || v > max) continue; int bucketnum = (int)((v - min) * numBuckets / (max-min)); if (bucketnum >= numBuckets) bucketnum = numBuckets-1; b[bucketnum]++; count++; } if (count != 0) for(int x=0;x<b.length;x++) b[x] /= count; return b; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -