/* * Copyright (c) 2012 Patrick Meyer * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.itemanalysis.jmetrik.graph.histogram; import com.itemanalysis.jmetrik.dao.DatabaseAccessObject; import com.itemanalysis.jmetrik.sql.DataTableName; import com.itemanalysis.jmetrik.sql.VariableTableName; import com.itemanalysis.jmetrik.workspace.VariableChangeEvent; import com.itemanalysis.jmetrik.workspace.VariableChangeListener; import com.itemanalysis.psychometrics.data.DataType; import com.itemanalysis.psychometrics.data.VariableAttributes; import com.itemanalysis.psychometrics.histogram.*; import com.itemanalysis.psychometrics.tools.StopWatch; import com.itemanalysis.squiggle.base.Column; import com.itemanalysis.squiggle.base.SelectQuery; import com.itemanalysis.squiggle.base.Table; import com.itemanalysis.squiggle.criteria.MatchCriteria; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.TreeMap; import javax.swing.SwingWorker; import org.apache.log4j.Logger; public class HistogramAnalysis extends SwingWorker<HistogramPanel, Void> { private HistogramCommand command = null; private DatabaseAccessObject dao = null; private HistogramPanel histogramPanel = null; private Throwable theException = null; private Connection conn = null; public StopWatch sw = null; private DataTableName tableName = null; private boolean hasGroupingVariable = false; private VariableAttributes groupVar = null; private VariableAttributes variable = null; private ArrayList<Object> groupbyValues = null; private int progressValue = 0; private int lineNumber = 0; private double maxProgress = 100.0; private TreeMap<Object, BinCalculation> binCalc = null; private ArrayList<VariableChangeListener> variableChangeListeners = null; static Logger logger = Logger.getLogger("jmetrik-logger"); static Logger scriptLogger = Logger.getLogger("jmetrik-script-logger"); public HistogramAnalysis(Connection conn, DatabaseAccessObject dao, HistogramCommand command, HistogramPanel histogramPanel){ this.command = command; this.histogramPanel = histogramPanel; this.conn = conn; this.dao = dao; groupbyValues = new ArrayList<Object>(); variableChangeListeners = new ArrayList<VariableChangeListener>(); } private void initializeProgressBar()throws SQLException{ int nrow = 0; nrow = dao.getRowCount(conn, tableName); maxProgress = (double)nrow*2.0;//two loops over db } private void updateProgress(){ progressValue=(int)((100*((double)lineNumber+1.0))/ maxProgress); setProgress(Math.max(0,Math.min(100,progressValue))); lineNumber++; } public void setGroupByValues()throws SQLException{ Statement stmt = null; ResultSet rs=null; try{ //get unique values of grouping variable if(hasGroupingVariable){ stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); SelectQuery select = new SelectQuery(); select.setDistinct(true); Table table = new Table(tableName.getNameForDatabase()); select.addColumn(table, groupVar.getName().nameForDatabase()); rs=stmt.executeQuery(select.toString()); Object g = null; while(rs.next()){ g = rs.getObject(groupVar.getName().nameForDatabase()); if(!rs.wasNull()){ groupbyValues.add(g); } } rs.close(); stmt.close(); }else{ groupbyValues.add("series1"); } }catch(SQLException ex){ logger.fatal(ex.getMessage(), ex); throw new SQLException(ex); } } /** * Loop over db to compute the number of bins needed to form the histogram. * Will loop over db a second time to compute histogram. This approach costs * time but it save memory. * * @throws SQLException * @throws IllegalArgumentException */ // private void binCalculation()throws SQLException, IllegalArgumentException{ // Statement stmt = null; // ResultSet rs=null; // // try{ // binCalc = new TreeMap<Object, BinCalculation>(); // // initializeProgressBar(); // // stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); // SelectQuery select = new SelectQuery(); // Table table = new Table(tableName.getNameForDatabase()); // select.addColumn(table, variable.getName().nameForDatabase()); // rs=stmt.executeQuery(select.toString()); // // for(Object o : groupbyValues){ // //select all cases ind b with groupByValue of Object o // select = new SelectQuery(); // table = new Table(tableName.getNameForDatabase()); // select.addColumn(table, variable.getName().nameForDatabase()); // // //add where clause if groupby variable provided // if(hasGroupingVariable && groupVar !=null){ // select.addColumn(table, groupVar.getName().nameForDatabase()); // if(groupVar.getType().getDataType()== VariableType.DOUBLE){ // select.addCriteria((new MatchCriteria( // new Column(table, groupVar.getName().nameForDatabase()), // MatchCriteria.EQUALS, // ((Double)o).doubleValue() // ))); // }else{ // select.addCriteria((new MatchCriteria( // new Column(table, groupVar.getName().nameForDatabase()), // MatchCriteria.EQUALS, // o.toString() // ))); // } // } // rs=stmt.executeQuery(select.toString()); // // //loop over data and add value sto array list // double value = Double.NaN; // while(rs.next()){ // value=rs.getDouble(variable.getName().nameForDatabase()); // if(!rs.wasNull()){ // BinCalculation bc = binCalc.get(o); // if(bc==null){ // bc = getBinCalculation(); // binCalc.put(o, bc); // } // bc.increment(value); // } // updateProgress(); // } // rs.close(); // } // stmt.close(); // }catch(SQLException ex){ // throw new SQLException(ex); // }catch(IllegalArgumentException ex){ // throw new IllegalArgumentException(ex); // } // // } // // private BinCalculation getBinCalculation()throws IllegalArgumentException{ // BinCalculation bc = null; // try{ // if(command.getSelectOneOption("bintype").isValueSelected("sturges")){ // bc = new SturgesBinCalculation(); // }else if(command.getSelectOneOption("bintype").isValueSelected("scott")){ // bc = new ScottBinCalculation(); // }else if(command.getSelectOneOption("bintype").isValueSelected("fd")){ // bc = new FreedmanDiaconisBinCalculation(); // } // return bc; // }catch(IllegalArgumentException ex){ // throw new IllegalArgumentException(ex); // } // // } /** * Second loop over db to compute histogram * * @return * @throws SQLException * @throws IllegalArgumentException */ public HistogramChartDataset evaluate()throws SQLException, IllegalArgumentException{ Statement stmt = null; ResultSet rs=null; HistogramChartDataset data = new HistogramChartDataset(); try{ setGroupByValues(); HistogramType histogramType = HistogramType.DENSITY; if(command.getSelectOneOption("yaxis").isValueSelected("freq")){ histogramType = HistogramType.FREQUENCY; } Histogram histogram = null; stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); SelectQuery select = new SelectQuery(); Table table = new Table(tableName.getNameForDatabase()); select.addColumn(table, variable.getName().nameForDatabase()); rs=stmt.executeQuery(select.toString()); for(Object o : groupbyValues){ //select all cases ind b with groupByValue of Object o select = new SelectQuery(); table = new Table(tableName.getNameForDatabase()); select.addColumn(table, variable.getName().nameForDatabase()); //add where clause if groupby variable provided if(hasGroupingVariable && groupVar !=null){ select.addColumn(table, groupVar.getName().nameForDatabase()); if(groupVar.getType().getDataType()== DataType.DOUBLE){ select.addCriteria((new MatchCriteria( new Column(table, groupVar.getName().nameForDatabase()), MatchCriteria.EQUALS, ((Double)o).doubleValue() ))); }else{ select.addCriteria((new MatchCriteria( new Column(table, groupVar.getName().nameForDatabase()), MatchCriteria.EQUALS, o.toString() ))); } } rs=stmt.executeQuery(select.toString()); //loop over data and add value sto array list histogram = new Histogram(histogramType); double value = Double.NaN; while(rs.next()){ value=rs.getDouble(variable.getName().nameForDatabase()); if(!rs.wasNull()){ histogram.increment(value); } updateProgress(); } histogram.evaluate();//do computations data.addHistogram(o.toString(), histogram); } //===========================================================OLd BELOW // setGroupByValues(); // binCalculation(); // // Histogram.HistogramType histType = null; // if(command.getSelectOneOption("yaxis").isValueSelected("freq")){ // histType = Histogram.HistogramType.FREQUENCY; // }else{ // histType = Histogram.HistogramType.DENSITY; // } // // stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); // SelectQuery select = new SelectQuery(); // Table table = new Table(tableName.getNameForDatabase()); // select.addColumn(table, variable.getName().nameForDatabase()); // rs=stmt.executeQuery(select.toString()); // // for(Object o : groupbyValues){ // //select all cases ind b with groupByValue of Object o // select = new SelectQuery(); // table = new Table(tableName.getNameForDatabase()); // select.addColumn(table, variable.getName().nameForDatabase()); // // //add where clause if groupby variable provided // if(hasGroupingVariable && groupVar !=null){ // select.addColumn(table, groupVar.getName().nameForDatabase()); // if(groupVar.getType().getDataType()==VariableType.DOUBLE){ // select.addCriteria((new MatchCriteria( // new Column(table, groupVar.getName().nameForDatabase()), // MatchCriteria.EQUALS, // ((Double)o).doubleValue() // ))); // }else{ // select.addCriteria((new MatchCriteria( // new Column(table, groupVar.getName().nameForDatabase()), // MatchCriteria.EQUALS, // o.toString() // ))); // } // } // rs=stmt.executeQuery(select.toString()); // // //loop over data and add values to array list // Histogram histogram = new Histogram(binCalc.get(o), histType); // double value = Double.NaN; // while(rs.next()){ // value=rs.getDouble(variable.getName().nameForDatabase()); // if(!rs.wasNull()){ // histogram.increment(value); // } // updateProgress(); // } // rs.close(); // data.addHistogram(o.toString(), histogram); // } // stmt.close(); // Iterator<Comparable> iter = data.iterator(); // while(iter.hasNext()){ // Histogram h = data.getHistogram(iter.next()); // System.out.println(h.toString()); // } return data; }catch(SQLException ex){ logger.fatal(ex.getMessage(), ex); throw new SQLException(ex); }catch(IllegalArgumentException ex){ logger.fatal(ex.getMessage(), ex); throw new IllegalArgumentException(ex); }finally{ if(rs!=null) rs.close(); if(stmt!=null) stmt.close(); } } protected HistogramPanel doInBackground(){ sw = new StopWatch(); this.firePropertyChange("status", "", "Running Histogram..."); this.firePropertyChange("progress-on", null, null); try{ //get variable info from db tableName = new DataTableName(command.getPairedOptionList("data").getStringAt("table")); String selectVariable = command.getFreeOption("variable").getString(); variable = dao.getVariableAttributes(conn, new VariableTableName(tableName.toString()), selectVariable); if(command.getFreeOption("groupvar").hasValue()){ String groupByName=command.getFreeOption("groupvar").getString(); groupVar = dao.getVariableAttributes(conn, new VariableTableName(tableName.toString()), groupByName); hasGroupingVariable = true; } histogramPanel.updateDataset(evaluate()); firePropertyChange("status", "", "Done: " + sw.getElapsedTime()); firePropertyChange("progress-off", null, null); //make statusbar progress not visible }catch(Throwable t){ logger.fatal(t.getMessage(), t); theException=t; } return histogramPanel; } @Override protected void done(){ try{ if(theException!=null){ logger.fatal(theException.getMessage(), theException); firePropertyChange("error", "", "Error - Check log for details."); } scriptLogger.info(command.paste()); }catch(Exception ex){ logger.fatal(ex.getMessage(), ex); firePropertyChange("error", "", "Error - Check log for details."); } } //=============================================================================================================== //Handle variable changes here // -Dialogs will use these methods to add their variable listeners //=============================================================================================================== public synchronized void addVariableChangeListener(VariableChangeListener l){ variableChangeListeners.add(l); } public synchronized void removeVariableChangeListener(VariableChangeListener l){ variableChangeListeners.remove(l); } public synchronized void removeAllVariableChangeListeners(){ variableChangeListeners.clear(); } public void fireVariableChanged(VariableChangeEvent event){ for(VariableChangeListener l : variableChangeListeners){ l.variableChanged(event); } } }