Species info

Sort out of species info which hopefully now deals with all
eventualities.
This commit is contained in:
Douglas Gillespie 2023-08-29 11:53:40 +01:00
parent 74deebe446
commit 07ced6ae6d
11 changed files with 150 additions and 45 deletions

View File

@ -3,7 +3,8 @@ package RightWhaleEdgeDetector.species;
import PamguardMVC.PamDataBlock; import PamguardMVC.PamDataBlock;
import RightWhaleEdgeDetector.RWEDataUnit; import RightWhaleEdgeDetector.RWEDataUnit;
import tethys.species.DataBlockSpeciesManager; import tethys.species.DataBlockSpeciesManager;
import tethys.species.DataBlockSpeciesTypes; import tethys.species.DataBlockSpeciesCodes;
import tethys.species.SpeciesMapItem;
public class RWSpeciesManager extends DataBlockSpeciesManager<RWEDataUnit> { public class RWSpeciesManager extends DataBlockSpeciesManager<RWEDataUnit> {
@ -11,15 +12,16 @@ public class RWSpeciesManager extends DataBlockSpeciesManager<RWEDataUnit> {
public RWSpeciesManager(PamDataBlock<RWEDataUnit> dataBlock) { public RWSpeciesManager(PamDataBlock<RWEDataUnit> dataBlock) {
super(dataBlock); super(dataBlock);
setDefaultDefaultSpecies(new SpeciesMapItem(RWSpeciesTypes.eubalaena, RWSpeciesTypes.onlyType, RWSpeciesTypes.defaultName));
} }
@Override @Override
public DataBlockSpeciesTypes getSpeciesTypes() { public DataBlockSpeciesCodes getSpeciesCodes() {
return rwSpeciesTypes; return null;
} }
@Override @Override
public String getSpeciesString(RWEDataUnit dataUnit) { public String getSpeciesCode(RWEDataUnit dataUnit) {
return RWSpeciesTypes.onlyType; return RWSpeciesTypes.onlyType;
} }

View File

@ -1,15 +1,17 @@
package RightWhaleEdgeDetector.species; package RightWhaleEdgeDetector.species;
import tethys.species.DataBlockSpeciesTypes; import tethys.species.DataBlockSpeciesCodes;
public class RWSpeciesTypes extends DataBlockSpeciesTypes { public class RWSpeciesTypes extends DataBlockSpeciesCodes {
public static final String onlyType = "Up call"; public static final String onlyType = "Up call";
private static final int glacialis = 180536; public static final int eubalaena = 180536;
public static final String defaultName = "Right Whale";
public RWSpeciesTypes() { public RWSpeciesTypes() {
super(glacialis, onlyType); super(eubalaena, defaultName, onlyType);
} }
} }

View File

@ -4,7 +4,7 @@ import clickDetector.ClickControl;
import clickDetector.ClickDataBlock; import clickDetector.ClickDataBlock;
import clickDetector.ClickDetection; import clickDetector.ClickDetection;
import tethys.species.DataBlockSpeciesManager; import tethys.species.DataBlockSpeciesManager;
import tethys.species.DataBlockSpeciesTypes; import tethys.species.DataBlockSpeciesCodes;
import tethys.species.ITISTypes; import tethys.species.ITISTypes;
import tethys.species.SpeciesMapItem; import tethys.species.SpeciesMapItem;
@ -16,11 +16,11 @@ public class ClickBlockSpeciesManager extends DataBlockSpeciesManager<ClickDetec
super(clickDataBlock); super(clickDataBlock);
this.clickControl = clickControl; this.clickControl = clickControl;
setDefaultDefaultSpecies(new SpeciesMapItem(ITISTypes.UNKNOWN, "Unknown", "Unknown")); setDefaultDefaultSpecies(new SpeciesMapItem(ITISTypes.UNKNOWN, "Unknown", "Unknown"));
setDefaultName("Unknown"); setDefaultSpeciesCode("Unknown");
} }
@Override @Override
public DataBlockSpeciesTypes getSpeciesTypes() { public DataBlockSpeciesCodes getSpeciesCodes() {
ClickTypeMasterManager masterManager = clickControl.getClickTypeMasterManager(); ClickTypeMasterManager masterManager = clickControl.getClickTypeMasterManager();
if (masterManager == null) { if (masterManager == null) {
return null; return null;
@ -28,16 +28,16 @@ public class ClickBlockSpeciesManager extends DataBlockSpeciesManager<ClickDetec
String[] speciesList = masterManager.getSpeciesList(); String[] speciesList = masterManager.getSpeciesList();
// add the default // add the default
String[] fullList = new String[speciesList.length+1]; String[] fullList = new String[speciesList.length+1];
fullList[0] = getDefaultName(); fullList[0] = getDefaultSpeciesCode();
for (int i = 0; i < speciesList.length; i++) { for (int i = 0; i < speciesList.length; i++) {
fullList[i+1] = speciesList[i]; fullList[i+1] = speciesList[i];
} }
return new DataBlockSpeciesTypes("Click", fullList); return new DataBlockSpeciesCodes("Click", fullList);
} }
@Override @Override
public String getSpeciesString(ClickDetection dataUnit) { public String getSpeciesCode(ClickDetection dataUnit) {
ClickTypeMasterManager masterManager = clickControl.getClickTypeMasterManager(); ClickTypeMasterManager masterManager = clickControl.getClickTypeMasterManager();
if (masterManager == null) { if (masterManager == null) {
return null; return null;

View File

@ -382,7 +382,7 @@ public class PamVector implements Serializable, Cloneable, PamCoordinate, Manage
* @return magnitude of those dimensions only. * @return magnitude of those dimensions only.
*/ */
public double norm(int nDim) { public double norm(int nDim) {
return Math.sqrt(normSquared(2)); return Math.sqrt(normSquared(nDim));
} }
/** /**
* *

View File

@ -9,11 +9,12 @@ import java.util.ArrayList;
* @author dg50 * @author dg50
* *
*/ */
public class DataBlockSpeciesTypes { public class DataBlockSpeciesCodes {
/** /**
* List of species names / codes associated with this data block. These can be translated, * List of species names / codes associated with this data block. These can be translated,
* via a HashMap to more detailed objects which include an ITIS code. * via a HashMap to more detailed objects which include an ITIS code.
* These are the internal codes of each detector - whatever it uses.
*/ */
private ArrayList<String> speciesNames; private ArrayList<String> speciesNames;
@ -31,7 +32,7 @@ public class DataBlockSpeciesTypes {
/** /**
* @param defaultType * @param defaultType
*/ */
public DataBlockSpeciesTypes(String defaultType) { public DataBlockSpeciesCodes(String defaultType) {
this.defaultType = defaultType; this.defaultType = defaultType;
} }
@ -39,8 +40,10 @@ public class DataBlockSpeciesTypes {
* @param itisDefault * @param itisDefault
* @param defaultType * @param defaultType
*/ */
public DataBlockSpeciesTypes(int itisDefault, String defaultType) { public DataBlockSpeciesCodes(int itisDefault, String defaultName, String defaultType) {
this.itisDefault = itisDefault; this.itisDefault = itisDefault;
speciesNames = new ArrayList<>();
speciesNames.add(defaultName);
this.defaultType = defaultType; this.defaultType = defaultType;
} }
@ -48,7 +51,7 @@ public class DataBlockSpeciesTypes {
* constructor to use with a array of String names. * constructor to use with a array of String names.
* @param speciesList * @param speciesList
*/ */
public DataBlockSpeciesTypes(String defaultType, String[] speciesList) { public DataBlockSpeciesCodes(String defaultType, String[] speciesList) {
this.defaultType = defaultType; this.defaultType = defaultType;
if (speciesList == null) { if (speciesList == null) {
speciesNames = new ArrayList<>(); speciesNames = new ArrayList<>();

View File

@ -1,5 +1,7 @@
package tethys.species; package tethys.species;
import java.util.ArrayList;
import PamController.PamController; import PamController.PamController;
import PamguardMVC.PamDataBlock; import PamguardMVC.PamDataBlock;
import PamguardMVC.PamDataUnit; import PamguardMVC.PamDataUnit;
@ -7,31 +9,86 @@ import tethys.species.swing.DataBlockSpeciesDialog;
/** /**
* Manage species conversion for a single datablock. * Manage species conversion for a single datablock.
*
* there seem to be three types of manager:<br>
* 1. Datablocks which have a totally free list of species codes, such as the click detector, or whistle classifier <br>
* 1a. A slight variation on this is blocks which have a list and also a default for data units which aren't classified.<br>
* 2. Datablocks which have a single type which may be unknown or partially known, but we want the possibility of overriding it.
* e.g. the whistle detector may default to odontocete, but may be overridden to a mystecete species.<br>
* 3. Datablocks with no information, or where the list from (1.) is empty. <p>
* In all cases, we need to handle this reasonably sensibly. The code list is always the start of this and must
* always return something, even if it's 'unknown'.
*
* @author dg50 * @author dg50
* *
*/ */
abstract public class DataBlockSpeciesManager<T extends PamDataUnit> { abstract public class DataBlockSpeciesManager<T extends PamDataUnit> {
/**
* The serialised bit. Always exists (or should be created) even if there
* are no real species, via a defaultdefaultSpecies.
*/
private DataBlockSpeciesMap datablockSpeciesMap; private DataBlockSpeciesMap datablockSpeciesMap;
private PamDataBlock<T> dataBlock; private PamDataBlock<T> dataBlock;
private String defaultName = null; /*
* Below are three ways of getting species codes. At least ONE of these
* must return something.
*/
/**
* Object that contains a list of species codes. This may be fluid
* between configurations and may change during a session, e.g. through
* the addition of a new click type or changes to the whistle classifier settings.
* @return object containing a list of species types.
*/
public abstract DataBlockSpeciesCodes getSpeciesCodes();
/**
* A default species code. Can be null, in which case it won't be used or
* can be set to something like 'Unknown'
*/
private String defaultSpeciesCode = null;
/**
* For use in detectors that have a strong default species, but no
* real list of different species codes. Can be left null.
*/
private SpeciesMapItem defaultDefaultSpecies = null; private SpeciesMapItem defaultDefaultSpecies = null;
public abstract DataBlockSpeciesTypes getSpeciesTypes();
public abstract String getSpeciesString(T dataUnit); /**
* Gets a species string for a specific data unit, This is abstracted
* since different detectors store this in non standard ways. The result of
* this should be within the set provided by getSpeciesCodes() which can then
* be used in the DataBlockSpeciesMap to look up an itis code.
* @param dataUnit
* @return A species code for a specific data unit. May be null (e.g. for an unclassified click)
*/
public abstract String getSpeciesCode(T dataUnit);
public DataBlockSpeciesManager(PamDataBlock<T> dataBlock) { public DataBlockSpeciesManager(PamDataBlock<T> dataBlock) {
super(); super();
this.dataBlock = dataBlock; this.dataBlock = dataBlock;
datablockSpeciesMap = SpeciesMapManager.getInstance().getSpeciesMap(dataBlock); datablockSpeciesMap = SpeciesMapManager.getInstance().getSpeciesMap(dataBlock);
// datablockSpeciesMap.clearMap();
clearMapNulls();
checkMapDefault();
}
/**
* Clear up some old maps which have got a null null default.
*/
private void clearMapNulls() {
SpeciesMapItem nullVal = datablockSpeciesMap.getItem(null);
if (nullVal == null) {
datablockSpeciesMap.removeItem(null);
}
} }
public SpeciesMapItem getSpeciesItem(T dataUnit) { public SpeciesMapItem getSpeciesItem(T dataUnit) {
String speciesString = getSpeciesString(dataUnit); String speciesString = getSpeciesCode(dataUnit);
if (speciesString == null) { if (speciesString == null) {
return getDefaultDefaultSpecies(); return getDefaultDefaultSpecies();
} }
@ -42,6 +99,30 @@ abstract public class DataBlockSpeciesManager<T extends PamDataUnit> {
return speciesMap.getItem(speciesString); return speciesMap.getItem(speciesString);
} }
/**
* Get all PAMGuard species codes, which may come from the DataBlockSpeciesCodes
* object, or the defaultSpeciesCode, or the defaultDefaultSpecies name. Ideally,
* at least one of these should have something, or we'll stick in an "Unknown"
* @return
*/
public ArrayList<String> getAllSpeciesCodes() {
ArrayList<String> allCodes = new ArrayList<String>();
if (defaultSpeciesCode != null) {
allCodes.add(defaultSpeciesCode);
}
if (defaultDefaultSpecies != null) {
allCodes.add(defaultDefaultSpecies.getPamguardName());
}
DataBlockSpeciesCodes codeList = getSpeciesCodes();
if (codeList != null) {
allCodes.addAll(codeList.getSpeciesNames());
}
if (allCodes.size() == 0) {
allCodes.add("Unknown");
}
return allCodes;
}
public DataBlockSpeciesMap getDatablockSpeciesMap() { public DataBlockSpeciesMap getDatablockSpeciesMap() {
if (datablockSpeciesMap == null) { if (datablockSpeciesMap == null) {
datablockSpeciesMap = new DataBlockSpeciesMap(); datablockSpeciesMap = new DataBlockSpeciesMap();
@ -51,9 +132,16 @@ abstract public class DataBlockSpeciesManager<T extends PamDataUnit> {
} }
private void checkMapDefault() { private void checkMapDefault() {
SpeciesMapItem defaultItem = datablockSpeciesMap.getItem(getDefaultName()); // SpeciesMapItem defaultItem = datablockSpeciesMap.getItem(getDefaultSpeciesCode());
// if (defaultItem == null) {
// datablockSpeciesMap.putItem(getDefaultSpeciesCode(), getDefaultDefaultSpecies());
// }
if (defaultDefaultSpecies == null) {
return;
}
SpeciesMapItem defaultItem = datablockSpeciesMap.getItem(defaultDefaultSpecies.getPamguardName());
if (defaultItem == null) { if (defaultItem == null) {
datablockSpeciesMap.putItem(getDefaultName(), getDefaultDefaultSpecies()); datablockSpeciesMap.putItem(defaultDefaultSpecies.getPamguardName(), defaultDefaultSpecies);
} }
} }
@ -84,19 +172,20 @@ abstract public class DataBlockSpeciesManager<T extends PamDataUnit> {
*/ */
public void setDefaultDefaultSpecies(SpeciesMapItem defaultDefaultSpecies) { public void setDefaultDefaultSpecies(SpeciesMapItem defaultDefaultSpecies) {
this.defaultDefaultSpecies = defaultDefaultSpecies; this.defaultDefaultSpecies = defaultDefaultSpecies;
checkMapDefault();
} }
/** /**
* @return the defaultName * @return the defaultName
*/ */
public String getDefaultName() { public String getDefaultSpeciesCode() {
return defaultName; return defaultSpeciesCode;
} }
/** /**
* @param defaultName the defaultName to set * @param defaultName the defaultName to set
*/ */
public void setDefaultName(String defaultName) { public void setDefaultSpeciesCode(String defaultName) {
this.defaultName = defaultName; this.defaultSpeciesCode = defaultName;
} }
} }

View File

@ -4,7 +4,10 @@ import java.io.Serializable;
import java.util.HashMap; import java.util.HashMap;
/** /**
* Species map for a specified data block * Species map for a specified data block <p>
* This is the bit that can be serialised, and is primarily (only) a hash table of
* SpeciesMapItems which relate String species codes for a detector to more
* details itis and scientific name information.
* @author dg50 * @author dg50
* *
*/ */
@ -34,4 +37,8 @@ public class DataBlockSpeciesMap implements Serializable {
speciesTable.remove(key); speciesTable.remove(key);
} }
public void clearMap() {
speciesTable.clear();
}
} }

View File

@ -129,9 +129,9 @@ public class SpeciesTest {
private void runJson() { private void runJson() {
// String jQ = "{\"return\":[\"Deployment\"],\"select\":[{\"op\":\"=\",\"operands\":[\"Deployment/Project\",\"DCLDE2022\"],\"optype\":\"binary\"}],\"enclose\":1}"; // String jQ = "{\"return\":[\"Deployment\"],\"select\":[{\"op\":\"=\",\"operands\":[\"Deployment/Project\",\"DCLDE2022\"],\"optype\":\"binary\"}],\"enclose\":1}";
// String jQ = "{\"return\":[\"ranks/rank\"],\"select\":[{\"op\":\"=\",\"operands\":[\"ranks/rank/tsn\",\"180488\"],\"optype\":\"binary\"}],\"enclose\":1}"; // String jQ = "{\"return\":[\"ranks/rank\"],\"select\":[{\"op\":\"=\",\"operands\":[\"ranks/rank/tsn\",\"180488\"],\"optype\":\"binary\"}],\"enclose\":1}";
String jQ = "{\"return\":[\"ranks/rank\"],\"select\":[{\"op\":\"=\",\"operands\":[\"ranks/rank/tsn\",\"180488\"],\"optype\":\"binary\"}],\"enclose\":1}"; // String jQ = "{\"return\":[\"ranks/rank\"],\"select\":[{\"op\":\"=\",\"operands\":[\"ranks/rank/tsn\",\"180488\"],\"optype\":\"binary\"}],\"enclose\":1}";
// String jQ = "{\"return\":[\"ranks/rank\"],\"select\":[{\"op\":\"=\",\"operands\":[\"ranks/rank/completename\",\"Physeter macrocephalus\"],\"optype\":\"binary\"}],\"enclose\":1}"; // String jQ = "{\"return\":[\"ranks/rank\"],\"select\":[{\"op\":\"=\",\"operands\":[\"ranks/rank/completename\",\"Physeter macrocephalus\"],\"optype\":\"binary\"}],\"enclose\":1}";
// String jQ = "{\"return\":[\"ranks/rank\"],\"select\":[{\"op\":\"dbxml:contains\",\"operands\":[\"ranks/rank/completename\",\"Sperm\"],\"optype\":\"function\"}],\"enclose\":1}"; String jQ = "{\"return\":[\"ranks/rank\"],\"select\":[{\"op\":\"dbxml:contains\",\"operands\":[\"ranks/rank/completename\",\"Sperm\"],\"optype\":\"function\"}],\"enclose\":1}";
System.out.println(jQ); System.out.println(jQ);

View File

@ -12,7 +12,7 @@ import PamView.dialog.PamDialogPanel;
import PamguardMVC.PamDataBlock; import PamguardMVC.PamDataBlock;
import tethys.species.DataBlockSpeciesManager; import tethys.species.DataBlockSpeciesManager;
import tethys.species.DataBlockSpeciesMap; import tethys.species.DataBlockSpeciesMap;
import tethys.species.DataBlockSpeciesTypes; import tethys.species.DataBlockSpeciesCodes;
import tethys.species.SpeciesMapItem; import tethys.species.SpeciesMapItem;
public class DataBlockSpeciesPanel implements PamDialogPanel { public class DataBlockSpeciesPanel implements PamDialogPanel {
@ -46,8 +46,8 @@ public class DataBlockSpeciesPanel implements PamDialogPanel {
subPanels.clear(); subPanels.clear();
DataBlockSpeciesManager speciesManager = dataBlock.getDatablockSpeciesManager(); DataBlockSpeciesManager speciesManager = dataBlock.getDatablockSpeciesManager();
DataBlockSpeciesTypes speciesTypes = speciesManager.getSpeciesTypes(); // DataBlockSpeciesCodes speciesTypes = speciesManager.getSpeciesCodes();
ArrayList<String> speciesNames = speciesTypes.getSpeciesNames(); ArrayList<String> speciesNames = speciesManager.getAllSpeciesCodes();
DataBlockSpeciesMap speciesMap = speciesManager.getDatablockSpeciesMap(); DataBlockSpeciesMap speciesMap = speciesManager.getDatablockSpeciesMap();
for (String aSpecies : speciesNames) { for (String aSpecies : speciesNames) {
SpeciesSubPanel subPanel = new SpeciesSubPanel(aSpecies); SpeciesSubPanel subPanel = new SpeciesSubPanel(aSpecies);

View File

@ -139,7 +139,7 @@ public class SpeciesSubPanel {
tsn = Integer.valueOf(itisCode.getText()); tsn = Integer.valueOf(itisCode.getText());
} }
catch (NumberFormatException e) { catch (NumberFormatException e) {
PamDialog.showWarning(PamController.getMainFrame(), pamguardName.getText(), "You must specified an ITIS taxanomic code"); PamDialog.showWarning(PamController.getMainFrame(), pamguardName.getText(), "You must specify an ITIS taxanomic code");
return null; return null;
} }
latin = latinName.getText(); latin = latinName.getText();
@ -149,7 +149,8 @@ public class SpeciesSubPanel {
PamDialog.showWarning(PamController.getMainFrame(), pamguardName.getText(), "You must specified a call type"); PamDialog.showWarning(PamController.getMainFrame(), pamguardName.getText(), "You must specified a call type");
return null; return null;
} }
return new SpeciesMapItem(tsn, callType, pamguardName.getText(), latin, vernacular); String pamName = pamguardName.getText().replace("\"", "");
return new SpeciesMapItem(tsn, callType, pamName, latin, vernacular);
} }
} }

View File

@ -3,7 +3,7 @@ package whistlesAndMoans.species;
import PamguardMVC.PamDataBlock; import PamguardMVC.PamDataBlock;
import PamguardMVC.PamDataUnit; import PamguardMVC.PamDataUnit;
import tethys.species.DataBlockSpeciesManager; import tethys.species.DataBlockSpeciesManager;
import tethys.species.DataBlockSpeciesTypes; import tethys.species.DataBlockSpeciesCodes;
import tethys.species.ITISTypes; import tethys.species.ITISTypes;
import tethys.species.SpeciesMapItem; import tethys.species.SpeciesMapItem;
import whistlesAndMoans.ConnectedRegionDataUnit; import whistlesAndMoans.ConnectedRegionDataUnit;
@ -15,19 +15,20 @@ public class WhistleSpeciesManager extends DataBlockSpeciesManager<ConnectedRegi
public WhistleSpeciesManager(PamDataBlock<ConnectedRegionDataUnit> dataBlock) { public WhistleSpeciesManager(PamDataBlock<ConnectedRegionDataUnit> dataBlock) {
super(dataBlock); super(dataBlock);
setDefaultDefaultSpecies(new SpeciesMapItem(180404, "Tonal", "Odontocete")); setDefaultDefaultSpecies(new SpeciesMapItem(180404, "Tonal", "Tonal"));
} }
@Override @Override
public DataBlockSpeciesTypes getSpeciesTypes() { public DataBlockSpeciesCodes getSpeciesCodes() {
String spList[] = {"Unknown"}; // String spList[] = {"Unknown"};
//
DataBlockSpeciesTypes whistleSpeciesTypes = new DataBlockSpeciesTypes("Tonal", spList); // DataBlockSpeciesCodes whistleSpeciesTypes = new DataBlockSpeciesCodes("Tonal", spList);
return whistleSpeciesTypes; // return whistleSpeciesTypes;
return null;
} }
@Override @Override
public String getSpeciesString(ConnectedRegionDataUnit dataUnit) { public String getSpeciesCode(ConnectedRegionDataUnit dataUnit) {
return defaultName; return defaultName;
} }