Detections output

more work on detections output.
This commit is contained in:
Douglas Gillespie 2023-09-15 15:15:28 +01:00
parent db1cc75bc1
commit 158eedce8c
19 changed files with 486 additions and 137 deletions

View File

@ -0,0 +1,29 @@
package PamguardMVC;
/**
* @author dg50
* Levels of automation for the various datas in PAMGuard.
* Should be used within DataAutomationInfo to perhaps combine with other info in the future.
*
*/
public enum DataAutomation {
AUTOMATIC, MANUAL, MANUALANDAUTOMATIC;
@Override
public String toString() {
switch (this) {
case AUTOMATIC:
return "Automatic";
case MANUAL:
return "Manual";
case MANUALANDAUTOMATIC:
return "Manual and automatic";
default:
break;
}
return null;
}
}

View File

@ -0,0 +1,44 @@
package PamguardMVC;
/**
* Returned by datablocks, though default is null, to give information on how
* automatic the process was.
* @author dg50
*
*/
public class DataAutomationInfo {
private DataAutomation automation;
/**
* @param automation
*/
public DataAutomationInfo(DataAutomation automation) {
this.setAutomation(automation);
}
/**
* @return the automation
*/
public DataAutomation getAutomation() {
return automation;
}
/**
* @param automation the automation to set
*/
public void setAutomation(DataAutomation automation) {
this.automation = automation;
}
@Override
public String toString() {
if (automation == null) {
return "Unknown data automation";
}
return automation.toString();
}
}

View File

@ -3100,11 +3100,12 @@ public class PamDataBlock<Tunit extends PamDataUnit> extends PamObservable {
}
/**
* Set a data provider for Tethys.
* @param tethysDataProvider the tethysDataProvider to set
* Get the level of automation employed by the generation of these data.
* Should ideally be completed for everything providing data to Tethys.
* @return level of automation for this data block.
*/
public void setTethysDataProvider(TethysDataProvider tethysDataProvider) {
this.tethysDataProvider = tethysDataProvider;
public DataAutomationInfo getDataAutomationInfo() {
return null;
}
/**

View File

@ -2,6 +2,8 @@ package RightWhaleEdgeDetector;
import PamView.GroupedDataSource;
import PamView.GroupedSourceParameters;
import PamguardMVC.DataAutomation;
import PamguardMVC.DataAutomationInfo;
import PamguardMVC.PamProcess;
import PamguardMVC.dataOffline.OfflineDataLoadInfo;
import PamguardMVC.dataSelector.DataSelectorCreator;
@ -77,4 +79,9 @@ public class RWEDataBlock extends AbstractWhistleDataBlock<RWEDataUnit> implemen
return rwTethysDataProvider;
}
@Override
public DataAutomationInfo getDataAutomationInfo() {
return new DataAutomationInfo(DataAutomation.AUTOMATIC);
}
}

View File

@ -846,6 +846,11 @@ public class DBXMLQueries {
description.setMethod(getElementData(result, "Description.Method"));
description.setObjectives(getElementData(result, "Description.Objectives"));
// get the effort start an end
String effStart = getElementData(result, "Effort.Start");
String effEnd = getElementData(result, "Effort.End");
detections.getEffort().setStart(TethysTimeFuncs.fromGregorianXML(effStart));
detections.getEffort().setEnd(TethysTimeFuncs.fromGregorianXML(effEnd));
// try to find the granularity.
String granularityString = getElementData(result, "Effort.Kind.Granularity");
GranularityEnumType granularity = null;

View File

@ -4,6 +4,8 @@ import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;
import PamguardMVC.PamDataBlock;
@ -29,9 +31,7 @@ import tethys.species.SpeciesMapItem;
*/
public class BinnedGranularityHandler extends GranularityHandler {
private double binDurationSeconds;
private long binStartMillis, binEndMillis;
private long binDurationMillis;
private TethysDataProvider dataProvider;
@ -43,7 +43,7 @@ public class BinnedGranularityHandler extends GranularityHandler {
TethysExportParams tethysExportParams, StreamExportParams streamExportParams) {
super(tethysControl, dataBlock, tethysExportParams, streamExportParams);
binDurationSeconds = streamExportParams.binDurationS;
binDurationMillis = (long) (streamExportParams.binDurationS*1000.);
dataProvider = dataBlock.getTethysDataProvider(tethysControl);
speciesManager = dataBlock.getDatablockSpeciesManager();
@ -52,61 +52,74 @@ public class BinnedGranularityHandler extends GranularityHandler {
@Override
public void prepare(long timeMillis) {
long binStart = DetectionsHandler.roundDownBinStart(timeMillis, (long) (binDurationSeconds*1000));
startBin(binStart);
// long binStart = DetectionsHandler.roundDownBinStart(timeMillis, binDurationMillis);
// startBin(binStart);
}
private void startBin(long timeMillis) {
binStartMillis = timeMillis;
binEndMillis = binStartMillis + (long) (binDurationSeconds*1000.);
/*
* now make a Detection object for every possible species that
* this might throw out.
*/
ArrayList<String> speciesCodes = speciesManager.getAllSpeciesCodes();
String defaultCode = speciesManager.getDefaultSpeciesCode();
Detection det;
currentDetections.put(defaultCode, det = new Detection());
det.setStart(TethysTimeFuncs.xmlGregCalFromMillis(binStartMillis));
det.setEnd(TethysTimeFuncs.xmlGregCalFromMillis(binEndMillis));
det.setCount(BigInteger.ZERO);
det.setChannel(BigInteger.ZERO);
// add codes at end, just before output.
if (speciesCodes != null) {
for (String code : speciesCodes) {
currentDetections.put(code, det = new Detection());
det.setStart(TethysTimeFuncs.xmlGregCalFromMillis(binStartMillis));
det.setEnd(TethysTimeFuncs.xmlGregCalFromMillis(binEndMillis));
det.setCount(BigInteger.ZERO);
det.setChannel(BigInteger.ZERO);
}
}
}
// private void startBin(long timeMillis) {
// binStartMillis = timeMillis;
// binEndMillis = binStartMillis + binDurationMillis;
// /*
// * now make a Detection object for every possible species that
// * this might throw out.
// */
// ArrayList<String> speciesCodes = speciesManager.getAllSpeciesCodes();
// String defaultCode = speciesManager.getDefaultSpeciesCode();
// Detection det;
// currentDetections.put(defaultCode, det = new Detection());
// det.setStart(TethysTimeFuncs.xmlGregCalFromMillis(binStartMillis));
// det.setEnd(TethysTimeFuncs.xmlGregCalFromMillis(binEndMillis));
// det.setCount(BigInteger.ZERO);
// det.setChannel(BigInteger.ZERO);
// // add codes at end, just before output.
// if (speciesCodes != null) {
// for (String code : speciesCodes) {
// currentDetections.put(code, det = new Detection());
// det.setStart(TethysTimeFuncs.xmlGregCalFromMillis(binStartMillis));
// det.setEnd(TethysTimeFuncs.xmlGregCalFromMillis(binEndMillis));
// det.setCount(BigInteger.ZERO);
// det.setChannel(BigInteger.ZERO);
// }
// }
// }
@Override
public Detection[] addDataUnit(PamDataUnit dataUnit) {
Detection[] detections = null;
if (dataUnit.getTimeMilliseconds() >= binEndMillis) {
detections = closeBins(dataUnit.getTimeMilliseconds());
prepare(dataUnit.getTimeMilliseconds());
Detection[] completeDetections = closeBins(dataUnit.getTimeMilliseconds());
// now look for new ones. First get the species of the dataUnit and find it in the hashmap
String groupName = getCallGroupName(dataUnit);
Detection det = currentDetections.get(groupName);
if (det == null) {
// need to make a new one.
det = new Detection();
long binStart = DetectionsHandler.roundDownBinStart(dataUnit.getTimeMilliseconds(), binDurationMillis);
det.setStart(TethysTimeFuncs.xmlGregCalFromMillis(binStart));
det.setEnd(TethysTimeFuncs.xmlGregCalFromMillis(binStart + binDurationMillis));
det.setCount(BigInteger.ONE);
det.setChannel(BigInteger.valueOf(dataUnit.getChannelBitmap()));
// this should always return something, so am going to crash if it doesn't.
// may revisit this later on if we've unassigned things we don't want to label
// in which case they should be rejected earlier than this.
SpeciesMapItem speciesStuff = speciesManager.getSpeciesItem(dataUnit);
SpeciesIDType species = new SpeciesIDType();
species.setValue(BigInteger.valueOf(speciesStuff.getItisCode()));
det.setSpeciesId(species);
if (speciesStuff.getCallType() != null) {
det.getCall().add(speciesStuff.getCallType());
}
currentDetections.put(groupName, det);
}
String speciesCode = speciesManager.getSpeciesCode(dataUnit);
Detection det = currentDetections.get(speciesCode);
if (det != null) {
/*
* Increase the detection count
*/
int count = det.getCount().intValue();
count++;
else {
// add to current detection. Set new end time and increment count
int count = det.getCount().intValue() + 1;
det.setCount(BigInteger.valueOf(count));
/*
* Add to the channel map too ...
*/
int channel = det.getChannel().intValue();
channel |= dataUnit.getChannelBitmap();
det.setChannel(BigInteger.valueOf(channel));
int chan = det.getChannel().intValue();
chan |= dataUnit.getChannelBitmap();
det.setChannel(BigInteger.valueOf(chan));
}
return detections;
return completeDetections;
}
/**
@ -115,33 +128,32 @@ public class BinnedGranularityHandler extends GranularityHandler {
* @param timeMilliseconds
* @return
*/
private Detection[] closeBins(long timeMilliseconds) {
private synchronized Detection[] closeBins(long timeMilliseconds) {
Set<String> speciesKeys = currentDetections.keySet();
int n = speciesKeys.size();
int nGood = 0;
DataBlockSpeciesMap speciesMap = speciesManager.getDatablockSpeciesMap();
Detection detections[] = new Detection[n];
for (String key : speciesKeys) {
Detection det = currentDetections.get(key);
Iterator<Entry<String, Detection>> iter = currentDetections.entrySet().iterator();
while (iter.hasNext()) {
Entry<String, Detection> entry = iter.next();
Detection det = entry.getValue();
long detEnd = TethysTimeFuncs.millisFromGregorianXML(det.getEnd());
if (timeMilliseconds < detEnd) {
// we're not at the end of the bin, so carry on.
continue;
}
// we've reached the end of the bin, so remove it from the map
iter.remove();
// now decide if we want to keep it or not.
int callCount = det.getCount().intValue();
if (callCount < Math.max(streamExportParams.minBinCount,1)) {
continue;
}
SpeciesMapItem speciesStuff = speciesMap.getItem(key); // should be non null!
if (speciesStuff == null) {
continue;
}
SpeciesIDType species = new SpeciesIDType();
species.setValue(BigInteger.valueOf(speciesStuff.getItisCode()));
det.setSpeciesId(species);
if (speciesStuff.getCallType() != null) {
det.getCall().add(speciesStuff.getCallType());
continue; // won't add to output list
}
detections[nGood++] = det;
}
/*
* Clean up the end of the array and return detections that have enough calls.
*/

View File

@ -349,9 +349,9 @@ public class DetectionsHandler {
/**
* Round a bin start so that it's aligned correctly with
* day starts.
* @param binStart
* @param binInterval
* @return
* @param binStart in milliseconds
* @param binInterval in milliseconds
* @return rounded time.
*/
public static long roundDownBinStart(long binStart, long binInterval) {
binStart/=binInterval;
@ -441,6 +441,10 @@ public class DetectionsHandler {
// currentDetections = null;
// }
}
Detection dets[] = granularityHandler.cleanup(deployment.getAudioEnd());
if (dets != null) {
exportCount += dets.length;
}
@ -578,8 +582,9 @@ public class DetectionsHandler {
e.printStackTrace();
return null;
}
TethysDataProvider dataProvider = dataBlock.getTethysDataProvider(tethysControl);
String prefix = deployment.deployment.getId();
String prefix = deployment.deployment.getId() + "_" + dataProvider.getDetectionsName();
String fullId = "";
/*
* Check the document name isn't already used and increment id as necessary.
@ -599,7 +604,6 @@ public class DetectionsHandler {
detections.setDataSource(dataSource);
AlgorithmType algorithm = detections.getAlgorithm();
TethysDataProvider dataProvider = dataBlock.getTethysDataProvider(tethysControl);
if (dataProvider != null) {
algorithm = dataProvider.getAlgorithm();
// detections.setAlgorithm(algorithm);

View File

@ -6,6 +6,7 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Set;
import java.util.Map.Entry;
import PamguardMVC.PamDataBlock;
import PamguardMVC.PamDataUnit;
@ -54,8 +55,8 @@ public class EncounterGranularityHandler extends GranularityHandler {
public Detection[] addDataUnit(PamDataUnit dataUnit) {
Detection[] completeDetections = checkCurrentEncounters(dataUnit.getTimeMilliseconds());
// now look for new ones. First get the species of the dataUnit and find it in the hashmap
String speciesCode = speciesManager.getSpeciesCode(dataUnit);
Detection det = currentDetections.get(speciesCode);
String groupName = getCallGroupName(dataUnit);
Detection det = currentDetections.get(groupName);
if (det == null) {
// need to make a new one.
det = new Detection();
@ -73,7 +74,7 @@ public class EncounterGranularityHandler extends GranularityHandler {
if (speciesStuff.getCallType() != null) {
det.getCall().add(speciesStuff.getCallType());
}
currentDetections.put(speciesCode, det);
currentDetections.put(groupName, det);
}
else {
// add to current detection. Set new end time and increment count
@ -98,16 +99,18 @@ public class EncounterGranularityHandler extends GranularityHandler {
Set<String> keys = currentDetections.keySet();
int nGood = 0;
Detection[] newDetections = new Detection[currentDetections.size()];
for (String aKey : keys) {
Detection aDet = currentDetections.get(aKey);
Long detEnd = TethysTimeFuncs.millisFromGregorianXML(aDet.getEnd());
Iterator<Entry<String, Detection>> iter = currentDetections.entrySet().iterator();
while (iter.hasNext()) {
Entry<String, Detection> entry = iter.next();
Detection aDet = entry.getValue();
long detEnd = TethysTimeFuncs.millisFromGregorianXML(aDet.getEnd());
if (timeMilliseconds-detEnd > maxGapMillis) {
// only keep if it's got a min number of calls.
if (aDet.getCount().intValue() >= streamExportParams.minBinCount) {
newDetections[nGood++] = aDet;
}
// remove from set. A new one will be created only when required.
currentDetections.remove(aKey);
iter.remove();
}
}

View File

@ -7,6 +7,7 @@ import nilus.GranularityEnumType;
import tethys.TethysControl;
import tethys.output.StreamExportParams;
import tethys.output.TethysExportParams;
import tethys.species.DataBlockSpeciesManager;
public abstract class GranularityHandler {
@ -18,6 +19,8 @@ public abstract class GranularityHandler {
protected StreamExportParams streamExportParams;
private DataBlockSpeciesManager speciesManager;
/**
* @param tethysControl
* @param dataBlock
@ -30,6 +33,7 @@ public abstract class GranularityHandler {
this.dataBlock = dataBlock;
this.tethysExportParams = tethysExportParams;
this.streamExportParams = streamExportParams;
speciesManager = dataBlock.getDatablockSpeciesManager();
}
/**
@ -48,6 +52,23 @@ public abstract class GranularityHandler {
*/
public abstract Detection[] addDataUnit(PamDataUnit dataUnit);
/**
* Get a grouping name for the call. This may just be the calls species code,
* or it may be appended with the channel number. This is used to find bin and
* encounter data in HashMaps in
* @param dataUnit
* @return
*/
public String getCallGroupName(PamDataUnit dataUnit) {
String groupName = speciesManager.getSpeciesCode(dataUnit);
if (groupName == null) {
groupName = "NullSpecies";
}
if (streamExportParams.separateChannels) {
groupName += String.format("Chan%d", dataUnit.getChannelBitmap());
}
return groupName;
}
/**
* Called after end end of all data units to get the last bin / encounter. <p>
*

View File

@ -3,15 +3,20 @@ package tethys.output;
import java.io.IOException;
import java.io.Serializable;
import PamController.PamController;
import PamguardMVC.PamDataBlock;
import nilus.DescriptionType;
import nilus.GranularityEnumType;
import tethys.TethysControl;
import tethys.niluswraps.PDescriptionType;
import tethys.pamdata.TethysDataProvider;
/**
* Parameters controlling export of a single stream.
* Starts just with a boolean 'selected', but may grow.
* These all contain data names rather than references to a Datablock so that
* they can be serialised.
* they can be serialised. However, created with TethysControl and datablock
* so that some stuff canbe automatically initialised.
* @author dg50
*
*/
@ -19,24 +24,44 @@ public class StreamExportParams implements Serializable {
public static final long serialVersionUID = 1L;
public StreamExportParams(String longDataName, boolean selected) {
super();
this.longDataName = longDataName;
this.selected = selected;
}
/**
* Datablock long data name (used instead of datablock
* reference so this object and serialise.
*/
public String longDataName;
public boolean selected;
/**
* Granularity type, binned, call, encounter, grouped.
*/
public GranularityEnumType granularity = GranularityEnumType.CALL;
/**
* Bin duration, seconds.
*/
public double binDurationS = 60;
/**
* Minimum encounter gap, seconds
*/
public double encounterGapS = 60;
/**
* Minimum count for a bin to be retained.
*/
public int minBinCount = 1;
/**
* Minimum count for an encounter to be retained.
*/
public int minEncounterCount = 1;
/**
* Keep channels separate when using binned data.
*/
public boolean separateChannels = true;
/*
* Can't have this here since it isn't serializable.
*/
@ -49,6 +74,25 @@ public class StreamExportParams implements Serializable {
return detectionDescription;
}
public StreamExportParams(TethysControl tethysControl, PamDataBlock dataBlock, boolean selected) {
super();
this.longDataName = dataBlock.getLongDataName();
this.selected = selected;
autoFill(tethysControl, dataBlock);
}
/**
* Try to put some information automatically into the Methods.
* @param dataBlock2
* @param tethysControl
*/
private void autoFill(TethysControl tethysControl, PamDataBlock dataBlock) {
// there should always be a data provider or we'd never have got this far.
TethysDataProvider dataProvider = dataBlock.getTethysDataProvider(tethysControl);
PDescriptionType desc = getDetectionDescription();
desc.setMethod(dataProvider.getDetectionsMethod());
}
/**
* Get the nilus detection description
* @return

View File

@ -151,7 +151,7 @@ public class TethysExportDialog extends PamDialog {
}
int nSel = 0;
for (DataStreamSet streamSet : dataStreamSets) {
StreamExportParams streamOpts = new StreamExportParams(streamSet.dataBlock.getLongDataName(), streamSet.checkBox.isSelected());
StreamExportParams streamOpts = new StreamExportParams(tethysControl, streamSet.dataBlock, streamSet.checkBox.isSelected());
exportParams.setStreamParams(streamSet.dataBlock, streamOpts);
nSel++;
}

View File

@ -14,6 +14,7 @@ import PamController.PamSettings;
import PamController.PamguardVersionInfo;
import PamController.settings.output.xml.PamguardXMLWriter;
import PamUtils.XMLUtils;
import PamguardMVC.DataAutomationInfo;
import PamguardMVC.DataUnitBaseData;
import PamguardMVC.PamDataBlock;
import PamguardMVC.PamDataUnit;
@ -30,6 +31,7 @@ import nilus.Detection;
import nilus.Detection.Parameters;
import nilus.Detection.Parameters.UserDefined;
import nilus.DetectionEffortKind;
import nilus.GranularityEnumType;
import nilus.Helper;
import nilus.SpeciesIDType;
import tethys.TethysControl;
@ -90,11 +92,11 @@ public class AutoTethysProvider implements TethysDataProvider {
return schema;
}
@Override
public TethysDataPoint getDataPoint(PamDataUnit pamDataUnit) {
// TODO Auto-generated method stub
return null;
}
// @Override
// public TethysDataPoint getDataPoint(PamDataUnit pamDataUnit) {
// // TODO Auto-generated method stub
// return null;
// }
@Override
public DescriptionType getDescription(Deployment deployment, TethysExportParams tethysExportParams) {
@ -488,4 +490,49 @@ public class AutoTethysProvider implements TethysDataProvider {
}
@Override
public String getDetectionsMethod() {
/*
* could really do with knowing what type of detector we're dealing with, i.e. if it's
* automatic or manual. For most blocks this is fixed, though some may have a mixture of both !
*/
DataAutomationInfo dataAutomation = pamDataBlock.getDataAutomationInfo();
String method;
PamControlledUnit pcu = pamDataBlock.getParentProcess().getPamControlledUnit();
if (dataAutomation == null) {
method = String.format("Processing using the PAMGuard %s", pcu.getUnitType());
}
else {
method = String.format("%s processing using the PAMGuard %s", dataAutomation.getAutomation(), pcu.getUnitType());
}
return method;
}
@Override
public GranularityEnumType[] getAllowedGranularities() {
GranularityEnumType[] allowed = {GranularityEnumType.CALL, GranularityEnumType.BINNED, GranularityEnumType.ENCOUNTER};
return allowed;
}
@Override
public String getDetectionsName() {
PamProcess process = pamDataBlock.getParentProcess();
PamControlledUnit pcu = process.getPamControlledUnit();
String pcuName = pcu.getUnitName();
String blockName = pamDataBlock.getDataName();
String documentName;
/**
* If the datablock name is the same as the unit name, no need to repeat onesself.
*/
if (pcuName.equals(blockName)) {
documentName = new String(pcuName); // copy it, since we're about to modify it!
}
else {
documentName = pcuName + " " + blockName;
}
documentName = documentName.replace(' ', '_');
return documentName;
}
}

View File

@ -9,6 +9,7 @@ import nilus.Deployment;
import nilus.DescriptionType;
import nilus.Detection;
import nilus.DetectionEffortKind;
import nilus.GranularityEnumType;
import tethys.niluswraps.PDeployment;
import tethys.output.StreamExportParams;
import tethys.output.TethysExportParams;
@ -38,8 +39,14 @@ public interface TethysDataProvider {
* @param pamDataUnit
* @return
*/
public TethysDataPoint getDataPoint(PamDataUnit pamDataUnit);
// public TethysDataPoint getDataPoint(PamDataUnit pamDataUnit);
/**
* Get a standard Method string for each detector. This can be a bit
* verbose and might even have a reference to a paper ? Is this the best place for this ?
* @return
*/
public String getDetectionsMethod();
/**
* Get DescriptionType object to include in a Tethys Detections document.
@ -56,6 +63,22 @@ public interface TethysDataProvider {
*/
public AlgorithmType getAlgorithm();
/**
* Get a list of allowed granularity types for this output
* @return list of granularities.
*/
public GranularityEnumType[] getAllowedGranularities();
/**
* Get a name for the detections documents. This will be appended
* to the Deployment name and may also have a number after it. <br>
* Note that the name isn't really important since all the matching between
* different documents is done internally, but it helps to make everything
* human readable.
* @return A name, similar to datablock.getLongDataName(), but no spaces.
*/
public String getDetectionsName();
/**
* Create a Tethys Detection object from a PamDataUnit.<br>

View File

@ -17,6 +17,7 @@ import javax.swing.JTable;
import javax.swing.border.TitledBorder;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.JTableHeader;
import javax.xml.datatype.XMLGregorianCalendar;
import PamView.PamGui;
import PamView.dialog.warn.WarnOnce;
@ -97,10 +98,12 @@ public class DatablockDetectionsPanel extends TethysGUIPanel implements StreamTa
case 1:
return "Name of PAMGuard data stream";
case 2:
return "Output granularity";
return "Effort period";
case 3:
return "Number of detection elements in document";
return "Output granularity";
case 4:
return "Number of detection elements in document";
case 5:
return "Document abstract";
}
@ -229,7 +232,7 @@ public class DatablockDetectionsPanel extends TethysGUIPanel implements StreamTa
private class TableModel extends AbstractTableModel {
private String[] colNames = {"Document", "Detector", "Granularity", "Count", "Abstract"};
private String[] colNames = {"Document", "Detector", "Effort", "Granularity", "Count", "Abstract"};
@Override
public int getRowCount() {
@ -272,6 +275,10 @@ public class DatablockDetectionsPanel extends TethysGUIPanel implements StreamTa
}
return pDets.dataBlock.getDataName();
case 2:
XMLGregorianCalendar start = dets.getEffort().getStart();
XMLGregorianCalendar stop = dets.getEffort().getEnd();
return start + " to " + stop;
case 3:
List<DetectionEffortKind> kinds = dets.getEffort().getKind();
if (kinds == null) {
return null;
@ -286,9 +293,9 @@ public class DatablockDetectionsPanel extends TethysGUIPanel implements StreamTa
}
}
break;
case 3:
return pDets.count;
case 4:
return pDets.count;
case 5:
return dets.getDescription().getAbstract();
}
return null;

View File

@ -156,7 +156,7 @@ public class DatablockSynchPanel extends TethysGUIPanel {
private class SynchTableModel extends AbstractTableModel {
String[] columnNames = {"Data Stream", "N PAM Datas", "PAMGuard Time", "Tethys Documents", "Tethys Time", "Options"};
String[] columnNames = {"Data Stream", "N PAM Datas", "PAMGuard Time", "Tethys Documents"};//, "Tethys Time", "Options"};
@Override
public int getRowCount() {

View File

@ -14,6 +14,7 @@ import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.table.AbstractTableModel;
import PamController.PamController;
@ -58,6 +59,8 @@ public class TethysDocumentTable implements PamDialogPanel {
new SwingTableColumnWidths(tethysControl.getUnitName()+"TethysDocumentsTable", mainTable);
this.setCollectionName(collectionName);
mainTable.addMouseListener(new TableMouse());
mainTable.setRowSelectionAllowed(true);
mainTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
}
public void updateTableData() {
@ -94,6 +97,7 @@ public class TethysDocumentTable implements PamDialogPanel {
if (row < 0|| row >= documentNames.size()) {
return;
}
String docName = documentNames.get(row);
JPopupMenu popMenu = new JPopupMenu();
JMenuItem menuItem = new JMenuItem("Show document " + docName);
@ -104,14 +108,31 @@ public class TethysDocumentTable implements PamDialogPanel {
}
});
popMenu.add(menuItem);
menuItem = new JMenuItem("Delete document " + docName);
menuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
deleteDocument(docName);
}
});
popMenu.add(menuItem);
int[] rows = mainTable.getSelectedRows();
if (rows != null && rows.length == 1) {
// docName = documentNames.get(rows[0]);
menuItem = new JMenuItem("Delete document " + docName);
menuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
deleteDocument(docName);
}
});
popMenu.add(menuItem);
}
else if (rows != null && rows.length > 1) {
String mt = String.format("Delete multiple (%d) documents", rows.length);
menuItem = new JMenuItem(mt);
menuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
deleteDocuments(rows);
}
});
popMenu.add(menuItem);
}
popMenu.show(e.getComponent(), e.getX(), e.getY());
}
@ -134,6 +155,32 @@ public class TethysDocumentTable implements PamDialogPanel {
updateTableData();
}
private void deleteDocuments(int[] rows) {
int ans = WarnOnce.showNamedWarning("deletedoc"+collectionName, PamController.getMainFrame(), "Delete documents",
"Are you sure you want to delete multiple documents ", WarnOnce.OK_CANCEL_OPTION);
if (ans != WarnOnce.OK_OPTION) {
return;
}
/*
* make a new list before anything is deleted since the
* man list will get updated during deletion and be out of date.
*/
String[] docNames = new String[rows.length];
for (int i = 0; i < rows.length; i++) {
docNames[i] = documentNames.get(rows[i]);
}
// now it's safe to delete them.
for (int i = 0; i < docNames.length; i++) {
try {
tethysControl.getDbxmlConnect().removeDocument(collectionName, docNames[i]);
} catch (TethysException e) {
System.out.println("Failed to delete " + docNames[i]);
System.out.println(e.getMessage());
}
}
updateTableData();
}
private class TableModel extends AbstractTableModel {
private String[] columnNames = {"", "Document Id/Name"};

View File

@ -39,6 +39,13 @@ public class DescriptionTypePanel {
private static final int ctrlWidth = 40;
public static final String objectivesTip = "What are the objectives of this effort? Examples:\r\n"
+ "Beamform to increase SNR for detection.\r\n"
+ "Detect every click of a rare species.\r\n"
+ "Verify data quality.";
public static final String abstractTip = "Overview of effort.";
public static final String methodTip = "High-level description of the method used.";
public DescriptionTypePanel(String bordertitle, boolean requireObjective, boolean requireAbstract, boolean requireMethod) {
this.requireObjective = requireObjective;
this.requireAbstract = requireAbstract;
@ -51,6 +58,16 @@ public class DescriptionTypePanel {
tObjectives = new JTextArea(12, ctrlWidth);
tAbstract = new JTextArea(8, ctrlWidth);
tMethod = new JTextArea(9, ctrlWidth);
tObjectives.setLineWrap(true);
tObjectives.setWrapStyleWord(true);
tAbstract.setLineWrap(true);
tAbstract.setWrapStyleWord(true);
tMethod.setLineWrap(true);
tMethod.setWrapStyleWord(true);
tObjectives.setToolTipText(objectivesTip);
tAbstract.setToolTipText(abstractTip);
tMethod.setToolTipText(methodTip);
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
addScrollablePanel(tObjectives, "Objectives");
@ -78,6 +95,11 @@ public class DescriptionTypePanel {
tAbstract.setText(null);
tMethod.setText(null);
}
else {
tObjectives.setText(description.getObjectives());
tAbstract.setText(description.getAbstract());
tMethod.setText(description.getMethod());
}
}
public boolean getParams(PDescriptionType description) {

View File

@ -39,7 +39,7 @@ public class DetectionsExportWizard extends PamDialog {
streamExportParams = tethysControl.getTethysExportParams().getStreamParams(dataBlock);
if (streamExportParams == null) {
streamExportParams = new StreamExportParams(dataBlock.getLongDataName(), false);
streamExportParams = new StreamExportParams(tethysControl, dataBlock, false);
}
cardLayout = new CardLayout();

View File

@ -30,6 +30,7 @@ import nilus.GranularityEnumType;
import tethys.TethysControl;
import tethys.niluswraps.PGranularityType;
import tethys.output.StreamExportParams;
import tethys.pamdata.TethysDataProvider;
public class GranularityCard extends ExportWizardCard {
@ -37,7 +38,9 @@ public class GranularityCard extends ExportWizardCard {
private JTextArea dataSelectionText;
private JTextField binLength, minCalls, encounterGap;
private JTextField binLength, minBinnedCalls, encounterGap, minEncounterCalls;
private JRadioButton groupChannels, separateChannels;
private DataSelector dataSelector;
@ -45,51 +48,68 @@ public class GranularityCard extends ExportWizardCard {
private int encounterIndex, binnedIndex;
private GranularityEnumType[] allowedGranularities;
public GranularityCard(DetectionsExportWizard detectionsExportWizard, TethysControl tethysControl, PamDataBlock dataBlock) {
super(tethysControl, "Granularity", dataBlock);
this.detectionsExportWizard = detectionsExportWizard;
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
TethysDataProvider tethysDataProvider = dataBlock.getTethysDataProvider(tethysControl);
// granularity
GranularityEnumType[] grans = GranularityEnumType.values();
granularities = new JRadioButton[grans.length];
allowedGranularities = tethysDataProvider.getAllowedGranularities();
granularities = new JRadioButton[allowedGranularities.length];
JPanel granPanel = new WestAlignedPanel(new GridBagLayout());
GridBagConstraints c = new PamGridBagContraints();
granPanel.setBorder(new TitledBorder("Granularity"));
ButtonGroup granGroup = new ButtonGroup();
GranularityChange gc = new GranularityChange();
for (int i = 0; i < grans.length; i++) {
for (int i = 0; i < allowedGranularities.length; i++) {
c.gridx = 0;
granularities[i] = new JRadioButton(PGranularityType.prettyString(grans[i]));
granularities[i].setToolTipText(PGranularityType.toolTip(grans[i]));
granularities[i] = new JRadioButton(PGranularityType.prettyString(allowedGranularities[i]));
granularities[i].setToolTipText(PGranularityType.toolTip(allowedGranularities[i]));
granularities[i].addActionListener(gc);
granPanel.add(granularities[i], c);
granGroup.add(granularities[i]);
if (grans[i] == GranularityEnumType.BINNED) {
if (allowedGranularities[i] == GranularityEnumType.BINNED) {
binnedIndex = i;
c.gridx++;
granPanel.add(new JLabel(" bin duration ", JLabel.RIGHT), c);
granPanel.add(new JLabel(" Bin duration ", JLabel.RIGHT), c);
c.gridx++;
granPanel.add(binLength = new JTextField(5), c);
c.gridx++;
granPanel.add(new JLabel("(s), min Calls", JLabel.LEFT), c);
granPanel.add(new JLabel("(s), Min Calls", JLabel.LEFT), c);
c.gridx++;
granPanel.add(minCalls = new JTextField(5), c);
granPanel.add(minBinnedCalls = new JTextField(5), c);
binLength.setToolTipText("Time bin duration in seconds");
minCalls.setToolTipText("Minimum number of calls for a bin to be output");
minBinnedCalls.setToolTipText("Minimum number of calls for a bin to be output");
}
if (grans[i] == GranularityEnumType.ENCOUNTER) {
if (allowedGranularities[i] == GranularityEnumType.ENCOUNTER) {
encounterIndex = i;
c.gridx++;
granPanel.add(new JLabel(" min gap ", JLabel.RIGHT), c);
granPanel.add(new JLabel(" Minimum gap ", JLabel.RIGHT), c);
c.gridx++;
granPanel.add(encounterGap = new JTextField(5), c);
c.gridx++;
granPanel.add(new JLabel("(s) ", JLabel.LEFT), c);
granPanel.add(new JLabel("(s), Min Calls", JLabel.LEFT), c);
c.gridx++;
granPanel.add(minEncounterCalls = new JTextField(5), c);
encounterGap.setToolTipText("Minimum gap between separate encounters");
minEncounterCalls.setToolTipText("Minimum number of calls for an encounter to be output");
}
c.gridy++;
}
c.gridx = 1;
c.gridwidth = 2;
granPanel.add(separateChannels = new JRadioButton("Separate channels"), c);
c.gridx += c.gridwidth;
granPanel.add(groupChannels = new JRadioButton("Group channels"), c);
separateChannels.setToolTipText("Use separate bins/encounters for each detection channel");
groupChannels.setToolTipText("Combine detections from different channels into the same bins/encounters");
ButtonGroup chanGroup = new ButtonGroup();
chanGroup.add(separateChannels);
chanGroup.add(groupChannels);
this.add(granPanel);
// data selection
@ -127,8 +147,12 @@ public class GranularityCard extends ExportWizardCard {
private void enableControls() {
binLength.setEnabled(granularities[binnedIndex].isSelected());
minCalls.setEnabled(granularities[binnedIndex].isSelected());
minBinnedCalls.setEnabled(granularities[binnedIndex].isSelected());
encounterGap.setEnabled(granularities[encounterIndex].isSelected());
minEncounterCalls.setEnabled(granularities[encounterIndex].isSelected());
boolean binOrencount = granularities[binnedIndex].isSelected() | granularities[encounterIndex].isSelected();
separateChannels.setEnabled(binOrencount);
groupChannels.setEnabled(binOrencount);
}
protected void newDataSelection() {
@ -149,10 +173,9 @@ public class GranularityCard extends ExportWizardCard {
@Override
public boolean getParams(StreamExportParams streamExportParams) {
GranularityEnumType[] grans = GranularityEnumType.values();
for (int i = 0; i < grans.length; i++) {
for (int i = 0; i < allowedGranularities.length; i++) {
if (granularities[i].isSelected()) {
streamExportParams.granularity = grans[i];
streamExportParams.granularity = allowedGranularities[i];
break;
}
}
@ -164,10 +187,10 @@ public class GranularityCard extends ExportWizardCard {
return detectionsExportWizard.showWarning("Invalid bin duration parameter");
}
try {
streamExportParams.minBinCount = Integer.valueOf(minCalls.getText());
streamExportParams.minBinCount = Integer.valueOf(minBinnedCalls.getText());
}
catch (NumberFormatException e) {
return detectionsExportWizard.showWarning("Invalid minimum call count");
return detectionsExportWizard.showWarning("Invalid minimum binned call count");
}
}
if (streamExportParams.granularity == GranularityEnumType.ENCOUNTER) {
@ -177,20 +200,30 @@ public class GranularityCard extends ExportWizardCard {
catch (NumberFormatException e) {
return detectionsExportWizard.showWarning("Invalid encounter gap parameter");
}
try {
streamExportParams.minEncounterCount = Integer.valueOf(minEncounterCalls.getText());
}
catch (NumberFormatException e) {
return detectionsExportWizard.showWarning("Invalid minimum encounter call count");
}
}
streamExportParams.separateChannels = separateChannels.isSelected();
return streamExportParams.granularity != null;
}
@Override
public void setParams(StreamExportParams streamExportParams) {
GranularityEnumType[] grans = GranularityEnumType.values();
for (int i = 0; i < grans.length; i++) {
granularities[i].setSelected(streamExportParams.granularity == grans[i]);
for (int i = 0; i < granularities.length; i++) {
granularities[i].setSelected(streamExportParams.granularity == allowedGranularities[i]);
}
binLength.setText(String.format("%3.1f", streamExportParams.binDurationS));
minCalls.setText(String.format("%d", streamExportParams.minBinCount));
minBinnedCalls.setText(String.format("%d", streamExportParams.minBinCount));
encounterGap.setText(String.format("%3.1f", streamExportParams.encounterGapS));
minEncounterCalls.setText(String.format("%d", streamExportParams.minEncounterCount));
separateChannels.setSelected(streamExportParams.separateChannels);
groupChannels.setSelected(streamExportParams.separateChannels == false);
newDataSelection();
enableControls();
}