Java tutorial
/* * Copyright 2012 Diamond Light Source Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package uk.ac.diamond.scisoft.analysis.rcp.plotting.sideplot; import java.awt.Color; import java.io.File; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.ConcurrentModificationException; import java.util.List; import java.util.StringTokenizer; import java.util.UUID; import org.dawnsci.plotting.jreality.core.AxisMode; import org.dawnsci.plotting.jreality.impl.PlotException; import org.dawnsci.plotting.jreality.overlay.Overlay1DConsumer; import org.dawnsci.plotting.jreality.overlay.Overlay1DProvider; import org.dawnsci.plotting.jreality.overlay.OverlayProvider; import org.dawnsci.plotting.jreality.overlay.OverlayType; import org.dawnsci.plotting.jreality.overlay.VectorOverlayStyles; import org.dawnsci.plotting.jreality.overlay.primitives.PrimitiveType; import org.dawnsci.plotting.jreality.tool.AreaSelectEvent; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.IJobManager; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.viewers.ICellEditorListener; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.custom.ScrolledComposite; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.layout.RowLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.widgets.Spinner; import org.eclipse.ui.IWorkbenchPartSite; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.forms.events.ExpansionAdapter; import org.eclipse.ui.forms.events.ExpansionEvent; import org.eclipse.ui.forms.widgets.ExpandableComposite; import org.eclipse.ui.handlers.IHandlerService; import org.eclipse.ui.progress.UIJob; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import uk.ac.diamond.scisoft.analysis.IAnalysisMonitor; import uk.ac.diamond.scisoft.analysis.axis.AxisValues; import uk.ac.diamond.scisoft.analysis.dataset.AbstractDataset; import uk.ac.diamond.scisoft.analysis.dataset.DatasetUtils; import uk.ac.diamond.scisoft.analysis.dataset.DoubleDataset; import uk.ac.diamond.scisoft.analysis.dataset.IDataset; import uk.ac.diamond.scisoft.analysis.fitting.Generic1DFitter; import uk.ac.diamond.scisoft.analysis.fitting.functions.APeak; import uk.ac.diamond.scisoft.analysis.fitting.functions.CompositeFunction; import uk.ac.diamond.scisoft.analysis.fitting.functions.Gaussian; import uk.ac.diamond.scisoft.analysis.fitting.functions.IdentifiedPeak; import uk.ac.diamond.scisoft.analysis.fitting.functions.Lorentzian; import uk.ac.diamond.scisoft.analysis.fitting.functions.Offset; import uk.ac.diamond.scisoft.analysis.fitting.functions.PearsonVII; import uk.ac.diamond.scisoft.analysis.fitting.functions.PseudoVoigt; import uk.ac.diamond.scisoft.analysis.optimize.ApacheNelderMead; import uk.ac.diamond.scisoft.analysis.optimize.GeneticAlg; import uk.ac.diamond.scisoft.analysis.optimize.IOptimizer; import uk.ac.diamond.scisoft.analysis.optimize.NelderMead; import uk.ac.diamond.scisoft.analysis.plotserver.GuiBean; import uk.ac.diamond.scisoft.analysis.plotserver.GuiParameters; import uk.ac.diamond.scisoft.analysis.rcp.AnalysisRCPActivator; import uk.ac.diamond.scisoft.analysis.rcp.plotting.DataSetPlotter; import uk.ac.diamond.scisoft.analysis.rcp.plotting.IPlotUI; import uk.ac.diamond.scisoft.analysis.rcp.plotting.Plot1DUIAdapter; import uk.ac.diamond.scisoft.analysis.rcp.plotting.PlottingMode; import uk.ac.diamond.scisoft.analysis.rcp.plotting.fitting.FittedPeakData; import uk.ac.diamond.scisoft.analysis.rcp.plotting.fitting.FittedPeakList; import uk.ac.diamond.scisoft.analysis.rcp.plotting.fitting.FittedPeakTableViewer; import uk.ac.diamond.scisoft.analysis.rcp.plotting.roi.ROITableViewer; import uk.ac.diamond.scisoft.analysis.rcp.plotting.utils.PlotExportUtil; import uk.ac.diamond.scisoft.analysis.rcp.preference.PreferenceConstants; import uk.ac.diamond.scisoft.analysis.rcp.preference.PreferenceInitializer; import uk.ac.diamond.scisoft.analysis.rcp.util.ResourceProperties; public class Fitting1D extends SidePlot implements Overlay1DConsumer, SelectionListener, ICellEditorListener, ISelectionChangedListener { transient private static final Logger logger = LoggerFactory.getLogger(Fitting1D.class); private Composite parent; private final FittedPeakList fittedPeakList = new FittedPeakList(); private FittedPeakTableViewer fittedPeakTable; private PlotFittedPeaks fittedPlot; private Overlay1DProvider oProvider; private Combo peakType; private Combo chooseDataCombo; private Spinner numPeaks; private Button fitPeaks; private Button clearPeaks; private Button showAllPeaks; private int selectedAlg; private int selectedPeak; private String[] algNames; private String[] peaknames; private IOptimizer alg; private List<DoubleDataset> dataSetList; private DoubleDataset currentDataSet; private List<AxisValues> xAxisList; private AxisValues currentXAxis; private APeak peakToFit; private DoubleDataset slicedData; private List<Integer> primitiveIDs = new ArrayList<Integer>(); private int draggingPrimID = -1; private double[] startCoord = new double[2]; private double MAXYVALUE = Short.MAX_VALUE; private double accuracy; private int smoothing; private boolean currentlyZooming = false; private boolean autoStopping; private boolean thresholdMeasure; private double threshold; private final Color colorButtonFitted = Color.BLUE; private final Color colorDraggedFitted = Color.GREEN; private String BUTTON_FITTING_UUID; private String REFITTING_UUID; private IAction showLeg; private Action saveGraph; private Action copyGraph; private Action printGraph; private String printButtonText = ResourceProperties.getResourceString("PRINT_BUTTON"); private String printToolTipText = ResourceProperties.getResourceString("PRINT_TOOLTIP"); private String printImagePath = ResourceProperties.getResourceString("PRINT_IMAGE_PATH"); private String copyButtonText = ResourceProperties.getResourceString("COPY_BUTTON"); private String copyToolTipText = ResourceProperties.getResourceString("COPY_TOOLTIP"); private String copyImagePath = ResourceProperties.getResourceString("COPY_IMAGE_PATH"); private String saveButtonText = ResourceProperties.getResourceString("SAVE_BUTTON"); private String saveToolTipText = ResourceProperties.getResourceString("SAVE_TOOLTIP"); private String saveImagePath = ResourceProperties.getResourceString("SAVE_IMAGE_PATH"); @Override public void registerProvider(OverlayProvider provider) { oProvider = (Overlay1DProvider) provider; } @Override public void removePrimitives() { int primNumMax = primitiveIDs.size(); if (primNumMax > 0 && !mainPlotter.isDisposed()) { oProvider.unregisterPrimitive(primitiveIDs); } if (draggingPrimID != -1) { oProvider.unregisterPrimitive(draggingPrimID); draggingPrimID = -1; } } @Override public void unregisterProvider() { if (oProvider != null) { removePrimitives(); oProvider = null; } } private void overlaysVisible(boolean visible) { if (oProvider != null) { for (Integer i : primitiveIDs) { oProvider.setPrimitiveVisible(i, visible); } } } @Override public void widgetDefaultSelected(SelectionEvent e) { } @Override public void widgetSelected(SelectionEvent e) { IStructuredSelection selection = (IStructuredSelection) fittedPeakTable.getSelection(); if (selection != null) { if (e.widget instanceof MenuItem) { final FittedPeakData cRData = (FittedPeakData) selection.getFirstElement(); final int onum = fittedPeakList.indexOf(cRData); // index of selected overlay switch (fittedPeakTable.getContextMenu().indexOf((MenuItem) e.widget)) { case ROITableViewer.ROITABLEMENU_EDIT: FitMenuDialog menu = new FitMenuDialog(PlatformUI.getWorkbench().getDisplay().getActiveShell(), peaknames, algNames, selectedPeak, selectedAlg, accuracy); final boolean ok = menu.open(); if (!ok) { overlaysVisible(false); return; } APeak peak = cRData.getFittedPeak(); double min = peak.getPosition() - 2 * peak.getFWHM(); double max = peak.getPosition() + 2 * peak.getFWHM(); fitPeakFromOverlay(min, max, menu.getFitData()); fittedPeakList.remove(onum); break; case ROITableViewer.ROITABLEMENU_DELETE: fittedPeakList.remove(onum); peaksUpdated(); break; case ROITableViewer.ROITABLEMENU_DELETE_ALL: fittedPeakList.clear(); peaksUpdated(); break; case ROITableViewer.ROITABLEMENU_COPY: logger.warn("This function has not been enabled"); break; } } } } @Override public void applyEditorValue() { // not going to be implemented } @Override public void cancelEditor() { // not going to be implemented } @Override public void editorValueChanged(boolean oldValidState, boolean newValidState) { // not going to be implemented } @Override public void addToHistory() { // not going to be implemented } /** * @wbp.parser.entryPoint */ @Override public void createPartControl(final Composite parent) { this.parent = parent; this.parent.setLayout(new FillLayout()); container = new Composite(this.parent, SWT.NONE); container.setLayout(new GridLayout(1, false)); // GUI creation and layout final ScrolledComposite scrollControls = new ScrolledComposite(container, SWT.H_SCROLL | SWT.V_SCROLL); scrollControls.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); // final Composite mainControls = new Composite(scrollControls, SWT.FILL); mainControls.setLayout(new GridLayout(1, false)); final Group controls = new Group(mainControls, SWT.NONE); controls.setLayout(new RowLayout(SWT.HORIZONTAL)); controls.setText("Choose data and fit"); chooseDataCombo = new Combo(controls, SWT.READ_ONLY); chooseDataCombo.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { dataComboChanged(); } }); chooseDataCombo.add(" "); fitPeaks = new Button(controls, SWT.NONE); fitPeaks.setText("&Fit"); fitPeaks.addSelectionListener(fitPeakListener); clearPeaks = new Button(controls, SWT.NONE); clearPeaks.setText("Clear"); clearPeaks.addSelectionListener(clearPeaksListener); showAllPeaks = new Button(controls, SWT.CHECK); showAllPeaks.setText("Show all peaks"); showAllPeaks.setToolTipText("Show the position of all peaks as an overlay on the plot"); showAllPeaks.addSelectionListener(showAllPeaksOverlay); showAllPeaks.setSelection(true); ExpandableComposite advancedExpandableComposite = new ExpandableComposite(mainControls, SWT.NONE); advancedExpandableComposite.setText("Advanced controls"); advancedExpandableComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, true)); Group advanced = new Group(advancedExpandableComposite, SWT.NONE); advanced.setLayout(new GridLayout(4, false)); Label lab = new Label(advanced, SWT.NONE); lab.setText("Peak Type"); peakType = new Combo(advanced, SWT.READ_ONLY); peakType.addSelectionListener(peakTypeSelection); lab = new Label(advanced, SWT.NONE); lab.setText("Number of peaks"); numPeaks = new Spinner(advanced, SWT.NONE); numPeaks.setMinimum(-1); numPeaks.setIncrement(1); numPeaks.setMaximum(200000); advancedExpandableComposite.setClient(advanced); ExpansionAdapter expansionListener = new ExpansionAdapter() { @Override public void expansionStateChanged(ExpansionEvent e) { mainControls.layout(); scrollControls.setContent(mainControls); final Point controlsSize = mainControls.computeSize(SWT.DEFAULT, SWT.DEFAULT); mainControls.setSize(controlsSize); } }; advancedExpandableComposite.addExpansionListener(expansionListener); final SashForm ss = new SashForm(container, SWT.VERTICAL); ss.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); Composite peakTable = new Composite(ss, SWT.NONE); peakTable.setLayout(new FillLayout()); fittedPeakTable = new FittedPeakTableViewer(peakTable, this, this, this); fittedPeakTable.setInput(fittedPeakList); fittedPlot = new PlotFittedPeaks(ss); ss.setWeights(new int[] { 10, 20 }); scrollControls.setContent(mainControls); final Point controlsSize = mainControls.computeSize(SWT.DEFAULT, SWT.DEFAULT); mainControls.setSize(controlsSize); addPropertyListeners(); setupInitialValues(); this.parent.getShell().getDisplay().asyncExec(new Runnable() { @Override public void run() { parent.layout(); } }); } @Override public Action createSwitchAction(final int index, final IPlotUI plotUI) { Action action = super.createSwitchAction(index, plotUI); action.setText("1D Fitting tool"); action.setId("uk.ac.diamond.scisoft.analysis.rcp.plotting.sideplot.Fitting1DAction"); action.setToolTipText("Switch side plot to 1D fitting tool"); action.setImageDescriptor(AnalysisRCPActivator.getImageDescriptor("icons/SidePlot-PeakFit.png")); return action; } private void createExportActions() { saveGraph = new Action() { // Cache file name otherwise they have to keep // choosing the folder. private String filename; @Override public void run() { FileDialog dialog = new FileDialog(parent.getShell(), SWT.SAVE); String[] filterExtensions = new String[] { "*.jpg;*.JPG;*.jpeg;*.JPEG;*.png;*.PNG", "*.ps;*.eps", "*.svg;*.SVG" }; if (filename != null) { dialog.setFilterPath((new File(filename)).getParent()); } else { String filterPath = "/"; String platform = SWT.getPlatform(); if (platform.equals("win32") || platform.equals("wpf")) { filterPath = "c:\\"; } dialog.setFilterPath(filterPath); } dialog.setFilterNames(PlotExportUtil.FILE_TYPES); dialog.setFilterExtensions(filterExtensions); filename = dialog.open(); if (filename == null) return; fittedPlot.saveGraph(filename, PlotExportUtil.FILE_TYPES[dialog.getFilterIndex()]); } }; saveGraph.setText(saveButtonText); saveGraph.setToolTipText(saveToolTipText); saveGraph.setImageDescriptor(AnalysisRCPActivator.getImageDescriptor(saveImagePath)); copyGraph = new Action() { @Override public void run() { fittedPlot.copyGraph(); } }; copyGraph.setText(copyButtonText); copyGraph.setToolTipText(copyToolTipText); copyGraph.setImageDescriptor(AnalysisRCPActivator.getImageDescriptor(copyImagePath)); printGraph = new Action() { @Override public void run() { fittedPlot.printGraph(); } }; printGraph.setText(printButtonText); printGraph.setToolTipText(printToolTipText); printGraph.setImageDescriptor(AnalysisRCPActivator.getImageDescriptor(printImagePath)); } private void createExtraActions() { showLeg = PlotFittedPeaks.createShowLegend(); showLeg.setChecked(true); } @Override public void setMainPlotUI(final IPlotUI ui) { if (mainPlotUI != null) { final Plot1DUIAdapter ad = (Plot1DUIAdapter) ui; ad.removeZoomListener(ZOOM_LISTENER); } super.setMainPlotUI(ui); if (mainPlotUI != null) { final Plot1DUIAdapter ad = (Plot1DUIAdapter) ui; ad.addZoomListener(ZOOM_LISTENER); } else { logger.error("Unable to determine IPlotUI, so cannot ignore zoom events!"); } } private IPropertyChangeListener ZOOM_LISTENER = new IPropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent event) { Fitting1D.this.currentlyZooming = (Boolean) event.getNewValue(); } }; @Override public void dispose() { super.dispose(); if (fittedPlot != null) fittedPlot.dispose(); } @Override public void processPlotUpdate() { try { if (dataSetList == null) { dataSetList = new ArrayList<DoubleDataset>(); } dataSetList.clear(); // removePrimitives(); if (mainPlotter == null) { return; } List<IDataset> dataList = mainPlotter.getCurrentDataSets(); if (dataList != null && !dataList.isEmpty()) { xAxisList = mainPlotter.getXAxisValues(); for (IDataset data : dataList) { if (MAXYVALUE < data.max().doubleValue()) { MAXYVALUE = data.max().intValue() * 1.5; } if (-MAXYVALUE > data.min().doubleValue()) { MAXYVALUE = -data.min().doubleValue() * 1.5; } dataSetList.add((DoubleDataset) DatasetUtils.cast(DatasetUtils.convertToAbstractDataset(data), AbstractDataset.FLOAT64)); } } updateDataSetComboBox(dataSetList); } catch (Throwable t) { logger.error("a disaster: {}", t); } } private void updateDataSetComboBox(List<DoubleDataset> dataList) { String lastSelected = chooseDataCombo.getSelectionIndex() == -1 ? "no dataset" : chooseDataCombo.getItem((chooseDataCombo.getSelectionIndex())); chooseDataCombo.removeAll(); if (dataSetList != null && !dataSetList.isEmpty()) { int i = 0; for (DoubleDataset d : dataList) { String name = d.getName(); if (name.isEmpty()) { name = "Data Set " + i++; } chooseDataCombo.add(name); if (name.equals(lastSelected)) { chooseDataCombo.select(i); } } if (chooseDataCombo.getSelectionIndex() == -1) { chooseDataCombo.select(0); } setupSmoothing(); } chooseDataCombo.update(); dataComboChanged(); } private void refitPeaks() { final List<APeak> newList = new ArrayList<APeak>(fittedPeakList.size()); final IOptimizer optimiser = alg; final int smooth = smoothing; final FittedPeakList currentPeakList = fittedPeakList; IJobManager manager = Job.getJobManager(); // kill current fitting job is data changes manager.cancel(BUTTON_FITTING_UUID); // kill all running refit jobs manager.cancel(REFITTING_UUID); new refitPeaksOnNewDataset(newList, optimiser, smooth, currentPeakList, REFITTING_UUID).schedule(); } private class refitPeaksOnNewDataset extends Job { final List<APeak> newList; final IOptimizer optimiser; final int smooth; final FittedPeakList currentPeakList; private final static String name = "Refitting peaks on new Data"; private String UUID; public refitPeaksOnNewDataset(List<APeak> newList, IOptimizer alg, int smooting, FittedPeakList fittedPeakList, String UUID) { super(name); this.newList = newList; this.optimiser = alg; this.smooth = smooting; this.currentPeakList = fittedPeakList; this.UUID = UUID; } @Override protected IStatus run(IProgressMonitor monitor) { try { for (FittedPeakData peakData : currentPeakList) { if (monitor.isCanceled()) { newList.clear(); return Status.CANCEL_STATUS; } APeak peak = peakData.getFittedPeak(); double min = peak.getPosition() - 2 * peak.getFWHM(); double max = peak.getPosition() + 2 * peak.getFWHM(); try { List<CompositeFunction> functions = Generic1DFitter.fitPeakFunctions(createXData(min, max), sliceDataSet(min, max), peak, optimiser, smooth, 1); if (functions != null && !functions.isEmpty()) { List<APeak> fittedPeaks = new ArrayList<APeak>(functions.size()); for (CompositeFunction compositeFunction : functions) { fittedPeaks.add((APeak) compositeFunction.getFunction(0)); } newList.addAll(fittedPeaks); } } catch (Throwable t) { logger.info("exception trying to refit peaks {} - no problem usually", t); } } } catch (ConcurrentModificationException e) { logger.debug("This was caused by the fitting continuing after the job was canceled"); } if (monitor.isCanceled()) return Status.CANCEL_STATUS; UIJob updatePlot = new UIJob("Update Plot") { @Override public IStatus runInUIThread(IProgressMonitor monitor) { fittedPeakList.clear(); addPeaksToList(newList, colorDraggedFitted); return Status.OK_STATUS; } }; updatePlot.schedule(); return Status.OK_STATUS; } @Override public boolean belongsTo(Object family) { return UUID.equals(family); } } private void clearPeakTable() { fittedPeakList.clear(); peaksUpdated(); } @Override public void removeFromHistory() { } @Override public void areaSelected(AreaSelectEvent event) { // When the user is zooming, we do not want to do fitting. if (currentlyZooming) { overlaysVisible(false); return; } if (currentDataSet != null) { oProvider.begin(OverlayType.VECTOR2D); if (draggingPrimID == -1) { draggingPrimID = oProvider.registerPrimitive(PrimitiveType.BOX); } if (event.getMode() == 0) { overlaysVisible(false); oProvider.setColour(draggingPrimID, java.awt.Color.GREEN); oProvider.setStyle(draggingPrimID, VectorOverlayStyles.FILLED_WITH_OUTLINE); oProvider.setTransparency(draggingPrimID, 0.8); oProvider.setOutlineTransparency(draggingPrimID, 0); oProvider.setPrimitiveVisible(draggingPrimID, true); startCoord[0] = event.getX(); startCoord[1] = MAXYVALUE; } if (event.getMode() == 1) { double[] current = { event.getX(), -MAXYVALUE }; oProvider.drawBox(draggingPrimID, startCoord[0], startCoord[1], current[0], current[1]); } if (event.getMode() == 2) { final double[] finalPos = { event.getX(), -MAXYVALUE }; oProvider.drawBox(draggingPrimID, startCoord[0], startCoord[1], finalPos[0], finalPos[1]); slicedData = sliceDataSet(startCoord[0], finalPos[0]); // Sometimes mainPlotter is null or the component above it is disposed. // So we use the general platform display to show the fit dialog. PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() { @Override public void run() { // Must use active shell as parent or icon is not correct on some platforms // and it appears in a different window with a different window manager bar. FitMenuDialog menu = new FitMenuDialog( PlatformUI.getWorkbench().getDisplay().getActiveShell(), peaknames, algNames, selectedPeak, selectedAlg, accuracy); final boolean ok = menu.open(); if (!ok) { overlaysVisible(false); return; } fitPeakFromOverlay(startCoord[0], finalPos[0], menu.getFitData()); } }); overlaysVisible(true); } oProvider.end(OverlayType.VECTOR2D); } } private DoubleDataset sliceDataSet(double startPos, double endPos) { if (startPos > endPos) { double temp = startPos; startPos = endPos; endPos = temp; } int start = currentXAxis.nearestLowEntry(startPos); if (start < 0) { start = 0; } int stop = currentXAxis.nearestUpEntry(endPos); if (stop < 0) { stop = currentXAxis.size(); } return currentDataSet.getSlice(new int[] { start }, new int[] { stop }, null); } private DoubleDataset createXData(double startPos, double endPos) { if (endPos < startPos) { double temp = startPos; startPos = endPos; endPos = temp; } int start = currentXAxis.nearestLowEntry(startPos); if (start < 0) { start = 0; } int stop = currentXAxis.nearestUpEntry(endPos); if (stop < 0) { stop = currentXAxis.size(); } return currentXAxis.subset(start, stop).toDataset(); } /** * Controls the fitting from clicking on the plot window. There are 2 paths from this method, a single peak fitted * from the selected region and the normal peak fitting for >1 peak selected. This method will be run as a job and * also update the GUI. * * @param start * start x click * @param finalpos * final x click * @param fitData * information from the popup menu */ public void fitPeakFromOverlay(final double start, final double finalpos, final FitData fitData) { Job fitPeaksFromDragging = new Job("Fit peaks from dragging") { @Override protected IStatus run(IProgressMonitor monitor) { slicedData = sliceDataSet(start, finalpos); DoubleDataset xData = createXData(start, finalpos); selectPeakFuction(fitData.getPeakSelection()); selectAlg(fitData.getAlgType()); List<APeak> fittedPeaks = null; if (fitData.getNumberOfPeaks() == 1) { fittedPeaks = fitSinglePeak(xData, slicedData, alg, peakToFit, start, finalpos); } else { final List<CompositeFunction> functions = Generic1DFitter.fitPeakFunctions(xData, slicedData, peakToFit, alg, fitData.getSmoothing(), fitData.getNumberOfPeaks()); fittedPeaks = new ArrayList<APeak>(functions.size()); for (CompositeFunction compositeFunction : functions) { fittedPeaks.add((APeak) compositeFunction.getFunction(0)); } } if (fittedPeaks == null || fittedPeaks.isEmpty()) { logger.warn("No peaks were found when the region on the plot was selected"); return Status.OK_STATUS; } final List<APeak> currentFittedPeaks = fittedPeaks; UIJob updateGUI = new UIJob("Updating GUI") { @Override public IStatus runInUIThread(IProgressMonitor monitor) { addPeaksToList(currentFittedPeaks, colorDraggedFitted); return Status.OK_STATUS; } }; updateGUI.schedule(); return Status.OK_STATUS; } }; fitPeaksFromDragging.schedule(); } /** * @param xData * @param yData * @param fittingAlg * @param peak * @param start * @param finalpos * @return a list containing a single fitted peak */ private List<APeak> fitSinglePeak(final AbstractDataset xData, final AbstractDataset yData, IOptimizer fittingAlg, APeak peak, double start, double finalpos) { final List<APeak> fittedpeaks = new ArrayList<APeak>(); List<Double> crossings = new ArrayList<Double>(); final IOptimizer optomiser = fittingAlg; double quartitle = (finalpos - start) / 4; crossings.add(start + quartitle); crossings.add(finalpos - quartitle); final IdentifiedPeak idPeak = new IdentifiedPeak(xData.getDouble(Math.round(xData.getSize() / 2)), xData.getDouble(0), xData.getDouble(xData.getSize() - 1), (Double) yData.sum(), yData.max().doubleValue() - yData.min().doubleValue(), currentXAxis.nearestLowEntry(start), currentXAxis.nearestUpEntry(finalpos), crossings); final APeak localPeak = generatePeak(idPeak, peak); double lowOffset = yData.min().doubleValue(); double highOffset = (Double) yData.mean(); Offset offset = new Offset(lowOffset, highOffset); CompositeFunction comp = new CompositeFunction(); comp.addFunction(localPeak); comp.addFunction(offset); try { optomiser.optimize(new AbstractDataset[] { xData }, yData, comp); fittedpeaks.add(localPeak); } catch (Exception e) { logger.error("Could not fit single peak", e); } return fittedpeaks; } private APeak generatePeak(IdentifiedPeak idPeak, APeak peak) { APeak localPeak = null; try { Constructor<? extends APeak> ctor = peak.getClass().getConstructor(IdentifiedPeak.class); localPeak = ctor.newInstance(idPeak); } catch (IllegalArgumentException e1) { logger.error("There was a problem optimising the peak", e1); } catch (InstantiationException e1) { logger.error("The function could not be created for fitting", e1); } catch (NoSuchMethodException e1) { logger.error("The peak function could not be created.", e1); } catch (IllegalAccessException e1) { logger.error("The function could not be created for fitting", e1); } catch (InvocationTargetException e1) { logger.error("The function could not be created for fitting", e1); } catch (Exception e) { logger.error("There was a problem creating the optimizer.", e); } return localPeak; } private void selectAlg(int algType) { String currentAlgName = algNames[algType]; if (currentAlgName.equalsIgnoreCase("Genetic Algorithm")) alg = new GeneticAlg(accuracy); else if (currentAlgName.equalsIgnoreCase("Nelder Mead")) alg = new NelderMead(accuracy); else if (currentAlgName.equalsIgnoreCase("Apache Nelder Mead")) alg = new ApacheNelderMead(); else throw new IllegalArgumentException("Did not recognise the fitting routine"); } private void addPeaksToList(List<APeak> fittedPeaks, Color color) { if (fittedPeaks == null || fittedPeaks.size() < 1) { clearPeakTable(); return; } for (APeak p : fittedPeaks) { // would be nice to get rid of duplicates here // in a clever way that would allow e.g. a Gaussian and a Lorentian to be fitted to the same peak fittedPeakList.add(new FittedPeakData(p, color)); } peaksUpdated(); } private void selectPeakFuction(int peakNum) { // "Gaussian", "Lorentzian", "Pearson VII", "PseudoVoigt" String peakName = peaknames[peakNum]; if (peakName.compareToIgnoreCase("Gaussian") == 0) { peakToFit = new Gaussian(1, 1, 1, 1); } else if (peakName.compareToIgnoreCase("Lorentzian") == 0) { peakToFit = new Lorentzian(1, 1, 1, 1); } else if (peakName.compareToIgnoreCase("Pearson VII") == 0) { peakToFit = new PearsonVII(1, 1, 1, 1); } else if (peakName.compareToIgnoreCase("PseudoVoigt") == 0) { peakToFit = new PseudoVoigt(1, 1, 1, 1); } else { logger.warn("Peak type not recognised. Defaulting to Gaussian"); peakToFit = new Gaussian(1, 1, 1, 1); peakType.select(0); // displays gaussian in combo box } } private SelectionAdapter peakTypeSelection = new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { selectPeakFuction(peakType.getSelectionIndex()); } }; private void dataComboChanged() { if (dataSetList != null && dataSetList.size() > 0) { currentDataSet = dataSetList.get(chooseDataCombo.getSelectionIndex()); currentXAxis = xAxisList.get(chooseDataCombo.getSelectionIndex()); setupSmoothing(); removeAllPeakOverlays(); refitPeaks(); } } private void setupSmoothing() { if (currentDataSet != null) { IPreferenceStore preferenceStore = AnalysisRCPActivator.getDefault().getPreferenceStore(); if (preferenceStore.getBoolean(PreferenceConstants.FITTING_1D_AUTO_SMOOTHING)) { smoothing = (int) (currentDataSet.getSize() * 0.01); } else { smoothing = preferenceStore.getInt(PreferenceConstants.FITTING_1D_SMOOTHING_VALUE); } } } private void setupInitialValues() { IPreferenceStore preferenceStore = AnalysisRCPActivator.getDefault().getPreferenceStore(); accuracy = preferenceStore.getDouble(PreferenceConstants.FITTING_1D_ALG_ACCURACY); threshold = preferenceStore.getInt(PreferenceConstants.FITTING_1D_THRESHOLD); String peaksList = preferenceStore.getString(PreferenceConstants.FITTING_1D_PEAKLIST); String selectedPeakName = preferenceStore.getString(PreferenceConstants.FITTING_1D_PEAKTYPE); populateAndSelectPeak(peaksList, selectedPeakName); if (preferenceStore.getBoolean(PreferenceConstants.FITTING_1D_AUTO_STOPPING)) { numPeaks.setSelection(-1); numPeaks.setEnabled(false); } else { numPeaks.setEnabled(true); numPeaks.setSelection(preferenceStore.getInt(PreferenceConstants.FITTING_1D_PEAK_NUM)); } autoStopping = preferenceStore.getBoolean(PreferenceConstants.FITTING_1D_AUTO_STOPPING); determineThresholdMeasure(preferenceStore.getString(PreferenceConstants.FITTING_1D_THRESHOLD_MEASURE)); String algList = preferenceStore.getDefaultString(PreferenceConstants.FITTING_1D_ALG_LIST); String algDefaultName = preferenceStore.getString(PreferenceConstants.FITTING_1D_ALG_TYPE); populateAndSelectAlgnames(algList, algDefaultName); // Adding UUID for fitting jobs BUTTON_FITTING_UUID = UUID.randomUUID().toString(); REFITTING_UUID = UUID.randomUUID().toString(); } private void populateAndSelectAlgnames(String algList, String algDefaultName) { StringTokenizer st = new StringTokenizer(algList, PreferenceInitializer.DELIMITER); algNames = new String[st.countTokens()]; int count = 0; String algName = ""; while (st.hasMoreTokens()) { String temp = st.nextToken(); algNames[count] = temp; if (temp.equalsIgnoreCase(algDefaultName)) { algName = temp; selectedAlg = count; } count++; } if (algName.equalsIgnoreCase("Genetic Algorithm")) alg = new GeneticAlg(accuracy); else if (algName.equalsIgnoreCase("Nelder Mead")) alg = new NelderMead(accuracy); else if (algName.equalsIgnoreCase("Apache Nelder Mead")) alg = new ApacheNelderMead(); else throw new IllegalArgumentException("Did not recognise the fitting routine"); } private void populateAndSelectPeak(String peaksList, String defaultPeakName) { StringTokenizer st = new StringTokenizer(peaksList, PreferenceInitializer.DELIMITER); peaknames = new String[st.countTokens()]; int count = 0; while (st.hasMoreTokens()) { String temp = st.nextToken(); peaknames[count] = temp; peakType.add(temp); if (temp.equalsIgnoreCase(defaultPeakName)) { selectedPeak = count; } count++; } peakType.select(selectedPeak); } private void addPropertyListeners() { AnalysisRCPActivator.getDefault().getPreferenceStore() .addPropertyChangeListener(new IPropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent event) { String property = event.getProperty(); IPreferenceStore preferenceStore = AnalysisRCPActivator.getDefault().getPreferenceStore(); if (property.equals(PreferenceConstants.FITTING_1D_ALG_ACCURACY) || property.equals(PreferenceConstants.FITTING_1D_SMOOTHING_VALUE) || property.equals(PreferenceConstants.FITTING_1D_ALG_TYPE) || property.equals(PreferenceConstants.FITTING_1D_AUTO_SMOOTHING) || property.equals(PreferenceConstants.FITTING_1D_PEAKTYPE)) { String peakName; if (preferenceStore.isDefault(PreferenceConstants.FITTING_1D_PEAKTYPE)) { peakName = preferenceStore .getDefaultString(PreferenceConstants.FITTING_1D_PEAKTYPE); } else { peakName = preferenceStore.getString(PreferenceConstants.FITTING_1D_PEAKTYPE); } for (int i = 0; i < peaknames.length; i++) { if (peaknames[i].equalsIgnoreCase(peakName)) { peakType.select(i); break; } } if (preferenceStore.isDefault(PreferenceConstants.FITTING_1D_ALG_ACCURACY)) { accuracy = preferenceStore .getDefaultDouble(PreferenceConstants.FITTING_1D_ALG_ACCURACY); } else { accuracy = preferenceStore.getDouble(PreferenceConstants.FITTING_1D_ALG_ACCURACY); } boolean autoSmooth; if (preferenceStore.isDefault(PreferenceConstants.FITTING_1D_AUTO_SMOOTHING)) { autoSmooth = preferenceStore .getDefaultBoolean(PreferenceConstants.FITTING_1D_AUTO_SMOOTHING); } else { autoSmooth = preferenceStore .getBoolean(PreferenceConstants.FITTING_1D_AUTO_SMOOTHING); } if (autoSmooth) { setupSmoothing(); } else { if (preferenceStore.isDefault(PreferenceConstants.FITTING_1D_SMOOTHING_VALUE)) { smoothing = preferenceStore .getDefaultInt(PreferenceConstants.FITTING_1D_SMOOTHING_VALUE); } else { smoothing = preferenceStore .getInt(PreferenceConstants.FITTING_1D_SMOOTHING_VALUE); } } String algTypeList; if (preferenceStore.isDefault(PreferenceConstants.FITTING_1D_ALG_LIST)) { algTypeList = preferenceStore .getDefaultString(PreferenceConstants.FITTING_1D_ALG_LIST); } else { algTypeList = preferenceStore.getString(PreferenceConstants.FITTING_1D_ALG_LIST); } StringTokenizer st = new StringTokenizer(algTypeList, PreferenceInitializer.DELIMITER); algNames = new String[st.countTokens()]; int numAlgs = 0; while (st.hasMoreTokens()) { algNames[numAlgs++] = st.nextToken(); } String algName; if (preferenceStore.isDefault(PreferenceConstants.FITTING_1D_ALG_TYPE)) algName = preferenceStore.getDefaultString(PreferenceConstants.FITTING_1D_ALG_TYPE); else algName = preferenceStore.getString(PreferenceConstants.FITTING_1D_ALG_TYPE); if (algName.equalsIgnoreCase("Genetic Algorithm")) alg = new GeneticAlg(accuracy); else if (algName.equalsIgnoreCase("Nelder Mead")) alg = new NelderMead(accuracy); else if (algName.equalsIgnoreCase("Apache Nelder Mead")) alg = new ApacheNelderMead(); else throw new IllegalArgumentException("Did not recognise the fitting routine"); } else if (property.equals(PreferenceConstants.FITTING_1D_AUTO_STOPPING) || property.equals(PreferenceConstants.FITTING_1D_THRESHOLD) || property.equals(PreferenceConstants.FITTING_1D_THRESHOLD_MEASURE) || property.equals(PreferenceConstants.FITTING_1D_PEAK_NUM)) { if (preferenceStore.isDefault(PreferenceConstants.FITTING_1D_AUTO_STOPPING)) { autoStopping = preferenceStore .getDefaultBoolean(PreferenceConstants.FITTING_1D_AUTO_STOPPING); } else { autoStopping = preferenceStore .getBoolean(PreferenceConstants.FITTING_1D_AUTO_STOPPING); } if (preferenceStore.isDefault(PreferenceConstants.FITTING_1D_THRESHOLD)) { threshold = preferenceStore.getDefaultInt(PreferenceConstants.FITTING_1D_THRESHOLD); } else { threshold = preferenceStore.getInt(PreferenceConstants.FITTING_1D_THRESHOLD); } String measure; if (preferenceStore.isDefault(PreferenceConstants.FITTING_1D_THRESHOLD_MEASURE)) { measure = preferenceStore .getDefaultString(PreferenceConstants.FITTING_1D_THRESHOLD_MEASURE); } else { measure = preferenceStore .getString(PreferenceConstants.FITTING_1D_THRESHOLD_MEASURE); } determineThresholdMeasure(measure); if (autoStopping) { numPeaks.setSelection(-1); numPeaks.setEnabled(false); } else { numPeaks.setEnabled(true); if (preferenceStore.isDefault(PreferenceConstants.FITTING_1D_PEAK_NUM)) { numPeaks.setSelection( preferenceStore.getDefaultInt(PreferenceConstants.FITTING_1D_PEAK_NUM)); } else { numPeaks.setSelection( preferenceStore.getInt(PreferenceConstants.FITTING_1D_PEAK_NUM)); } } } else if (property.equals(PreferenceConstants.FITTING_1D_DECIMAL_PLACES)) { fittedPeakTable.refresh(); } } }); } protected void determineThresholdMeasure(String measure) { if (measure.equalsIgnoreCase("Height")) { thresholdMeasure = true; } else if (measure.equalsIgnoreCase("Area")) { thresholdMeasure = false; } else { throw new IllegalArgumentException("Did not recognise the threashold measure"); } } private SelectionAdapter fitPeakListener = new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { clearPeakTable(); removeAllPeakOverlays(); selectPeakFuction(peakType.getSelectionIndex()); IJobManager manager = Job.getJobManager(); // Cancel all outstanding jobs. manager.cancel(BUTTON_FITTING_UUID); manager.cancel(REFITTING_UUID); new FitWholeDataset(currentXAxis.toDataset(), currentDataSet, peakToFit, alg, smoothing, numPeaks.getSelection(), threshold / 100, autoStopping, thresholdMeasure, chooseDataCombo.getItem(chooseDataCombo.getSelectionIndex()), BUTTON_FITTING_UUID).schedule(); } }; private class FitWholeDataset extends Job { final DoubleDataset xAxis; final DoubleDataset yAxis; final APeak peak; final IOptimizer optomiser; final int smooth; final int numberOfPeaks; final double cutoff; final boolean autoStop; final boolean measure; private static final String name = "Fitting peaks"; private String UUID; public FitWholeDataset(DoubleDataset xaxis, DoubleDataset yaxis, APeak peakToFit, IOptimizer alg, int smoothing, int numPeaks, double cutOff, boolean autostop, boolean stoppingMeasure, String dataName, String UUID) { super(name + " " + dataName); xAxis = xaxis; yAxis = yaxis; peak = peakToFit; optomiser = alg; smooth = smoothing; numberOfPeaks = numPeaks; cutoff = cutOff; autoStop = autostop; measure = stoppingMeasure; this.UUID = UUID; } @Override protected IStatus run(final IProgressMonitor monitor) { final List<CompositeFunction> functions = Generic1DFitter.fitPeakFunctions(xAxis, yAxis, peak, optomiser, smooth, numberOfPeaks, cutoff, autoStop, measure, new IAnalysisMonitor() { @Override public boolean hasBeenCancelled() { return monitor.isCanceled(); } }); if (monitor.isCanceled()) return Status.CANCEL_STATUS; if (functions.isEmpty()) { logger.warn("No peaks found"); return Status.OK_STATUS; } UIJob updateGUI = new UIJob("Updating GUI") { @Override public IStatus runInUIThread(IProgressMonitor monitor) { List<APeak> fittedPeaks = new ArrayList<APeak>(functions.size()); for (CompositeFunction compositeFunction : functions) { fittedPeaks.add((APeak) compositeFunction.getFunction(0)); } addPeaksToList(fittedPeaks, colorButtonFitted); return Status.OK_STATUS; } }; updateGUI.schedule(); return Status.OK_STATUS; } @Override public boolean belongsTo(Object family) { return UUID.equals(family); } } private SelectionAdapter showAllPeaksOverlay = new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { if (showAllPeaks.getSelection()) { drawAllPeakOverlays(); } if (!showAllPeaks.getSelection()) { removeAllPeakOverlays(); } } }; private void drawAllPeakOverlays() { removeAllPeakOverlays(); if (!showAllPeaks.getSelection()) { return; } if (fittedPeakList == null || fittedPeakList.isEmpty()) { return; } overlaysVisible(false); if (showAllPeaks.getSelection()) { for (FittedPeakData fpd : fittedPeakList) { int primID = oProvider.registerPrimitive(PrimitiveType.BOX); oProvider.begin(OverlayType.VECTOR2D); double start = fpd.getFittedPeak().getPosition(); double fwhm = fpd.getFittedPeak().getFWHM(); oProvider.drawBox(primID, start - (fwhm / 2), MAXYVALUE, start + (fwhm / 2), -MAXYVALUE); oProvider.setColour(primID, Color.ORANGE); oProvider.setStyle(primID, VectorOverlayStyles.FILLED_WITH_OUTLINE); oProvider.setTransparency(primID, 0.8); oProvider.setOutlineTransparency(primID, 0); oProvider.end(OverlayType.VECTOR2D); primitiveIDs.add(primID); } } } private void removeAllPeakOverlays() { oProvider.begin(OverlayType.VECTOR2D); if (draggingPrimID != -1) { oProvider.setPrimitiveVisible(draggingPrimID, false); } if (primitiveIDs != null && !primitiveIDs.isEmpty()) { oProvider.unregisterPrimitive(primitiveIDs); primitiveIDs.clear(); } oProvider.end(OverlayType.VECTOR2D); } private void peaksUpdated() { updatePeaksTable(); pushPeaksToPlotter(); drawAllPeakOverlays(); } private void pushPeaksToPlotter() { ArrayList<APeak> peaks = new ArrayList<APeak>(); for (FittedPeakData p : fittedPeakList) { peaks.add(p.getFittedPeak()); } if (guiUpdateManager != null) { guiUpdateManager.putGUIInfo(GuiParameters.FITTEDPEAKS, peaks); } } private void updatePeaksTable() { Collections.sort(fittedPeakList, new Compare()); fittedPeakTable.refresh(); } private static class Compare implements Comparator<FittedPeakData> { @Override public int compare(FittedPeakData arg0, FittedPeakData arg1) { if (arg0.getFittedPeak().getPosition() > arg1.getFittedPeak().getPosition()) { return 1; } if (arg0.getFittedPeak().getPosition() < arg1.getFittedPeak().getPosition()) { return -1; } return 0; } } private SelectionAdapter clearPeaksListener = new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { fittedPeakList.clear(); peaksUpdated(); } }; @Override public void selectionChanged(SelectionChangedEvent event) { ISelection selection = event.getSelection(); IStructuredSelection selection2 = (IStructuredSelection) selection; FittedPeakData selectedPeak = (FittedPeakData) selection2.getFirstElement(); if (selectedPeak != null) { processPeakInformation(selectedPeak); drawFittedPeakOverlays(selectedPeak); fittedPlot.removePrimitives(); fittedPlot.drawCurrentOverlay(selectedPeak); } } private void drawFittedPeakOverlays(FittedPeakData selectedPeak) { int primID = oProvider.registerPrimitive(PrimitiveType.BOX); overlaysVisible(false); oProvider.begin(OverlayType.VECTOR2D); double start = selectedPeak.getFittedPeak().getPosition(); double fwhm = selectedPeak.getFittedPeak().getFWHM(); oProvider.drawBox(primID, (start - (fwhm / 2)), MAXYVALUE, (start + (fwhm / 2)), -MAXYVALUE); oProvider.setColour(primID, Color.ORANGE); oProvider.setStyle(primID, VectorOverlayStyles.FILLED_WITH_OUTLINE); oProvider.setTransparency(primID, 0.8); oProvider.setOutlineTransparency(primID, 0); oProvider.end(OverlayType.VECTOR2D); primitiveIDs.add(primID); } /** * this method will extract the datasets and then send them for plotting * * @param selectedPeak */ private void processPeakInformation(FittedPeakData selectedPeak) { APeak peak = selectedPeak.getFittedPeak(); double min = peak.getPosition() - 2 * peak.getFWHM(); double max = peak.getPosition() + 2 * peak.getFWHM(); DoubleDataset measuredData = sliceDataSet(min, max); double slicedDataMin = (Double) measuredData.min(); CompositeFunction function = new CompositeFunction(); Offset os = new Offset(slicedDataMin, slicedDataMin); function.addFunction(peak); function.addFunction(os); AbstractDataset axis = createXData(min, max); DoubleDataset fittedData = function.makeDataset(axis); fittedPlot.plotDataSets(measuredData, fittedData, new AxisValues(axis)); } @Override public void showSidePlot() { processPlotUpdate(); } @Override public int updateGUI(GuiBean bean) { return 0; } @Override public void generateMenuActions(IMenuManager manager, final IWorkbenchPartSite site) { createExportActions(); manager.add(new Separator(getClass().getName() + printButtonText)); manager.add(saveGraph); manager.add(copyGraph); manager.add(printGraph); manager.add(new Separator(getClass().getName() + "extraActions")); Action fitting1dmenu = new Action() { @Override public void run() { IHandlerService handler = (IHandlerService) site.getService(IHandlerService.class); try { handler.executeCommand("uk.ac.diamond.scisoft.analysis.rcp.Fitting1DSettings", null); } catch (Exception e) { logger.error(e.getMessage()); } } }; fitting1dmenu.setText("Preferences"); manager.add(fitting1dmenu); } @Override public void generateToolActions(IToolBarManager manager) { createExportActions(); createExtraActions(); manager.add(new Separator(getClass().getName() + printButtonText)); manager.add(saveGraph); manager.add(copyGraph); manager.add(printGraph); manager.add(new Separator(getClass().getName() + "extraActions")); manager.add(showLeg); } } class PlotFittedPeaks implements Overlay1DConsumer { transient private static final Logger logger = LoggerFactory.getLogger(PlotFittedPeaks.class); private static DataSetPlotter plotter; private Overlay1DProvider sideProvider; private List<Integer> sidePrimID; private int sideID; double MaxY = Double.MAX_VALUE, MinY = -Double.MAX_VALUE; public PlotFittedPeaks(SashForm ss) { Composite peakPlotter = new Composite(ss, SWT.NONE); peakPlotter.setLayout(new FillLayout()); plotter = new DataSetPlotter(PlottingMode.ONED, peakPlotter); plotter.setAxisModes(AxisMode.CUSTOM, AxisMode.LINEAR, AxisMode.LINEAR); } public static IAction createShowLegend() { return Plot1DUIAdapter.createShowLegend(plotter); } public void saveGraph(String filename, String fileType) { plotter.saveGraph(filename, fileType); } public void copyGraph() { plotter.copyGraph(); } public void printGraph() { plotter.printGraph(); } public void plotDataSets(DoubleDataset measuredData, DoubleDataset fittedData, AxisValues xAxis) { MaxY = fittedData.max().doubleValue(); MinY = fittedData.min().doubleValue(); List<IDataset> plottingData = new ArrayList<IDataset>(); List<AxisValues> axisValues = new ArrayList<AxisValues>(); plottingData.add(measuredData); plottingData.add(fittedData); axisValues.add(xAxis); axisValues.add(xAxis); try { plotter.replaceAllPlots(plottingData, axisValues); } catch (PlotException e) { e.printStackTrace(); } plotter.refresh(false); } public void clearPeakPlotter() { if (plotter != null) { try { plotter.replaceAllPlots(new ArrayList<IDataset>()); removePrimitives(); } catch (PlotException e) { logger.warn("The plot could not be cleared in fitting1D sideplot"); } plotter.refresh(false); } } public void dispose() { if (plotter != null) { plotter.cleanUp(); } } public void drawCurrentOverlay(FittedPeakData selectedPeak) { double fwhm = selectedPeak.getFittedPeak().getFWHM(); double pos = selectedPeak.getFittedPeak().getPosition(); if (sideProvider == null) { plotter.registerOverlay(this); } sideProvider.begin(OverlayType.VECTOR2D); sideID = sideProvider.registerPrimitive(PrimitiveType.BOX); sideProvider.setColour(sideID, Color.RED); sideProvider.setStyle(sideID, VectorOverlayStyles.FILLED_WITH_OUTLINE); sideProvider.setTransparency(sideID, 0.8); sideProvider.setOutlineTransparency(sideID, 0); sideProvider.drawBox(sideID, pos - (fwhm / 2), ((MaxY - MinY) / 2) + MinY, pos + (fwhm / 2), MinY); sidePrimID.add(sideID); // position line sideID = sideProvider.registerPrimitive(PrimitiveType.LINE); sideProvider.setColour(sideID, Color.GREEN); sideProvider.drawLine(sideID, pos, MinY, pos, MaxY); sidePrimID.add(sideID); sideProvider.end(OverlayType.VECTOR2D); } @Override public void registerProvider(OverlayProvider provider) { sideProvider = (Overlay1DProvider) provider; sidePrimID = new ArrayList<Integer>(); } @Override public void removePrimitives() { if (sideProvider != null) { // Call directly unregisterPrimitive(...) list much faster than // call to sideProvider.unregisterPrimitive(int) when run // in debugger. This then speeds selection of the table up. sideProvider.unregisterPrimitive(sidePrimID); } } @Override public void unregisterProvider() { if (sideProvider != null) { sideProvider = null; } } @Override public void areaSelected(AreaSelectEvent event) { } }