All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.math.plot.DataSelectPanel Maven / Gradle / Ivy

There is a newer version: 1.0.1
Show newest version
/*
 * Created on 6 juil. 07 by richet
 */
package org.math.plot;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeListener;
import java.util.LinkedList;
import java.util.Vector;
import javax.swing.AbstractAction;

import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import org.math.plot.utils.Array;

/**
 * Panel designed to select a given number of columns in a multi columns matrix.
 * Useful to provide a 3d plot view of Nd data matrix.
 */
public class DataSelectPanel extends JPanel {

    private static final long serialVersionUID = 419181752327223313L;
    ParameterRow[] rows;
    private Object[][] _data, _selecteddata;
    private LinkedList _tmpselecteddata;
    boolean dataUpdated = false;
    private int[] _tmpselectedIndex;
    private int _nbselected;
    private int[] _selectedindex;
    private String[] _parametersNames;
    //boolean Zselected = false;
    int _dimension;

    void autoSelectVariableParam() {
        int d = 0;
        for (int i = 0; i < _data[0].length; i++) {
            boolean constant = true;
            String val = _data[0][i].toString();
            for (int j = 1; j < _data.length; j++) {
                if (!_data[j][i].toString().equals(val)) {
                    //System.err.println(_data[j][i] + " != " + val);
                    constant = false;
                    break;
                }
            }
            if (!constant && _dimension > d) {
                if (d == 0) {
                    selectAsX(i);
                    d++;
                    continue;
                } else if (d == 1) {
                    selectAsY(i);
                    d++;
                    continue;
                } else if (d == 2) {
                    selectAsZ(i);
                    break;
                }
            }
        }
    }

    public DataSelectPanel(Object[][] data, int dimension, String... parametersNames) {
        _data = data;
        _dimension = dimension;

        _parametersNames = parametersNames;

        if (_dimension > parametersNames.length) {
            throw new IllegalArgumentException("Number of parameters must be > to dimension=" + _dimension);
        }

        setLayout(new GridLayout(_parametersNames.length /*+ 1*/, 1));
        //JPanel title = new JPanel();
        //title.setLayout(new GridLayout(1, 2));
        //title.add(new JLabel("Variable"));
        //title.add(new JLabel("Axis / Parameter"));
        //add(title);

        if (_dimension == 0) {
            buildRows();
        } else if (_dimension == 1) {
            buildRows(0);
        } else if (_dimension == 2) {
            buildRows(0, 1);
        } else if (_dimension == 3) {
            buildRows(0, 1, 2);
        }

        fireSelectedDataChanged("init");
    }

    void buildRows(int... selectedaxis) {
        ButtonGroup xgrp = new ButtonGroup();
        ButtonGroup ygrp = new ButtonGroup();
        ButtonGroup zgrp = new ButtonGroup();
        rows = new ParameterRow[_parametersNames.length];
        for (int i = 0; i < _parametersNames.length; i++) {
            rows[i] = new ParameterRow(_parametersNames[i], getColumn(i, _data));

            if (selectedaxis != null && selectedaxis.length > 0) {
                if (selectedaxis.length >= 1) {
                    rows[i].xaxis.setSelected(selectedaxis[0] == i);
                }
                if (selectedaxis.length >= 2) {
                    rows[i].yaxis.setSelected(selectedaxis[1] == i);
                }
                if (selectedaxis.length == 3) {
                    rows[i].zaxis.setSelected(selectedaxis[2] == i);
                }
            }

            xgrp.add(rows[i].xaxis);
            ygrp.add(rows[i].yaxis);
            zgrp.add(rows[i].zaxis);

            add(rows[i]);
        }
        setPreferredSize(new Dimension(row_width, row_height * _parametersNames.length));
        setSize(new Dimension(row_width, row_height * _parametersNames.length));

        autoSelectVariableParam();
        updateSelectedData();
    }

    public void setData(Object[][] data) {
        if (data[0].length != _data[0].length) {
            throw new IllegalArgumentException("new data dimension is not consistent with previous one.");
        }
        _data = data;

        int[] selectedaxis = new int[_dimension];
        for (int i = 0; i < rows.length; i++) {
            if (selectedaxis.length >= 1) {
                if (rows[i].xaxis.isSelected()) {
                    selectedaxis[0] = i;
                }
            }
            if (selectedaxis.length >= 2) {
                if (rows[i].yaxis.isSelected()) {
                    selectedaxis[1] = i;
                }
            }
            if (selectedaxis.length == 3) {
                if (rows[i].zaxis.isSelected()) {
                    selectedaxis[2] = i;
                }
            }
            remove(rows[i]);
        }

        dataUpdated = false;
        buildRows(selectedaxis);

        fireSelectedDataChanged("set");
    }

    void updateSelectedData() {
        if (dataUpdated) {
            return;
        }

        for (ParameterRow row : rows) {
            boolean isaxis = row.xaxis.isSelected() || row.yaxis.isSelected() || row.zaxis.isSelected();
            if (row._isNumber) {
                row.min.setEnabled(!isaxis);
                row.max.setEnabled(!isaxis);
            } else {
                row.list.setEnabled(!isaxis);
            }
            if (!isaxis) {
                if (row._isNumber) {
                    row.name.setText(row._paramName + "=[" + row._kernelDoubleValues[row.min.getValue() - 1] + "," + row._kernelDoubleValues[row.max.getValue() - 1] + "]");
                } else {
                    row.name.setText(row._paramName + "={" + Array.cat(row.list.getSelectedValues()) + "}");
                }
            } else {
                row.name.setText(row._paramName);
            }
        }

        _tmpselectedIndex = new int[_data.length];
        _nbselected = 0;
        _tmpselecteddata = new LinkedList();
        for (int i = 0; i < _data.length; i++) {
            boolean sel = true;
            for (int j = 0; j < rows.length; j++) {
                ParameterRow row = rows[j];
                if (!row.xaxis.isSelected() && !row.yaxis.isSelected() && !row.zaxis.isSelected() && !row.check(_data[i][j])) {
                    sel = false;
                }
            }

            if (sel) {
                _tmpselecteddata.add(_data[i]);
                _tmpselectedIndex[_nbselected] = i;
                _nbselected++;
                /*System.out.print("OK:");
                for (int j = 0; j < _tmpselecteddata.getLast().length; j++)
                System.out.print(_tmpselecteddata.getLast()[j]+",");
                System.out.println("");*/
            }
        }
        dataUpdated = true;
    }

    /**Method to override if you want to link to any gui component (for instance, a plotpanel).*/
    public void fireSelectedDataChanged(String from) {
        System.err.println("fireSelectedDataChanged from " + from);
        Object[][] sel = getSelectedFullData();
        System.err.println("selected full data :");
        System.err.println(Array.cat(_parametersNames));
        if (sel.length > 0) {
            System.err.println(Array.cat(getSelectedFullData()));
        }

        sel = getSelectedProjectedData();
        System.err.println("selected projected data :");
        switch (_dimension) {
            case 0:
                System.err.println("No axis selected");
                break;
            case 1:
                System.err.println(Array.cat(new String[]{getSelectedXAxis()}));
                break;
            case 2:
                System.err.println(Array.cat(new String[]{getSelectedXAxis(), getSelectedYAxis()}));
                break;
            case 3:
                System.err.println(Array.cat(new String[]{getSelectedXAxis(), getSelectedYAxis(), getSelectedZAxis()}));
                break;
        }
        if (sel.length > 0) {
            System.err.println(Array.cat(sel));
        }
        System.err.println("Done.");
    }

    /**return selected data*/
    public int[] getSelectedDataIndex() {
        updateSelectedData();
        _selectedindex = new int[_nbselected];
        for (int i = 0; i < _nbselected; i++) {
            _selectedindex[i] = _tmpselectedIndex[i];
        }
        return _selectedindex;
    }

    /**return selected data*/
    public Object[][] getSelectedFullData() {
        updateSelectedData();
        _selecteddata = new Object[_tmpselecteddata.size()][_data[0].length];
        for (int i = 0; i < _selecteddata.length; i++) {
            for (int j = 0; j < _selecteddata[i].length; j++) {
                _selecteddata[i][j] = _tmpselecteddata.get(i)[j];
            }
        }
        return _selecteddata;
    }

    /**return selected data projected on axis selected*/
    public Object[][] getSelectedProjectedData() {
        //updateSelectedData();
        /*if (_dimension == 0) {
        return getSelectedFullData();
        }*/
        int[] selectedaxis = getSelectedAxisIndex();
        _selecteddata = new Object[_tmpselecteddata.size()][_dimension];
        for (int i = 0; i < _selecteddata.length; i++) {
            for (int j = 0; j < _dimension; j++) {
                _selecteddata[i][j] = _tmpselecteddata.get(i)[selectedaxis[j]];
            }
        }
        return _selecteddata;
    }

    public int[] getSelectedAxisIndex() {
        int[] selectedaxis = new int[_dimension];
        updateSelectedData();
        for (int i = 0; i < rows.length; i++) {
            if (rows[i].xaxis.isSelected()) {
                //System.out.println("selextedaxis[0] =" + i);
                selectedaxis[0] = i;
            }
            if (rows[i].yaxis.isSelected()) {
                //System.out.println("selextedaxis[1] =" + i);
                selectedaxis[1] = i;
            }
            if (rows[i].zaxis.isSelected()) {
                //System.out.println("selextedaxis[2] =" + i);
                selectedaxis[2] = i;
            }
        }
        return selectedaxis;
    }

    /**return selected X axis name*/
    public String getSelectedXAxis() {
        updateSelectedData();
        for (ParameterRow row : rows) {
            if (row.xaxis.isSelected()) {
                return row._paramName;
            }
        }
        return null;
    }

    /**return selected Y axis name*/
    public String getSelectedYAxis() {
        updateSelectedData();
        for (ParameterRow row : rows) {
            if (row.yaxis.isSelected()) {
                return row._paramName;
            }
        }
        return null;
    }

    /**return selected Z axis name*/
    public String getSelectedZAxis() {
        updateSelectedData();
        for (ParameterRow row : rows) {
            if (row.zaxis.isSelected()) {
                return row._paramName;
            }
        }
        return null;
    }

    static Object[] getColumn(int j, Object[][] mat) {
        Object[] col = new Object[mat.length];
        for (int i = 0; i < col.length; i++) {
            col[i] = mat[i][j];
        }
        return col;
    }
    public Font font = new Font("Arial", Font.PLAIN, 10);
    public int row_height = 60;
    public int row_width = 300;

    public void selectAsX(int row) {
        rows[row].selectAsX();
    }

    public void selectAsY(int row) {
        rows[row].selectAsY();
    }

    public void selectAsZ(int row) {
        rows[row].selectAsZ();
    }

    class ParameterRow extends JPanel {

        String _paramName;
        JLabel name;
        JRadioButton xaxis, yaxis, zaxis;
        JComponent parameter;
        JSlider min, max;
        JCheckBox linkminmax;
        JList list;
        //Object[] _values;
        Vector _kernelStringValues;
        boolean _isNumber;
        //double[] _dvalues;
        double[] _kernelDoubleValues;

        /**
         * Quick Sort algoritm.
         * 

* Allows to sort a column quickly, Using a generic version of C.A.R Hoare's * Quick Sort algorithm. *

*/ public class Sorting { /* * ------------------------ Class variables ------------------------ */ /** * Array for internal storage of the matrix to sort. */ private double[] A; /** * Array for internal storage of the order. */ private int[] order; /* * ------------------------ Constructors ------------------------ */ /** * Construct an ascending order. * * @param array * Array to sort. * @param copyArray * Specify if the sort is made directly : true -> array is * modified (usefull for big arrays !), false -> array is copied * and not modified (more memory used). */ public Sorting(double[] array, boolean copyArray) { if (copyArray) { A = new double[array.length]; System.arraycopy(array, 0, A, 0, array.length); // for (int i = 0; i < A.length; i++) { // A[i] = array[i]; // } } else { A = array; } order = new int[A.length]; for (int i = 0; i < A.length; i++) { order[i] = i; } sort(A); } /* * ------------------------ Public Methods ------------------------ */ public int[] invertIndex(int[] ind) { int[] invind = new int[ind.length]; for (int i = 0; i < ind.length; i++) { invind[ind[i]] = i; } return invind; } /** * Get the ascending order of one line. * * @param i * Line number. * @return Ascending order of the line. */ public int getIndex(int i) { return order[i]; } /** * Get the ascending order of all lines. * * @return Ascending order of lines. */ public int[] getIndex() { return order; } /* * ------------------------ Private Methods ------------------------ */ /** * This is a generic version of C.A.R Hoare's Quick Sort algorithm. This * will handle arrays that are already sorted, and arrays with duplicate * keys.
* * If you think of a one dimensional array as going from the lowest index on * the left to the highest index on the right then the parameters to this * function are lowest index or left and highest index or right. The first * time you call this function it will be with the parameters 0, a.length - * 1. * * @param a * A double array. * @param lo0 * Int. * @param hi0 * Int. */ private void QuickSort(double a[], int lo0, int hi0) { int lo = lo0; int hi = hi0; double mid; if (hi0 > lo0) { // Arbitrarily establishing partition element as the midpoint of the // array. mid = a[(lo0 + hi0) / 2]; // loop through the array until indices cross while (lo <= hi) { // find the first element that is greater than or equal to the // partition element starting from the left Index. while ((lo < hi0) && (a[lo] < mid)) { ++lo; } // find an element that is smaller than or equal to the // partition element starting from the right Index. while ((hi > lo0) && (a[hi] > mid)) { --hi; } // if the indexes have not crossed, swap if (lo <= hi) { swap(a, lo, hi); ++lo; --hi; } } // If the right index has not reached the left side of array must // now sort the left partition. if (lo0 < hi) { QuickSort(a, lo0, hi); // If the left index has not reached the right side of array // must now sort the right partition. } if (lo < hi0) { QuickSort(a, lo, hi0); } } } /** * Swap two positions. * * @param a * Array. * @param i * Line number. * @param j * Line number. */ private void swap(double a[], int i, int j) { double T; T = a[i]; a[i] = a[j]; a[j] = T; int t; t = order[i]; order[i] = order[j]; order[j] = t; } private void sort(double[] a) { QuickSort(a, 0, a.length - 1); } } public void selectAsX() { xaxis.setSelected(true); yaxis.setSelected(false); zaxis.setSelected(false); for (ParameterRow r : rows) { if (!r._paramName.equals(_paramName)) { r.xaxis.setSelected(false); } } dataUpdated = false; fireSelectedDataChanged(_paramName + " xaxis"); } public void selectAsY() { xaxis.setSelected(false); yaxis.setSelected(true); zaxis.setSelected(false); for (ParameterRow r : rows) { if (!r._paramName.equals(_paramName)) { r.yaxis.setSelected(false); } } dataUpdated = false; fireSelectedDataChanged(_paramName + " yaxis"); } public void selectAsZ() { xaxis.setSelected(false); yaxis.setSelected(false); zaxis.setSelected(true); for (ParameterRow r : rows) { if (!r._paramName.equals(_paramName)) { r.zaxis.setSelected(false); } } dataUpdated = false; fireSelectedDataChanged(_paramName + " zaxis"); } public ParameterRow(String paramName, Object[] values) { _paramName = paramName; _isNumber = Array.isDouble(values[0].toString()); if (!_isNumber) { _kernelStringValues = new Vector(values.length); for (int i = 0; i < values.length; i++) { if (!_kernelStringValues.contains(values[i])) { _kernelStringValues.add(values[i]); } } } else { Vector _tmpdvalues = new Vector(values.length); for (int i = 0; i < values.length; i++) { if (!_tmpdvalues.contains(Double.valueOf(values[i].toString()))) { _tmpdvalues.add(Double.valueOf(values[i].toString())); } } _kernelDoubleValues = new double[_tmpdvalues.size()]; for (int i = 0; i < _kernelDoubleValues.length; i++) { _kernelDoubleValues[i] = _tmpdvalues.get(i); } new Sorting(_kernelDoubleValues, false); } setLayout(new GridLayout(1, 2)); name = new JLabel(_paramName); name.setFont(font); JPanel left = new JPanel(new BorderLayout()); left.add(name, BorderLayout.CENTER); add(left, 0); JPanel right = new JPanel(new BorderLayout()); JPanel XYZ = new JPanel(); if (_dimension > 0) { XYZ = new JPanel(new GridLayout(_dimension, 1)); } xaxis = new JRadioButton("X"); xaxis.setFont(font); xaxis.addActionListener(new AbstractAction() { public void actionPerformed(ActionEvent e) { selectAsX(); } }); if (_dimension >= 1) { XYZ.add(xaxis); } yaxis = new JRadioButton("Y"); yaxis.setFont(font); yaxis.addActionListener(new AbstractAction() { public void actionPerformed(ActionEvent e) { selectAsY(); } }); if (_dimension >= 2) { XYZ.add(yaxis); } zaxis = new JRadioButton("Z"); zaxis.setFont(font); zaxis.addActionListener(new AbstractAction() { public void actionPerformed(ActionEvent e) { selectAsZ(); } }); if (_dimension == 3) { XYZ.add(zaxis); } left.add(XYZ, BorderLayout.EAST); if (_isNumber) { parameter = new JPanel(); parameter.setLayout(new GridLayout(2, 1)); min = new JSlider(1, _kernelDoubleValues.length, 1); min.setFont(font); min.setMinorTickSpacing(1); min.setSnapToTicks(true); min.setPaintTicks(true); max = new JSlider(1, _kernelDoubleValues.length, _kernelDoubleValues.length); max.setFont(font); max.setMinorTickSpacing(1); max.setSnapToTicks(true); max.setPaintTicks(true); min.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { if (max.getValue() < min.getValue()) { max.setValue(min.getValue()); } dataUpdated = false; fireSelectedDataChanged(_paramName + " min"); } }); max.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { if (max.getValue() < min.getValue()) { min.setValue(max.getValue()); } dataUpdated = false; fireSelectedDataChanged(_paramName + " max"); } }); parameter.add(min, 0); parameter.add(max, 1); } else { list = new JList(_kernelStringValues); list.setFont(font); list.setSelectedIndices(buildIntSeq(0, _kernelStringValues.size() - 1)); list.addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { dataUpdated = false; fireSelectedDataChanged(_paramName + " list"); } }); parameter = new JScrollPane(list); } right.add(parameter, BorderLayout.CENTER); add(right, 1); setBorder(BorderFactory.createEtchedBorder()); setPreferredSize(new Dimension(row_width, row_height)); setSize(new Dimension(row_width, row_height)); } int[] buildIntSeq(int min, int max) { int[] seq = new int[max - min + 1]; for (int i = 0; i < seq.length; i++) { seq[i] = min + i; } return seq; } boolean check(Object value) { if (_isNumber) { double dval = Double.valueOf(value.toString()); return (dval >= _kernelDoubleValues[min.getValue() - 1] && dval <= _kernelDoubleValues[max.getValue() - 1]); } else { for (int i = 0; i < list.getSelectedIndices().length; i++) { if (_kernelStringValues.get(list.getSelectedIndices()[i]).equals(value)) { return true; } } return false; } } } public static void main(String[] args) { final PlotPanel pp = new Plot3DPanel(PlotPanel.WEST); pp.setPreferredSize(new Dimension(400, 400)); new FrameView(pp).setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Object[][] data = {{1, 3, 4, 5, "a0"}, {1, 3, 1, 1, "a1"}, {1, 3, 2, 2, "a2"}, {1, 3, 3, 3, "a5"}, {1, 3, 3, 3, "a3"}, {1.5, 3.5, 3, 4, "a2"}}; DataSelectPanel dsp3 = new DataSelectPanel(data, 3, "x1", "x2", "x3", "x4", "x5") { private static final long serialVersionUID = 1L; @Override public void fireSelectedDataChanged(String from) { super.fireSelectedDataChanged(from); pp.setAxisLabel(0, getSelectedXAxis()); pp.setAxisLabel(1, getSelectedYAxis()); pp.setAxisLabel(2, getSelectedZAxis()); System.err.println("plotting ..."); if (pp.getPlots().size() == 0) { System.err.println(" new"); pp.addPlot("SCATTER", "data", pp.mapData(getSelectedProjectedData())); } else { System.err.println(" existing"); if (from != null && from.endsWith("axis")) { pp.resetMapData(); pp.removeAllPlots(); pp.addPlot("SCATTER", "data", pp.mapData(getSelectedProjectedData())); } else { pp.getPlot(0).setData(pp.mapData(getSelectedProjectedData())); } } //System.out.println(Array.cat(pp.getAxesScales())); } }; JFrame f3 = new JFrame("Test mat editor 3"); f3.setContentPane(dsp3); f3.pack(); f3.setVisible(true); f3.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); /*try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } Object[][] data2 = { { 0, 0, 0, 0, "a0" }, { 1, 1, 1, 1, "a1" }, { 2, 2, 2, 2, "a2" }, { 3, 3, 3, 3, "a3" }, { 4, 3, 3, 3, "a3" }, { 5, 3, 3, 3, "a4" }, { 5, 4, 3, 3, "a4" } }; dsp.setData(data2);*/ } }