001/**
002    Create and return a window containing a 2D XY type chart plotting the specified data.
003    The window returned is initially hidden so that the user can customize the chart if
004    desired. To show the window, call the "setVisible(true)" method on the returned window
005    object.
006     
007    @method PlotXYWindow plotXY(windowTitle, xArr1,yArr1,xArr2,yArr2,...)
008    @method PlotXYWindow plotXY(windowTitle, xList1,yList1,xList2,yList2,...)
009    @method PlotXYWindow plotXY(windowTitle, xVector1,yVector1,xVector2,yVector2,...)
010    @method PlotXYWindow plotXY(windowTitle, xDim, yDim, pointStr1,pointStr2,...)
011    @method PlotXYWindow plotXY(windowTitle, pointStr1,pointStr2,...)
012 */
013package geomss.app.GeomSSCommands;
014
015import bsh.*;
016import geomss.geom.GeomPoint;
017import geomss.geom.GeomVector;
018import geomss.geom.PointString;
019import geomss.ui.PlotXYWindow;
020import jahuwaldt.js.datareader.ArrayParam;
021import jahuwaldt.js.datareader.DataCase;
022import jahuwaldt.js.datareader.DataSet;
023import jahuwaldt.js.param.Parameter;
024import java.util.HashMap;
025import java.util.List;
026import javax.measure.quantity.Dimensionless;
027import javax.measure.quantity.Length;
028import javax.measure.unit.Unit;
029
030public class plotXY {
031
032    public static String usage() {
033        return "usage: plotXY(windowTitle, xData1,yData1,xData2,yData2,...);";
034    }
035
036    /**
037     * Implement plotXY( String windowTitle, double[]... arrayVarArg ) command. This
038     * version plots a list of pairs of Java arrays of doubles.
039     */
040    public static PlotXYWindow invoke(Interpreter env, CallStack callstack,
041            String windowTitle, double[]... arrayVarArg) {
042
043        int numCols = arrayVarArg.length;
044        if (numCols % 2 != 0)
045            throw new IllegalArgumentException("X-Y data must be provided in pairs of arrays.");
046        int numCases = numCols / 2;
047
048        DataSet data = DataSet.newInstance(windowTitle);
049        for (int i = 0; i < numCols; ++i) {
050            int caseNum = i / 2 + 1;
051            double[] xData = arrayVarArg[i++];
052            double[] yData = arrayVarArg[i];
053            ArrayParam xArr = ArrayParam.valueOf("X", Dimensionless.UNIT, xData);
054            ArrayParam yArr = ArrayParam.valueOf("Y", Dimensionless.UNIT, yData);
055            DataCase aCase = DataCase.newInstance("Case #" + (numCases > 1 ? String.valueOf(caseNum) : ""));
056            aCase.add(xArr);
057            aCase.add(yArr);
058            data.add(aCase);
059        }
060
061        PlotXYWindow window = new PlotXYWindow(windowTitle, data);
062        return window;
063    }
064
065    /**
066     * Implement plotXY( String windowTitle, List... listVarArg ) command. This version
067     * plots a list of pairs of lists of Double or Parameter or GeomPoint or combinations.
068     */
069    public static PlotXYWindow invoke(Interpreter env, CallStack callstack,
070            String windowTitle, List... listVarArg) {
071
072        int numCols = listVarArg.length;
073        if (numCols % 2 != 0)
074            throw new IllegalArgumentException("X-Y data must be provided in pairs of lists.");
075        int numCases = numCols / 2;
076
077        DataSet data = DataSet.newInstance(windowTitle);
078        for (int i = 0; i < numCols; ++i) {
079            int caseNum = i / 2 + 1;
080            List xData = listVarArg[i++];
081            List yData = listVarArg[i];
082            ArrayParam xArr = list2ArrayParam("X", xData);
083            ArrayParam yArr = list2ArrayParam("Y", yData);
084            DataCase aCase = DataCase.newInstance("Case #" + (numCases > 1 ? String.valueOf(caseNum) : ""));
085            aCase.add(xArr);
086            aCase.add(yArr);
087            data.add(aCase);
088        }
089
090        PlotXYWindow window = new PlotXYWindow(windowTitle, data);
091        return window;
092    }
093
094    /**
095     * Return true if the supplied list contains only Number objects.
096     */
097    private static boolean isNumberList(List data) {
098        int size = data.size();
099        for (int i = 0; i < size; ++i) {
100            if (!(data.get(i) instanceof Number))
101                return false;
102        }
103        return true;
104    }
105
106    /**
107     * Return true if the supplied list contains only Parameter objects.
108     */
109    private static boolean isParameterList(List data) {
110        int size = data.size();
111        for (int i = 0; i < size; ++i) {
112            if (!(data.get(i) instanceof Parameter))
113                return false;
114        }
115        return true;
116    }
117
118    /**
119     * Return true if the supplied list contains only GeomPoint objects.
120     */
121    private static boolean isPointList(List data) {
122        int size = data.size();
123        for (int i = 0; i < size; ++i) {
124            if (!(data.get(i) instanceof GeomPoint))
125                return false;
126        }
127        return true;
128    }
129
130    /**
131     * Convert the input list of data into an ArrayParam object if possible.
132     */
133    private static ArrayParam list2ArrayParam(String name, List data) {
134        if (isNumberList(data)) {
135            int size = data.size();
136            double[] arr = new double[size];
137            for (int i = size - 1; i >= 0; --i)
138                arr[i] = ((Number)data.get(i)).doubleValue();
139            return ArrayParam.valueOf(name, Dimensionless.UNIT, arr);
140
141        } else if (isParameterList(data)) {
142            Unit unit = ((Parameter)data.get(0)).getUnit();
143            int size = data.size();
144            double[] arr = new double[size];
145            for (int i = size - 1; i >= 0; --i) {
146                arr[i] = ((Parameter)data.get(i)).getValue(unit);
147            }
148            return ArrayParam.valueOf(name, unit, arr);
149
150        } else if (isPointList(data)) {
151            //  Assume a 1D point (well, assume the X value is to be plotted anyway).
152            Unit unit = ((GeomPoint)data.get(0)).getUnit();
153            int size = data.size();
154            double[] arr = new double[size];
155            for (int i = size - 1; i >= 0; --i) {
156                arr[i] = ((GeomPoint)data.get(i)).getValue(0, unit);
157            }
158            return ArrayParam.valueOf(name, unit, arr);
159
160        }
161        throw new IllegalArgumentException("Unknown data type in list.");
162    }
163
164    /**
165     * Implement plotXY( String windowTitle, GeomVector... vectorVarArg ) command. This
166     * version plots a list of pairs of GeomVector objects.
167     */
168    public static PlotXYWindow invoke(Interpreter env, CallStack callstack,
169            String windowTitle, GeomVector... vectorVarArg) {
170
171        int numCols = vectorVarArg.length;
172        if (numCols % 2 != 0)
173            throw new IllegalArgumentException("X-Y data must be provided in pairs of vectors.");
174        int numCases = numCols / 2;
175
176        DataSet data = DataSet.newInstance(windowTitle);
177        for (int i = 0; i < numCols; ++i) {
178            int caseNum = i / 2 + 1;
179            GeomVector xData = vectorVarArg[i++];
180            GeomVector yData = vectorVarArg[i];
181
182            int size = xData.getPhyDimension();
183            if (size < 1)
184                throw new IllegalArgumentException("Empty vector provided for pair #" + caseNum);
185            if (yData.getPhyDimension() != size)
186                throw new IllegalArgumentException("Vectors are different dimensions for pair #" + caseNum);
187
188            Unit xUnit = xData.getUnit();
189            Unit yUnit = yData.getUnit();
190            double[] x = new double[size];
191            double[] y = new double[size];
192            for (int j = size - 1; j >= 0; --j) {
193                x[j] = xData.getValue(j);
194                y[j] = yData.getValue(j);
195            }
196
197            String name = xData.getName();
198            name = (name == null ? "X" : name);
199            ArrayParam xArr = ArrayParam.valueOf(name, xUnit, x);
200            name = yData.getName();
201            name = (name == null ? "Y" : name);
202            ArrayParam yArr = ArrayParam.valueOf(name, yUnit, y);
203            DataCase aCase = DataCase.newInstance(name);
204            aCase.add(xArr);
205            aCase.add(yArr);
206            data.add(aCase);
207        }
208
209        PlotXYWindow window = new PlotXYWindow(windowTitle, data);
210        return window;
211    }
212
213    private static final HashMap<Integer, String> DIM_MAP;
214
215    static {
216        DIM_MAP = new HashMap();
217        DIM_MAP.put(0, "X");
218        DIM_MAP.put(1, "Y");
219        DIM_MAP.put(2, "Z");
220    }
221
222    /**
223     * Implement plotXY( String windowTitle, int xDim, int yDim, GeomVector...
224     * pointStrVarArg ) command. This version plots the specified dimensions of a list
225     * PointString objects each containing points with at least max(xDim,yDim) physical
226     * dimensions.
227     */
228    public static PlotXYWindow invoke(Interpreter env, CallStack callstack,
229            String windowTitle, int xDim, int yDim, PointString... pointStrVarArg) {
230
231        int numCols = pointStrVarArg.length;
232        int minDim = Math.max(xDim, yDim);
233
234        DataSet data = DataSet.newInstance(windowTitle);
235        for (int i = 0; i < numCols; ++i) {
236            PointString pnts = pointStrVarArg[i];
237
238            int size = pnts.size();
239            if (size < 1)
240                throw new IllegalArgumentException("Empty PointString provided for string #" + (i + 1));
241            if (pnts.getPhyDimension() < minDim)
242                throw new IllegalArgumentException("Dimensions to small for PointString #" + (i + 1));
243
244            Unit unit = pnts.getUnit();
245            double[] x = new double[size];
246            double[] y = new double[size];
247            for (int j = 0; j < size; ++j) {
248                GeomPoint pnt = (GeomPoint)pnts.get(j);
249                x[j] = pnt.getValue(xDim, unit);
250                y[j] = pnt.getValue(yDim, unit);
251            }
252
253            String label = DIM_MAP.get(xDim);
254            ArrayParam xArr = ArrayParam.valueOf((label == null ? "X" : label), unit, x);
255            label = DIM_MAP.get(yDim);
256            ArrayParam yArr = ArrayParam.valueOf((label == null ? "Y" : label), unit, y);
257            String caseName = pnts.getName();
258            caseName = (caseName == null ? "Case #" + (i + 1) : caseName);
259            DataCase aCase = DataCase.newInstance(caseName);
260            aCase.add(xArr);
261            aCase.add(yArr);
262            data.add(aCase);
263        }
264
265        PlotXYWindow window = new PlotXYWindow(windowTitle, data);
266        return window;
267    }
268
269    /**
270     * Implement plotXY( String windowTitle, GeomVector... pointStrVarArg ) command. This
271     * version plots 2D points from a list PointString objects.
272     */
273    public static PlotXYWindow invoke(Interpreter env, CallStack callstack,
274            String windowTitle, PointString... pointStrVarArg) {
275        return invoke(env, callstack, windowTitle, GeomPoint.X, GeomPoint.Y, pointStrVarArg);
276    }
277}