package org.geogebra.desktop.gui.view.data;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.border.TitledBorder;
import org.geogebra.common.gui.view.data.DataAnalysisModel;
import org.geogebra.common.gui.view.data.DataAnalysisModel.Regression;
import org.geogebra.common.kernel.StringTemplate;
import org.geogebra.common.kernel.arithmetic.ExpressionNodeConstants.StringType;
import org.geogebra.common.kernel.arithmetic.NumberValue;
import org.geogebra.common.kernel.geos.GeoFunctionable;
import org.geogebra.desktop.gui.inputfield.MyTextFieldD;
import org.geogebra.desktop.gui.util.GeoGebraIconD;
import org.geogebra.desktop.gui.util.LayoutUtil;
import org.geogebra.desktop.main.AppD;
import org.geogebra.desktop.main.LocalizationD;
/**
* Panel to select and display the DataAnalysisView regression model.
*
* @author G. Sturr
*/
public class RegressionPanel extends JPanel
implements ActionListener, StatPanelInterface {
private static final long serialVersionUID = 1L;
private AppD app;
private final LocalizationD loc;
private DataAnalysisViewD statDialog;
// regression panel objects
private JLabel lblRegEquation, lblEqn;
private JComboBox cbRegression, cbPolyOrder;
private JLabel lblEvaluate;
private MyTextFieldD fldInputX;
private JLabel lblOutputY;
private String[] regressionLabels;
private JLabel fldOutputY;
private boolean isIniting = true;
private JPanel predictionPanel;
private DataAnalysisModel daModel;
/**
* Construct a regression panel
*
* @param app
* application
* @param statDialog
* invoking instance of DataAnalysisView
*/
public RegressionPanel(AppD app, DataAnalysisViewD statDialog) {
this.app = app;
this.loc = app.getLocalization();
this.statDialog = statDialog;
this.daModel = statDialog.getModel();
this.setLayout(new BorderLayout());
this.add(createRegressionPanel(), BorderLayout.CENTER);
setLabels();
updateRegressionPanel();
updateGUI();
isIniting = false;
}
private JPanel regressionPanel;
private JPanel createRegressionPanel() {
// components
String[] orders = { "2", "3", "4", "5", "6", "7", "8", "9" };
cbPolyOrder = new JComboBox(orders);
cbPolyOrder.setSelectedIndex(0);
cbPolyOrder.addActionListener(this);
cbPolyOrder.setFocusable(false);
regressionLabels = new String[Regression.values().length];
setRegressionLabels();
cbRegression = new JComboBox(regressionLabels);
cbRegression.addActionListener(this);
cbRegression.setFocusable(false);
lblRegEquation = new JLabel();
lblEqn = new JLabel();
// regression combo panel
JPanel cbPanel = new JPanel();
cbPanel.setLayout(new BoxLayout(cbPanel, BoxLayout.Y_AXIS));
cbPanel.add(LayoutUtil.flowPanel(cbRegression));
cbPanel.add(LayoutUtil.flowPanel(cbPolyOrder));
// regression label panel
JPanel eqnPanel = new JPanel(new BorderLayout());
eqnPanel.add(lblRegEquation, BorderLayout.CENTER);
JScrollPane scroller = new JScrollPane(eqnPanel);
scroller.setBorder(BorderFactory.createEmptyBorder());
// prediction panel
createPredictionPanel();
// model panel: equation + prediction
JPanel modelPanel = new JPanel();
modelPanel.setLayout(new BoxLayout(modelPanel, BoxLayout.Y_AXIS));
modelPanel.add(scroller);
modelPanel.add(predictionPanel);
// put it all together
regressionPanel = new JPanel(new BorderLayout(30, 0));
regressionPanel.add(modelPanel, BorderLayout.CENTER);
regressionPanel.add(cbPanel, loc.borderWest());
regressionPanel.setBorder(BorderFactory
.createTitledBorder(loc.getMenu("RegressionModel")));
JPanel mainPanel = new JPanel(new BorderLayout());
mainPanel.add(regressionPanel, BorderLayout.CENTER);
return mainPanel;
}
/**
* Creates a panel to evaluate the regression model for a given x value
*/
private void createPredictionPanel() {
JPanel p = new JPanel(new FlowLayout(FlowLayout.LEFT));
lblEvaluate = new JLabel();
fldInputX = new MyTextFieldD(app);
fldInputX.addActionListener(this);
fldInputX.setColumns(6);
lblOutputY = new JLabel();
fldOutputY = new JLabel();
p.add(lblEvaluate);
p.add(new JLabel("x = "));
p.add(fldInputX);
p.add(new JLabel("y = "));
p.add(lblOutputY);
p.add(fldOutputY);
predictionPanel = new JPanel(new BorderLayout());
predictionPanel.add(p, loc.borderWest());
}
/**
* Updates the regression equation label and the prediction panel
*/
public void updateRegressionPanel() {
if (statDialog.getController().isValidData()) {
setRegressionEquationLabel();
doTextFieldActionPerformed(fldInputX);
} else {
setRegressionEquationLabelEmpty();
}
updateGUI();
}
/**
* Clears the X and Y fields of the prediction panel
*/
public void clearPredictionPanel() {
fldInputX.setText("");
fldOutputY.setText("");
}
private void setRegressionLabels() {
for (Regression r : Regression.values()) {
regressionLabels[r.ordinal()] = loc.getMenu(r.getLabel());
}
}
/**
* Sets the labels according to current locale
*/
@Override
public void setLabels() {
regressionLabels = new String[Regression.values().length];
setRegressionLabels();
// we need to remove old labels from combobox and we don't want the
// listener to
// be operational since it will call unnecessary Construction updates
int j = cbRegression.getSelectedIndex();
ActionListener al = cbRegression.getActionListeners()[0];
cbRegression.removeActionListener(al);
cbRegression.removeAllItems();
for (int i = 0; i < regressionLabels.length; i++) {
cbRegression.addItem(regressionLabels[i]);
}
cbRegression.setSelectedIndex(j);
cbRegression.addActionListener(al);
((TitledBorder) regressionPanel.getBorder())
.setTitle(loc.getMenu("RegressionModel"));
lblEqn.setText(loc.getMenu("Equation") + ":");
lblEvaluate.setText(loc.getMenu("Evaluate") + ": ");
}
/**
* Draws the regression equation into the regression equation JLabel icon
*/
public void setRegressionEquationLabel() {
// get the LaTeX string for the regression equation
String eqn;
// GeoElement geoRegression = statDialog.getRegressionModel();
try {
// prepare number format
StringTemplate highPrecision;
if (daModel.getPrintDecimals() >= 0) {
highPrecision = StringTemplate.printDecimals(StringType.LATEX,
daModel.getPrintDecimals(), false);
} else {
highPrecision = StringTemplate.printFigures(StringType.LATEX,
daModel.getPrintFigures(), false);
}
// no regression
if (daModel.getRegressionMode().equals(Regression.NONE)
|| statDialog.getRegressionModel() == null) {
eqn = "";
}
// nonlinear
else {
eqn = "y = " + statDialog.getRegressionModel()
.getFormulaString(highPrecision, true);
}
}
catch (Exception e) {
e.printStackTrace();
eqn = "\\text{" + loc.getPlain("NotAvailable") + "}";
}
// create an icon with the LaTeX string
ImageIcon icon = GeoGebraIconD.createLatexIcon(app, eqn,
this.getFont(), Color.RED, null);
// set the label icon with our equation string
lblRegEquation.setIcon(icon);
lblRegEquation.revalidate();
updateGUI();
}
/**
* Set the regression equation label to an empty string
*/
private void setRegressionEquationLabelEmpty() {
lblRegEquation.setIcon(null);
lblRegEquation.revalidate();
updateGUI();
}
private void updateGUI() {
cbPolyOrder.setVisible(
daModel.getRegressionMode().equals(Regression.POLY));
predictionPanel.setVisible(
!(daModel.getRegressionMode().equals(Regression.NONE)));
repaint();
}
@Override
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (source instanceof JTextField) {
doTextFieldActionPerformed((JTextField) source);
}
else if (source == cbRegression) {
cbRegression.removeActionListener(this);
daModel.setRegressionMode(cbRegression.getSelectedIndex());
updateRegressionPanel();
cbRegression.addActionListener(this);
}
else if (source == cbPolyOrder) {
daModel.setRegressionOrder(cbPolyOrder.getSelectedIndex() + 2);
statDialog.getController().setRegressionGeo();
statDialog.getController().updateRegressionPanel();
setRegressionEquationLabel();
// force update
daModel.setRegressionMode(Regression.POLY.ordinal());
}
}
private void doTextFieldActionPerformed(JTextField source) {
if (isIniting) {
return;
}
if (source == fldInputX) {
try {
String inputText = source.getText().trim();
if (inputText == null || inputText.length() == 0) {
return;
}
NumberValue nv;
nv = app.getKernel().getAlgebraProcessor()
.evaluateToNumeric(inputText, true);
double value = nv.getDouble();
double output = ((GeoFunctionable) statDialog
.getRegressionModel()).getGeoFunction().value(value);
fldOutputY.setText(statDialog.format(output));
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
public void updateFonts(Font font) {
// TODO Auto-generated method stub
}
@Override
public void updatePanel() {
// TODO Auto-generated method stub
}
}