Changeset 2662


Ignore:
Timestamp:
04/24/07 13:19:36 (13 years ago)
Author:
curtis
Message:
  • Fix bug in bins-to-nm conversion logic
  • Fix up full width half max support
  • Improve log scale labeling
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/loci/apps/slim/SlimPlotter.java

    r2650 r2662  
    55/* 
    66Coded in 2006-@year@ by Curtis Rueden, with suggestions from 
    7 Long Yan, Steve Trier, Kraig Kumfer and Paolo Provenzano. 
     7Long Yan, Steve Trier, Kraig Kumfer, Paolo Provenzano and Tony Collins. 
    88Permission is granted to use this code for anything. 
    99*/ 
     
    9595  private float timeRange; 
    9696  private int minWave, waveStep, maxWave; 
    97   private boolean adjustPeaks, cutEnd; 
     97  private boolean adjustPeaks, computeFWHMs, cutEnd; 
    9898  private boolean[] cVisible; 
    9999  private int maxPeak; 
     
    118118  private JDialog paramDialog; 
    119119  private JTextField wField, hField, tField, cField, trField, wlField, sField; 
    120   private JCheckBox peaksBox, cutBox; 
     120  private JCheckBox peaksBox, fwhmBox, cutBox; 
    121121 
    122122  // GUI components for intensity pane 
     
    142142  private JSpinner numCurves; 
    143143  private JCheckBox showData, showScale; 
    144   private JCheckBox showBox, showLine, showFWHMs; 
     144  private JCheckBox showBox, showLine; 
    145145  private JCheckBox showFit, showResiduals; 
     146  private JCheckBox showFWHMs; 
    146147  private JCheckBox zOverride; 
    147148  private JTextField zScaleValue; 
     
    155156  private Unit[] bcUnits; 
    156157  private RealType bType, cType; 
    157   private RealTupleType bc, bcv; 
     158  private RealTupleType bc, bv, bcv; 
    158159  private FunctionType bcvFunc, bcvFuncFit, bcvFuncRes; 
    159160  private ScalarMap zMap, zMapFit, zMapRes, vMap, vMapFit, vMapRes; 
    160161  private DataRenderer decayRend, fitRend, resRend, lineRend, fwhmRend; 
    161   private DataReferenceImpl decayRef, fitRef, resRef; 
     162  private DataReferenceImpl decayRef, fwhmRef, fitRef, resRef; 
    162163  private DisplayImpl iPlot, decayPlot; 
    163164  private ScalarMap intensityMap; 
     
    262263      paramPane.setBorder(new EmptyBorder(10, 10, 10, 10)); 
    263264      paramDialog.setContentPane(paramPane); 
    264       paramPane.setLayout(new GridLayout(11, 3)); 
     265      paramPane.setLayout(new GridLayout(12, 3)); 
    265266      wField = addRow(paramPane, "Image width", width, "pixels"); 
    266267      hField = addRow(paramPane, "Image height", height, "pixels"); 
     
    284285      paramPane.add(new JLabel()); 
    285286      paramPane.add(new JLabel()); 
    286       // row 8 
     287      // row 9 
     288      fwhmBox = new JCheckBox("Compute FWHMs", false); 
     289      fwhmBox.setToolTipText( 
     290        "<html>Computes the full width half max at each channel.</html>"); 
     291      paramPane.add(fwhmBox); 
     292      paramPane.add(new JLabel()); 
     293      paramPane.add(new JLabel()); 
     294      // row 10 
    287295      cutBox = new JCheckBox("Cut 1.5ns from fit", true); 
    288296      cutBox.setToolTipText("<html>When performing exponential curve " + 
     
    293301      paramPane.add(new JLabel()); 
    294302      paramPane.add(new JLabel()); 
    295       // row 10 
     303      // row 11 
    296304      paramPane.add(new JLabel()); 
    297305      paramPane.add(new JLabel()); 
    298306      paramPane.add(new JLabel()); 
    299       // row 11 
     307      // row 12 
    300308      paramPane.add(new JLabel()); 
    301309      paramPane.add(ok); 
     
    348356        minWave, maxWave, channels, null, new Unit[] {nm}, null); 
    349357      bc = new RealTupleType(bType, cType); 
     358      bv = new RealTupleType(bType, vType); 
    350359      bcv = new RealTupleType(bType, cType, vType); 
    351360      RealType vType2 = RealType.getRealType("value"); 
     
    397406      } 
    398407      final DataReferenceImpl curveRef = new DataReferenceImpl("curve"); 
    399       UnionSet dummyCurve = new UnionSet(xy, new Gridded2DSet[] { 
     408      UnionSet dummyCurve = new UnionSet(new Gridded2DSet[] { 
    400409        new Gridded2DSet(xy, new float[][] {{0}, {0}}, 1) 
    401410      }); 
     
    453462      decayRef = new DataReferenceImpl("decay"); 
    454463      decayPlot.addReferences(decayRend, decayRef); 
     464 
     465      if (computeFWHMs) { 
     466        // add reference for full width half maxes 
     467        fwhmRend = new DefaultRendererJ3D(); 
     468        fwhmRef = new DataReferenceImpl("fwhm"); 
     469        decayPlot.addReferences(fwhmRend, fwhmRef, new ConstantMap[] { 
     470          new ConstantMap(0, Display.Red), 
     471          new ConstantMap(0, Display.Blue), 
     472          //new ConstantMap(2, Display.LineWidth) 
     473        }); 
     474      } 
     475 
    455476      if (adjustPeaks) { 
     477        // add references for curve fitting 
    456478        fitRend = new DefaultRendererJ3D(); 
    457479        fitRef = new DataReferenceImpl("fit"); 
    458480        decayPlot.addReferences(fitRend, fitRef, new ConstantMap[] { 
    459           new ConstantMap(1.0, Display.Red), 
    460           new ConstantMap(1.0, Display.Green), 
    461           new ConstantMap(1.0, Display.Blue) 
     481          new ConstantMap(1, Display.Red), 
     482          new ConstantMap(1, Display.Green), 
     483          new ConstantMap(1, Display.Blue) 
    462484        }); 
    463485        fitRend.toggle(false); 
     
    582604              " (shifting by " + shift + ")"); 
    583605          } 
    584           setProgress(progress, 940 + 10 * 
    585             (c + 1) / channels); // estimate: 94% -> 95% 
    586           if (progress.isCanceled()) System.exit(0); 
    587         } 
    588         log("Calculating full width half maxes"); 
    589         float[] half = new float[channels]; 
    590         float[] fwhm1 = new float[channels], fwhm2 = new float[channels]; 
    591         for (int c=0; c<channels; c++) { 
    592           // sum across all pixels 
    593           int[] sum = new int[timeBins]; 
    594           for (int h=0; h<height; h++) { 
    595             for (int w=0; w<width; w++) { 
    596               for (int t=0; t<timeBins; t++) sum[t] += values[c][h][w][t]; 
    597             } 
    598           } 
    599           // find full width half max 
    600           half[c] = sum[maxPeak] / 2f; 
    601           fwhm1[c] = fwhm2[c] = Float.NaN; 
    602           boolean up = true; 
    603           for (int t=0; t<timeBins-1; t++) { 
    604             if (sum[t] <= half[c] && sum[t + 1] >= half[c]) { // upslope 
    605 //              System.out.println("Found upslope: t=" + t + ", low=" + sum[t] + ", hi=" + sum[t+1]);//TEMP 
    606               float q = (half[c] - sum[t]) / (sum[t + 1] - sum[t]); 
    607               fwhm1[c] = timeRange * (t + q) / timeBins; // binsToNano 
    608             } 
    609             else if (sum[t] >= half[c] && sum[t + 1] <= half[c]) { // downslope 
    610 //              System.out.println("Found downslope: t=" + t + ", low=" + sum[t] + ", hi=" + sum[t+1]);//TEMP 
    611               float q = (half[c] - sum[t + 1]) / (sum[t] - sum[t + 1]); 
    612               fwhm2[c] = timeRange * (t + 1 - q) / timeBins; // binsToNano 
    613             } 
    614 //            else System.out.println("Unsuitable: t=" + t + ", low=" + sum[t] + ", hi=" + sum[t+1]);//TEMP 
    615             if (fwhm1[c] == fwhm1[c] && fwhm2[c] == fwhm2[c]) break; 
    616           } 
    617           String s = "#" + (c + 1); 
    618           while (s.length() < 3) s = " " + s; 
    619           float h1 = 1000 * fwhm1[c], h2 = 1000 * fwhm2[c]; 
    620           log("\tChannel " + s + ": fwhm = " + (h2 - h1) + " ps"); 
    621           log("\t             peak = " + sum[maxPeak]); 
    622           log("\t             center = " + ((h1 + h2) / 2) + " ps"); 
    623           log("\t             range = [" + h1 + ", " + h2 + "] ps"); 
    624           setProgress(progress, 950 + 10 * 
    625             (c + 1) / channels); // estimate: 95% -> 96% 
     606          setProgress(progress, 940 + 20 * 
     607            (c + 1) / channels); // estimate: 94% -> 96% 
    626608          if (progress.isCanceled()) System.exit(0); 
    627609        } 
     
    630612        lineRend = new DefaultRendererJ3D(); 
    631613        DataReferenceImpl peakRef = new DataReferenceImpl("peaks"); 
    632         float peakTime = (float) (maxPeak * timeRange / timeBins); 
     614        float peakTime = (float) (maxPeak * timeRange / (timeBins - 1)); 
    633615        peakRef.setData(new Gridded2DSet(bc, 
    634616          new float[][] {{peakTime, peakTime}, {minWave, maxWave}}, 2)); 
     
    638620          //new ConstantMap(2, Display.LineWidth) 
    639621        }); 
    640  
    641         // add green lines to indicate full width half maxes 
    642         fwhmRend = new DefaultRendererJ3D(); 
    643         DataReferenceImpl fwhmRef = new DataReferenceImpl("fwhm"); 
    644         Gridded3DSet[] fwhmSets = new Gridded3DSet[channels]; 
    645         for (int c=0; c<channels; c++) { 
    646           float wave = minWave + c * waveStep; 
    647           float[][] fwhmLines = { 
    648             {fwhm1[c], fwhm2[c]}, 
    649             {wave, wave}, 
    650             {half[c], half[c]} 
    651           }; 
    652           fwhmSets[c] = new Gridded3DSet(bcv, fwhmLines, 2); 
    653         } 
    654         fwhmRef.setData(new UnionSet(bcv, fwhmSets)); 
    655         decayPlot.addReferences(fwhmRend, fwhmRef, new ConstantMap[] { 
    656           new ConstantMap(0, Display.Red), 
    657           new ConstantMap(0, Display.Blue), 
    658           //new ConstantMap(2, Display.LineWidth) 
    659         }); 
    660         fwhmRend.toggle(false); 
    661622      } 
    662623 
     
    830791      showLine.setEnabled(adjustPeaks); 
    831792      showLine.addActionListener(this); 
    832       showFWHMs = new JCheckBox("FWHMs", false); 
    833       showFWHMs.setToolTipText("Toggles visibility of full width half maxes"); 
    834       showFWHMs.setEnabled(adjustPeaks); 
    835       showFWHMs.addActionListener(this); 
    836793      showFit = new JCheckBox("Fit", false); 
    837794      showFit.setToolTipText("Toggles visibility of fitted curves"); 
     
    843800      showResiduals.setEnabled(adjustPeaks); 
    844801      showResiduals.addActionListener(this); 
     802      showFWHMs = new JCheckBox("FWHMs", computeFWHMs); 
     803      showFWHMs.setToolTipText("Toggles visibility of full width half maxes"); 
     804      showFWHMs.setEnabled(computeFWHMs); 
     805      showFWHMs.addActionListener(this); 
    845806 
    846807      linear = new JRadioButton("Linear", true); 
     
    933894      showPanel.add(showBox); 
    934895      showPanel.add(showLine); 
    935       showPanel.add(showFWHMs); 
    936896      showPanel.add(showFit); 
    937897      showPanel.add(showResiduals); 
     898      showPanel.add(showFWHMs); 
    938899 
    939900      JPanel scalePanel = new JPanel(); 
     
    11561117    else if (src == showData) decayRend.toggle(showData.isSelected()); 
    11571118    else if (src == showLine) lineRend.toggle(showLine.isSelected()); 
    1158     else if (src == showFWHMs) fwhmRend.toggle(showFWHMs.isSelected()); 
    11591119    else if (src == showBox) { 
    11601120      try { decayPlot.getDisplayRenderer().setBoxOn(showBox.isSelected()); } 
     
    11741134      resRend.toggle(showResiduals.isSelected()); 
    11751135    } 
     1136    else if (src == showFWHMs) fwhmRend.toggle(showFWHMs.isSelected()); 
    11761137    else if (src == zOverride) { 
    11771138      boolean manual = zOverride.isSelected(); 
     
    12271188        waveStep = parse(sField.getText(), waveStep); 
    12281189        adjustPeaks = peaksBox.isSelected(); 
     1190        computeFWHMs = fwhmBox.isSelected(); 
    12291191        cutEnd = cutBox.isSelected(); 
    12301192        cVisible = new boolean[channels]; 
     
    13621324        AxisScale zScale = zMap.getAxisScale(); 
    13631325        Hashtable hash = new Hashtable(); 
    1364         for (int i=1; i<=maxVal; i*=BASE) { 
    1365           hash.put(new Double(Math.log(i) / BASE_LOG), "" + i); 
     1326        for (int i=1, v=1; v<=maxVal; i++, v*=BASE) { 
     1327          hash.put(new Double(Math.log(v) / BASE_LOG), 
     1328            i > 3 ? "1e" + i : "" + v); 
    13661329        } 
    13671330        try { 
     
    14031366      } 
    14041367 
     1368      // full width half maxes 
     1369      float[][][] fwhmLines = null; 
     1370      if (computeFWHMs) { 
     1371        log("Calculating full width half maxes"); 
     1372        fwhmLines = new float[channels][3][2]; 
     1373        for (int c=0, cc=0; c<channels; c++) { 
     1374          if (!cVisible[c]) continue; 
     1375          // sum across all pixels 
     1376          int[] sums = new int[timeBins]; 
     1377          for (int t=0; t<timeBins; t++) { 
     1378            if (roiCount == 1) sums[t] = values[c][roiY][roiX][t]; 
     1379            else { 
     1380              for (int h=0; h<height; h++) { 
     1381                for (int w=0; w<width; w++) { 
     1382                  if (roiMask[h][w]) sums[t] += values[c][h][w][t]; 
     1383                } 
     1384              } 
     1385            } 
     1386          } 
     1387          int maxSum = 0; 
     1388          for (int t=0; t<timeBins; t++) if (sums[t] > maxSum) maxSum = sums[t]; 
     1389          // find full width half max 
     1390          float half = maxSum / 2f; 
     1391          float fwhm1 = Float.NaN, fwhm2 = Float.NaN; 
     1392          boolean up = true; 
     1393          for (int t=0; t<timeBins-1; t++) { 
     1394            if (sums[t] <= half && sums[t + 1] >= half) { // upslope 
     1395              float q = (half - sums[t]) / (sums[t + 1] - sums[t]); 
     1396              fwhm1 = timeRange * (t + q) / (timeBins - 1); // binsToNano 
     1397            } 
     1398            else if (sums[t] >= half && sums[t + 1] <= half) { // downslope 
     1399              float q = (half - sums[t + 1]) / (sums[t] - sums[t + 1]); 
     1400              fwhm2 = timeRange * (t + 1 - q) / (timeBins - 1); // binsToNano 
     1401            } 
     1402            if (fwhm1 == fwhm1 && fwhm2 == fwhm2) break; 
     1403          } 
     1404          fwhmLines[c][0][0] = fwhm1; 
     1405          fwhmLines[c][0][1] = fwhm2; 
     1406          fwhmLines[c][1][0] = fwhmLines[c][1][1] = minWave + c * waveStep; 
     1407          fwhmLines[c][2][0] = fwhmLines[c][2][1] = half; 
     1408          String s = "#" + (c + 1); 
     1409          while (s.length() < 3) s = " " + s; 
     1410          float h1 = 1000 * fwhm1, h2 = 1000 * fwhm2; 
     1411          log("\tChannel " + s + ": fwhm = " + (h2 - h1) + " ps"); 
     1412          log("\t             peak = " + sums[maxPeak]); 
     1413          log("\t             center = " + ((h1 + h2) / 2) + " ps"); 
     1414          log("\t             range = [" + h1 + ", " + h2 + "] ps"); 
     1415          if (plotCanceled) break; 
     1416          cc++; 
     1417        } 
     1418      } 
     1419 
     1420      // curve fitting 
    14051421      double[][] fitResults = null; 
    14061422      int numExp = ((Integer) numCurves.getValue()).intValue(); 
     
    15921608        decayRef.setData(doDataLines ? makeLines(ff) : ff); 
    15931609 
     1610        if (fwhmLines != null) { 
     1611          // construct "FWHMs" plot 
     1612          SampledSet[] fwhmSets = new SampledSet[channels]; 
     1613          for (int c=0; c<channels; c++) { 
     1614            if (doLog) { 
     1615              // convert samples to log values for plotting 
     1616              // this is done AFTER any computations involving samples (above) 
     1617              for (int i=0; i<fwhmLines[c].length; i++) { 
     1618                for (int j=0; j<fwhmLines[c][i].length; i++) { 
     1619                  fwhmLines[c][i][j] = linearToLog(fwhmLines[c][i][j]); 
     1620                } 
     1621              } 
     1622            } 
     1623            if (channels > 1) { 
     1624              fwhmSets[c] = new Gridded3DSet(bcv, fwhmLines[c], 2); 
     1625            } 
     1626            else { 
     1627              fwhmSets[c] = new Gridded2DSet(bv, 
     1628                new float[][] {fwhmLines[c][0], fwhmLines[c][2]}, 2); 
     1629            } 
     1630          } 
     1631          fwhmRef.setData(new UnionSet(fwhmSets)); 
     1632        } 
     1633 
    15941634        if (fitSamps != null) { 
    15951635          // construct "Fit" plot 
     
    16751715  /** Converts value in picoseconds to histogram bins. */ 
    16761716  private float picoToBins(float pico) { 
    1677     return timeBins * pico / timeRange / 1000; 
     1717    return (timeBins - 1) * pico / timeRange / 1000; 
    16781718  } 
    16791719 
    16801720  /** Converts value in histogram bins to picoseconds. */ 
    16811721  private float binsToPico(float bins) { 
    1682     return 1000 * timeRange * bins / timeBins; 
     1722    return 1000 * timeRange * bins / (timeBins - 1); 
    16831723  } 
    16841724 
Note: See TracChangeset for help on using the changeset viewer.