Changeset 7107


Ignore:
Timestamp:
10/21/10 21:10:29 (9 years ago)
Author:
aivar
Message:

Cleanup, rewrote start/stop bars completely.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/maven/projects/slim-plugin/src/main/java/loci/slim/DecayGraph.java

    r7059 r7107  
    3535package loci.slim; 
    3636 
    37 import loci.slim.ui.IStartStopListener; 
    38 import javax.swing.*; 
    3937import java.awt.BasicStroke; 
    40 import java.awt.*; 
    41 import java.awt.event.*; 
     38import java.awt.Color; 
     39import java.awt.Graphics2D; 
     40import java.awt.event.MouseEvent; 
    4241import java.awt.geom.Ellipse2D; 
    4342import java.awt.geom.Rectangle2D; 
    44 import java.io.File; 
    45 import java.util.ArrayList; 
    46 import java.util.List; 
     43 
     44import javax.swing.JComponent; 
     45import javax.swing.JFrame; 
     46import javax.swing.SwingUtilities; 
    4747 
    4848import loci.curvefitter.ICurveFitData; 
    49  
    50 //import org.jdesktop.jxlayer.JXLayer; 
    51 //import org.jdesktop.jxlayer.plaf.AbstractLayerUI; 
     49import loci.slim.ui.IStartStopListener; 
     50 
    5251import org.jdesktop.jxlayer.JXLayer; 
    5352import org.jdesktop.jxlayer.plaf.AbstractLayerUI; 
    5453 
    5554import org.jfree.chart.ChartPanel; 
    56 import org.jfree.chart.ChartUtilities; 
    5755import org.jfree.chart.JFreeChart; 
    58 import org.jfree.chart.axis.DateAxis; 
    5956import org.jfree.chart.axis.LogarithmicAxis; 
    6057import org.jfree.chart.axis.NumberAxis; 
    61 import org.jfree.chart.axis.ValueAxis; 
    6258import org.jfree.chart.plot.CombinedDomainXYPlot; 
    63 import org.jfree.chart.plot.Plot; 
    6459import org.jfree.chart.plot.XYPlot; 
    65 import org.jfree.chart.renderer.xy.XYDotRenderer; 
    66 import org.jfree.chart.renderer.xy.XYItemRenderer; 
    6760import org.jfree.chart.renderer.xy.XYSplineRenderer; 
    68 import org.jfree.chart.title.TextTitle; 
    69 import org.jfree.data.time.TimeSeries; 
    70 import org.jfree.data.time.TimeSeriesCollection; 
    71 import org.jfree.data.xy.XYDataItem; 
    72 import org.jfree.data.xy.XYDataset; 
    7361import org.jfree.data.xy.XYSeries; 
    7462import org.jfree.data.xy.XYSeriesCollection; 
    75 import org.jfree.ui.ApplicationFrame; 
    76 import org.jfree.ui.RefineryUtilities; 
     63import org.jfree.ui.RectangleEdge; 
    7764 
    7865/** 
     
    8572 * @author Aivar Grislis grislis at wisc.edu 
    8673 */ 
    87 public class DecayGraph implements IStartStopListener, IStartStopProportionListener { 
     74public class DecayGraph implements IStartStopProportionListener { 
     75    static final int HORZ_TWEAK = 4; 
    8876    static final Color DECAY_COLOR = Color.BLUE; 
    8977    static final Color FITTED_COLOR = Color.MAGENTA; 
     78    JFrame m_frame; 
    9079    int m_start; 
    9180    int m_stop; 
     
    9584    boolean m_headless = false; 
    9685    boolean m_logarithmic = true; 
    97     MyXYPlot m_decaySubPlot; 
     86    XYPlot m_decaySubPlot; 
    9887    XYSeriesCollection m_decayDataset; 
    9988    XYSeriesCollection m_residualDataset; 
    100     ChartPanel m_panel; 
     89    static ChartPanel m_panel; 
    10190 
    10291    JFreeChart m_decayChart; 
    10392    JFreeChart m_residualsChart; 
    10493 
    105     DecayGraph(double timeInc, int start, int stop, ICurveFitData data) { 
    106         m_bins = data.getYCount().length; 
    107         JFreeChart chart = createCombinedChart(m_bins, timeInc, start, stop, data); //TODO got ugly; rethink params, globals etc. 
    108         setStartStop(start, stop); 
     94    /** 
     95     * Creates a JFreeChart graph showing the decay curve. 
     96     * 
     97     * @param start time bin 
     98     * @param stop time bin 
     99     * @param bins number of bins 
     100     * @param timeInc time increment per bin 
     101     * @param data fitted data 
     102     */ 
     103    DecayGraph(final int start, final int stop, final int bins, final double timeInc, ICurveFitData data) { 
     104        m_start = start; 
     105        m_stop = stop; 
     106        m_bins = bins; 
     107 
     108        // create the combined chart 
     109        JFreeChart chart = createCombinedChart(start, stop, bins, timeInc, data); //TODO got ugly; rethink params, globals etc 
    109110        m_panel = new ChartPanel(chart, true, true, true, false, true); 
    110111        m_panel.setDomainZoomable(false); 
    111112        m_panel.setRangeZoomable(false); 
    112113        m_panel.setPreferredSize(new java.awt.Dimension(500, 270)); 
    113         //try { 
    114         //ChartUtilities.saveChartAsPNG(new File("CHART_FILE"), chart, 500, 270); 
    115         //} 
    116         //catch (Exception e) { 
    117         //    System.out.println("exception " + e); 
    118         //} 
    119     } 
    120  
    121     void setLogarithmic(boolean logarithmic) { 
    122         m_logarithmic = logarithmic; 
    123     } 
    124  
    125     /** 
    126      * Registers an external start/stop listener. 
     114         
     115        // Add JXLayer to draw/drag start/stop bars 
     116        JXLayer<JComponent> layer = new JXLayer<JComponent>(m_panel); 
     117        m_startStopDraggingUI = new StartStopDraggingUI<JComponent>(m_panel, m_decaySubPlot, this); 
     118        layer.setUI(m_startStopDraggingUI); 
     119 
     120        // create a frame for the chart 
     121        m_frame = new JFrame("Fitted Decay Curve"); 
     122        m_frame.getContentPane().add(layer); 
     123        m_frame.setSize(450, 450); 
     124        m_frame.pack(); 
     125 
     126        // initialize the vertical bars that show start and stop time bins 
     127        m_startStopDraggingUI.setStartStopValues(timeInc * start, timeInc * stop, timeInc * bins); 
     128    } 
     129 
     130    /** 
     131     * Gets the chart JFrame 
     132     * 
     133     * @return JFrame 
     134     */ 
     135    public JFrame getFrame() { 
     136        return m_frame; 
     137    } 
     138 
     139    /** 
     140     * Registers a single, external start/stop listener. 
     141     * This receives new values of start and stop time bins. 
    127142     * 
    128143     * @param startStopListener 
     
    133148 
    134149    /** 
    135      * Handles start and stop being set externally.  Passes it on to the start/stop dragging UI layer. 
    136      * 
    137      * @param start index 
    138      * @param stop index, inclusive 
    139      */ 
    140     public void setStartStop(int start, int stop){ 
    141         m_start = start; 
    142         m_stop = stop; 
    143         if (null != m_startStopDraggingUI) { 
    144             System.out.println("start comes in " + start + " stop " + stop); 
    145             double startProportion = (double) start / m_bins; 
    146             double stopProportion = (double) stop / m_bins; 
    147             System.out.println("startP " + startProportion + " stopP " + stopProportion); 
    148  
    149             m_startStopDraggingUI.setStartStopProportions(startProportion, stopProportion); 
    150         } 
    151     } 
    152  
    153     /** 
    154      * Handles start and stop being set internally, from the start/stop dragging UI layer.  Validates 
     150     * Sets stop and start time bins, based on proportions 0.0..1.0.  This is called from 
     151     * the UI layer that lets user drag the start and stop vertical bars.  Validates 
    155152     * and passes changes on to external listener. 
    156153     * 
     
    165162        if (start != m_start || stop != m_stop) { 
    166163            // redraw UI on bin boundaries 
    167             setStartStop(start, stop); 
     164         //TODO NO NO NO!!!     setStartStop(start, stop); 
    168165            if (null != m_startStopListener) { 
    169166                //System.out.println("NOTIFY LISTENER"); 
     
    173170    } 
    174171 
    175     JFreeChart createCombinedChart(int bins, double timeInc, int start, int stop, ICurveFitData data) { 
    176  
    177         createDatasets(timeInc, start, stop, bins, data); 
     172    /** 
     173     * Creates the chart 
     174     *  
     175     * @param start time bin 
     176     * @param stop time bin 
     177     * @param bins number of bins 
     178     * @param timeInc time increment per bin 
     179     * @param data fitted data 
     180     * @return the chart 
     181     */ 
     182    JFreeChart createCombinedChart(int start, int stop, int bins, double timeInc, ICurveFitData data) { 
     183 
     184        // create chart data 
     185        createDatasets(start, stop, bins, timeInc, data); 
    178186 
    179187        // make a common horizontal axis for both sub-plots 
     
    193201            photonAxis = new NumberAxis("Photons"); 
    194202        } 
    195         photonAxis.setRange(0.0, 2000000.0); 
     203       // photonAxis.setRange(0.0, 2000000.0); 
    196204        XYSplineRenderer decayRenderer = new XYSplineRenderer(); 
    197205        decayRenderer.setSeriesShapesVisible(0, false); 
     
    200208        decayRenderer.setSeriesShape(2, new Ellipse2D.Float(2.0f, 2.0f, 2.0f, 2.0f)); // 1.5, 3.0 look ugly! 
    201209 
    202  
    203  
    204210        decayRenderer.setSeriesPaint(0, Color.green); 
    205211        decayRenderer.setSeriesPaint(1, Color.red); 
    206212        decayRenderer.setSeriesPaint(2, Color.blue); 
    207213 
    208         m_decaySubPlot = new MyXYPlot(m_decayDataset, null, photonAxis, decayRenderer); 
     214        m_decaySubPlot = new XYPlot(m_decayDataset, null, photonAxis, decayRenderer); 
    209215        m_decaySubPlot.setDomainCrosshairVisible(true); 
    210216        m_decaySubPlot.setRangeCrosshairVisible(true); 
     
    229235        // now make the top level JFreeChart 
    230236        JFreeChart chart = new JFreeChart(null, JFreeChart.DEFAULT_TITLE_FONT, parent, true); 
    231         //chart.setLegend(null); 
    232237        chart.removeLegend(); 
     238 
    233239        return chart; 
    234240    } 
    235241 
    236     private void createDatasets(double timeInc, int start, int stop, int bins, ICurveFitData data) { 
     242    /** 
     243     * Creates the data sets for the chart 
     244     * 
     245     * @param start time bin 
     246     * @param stop time bin 
     247     * @param bins number of time bins 
     248     * @param timeInc time increment per time bin 
     249     * @param data from the fit 
     250     */ 
     251    private void createDatasets(int start, int stop, int bins, double timeInc, ICurveFitData data) { 
    237252        //TODO lamp function; comes from where? 
    238253        XYSeries series1 = new XYSeries("IRF"); 
    239         series1.add(1.0, 1.0); 
     254   /*     series1.add(1.0, 1.0); 
    240255        series1.add(2.0, 4.0); 
    241256        series1.add(3.0, 3.0); 
     
    244259        series1.add(6.0, 7.0); 
    245260        series1.add(7.0, 7.0); 
    246         series1.add(8.0, 8.0); 
     261        series1.add(8.0, 8.0); */ 
    247262 
    248263        XYSeries series2 = new XYSeries("Fitted"); 
     
    250265        XYSeries series4 = new XYSeries("Residuals"); 
    251266 
    252      //// XYSeries series5 = new XYSeries("Sanity Check"); 
    253       double params[] = data.getParams(); 
    254267 
    255268        double yData, yFitted; 
     
    257270        for (int i = 0; i < bins; ++i) { 
    258271            yData = data.getYCount()[i]; 
    259             series3.add(xCurrent, yData); 
     272            // logarithmic plots can't handle <= 0.0 
     273            series3.add(xCurrent, (yData > 0.0 ? yData : null)); 
    260274            // are we in fitted region? 
    261275            if (start <= i && i <= stop) { 
    262276                // yes, show fitted curve and residuals 
    263277                yFitted = data.getYFitted()[i]; 
    264                 System.out.println("yFitted[" + i + "] " + yFitted); 
     278                // logarithmic plots can't handle <= 0.0 
    265279                if (yFitted > 0.0) { 
    266                 series2.add(xCurrent, yFitted); 
    267                 series4.add(xCurrent, yData - yFitted); 
     280                    series2.add(xCurrent, yFitted); 
     281                    series4.add(xCurrent, yData - yFitted); 
    268282                } 
    269  
    270 ////                double newlyCalculated; 
    271 ////series5.add(xCurrent, newlyCalculated = params[0] * Math.exp(-params[1] * xCurrent) + params[2]); 
    272 ////System.out.println(" i " + i + " " + newlyCalculated); 
    273                 //series5.add(xCurrent, Math.exp(-params[1] * xCurrent) + params[2]); 
     283                else { 
     284                    series2.add(xCurrent, null); 
     285                    series4.add(xCurrent, null); 
     286                } 
    274287            } 
    275288            else { 
    276289                series2.add(xCurrent, null); 
    277                 //series2.add(xCurrent, data.getYFitted()[i]); 
    278290                series4.add(xCurrent, null); 
    279291            } 
     
    285297        m_decayDataset.addSeries(series2); 
    286298        m_decayDataset.addSeries(series3); 
    287  ////   m_decayDataset.addSeries(series5); 
    288299 
    289300        m_residualDataset = new XYSeriesCollection(); 
     
    292303 
    293304    /** 
    294      * Gets a JComponent containing the chart.  Uses JXLayer to add 
    295      * the capability of dragging the start/stop lines. 
    296      * 
    297      * @return component 
    298      */ 
    299     JComponent getComponent() { 
    300         JXLayer<JComponent> layer = new JXLayer<JComponent>(m_panel); 
    301         m_startStopDraggingUI = new StartStopDraggingUI<JComponent>(m_decaySubPlot, this); 
    302         layer.setUI(m_startStopDraggingUI); 
    303         return layer; 
    304     } 
    305  
    306     /** 
    307305     * UI which allows us to paint on top of the components, using JXLayer. 
    308306     * 
     
    311309    static class StartStopDraggingUI<V extends JComponent> extends AbstractLayerUI<V> { 
    312310        private static final int CLOSE_ENOUGH = 4; // pizels 
    313         private MyXYPlot m_plot; 
     311        private ChartPanel m_panel; 
     312        private XYPlot m_plot; 
    314313        private IStartStopProportionListener m_listener; 
    315314        boolean m_draggingStartMarker = false; 
     
    322321        private int m_xStop; 
    323322 
    324         StartStopDraggingUI(MyXYPlot plot, IStartStopProportionListener listener) { 
    325             m_plot = plot; 
     323        /** 
     324         * Creates the UI. 
     325         * 
     326         * @param panel for the chart 
     327         * @param plot within the chart 
     328         * @param listener to be notified when user drags start/stop vertical bars 
     329         */ 
     330        StartStopDraggingUI(ChartPanel panel, XYPlot plot, IStartStopProportionListener listener) { 
     331            m_panel    = panel; 
     332            m_plot     = plot; 
    326333            m_listener = listener; 
    327334        } 
    328335 
    329         void setStartStopProportions(double startMarkerProportion, double stopMarkerProportion) { 
    330             //System.out.println("in UI getting new proportions " + startMarkerProportion + " " + stopMarkerProportion); 
    331             m_startMarkerProportion = startMarkerProportion; 
    332             m_stopMarkerProportion = stopMarkerProportion; 
    333             setDirty(true); 
    334         } 
    335  
    336         // override paintLayer(), not paint() 
     336        void setStartStopValues(double startValue, double stopValue, double maxValue) { 
     337            Rectangle2D area = getDataArea(); 
     338            double x = area.getX(); 
     339            double width = area.getWidth(); 
     340            if (0.1 > width) { 
     341                m_startMarkerProportion = startValue / maxValue; 
     342                m_stopMarkerProportion = stopValue / maxValue; 
     343            } 
     344            else { 
     345                double minRepresentedValue = screenToValue((int) x); 
     346                double maxRepresentedValue = screenToValue((int) (x + width)); 
     347                m_startMarkerProportion = (startValue - minRepresentedValue) / (maxRepresentedValue - minRepresentedValue); 
     348                m_stopMarkerProportion = (stopValue - minRepresentedValue) / (maxRepresentedValue - minRepresentedValue); 
     349            } 
     350        } 
     351 
     352        /** 
     353         * Used to draw the start/stop vertical bars. 
     354         * 
     355         * Overrides 'paintLayer()', not 'paint()'. 
     356         * 
     357         * @param g2 
     358         * @param l 
     359         */ 
     360        @Override 
    337361        protected void paintLayer(Graphics2D g2, JXLayer<? extends V> l) { 
    338362            // this paints layer as is 
     
    340364 
    341365            // adjust to current size 
    342             Rectangle2D area = m_plot.getArea(); 
     366            Rectangle2D area = getDataArea(); 
    343367            double x = area.getX(); 
    344368            m_y0 = (int) area.getY(); 
    345369            m_y1 = (int) (area.getY() + area.getHeight()); 
    346370            double width = area.getWidth(); 
    347             m_xStart = (int) (x + width * m_startMarkerProportion); 
    348             m_xStop = (int) (x + width * m_stopMarkerProportion); 
    349             System.out.println("startP " + m_startMarkerProportion + " stopP " + m_stopMarkerProportion + " xStart " + m_xStart + " xStop " + m_xStop); 
     371            m_xStart = (int) Math.round(x + width * m_startMarkerProportion) + HORZ_TWEAK; 
     372            m_xStop = (int) Math.round(x + width * m_stopMarkerProportion) + HORZ_TWEAK; 
    350373 
    351374            // custom painting is here 
     
    356379        } 
    357380 
    358         // catch drag events 
     381        /** 
     382         * Mouse listener, catches drag events 
     383         * 
     384         * @param e 
     385         * @param l 
     386         */ 
    359387        protected void processMouseMotionEvent(MouseEvent e, JXLayer<? extends V> l) { 
    360388            super.processMouseMotionEvent(e, l); 
    361389            if (e.getID() == MouseEvent.MOUSE_DRAGGED) { 
    362                 //Point point = SwingUtilities.convertPoint(e.getComponent(), e.getPoint(), l); 
    363390                if (m_draggingStartMarker || m_draggingStopMarker) { 
    364391                    double newProportion = getDraggedProportion(e); 
     
    379406        } 
    380407 
    381         /* 
    382          * Returns a value between 0.0 and 1.0. 
     408        /** 
     409         * Gets the currently dragged horizontal value as a proportion, 
     410         * a value between 0.0 and 1.0. 
     411         * 
     412         * @param e 
     413         * @return proportion 
    383414         */ 
    384415        private double getDraggedProportion(MouseEvent e) { 
    385             Rectangle2D area = m_plot.getArea(); 
     416            Rectangle2D dataArea = m_panel.getChartRenderingInfo().getPlotInfo().getDataArea(); 
     417            Rectangle2D area = getDataArea(); 
    386418            double proportion = ((double) e.getX() - area.getX()) / area.getWidth(); 
    387419            if (proportion < 0.0) { 
     
    394426        } 
    395427 
    396         // catch MouseEvent.MOUSE_RELEASED 
     428        /** 
     429         * Mouse listener, catches mouse button events. 
     430         * @param e 
     431         * @param l 
     432         */ 
    397433        protected void processMouseEvent(MouseEvent e, JXLayer<? extends V> l) { 
    398434            super.processMouseEvent(e, l); 
     
    411447                    } 
    412448                } 
    413                 System.out.println(" x " + e.getX() + " y " + e.getY()); 
    414449            } 
    415450            if (e.getID() == MouseEvent.MOUSE_RELEASED) { 
     
    418453                        new Runnable() { 
    419454                            public void run() { 
    420                                 //System.out.println("RELEASED " + m_startMarkerProportion + " " + m_stopMarkerProportion); 
    421455                                m_listener.setStartStopProportion(m_startMarkerProportion, m_stopMarkerProportion); 
    422456                            } 
    423457                }); 
    424  
    425 //TODO NOTIFY SOMEBODY!!! 
    426                 // mark the ui as dirty and needed to be repainted 
    427                 //setDirty(true); 
    428             } 
    429         } 
    430     } 
    431  
    432     /** 
    433      * Bit of a kludge.<p> 
    434      * XYPlot & Plot don't provide a method to get the size of the 
    435      * graph area. 
    436      */ 
    437     private class MyXYPlot extends XYPlot { 
    438         private Rectangle2D m_area; 
    439  
    440         MyXYPlot(XYDataset dataset, 
    441                         ValueAxis domainAxis, 
    442                         ValueAxis rangeAxis, 
    443                         XYItemRenderer renderer) { 
    444             super(dataset, domainAxis, rangeAxis, renderer); 
    445         } 
    446  
    447         @Override 
    448         public void drawOutline(Graphics2D g2, Rectangle2D area) { 
    449             super.drawOutline(g2, area); 
    450             m_area = area; 
    451         } 
    452  
    453         public Rectangle2D getArea() { 
    454             return m_area; 
     458            } 
     459        } 
     460 
     461        /** 
     462         * Gets the area of the chart panel. 
     463         * 
     464         * @return 2D rectangle area 
     465         */ 
     466        private Rectangle2D getDataArea() { 
     467            Rectangle2D dataArea = m_panel.getChartRenderingInfo().getPlotInfo().getDataArea(); 
     468            return dataArea; 
     469        } 
     470 
     471        /** 
     472         * Converts screen x to chart x value. 
     473         * 
     474         * @param x 
     475         * @return chart value 
     476         */ 
     477 
     478        private double screenToValue(int x) { 
     479            return m_plot.getDomainAxis().java2DToValue((double) x, getDataArea(), RectangleEdge.TOP); 
    455480        } 
    456481    } 
     
    458483 
    459484/** 
    460  * Used within DecayGraph, to communicate with StartStopDraggingUI inner class. 
     485 * Used within DecayGraph, to get results from StartStopDraggingUI inner class. 
    461486 * 
    462487 * @author Aivar Grislis grislis at wisc.edu 
Note: See TracChangeset for help on using the changeset viewer.