PageRenderTime 28ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/hdf-java/ncsa/hdf/view/Chart.java

#
Java | 417 lines | 269 code | 67 blank | 81 comment | 62 complexity | 5479f966c0c5172e9bbab7e5af5d6f71 MD5 | raw file
  1. /*****************************************************************************
  2. * Copyright by The HDF Group. *
  3. * Copyright by the Board of Trustees of the University of Illinois. *
  4. * All rights reserved. *
  5. * *
  6. * This file is part of the HDF Java Products distribution. *
  7. * The full copyright notice, including terms governing use, modification, *
  8. * and redistribution, is contained in the files COPYING and Copyright.html. *
  9. * COPYING can be found at the root of the source code distribution tree. *
  10. * Or, see http://hdfgroup.org/products/hdf-java/doc/Copyright.html. *
  11. * If you do not have access to either file, you may request a copy from *
  12. * help@hdfgroup.org. *
  13. ****************************************************************************/
  14. package ncsa.hdf.view;
  15. import java.awt.BorderLayout;
  16. import java.awt.Color;
  17. import java.awt.Dimension;
  18. import java.awt.Frame;
  19. import java.awt.Graphics;
  20. import java.awt.Point;
  21. import java.awt.Window;
  22. import java.awt.event.ActionEvent;
  23. import java.awt.event.ActionListener;
  24. import java.lang.reflect.Array;
  25. import javax.swing.BorderFactory;
  26. import javax.swing.JButton;
  27. import javax.swing.JComponent;
  28. import javax.swing.JDialog;
  29. import javax.swing.JPanel;
  30. import javax.swing.WindowConstants;
  31. /**
  32. * ChartView displays histogram/line chart of selected row/column of table data
  33. * or image. There are two types of chart, histogram and line plot.
  34. *
  35. * @author Peter X. Cao
  36. * @version 2.4 9/6/2007
  37. */
  38. public class Chart extends JDialog implements ActionListener {
  39. /**
  40. *
  41. */
  42. private static final long serialVersionUID = 6306479533747330357L;
  43. /** histogram style chart */
  44. public static final int HISTOGRAM = 0;
  45. /** line style chart */
  46. public static final int LINEPLOT = 1;
  47. /** The default colors of lines for selected columns */
  48. public static final Color[] LINE_COLORS = { Color.black, Color.red,
  49. Color.green.darker(), Color.blue, Color.magenta, Color.pink,
  50. Color.yellow, Color.orange, Color.gray, Color.cyan };
  51. /** the data values of line points or histogram */
  52. protected double data[][];
  53. /** Panel that draws plot of data values. */
  54. protected ChartPanel chartP;
  55. /** number of data points */
  56. protected int numberOfPoints;
  57. /** the style of chart: histogram or line */
  58. private int chartStyle;
  59. /** the maximum value of the Y axis */
  60. private double ymax;
  61. /** the minimum value of the Y axis */
  62. private double ymin;
  63. /** the maximum value of the X axis */
  64. private double xmax;
  65. /** the minimum value of the X axis */
  66. private double xmin;
  67. /** line labels */
  68. private String lineLabels[];
  69. /** line colors */
  70. private Color lineColors[];
  71. /** number of lines */
  72. private int numberOfLines;
  73. /* the data to plot against */
  74. private double[] xData = null;
  75. /**
  76. * True if the original data is integer (byte, short, integer, long).
  77. */
  78. private boolean isInteger;
  79. private java.text.DecimalFormat format;
  80. /**
  81. * Constructs a new ChartView given data and data ranges.
  82. * <p>
  83. *
  84. * @param owner
  85. * the owner frame of this dialog.
  86. * @param title
  87. * the title of this dialog.
  88. * @param style
  89. * the style of the chart. Valid values are: HISTOGRAM and LINE
  90. * @param data
  91. * the two dimensional data array: data[linenumber][datapoints]
  92. * @param xData
  93. * the range of the X values, xRange[0]=xmin, xRange[1]=xmax.
  94. * @param yRange
  95. * the range of the Y values, yRange[0]=ymin, yRange[1]=ymax.
  96. */
  97. public Chart(Frame owner, String title, int style, double[][] data,
  98. double[] xData, double[] yRange) {
  99. super(owner, title, false);
  100. setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
  101. format = new java.text.DecimalFormat("0.00E0");
  102. if (data == null) {
  103. return;
  104. }
  105. this.chartStyle = style;
  106. this.data = data;
  107. if (style == HISTOGRAM) {
  108. isInteger = true;
  109. }
  110. else {
  111. isInteger = false;
  112. }
  113. if (xData != null) {
  114. int len = xData.length;
  115. if (len == 2) {
  116. this.xmin = xData[0];
  117. this.xmax = xData[1];
  118. }
  119. else {
  120. this.xData = xData;
  121. xmin = xmax = xData[0];
  122. for (int i = 0; i < len; i++) {
  123. if (xData[i] < xmin) {
  124. xmin = xData[i];
  125. }
  126. if (xData[i] > xmax) {
  127. xmax = xData[i];
  128. }
  129. }
  130. }
  131. }
  132. else {
  133. this.xmin = 1;
  134. this.xmax = data[0].length;
  135. }
  136. this.numberOfLines = Array.getLength(data);
  137. this.numberOfPoints = Array.getLength(data[0]);
  138. this.lineColors = LINE_COLORS;
  139. if (yRange != null) {
  140. // data range is given
  141. this.ymin = yRange[0];
  142. this.ymax = yRange[1];
  143. }
  144. else {
  145. // search data range from the data
  146. findDataRange();
  147. }
  148. if ((ymax < 0.0001) || (ymax > 100000)) {
  149. format = new java.text.DecimalFormat("###.####E0#");
  150. }
  151. chartP = new ChartPanel();
  152. chartP.setBackground(Color.white);
  153. createUI();
  154. }
  155. /**
  156. * Creates and layouts GUI components.
  157. */
  158. protected void createUI() {
  159. Window owner = getOwner();
  160. JPanel contentPane = (JPanel) getContentPane();
  161. contentPane.setLayout(new BorderLayout(5, 5));
  162. contentPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
  163. int w = 640 + (ViewProperties.getFontSize() - 12) * 15;
  164. int h = 400 + (ViewProperties.getFontSize() - 12) * 10;
  165. contentPane.setPreferredSize(new Dimension(w, h));
  166. contentPane.add(chartP, BorderLayout.CENTER);
  167. JButton button = new JButton("Close");
  168. button.addActionListener(this);
  169. button.setActionCommand("Close");
  170. JPanel tmp = new JPanel();
  171. tmp.add(button);
  172. contentPane.add(tmp, BorderLayout.SOUTH);
  173. Point l = owner.getLocation();
  174. l.x += 220;
  175. l.y += 100;
  176. setLocation(l);
  177. pack();
  178. }
  179. public void actionPerformed(ActionEvent e) {
  180. String cmd = e.getActionCommand();
  181. if (cmd.equals("Close")) {
  182. dispose();
  183. }
  184. }
  185. /** Sets the color of each line of a line plot */
  186. public void setLineColors(Color c[]) {
  187. lineColors = c;
  188. }
  189. /** Sets the labels of each line. */
  190. public void setLineLabels(String l[]) {
  191. lineLabels = l;
  192. }
  193. /** Set the data type of the plot data to be integer. */
  194. public void setTypeToInteger() {
  195. isInteger = true;
  196. }
  197. /** find and set the minimum and maximum values of the data */
  198. private void findDataRange() {
  199. if (data == null) {
  200. return;
  201. }
  202. ymin = ymax = data[0][0];
  203. for (int i = 0; i < numberOfLines; i++) {
  204. for (int j = 0; j < numberOfPoints; j++) {
  205. if (data[i][j] < ymin) {
  206. ymin = data[i][j];
  207. }
  208. if (data[i][j] > ymax) {
  209. ymax = data[i][j];
  210. }
  211. }
  212. }
  213. }
  214. /** The canvas that paints the data lines. */
  215. private class ChartPanel extends JComponent {
  216. private static final long serialVersionUID = -3701826094727309097L;
  217. /**
  218. * Paints the plot components.
  219. */
  220. @Override
  221. public void paint(Graphics g) {
  222. if (numberOfLines <= 0) {
  223. return; // no data
  224. }
  225. Dimension d = getSize();
  226. int gap = 20;
  227. int xgap = 2 * gap;
  228. int ygap = 2 * gap;
  229. int legendSpace = 0;
  230. if ((chartStyle == LINEPLOT) && (lineLabels != null)) {
  231. legendSpace = 60;
  232. }
  233. int h = d.height - gap;
  234. int w = d.width - (3 * gap + legendSpace);
  235. int xnpoints = Math.min(10, numberOfPoints - 1);
  236. int ynpoints = 10;
  237. // draw the X axis
  238. g.drawLine(xgap, h, w + xgap, h);
  239. // draw the Y axis
  240. g.drawLine(ygap, h, ygap, 0);
  241. // draw x labels
  242. double xp = 0, x = xmin;
  243. double dw = (double) w / (double) xnpoints;
  244. double dx = (xmax - xmin) / xnpoints;
  245. boolean gtOne = (dx >= 1);
  246. for (int i = 0; i <= xnpoints; i++) {
  247. x = xmin + i * dx;
  248. xp = xgap + i * dw;
  249. g.drawLine((int) xp, h, (int) xp, h - 5);
  250. if (gtOne) {
  251. g
  252. .drawString(String.valueOf((int) x), (int) xp - 5,
  253. h + gap);
  254. }
  255. else {
  256. g.drawString(String.valueOf(x), (int) xp - 5, h + gap);
  257. }
  258. }
  259. // draw y labels
  260. double yp = 0, y = ymin;
  261. double dh = (double) h / (double) ynpoints;
  262. double dy = (ymax - ymin) / (ynpoints);
  263. if (dy > 1) {
  264. dy = Math.round(dy * 10.0) / 10.0;
  265. }
  266. for (int i = 0; i <= ynpoints; i++) {
  267. yp = i * dh;
  268. y = i * dy + ymin;
  269. g.drawLine(ygap, h - (int) yp, ygap + 5, h - (int) yp);
  270. if (isInteger) {
  271. g.drawString(String.valueOf((int) y), 0, h - (int) yp + 8);
  272. }
  273. else {
  274. g.drawString(format.format(y), 0, h - (int) yp + 8);
  275. }
  276. }
  277. Color c = g.getColor();
  278. double x0, y0, x1, y1;
  279. if (chartStyle == LINEPLOT) {
  280. dw = (double) w / (double) (numberOfPoints - 1);
  281. // use y = a + b* x to calculate pixel positions
  282. double b = h / (ymin - ymax);
  283. double a = -b * ymax;
  284. boolean hasXdata = ((xData != null) && (xData.length >= numberOfPoints));
  285. double xRatio = (1 / (xmax - xmin)) * w;
  286. double xD = (xmin / (xmax - xmin)) * w;
  287. // draw lines for selected spreadsheet columns
  288. for (int i = 0; i < numberOfLines; i++) {
  289. if ((lineColors != null)
  290. && (lineColors.length >= numberOfLines)) {
  291. g.setColor(lineColors[i]);
  292. }
  293. // set up the line data for drawing one line a time
  294. if (hasXdata) {
  295. x0 = xgap + xData[0] * xRatio - xD;
  296. }
  297. else {
  298. x0 = xgap;
  299. }
  300. y0 = a + b * data[i][0];
  301. for (int j = 1; j < numberOfPoints; j++) {
  302. if (hasXdata) {
  303. x1 = xgap + xData[j] * xRatio - xD;
  304. }
  305. else {
  306. x1 = xgap + j * dw;
  307. }
  308. y1 = a + b * data[i][j];
  309. g.drawLine((int) x0, (int) y0, (int) x1, (int) y1);
  310. x0 = x1;
  311. y0 = y1;
  312. }
  313. // draw line legend
  314. if ((lineLabels != null)
  315. && (lineLabels.length >= numberOfLines)) {
  316. x0 = w + legendSpace;
  317. y0 = gap + gap * i;
  318. g.drawLine((int) x0, (int) y0, (int) x0 + 7, (int) y0);
  319. g
  320. .drawString(lineLabels[i], (int) x0 + 10,
  321. (int) y0 + 3);
  322. }
  323. }
  324. g.setColor(c); // set the color back to its default
  325. // draw a box on the legend
  326. if ((lineLabels != null)
  327. && (lineLabels.length >= numberOfLines)) {
  328. g.drawRect(w + legendSpace - 10, 10, legendSpace, 10 * gap);
  329. }
  330. } // if (chartStyle == LINEPLOT)
  331. else if (chartStyle == HISTOGRAM) {
  332. // draw histogram for selected image area
  333. xp = xgap;
  334. yp = 0;
  335. g.setColor(Color.blue);
  336. int barWidth = w / numberOfPoints;
  337. if (barWidth <= 0) {
  338. barWidth = 1;
  339. }
  340. dw = (double) w / (double) numberOfPoints;
  341. for (int j = 0; j < numberOfPoints; j++) {
  342. xp = xgap + j * dw;
  343. yp = (int) (h * (data[0][j] - ymin) / (ymax - ymin));
  344. g.fillRect((int) xp, (int) (h - yp), barWidth, (int) yp);
  345. }
  346. g.setColor(c); // set the color back to its default
  347. } // else if (chartStyle == HISTOGRAM)
  348. } // public void paint(Graphics g)
  349. } // private class ChartPanel extends Canvas
  350. }