//
// BarGraph.java
//
/*
VisAD system for interactive analysis and visualization of numerical
data. Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom
Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and
Tommy Jasmin.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/
package visad.util;
import javax.swing.*;
import java.awt.*;
import java.rmi.RemoteException;
import visad.*;
import visad.java3d.*;
/** BarGraph provides methods for plotting colored bar graphs in 2D or 3D. */
public class BarGraph {
// -- Constants --
protected static final RealType BAR_X = RealType.getRealType("Bar_X");
protected static final RealType BAR_Y = RealType.getRealType("Bar_Y");
protected static final RealType BAR_Z = RealType.getRealType("Bar_Z");
protected static final RealType BAR_R = RealType.getRealType("Bar_Red");
protected static final RealType BAR_G = RealType.getRealType("Bar_Green");
protected static final RealType BAR_B = RealType.getRealType("Bar_Blue");
protected static final FunctionType BOX_2D;
protected static final FunctionType BOX_3D;
static {
FunctionType func2d = null, func3d = null;
try {
RealTupleType rgb = new RealTupleType(BAR_R, BAR_G, BAR_B);
func2d = new FunctionType(new RealTupleType(BAR_X, BAR_Y), rgb);
func3d = new FunctionType(new RealTupleType(BAR_X, BAR_Y, BAR_Z), rgb);
}
catch (VisADException exc) { exc.printStackTrace(); }
BOX_2D = func2d;
BOX_3D = func3d;
}
// -- 2D bar graph method signatures --
/**
* Constructs a 2D bar graph.
* @param heights Height of each bar
* @param spacing Spacing between bars (at least 0, and less than 1)
* @param colors Color of each bar
*/
public static FlatField makeBarGraph2D(float[] heights, float spacing,
Color[] colors) throws VisADException, RemoteException
{
return makeBarGraph2D(BOX_2D, heights, spacing, colors);
}
/**
* Constructs a 2D bar graph.
* @param type MathType to use, of the form ((X, Y) -> (R, G, B))
* @param heights Height of each bar
* @param spacing Spacing between bars (at least 0, and less than 1)
* @param colors Color of each bar
*/
public static FlatField makeBarGraph2D(FunctionType type, float[] heights,
float spacing, Color[] colors) throws VisADException, RemoteException
{
if (heights == null) throw new VisADException("Heights is null");
int len = heights.length;
float[] x1 = new float[len], y1 = new float[len];
float[] x2 = new float[len], y2 = new float[len];
float s = spacing / 2;
for (int i=0; i<len; i++) {
x1[i] = i + s;
y1[i] = 0;
x2[i] = i + 1 - s;
y2[i] = heights[i];
}
return makeBoxes2D(type, x1, y1, x2, y2, colors);
}
public static FlatField makeBoxes2D(float[] x1, float[] y1,
float[] x2, float[] y2, Color[] c) throws VisADException, RemoteException
{
return makeBoxes2D(BOX_2D, x1, y1, x2, y2, c);
}
public static FlatField makeBoxes2D(float[] x1, float[] y1,
float[] x2, float[] y2, float[] r, float[] g, float[] b)
throws VisADException, RemoteException
{
return makeBoxes2D(BOX_2D, x1, y1, x2, y2, r, g, b);
}
public static FlatField makeBoxes2D(FunctionType type,
float[] x1, float[] y1, float[] x2, float[] y2, Color[] c)
throws VisADException, RemoteException
{
float[][] rgb = extractColors(c);
return makeBoxes2D(BOX_2D, x1, y1, x2, y2, rgb[0], rgb[1], rgb[2]);
}
public static FlatField makeBoxes2D(FunctionType type,
float[] x1, float[] y1, float[] x2, float[] y2,
float[] r, float[] g, float[] b) throws VisADException, RemoteException
{
if (type == null) throw new VisADException("Type is null");
if (x1 == null || y1 == null || x2 == null || y2 == null) {
throw new VisADException("Coordinates are null");
}
if (r == null || g == null || b == null) {
throw new VisADException("Color values are null");
}
int len = x1.length;
if (len != y1.length || len != x2.length || len != y2.length ||
len != r.length || len != g.length || len != b.length)
{
throw new VisADException("Lengths do not match");
}
RealTupleType domain = type.getDomain();
Gridded2DSet[] sets = new Gridded2DSet[len];
float[][] colors = new float[3][4 * len];
for (int i=0; i<len; i++) {
float[][] samples = {
{x1[i], x2[i], x1[i], x2[i]},
{y1[i], y1[i], y2[i], y2[i]}
};
sets[i] = new Gridded2DSet(domain,
samples, 2, 2, null, null, null, false);
for (int j=0; j<4; j++) {
int ndx = 4 * i + j;
colors[0][ndx] = r[i];
colors[1][ndx] = g[i];
colors[2][ndx] = b[i];
}
}
UnionSet uset = new UnionSet(domain, sets);
FlatField ff = new FlatField(type, uset);
ff.setSamples(colors, false);
return ff;
}
// -- 3D bar graph method signatures --
/**
* Constructs a 3D bar graph.
* @param heights Height of each bar (dimensioned cols X rows)
* @param spacing Spacing between bars (at least 0, and less than 1)
* @param colors Color of each bar (dimensioned cols X rows)
*/
public static FlatField makeBarGraph3D(float[][] heights, float spacing,
Color[][] colors) throws VisADException, RemoteException
{
return makeBarGraph3D(BOX_2D, heights, spacing, colors);
}
/**
* Constructs a 3D bar graph.
* @param type MathType to use, of the form ((X, Y, Z) -> (R, G, B))
* @param heights Height of each bar (dimensioned cols X rows)
* @param spacing Spacing between bars (at least 0, and less than 1)
* @param colors Color of each bar (dimensioned cols X rows)
*/
public static FlatField makeBarGraph3D(FunctionType type, float[][] heights,
float spacing, Color[][] colors) throws VisADException, RemoteException
{
if (heights == null) throw new VisADException("Heights is null");
if (colors == null) throw new VisADException("Colors are null");
int lenX = heights.length;
if (lenX < 1) throw new VisADException("Not enough bars");
if (lenX != colors.length) {
throw new VisADException("Lengths do not match");
}
int lenY = heights[0].length;
for (int c=0; c<lenX; c++) {
if (heights[c] == null) {
throw new VisADException("Heights[" + c + "] is null");
}
if (colors[c] == null) {
throw new VisADException("Colors[" + c + "] is null");
}
if (lenY != heights[c].length || lenY != colors[c].length) {
throw new VisADException("Lengths do not match");
}
}
int len = lenX * lenY;
float[] x1 = new float[len], y1 = new float[len], z1 = new float[len];
float[] x2 = new float[len], y2 = new float[len], z2 = new float[len];
Color[] cols = new Color[len];
float s = spacing / 2;
for (int r=0; r<lenY; r++) {
for (int c=0; c<lenX; c++) {
int i = lenX * r + c;
x1[i] = c + s;
y1[i] = r + s;
z1[i] = 0;
x2[i] = c + 1 - s;
y2[i] = r + 1 - s;
z2[i] = heights[c][r];
cols[i] = colors[c][r];
}
}
return makeBoxes3D(type, x1, y1, z1, x2, y2, z2, cols);
}
public static FlatField makeBoxes3D(float[] x1, float[] y1, float[] z1,
float[] x2, float[] y2, float[] z2, Color[] c)
throws VisADException, RemoteException
{
return makeBoxes3D(BOX_3D, x1, y1, z1, x2, y2, z2, c);
}
public static FlatField makeBoxes3D(float[] x1, float[] y1, float[] z1,
float[] x2, float[] y2, float[] z2, float[] r, float[] g, float[] b)
throws VisADException, RemoteException
{
return makeBoxes3D(BOX_3D, x1, y1, z1, x2, y2, z2, r, g, b);
}
public static FlatField makeBoxes3D(FunctionType type,
float[] x1, float[] y1, float[] z1, float[] x2, float[] y2, float[] z2,
Color[] c) throws VisADException, RemoteException
{
float[][] rgb = extractColors(c);
return makeBoxes3D(BOX_3D,
x1, y1, z1, x2, y2, z2, rgb[0], rgb[1], rgb[2]);
}
public static FlatField makeBoxes3D(FunctionType type,
float[] x1, float[] y1, float[] z1, float[] x2, float[] y2, float[] z2,
float[] r, float[] g, float[] b) throws VisADException, RemoteException
{
if (type == null) throw new VisADException("Type is null");
if (x1 == null || y1 == null || z1 == null ||
x2 == null || y2 == null || z2 == null)
{
throw new VisADException("Coordinates are null");
}
if (r == null || g == null || b == null) {
throw new VisADException("Color values are null");
}
int len = x1.length;
if (len != y1.length || len != z1.length ||
len != x2.length || len != y2.length || len != z2.length ||
len != r.length || len != g.length || len != b.length)
{
throw new VisADException("Lengths do not match");
}
RealTupleType domain = type.getDomain();
UnionSet[] sets = new UnionSet[len];
float[][] colors = new float[3][4 * 6 * len];
for (int i=0; i<len; i++) {
float[][] bottomSamples = {
{x1[i], x2[i], x1[i], x2[i]},
{y1[i], y1[i], y2[i], y2[i]},
{z1[i], z1[i], z1[i], z1[i]}
};
Gridded3DSet bottom = new Gridded3DSet(domain,
bottomSamples, 2, 2, null, null, null, false);
float[][] topSamples = {
{x1[i], x2[i], x1[i], x2[i]},
{y1[i], y1[i], y2[i], y2[i]},
{z2[i], z2[i], z2[i], z2[i]}
};
Gridded3DSet top = new Gridded3DSet(domain,
topSamples, 2, 2, null, null, null, false);
float[][] frontSamples = {
{x1[i], x2[i], x1[i], x2[i]},
{y1[i], y1[i], y1[i], y1[i]},
{z1[i], z1[i], z2[i], z2[i]}
};
Gridded3DSet front = new Gridded3DSet(domain,
frontSamples, 2, 2, null, null, null, false);
float[][] backSamples = {
{x1[i], x2[i], x1[i], x2[i]},
{y2[i], y2[i], y2[i], y2[i]},
{z1[i], z1[i], z2[i], z2[i]}
};
Gridded3DSet back = new Gridded3DSet(domain,
backSamples, 2, 2, null, null, null, false);
float[][] leftSamples = {
{x1[i], x1[i], x1[i], x1[i]},
{y1[i], y2[i], y1[i], y2[i]},
{z1[i], z1[i], z2[i], z2[i]}
};
Gridded3DSet left = new Gridded3DSet(domain,
leftSamples, 2, 2, null, null, null, false);
float[][] rightSamples = {
{x2[i], x2[i], x2[i], x2[i]},
{y1[i], y2[i], y1[i], y2[i]},
{z1[i], z1[i], z2[i], z2[i]}
};
Gridded3DSet right = new Gridded3DSet(domain,
rightSamples, 2, 2, null, null, null, false);
sets[i] = new UnionSet(domain,
new SampledSet[] {bottom, top, front, back, left, right});
for (int j=0; j<24; j++) {
int ndx = 24 * i + j;
colors[0][ndx] = r[i];
colors[1][ndx] = g[i];
colors[2][ndx] = b[i];
}
}
UnionSet uset = new UnionSet(domain, sets);
FlatField ff = new FlatField(type, uset);
ff.setSamples(colors, false);
return ff;
}
// -- Helper methods --
/** Converts java.awt.Color objects to floating point RGB values. */
public static float[][] extractColors(Color[] c) {
if (c == null) return new float[][] {null, null, null};
float[][] rgb = new float[3][c.length];
for (int i=0; i<c.length; i++) {
rgb[0][i] = c[i].getRed() / 255f;
rgb[1][i] = c[i].getGreen() / 255f;
rgb[2][i] = c[i].getBlue() / 255f;
}
return rgb;
}
// -- Main method --
/** Run 'java visad.util.BarGraph' to test bar graphing. */
public static void main(String[] argv)
throws VisADException, RemoteException
{
JFrame frame = new JFrame("Bar Graphs in VisAD");
JPanel pane = new JPanel();
pane.setLayout(new BoxLayout(pane, BoxLayout.X_AXIS));
frame.setContentPane(pane);
// 2D bar graph
float[] heights2 = {4, 7, 5, 11, 9};
float max2 = 12; // top of graph
Color[] colors2 = {Color.red, Color.yellow,
Color.green, Color.gray, Color.magenta};
FlatField barGraph2 = makeBarGraph2D(heights2, 0.2f, colors2);
DisplayImplJ3D d2 = new DisplayImplJ3D("d2", new TwoDDisplayRendererJ3D());
ScalarMap xMap2 = new ScalarMap(BAR_X, Display.XAxis);
xMap2.setRange(0, heights2.length);
d2.addMap(xMap2);
ScalarMap yMap2 = new ScalarMap(BAR_Y, Display.YAxis);
yMap2.setRange(0, max2);
d2.addMap(yMap2);
d2.addMap(new ScalarMap(BAR_R, Display.Red));
d2.addMap(new ScalarMap(BAR_G, Display.Green));
d2.addMap(new ScalarMap(BAR_B, Display.Blue));
DataReferenceImpl ref2 = new DataReferenceImpl("ref2");
ref2.setData(barGraph2);
d2.addReference(ref2);
pane.add(d2.getComponent());
d2.getGraphicsModeControl().setScaleEnable(true);
// 3D bar graph
float[][] heights3 = {
{8, 7, 5, 14, 9},
{13, 1, 19, 7, 16},
{6, 11, 12, 13, 4}
};
float max3 = 20; // top of graph
Color darkPink = Color.pink.darker();
Color darkYellow = Color.yellow.darker();
Color darkMagenta = Color.magenta.darker();
Color[][] colors3 = {
{Color.red, Color.yellow, Color.green, Color.gray, Color.magenta},
{Color.blue, Color.white, Color.orange, Color.pink, Color.lightGray},
{Color.cyan, Color.darkGray, darkYellow, darkPink, darkMagenta}
};
FlatField barGraph3 = makeBarGraph3D(heights3, 0.2f, colors3);
DisplayImplJ3D d3 = new DisplayImplJ3D("d3");
ScalarMap xMap3 = new ScalarMap(BAR_X, Display.XAxis);
xMap3.setRange(0, heights3.length);
d3.addMap(xMap3);
ScalarMap yMap3 = new ScalarMap(BAR_Y, Display.YAxis);
yMap3.setRange(0, heights3[0].length);
d3.addMap(yMap3);
ScalarMap zMap3 = new ScalarMap(BAR_Z, Display.ZAxis);
zMap3.setRange(0, max3);
d3.addMap(zMap3);
d3.addMap(new ScalarMap(BAR_R, Display.Red));
d3.addMap(new ScalarMap(BAR_G, Display.Green));
d3.addMap(new ScalarMap(BAR_B, Display.Blue));
DataReferenceImpl ref3 = new DataReferenceImpl("ref3");
ref3.setData(barGraph3);
d3.addReference(ref3);
pane.add(d3.getComponent());
d3.getGraphicsModeControl().setScaleEnable(true);
Dimension ss = Toolkit.getDefaultToolkit().getScreenSize();
int w = ss.width - 100;
frame.setBounds(50, 50, w, w / 2);
frame.show();
}
}