Difference between revisions of "How-to Implement Algorithms for the Statistical Manager"
Line 202: | Line 202: | ||
= Complete Example with multiple output = | = Complete Example with multiple output = | ||
<source lang="java"> | <source lang="java"> | ||
− | public class | + | public class AbsoluteSpeciesBarChartsAlgorithm extends |
− | + | StandardLocalExternalAlgorithm { | |
− | + | LinkedHashMap<String, StatisticalType> map = new LinkedHashMap<String, StatisticalType>(); | |
− | + | static String databaseName = "DatabaseName"; | |
− | static String | + | |
static String userParameterName = "DatabaseUserName"; | static String userParameterName = "DatabaseUserName"; | ||
static String passwordParameterName = "DatabasePassword"; | static String passwordParameterName = "DatabasePassword"; | ||
− | + | static String urlParameterName = "DatabaseURL"; | |
− | + | private String firstSpeciesNumber="Species# :"; | |
− | + | private String yearStart="Starting year :"; | |
− | + | private String yearEnd="Ending year :"; | |
− | + | private int speciesNumber; | |
private DefaultCategoryDataset defaultcategorydataset; | private DefaultCategoryDataset defaultcategorydataset; | ||
− | |||
− | |||
− | |||
@Override | @Override | ||
public void init() throws Exception { | public void init() throws Exception { | ||
− | AnalysisLogger.getLogger().debug("Initialization"); | + | AnalysisLogger.getLogger().debug("Initialization"); |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
} | } | ||
@Override | @Override | ||
public String getDescription() { | public String getDescription() { | ||
− | + | return "Algorithm returning bar chart of most observed species in a specific years range (with respect to the OBIS database)"; | |
− | return | + | |
} | } | ||
@Override | @Override | ||
protected void process() throws Exception { | protected void process() throws Exception { | ||
− | String | + | defaultcategorydataset = new DefaultCategoryDataset(); |
+ | String driverName = "org.postgresql.Driver"; | ||
+ | String tmp=getInputParameter(firstSpeciesNumber); | ||
+ | speciesNumber = Integer.parseInt(tmp); | ||
+ | Class driverClass = Class.forName(driverName); | ||
+ | Driver driver = (Driver) driverClass.newInstance(); | ||
String databaseJdbc = getInputParameter(urlParameterName); | String databaseJdbc = getInputParameter(urlParameterName); | ||
+ | String year_start = getInputParameter(yearStart); | ||
+ | String year_end = getInputParameter(yearEnd); | ||
+ | |||
String databaseUser = getInputParameter(userParameterName); | String databaseUser = getInputParameter(userParameterName); | ||
String databasePwd = getInputParameter(passwordParameterName); | String databasePwd = getInputParameter(passwordParameterName); | ||
− | + | Connection connection = null; | |
connection = DriverManager.getConnection(databaseJdbc, databaseUser, | connection = DriverManager.getConnection(databaseJdbc, databaseUser, | ||
databasePwd); | databasePwd); | ||
Statement stmt = connection.createStatement(); | Statement stmt = connection.createStatement(); | ||
− | String query = "SELECT | + | String query = "SELECT tname, sum(count)AS count FROM public.count_species_per_year WHERE year::integer >=" |
− | + | + | + year_start |
+ | + "AND year::integer <=" | ||
+ | + year_end | ||
+ | + "GROUP BY tname ORDER BY count desc;"; | ||
ResultSet rs = stmt.executeQuery(query); | ResultSet rs = stmt.executeQuery(query); | ||
int i =0; | int i =0; | ||
String s = "Species"; | String s = "Species"; | ||
− | while (rs.next()) { | + | while (rs.next()&& i<speciesNumber) { |
− | + | ||
− | String count = rs.getString(" | + | String tname = rs.getString("tname"); |
+ | String count = rs.getString("count"); | ||
int countOcc=Integer.parseInt(count); | int countOcc=Integer.parseInt(count); | ||
− | PrimitiveType val = new PrimitiveType(String.class.getName(), count, PrimitiveTypes.STRING, | + | PrimitiveType val = new PrimitiveType(String.class.getName(), count, PrimitiveTypes.STRING, tname, tname); |
− | map.put( | + | map.put(tname, val); |
if(i<16) | if(i<16) | ||
− | defaultcategorydataset.addValue(countOcc,s, | + | defaultcategorydataset.addValue(countOcc,s,tname); |
else | else | ||
break; | break; | ||
Line 266: | Line 266: | ||
} | } | ||
connection.close(); | connection.close(); | ||
+ | |||
+ | |||
} | } | ||
Line 271: | Line 273: | ||
@Override | @Override | ||
protected void setInputParameters() { | protected void setInputParameters() { | ||
− | addStringInput( | + | addStringInput(firstSpeciesNumber, |
+ | "Number of shown species", "10"); | ||
+ | addStringInput(yearStart, "Starting year of observations", | ||
+ | "1800"); | ||
+ | addStringInput(yearEnd, "Ending year of observations", "2020"); | ||
addRemoteDatabaseInput("Obis2Repository", urlParameterName, | addRemoteDatabaseInput("Obis2Repository", urlParameterName, | ||
userParameterName, passwordParameterName, "driver", "dialect"); | userParameterName, passwordParameterName, "driver", "dialect"); | ||
Line 280: | Line 286: | ||
@Override | @Override | ||
public void shutdown() { | public void shutdown() { | ||
− | AnalysisLogger.getLogger().debug("Shutdown"); | + | AnalysisLogger.getLogger().debug("Shutdown"); |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
} | } | ||
+ | |||
+ | |||
@Override | @Override | ||
public StatisticalType getOutput() { | public StatisticalType getOutput() { | ||
Line 314: | Line 316: | ||
return output; | return output; | ||
} | } | ||
+ | |||
+ | } | ||
+ | |||
Revision as of 13:44, 21 June 2013
Contents
Prerequisites
IDE: Eclipse Java EE IDE for Web Developers. Version: 3.7+
Step by Step
Let's start creating a project using the eclipse IDE that is mavenized. After having mavenized the project in eclipse you have to put dependencies.
Maven coordinates
The maven artifact coordinates are:
<dependency> <groupId>org.gcube.dataanalysis</groupId> <artifactId>ecological-engine</artifactId> <version>1.6.1-SNAPSHOT</version> </dependency>
Let's start creating a new call which implements basic algorithm; it will be executed by Statistical Manager.
Next step is to extend basic interface StandardLocalExternalAlgorithm
.
The following snippet shows unimplemented interface methods that we are going to fulfill.
public class SimpleAlgorithm extends StandardLocalExternalAlgorithm{ @Override public void init() throws Exception { // TODO Auto-generated method stub } @Override public String getDescription() { // TODO Auto-generated method stub return null; } @Override protected void process() throws Exception { // TODO Auto-generated method stub } @Override protected void setInputParameters() { // TODO Auto-generated method stub } @Override public void shutdown() { // TODO Auto-generated method stub } @Override public StatisticalType getOutput() { return null; } }
The init()
is the initialization method. In this simple example we need to initialize log and we use logger from ecological engine library. In case algorithm uses database, we have to open its connection in this method.
The shutdown()
closes database connection.
In the getDescription()
method we add a simple description for the algorithm.
Customize input visualization
String input parameters
User input is obtained calling from setInputParameters()
the method addStringInput with following parameters:
- name of the variable ;
- description for the variable;
- default value;
User input is retrieved using getInputParameter()
passing name used as parameter into setInputParameters()
.
protected void setInputParameters() { addStringInput(NameOfVariable, "Description", "DefaultInput"); }
The input parameter will be automatically passed by Statistical Manager to the procedure. In particular, to process method we can retrieve such parameter by name that we set in addStringInput method.
@Override protected void process() throws Exception { .... String userInputValue = getInputParameter(NameOfVariable); }
Combo box input parameter
In order to obtain a combo box we have to define enumerator that contains the possible
choice that could be selected in the combo box and you have to pass it to the method addEnumerateInput
as follow:
public enum Enum { FIRST_ENUM, SECOND_ENUM } protected void setInputParameters() { addEnumerateInput(Enum.values(), variableName, "Description", Enum.FIRST_ENUM.name()); }
addEnumerateInput
parameters are rispectivly:
- values of declared enumerator;
- name of variable used to extract value insert by user;
- description of value;
- default value visualized in comboBox
Case of algorithm use database
In order to use database it is required to call into setInputParameters()
the method addRemoteDatabaseInput()
.
An important step is to pass as first parameters the name of Runtime Resource addressing database.
Statistical manager automatically retrieves from runtime resource: url ,user and password. Into process method ,before database connection, url,user and password will be retrieve using getInputParameter
. Each of them are retrieved using the name and passing it into addRemoteDatabaseInput
as parameters.
@Override protected void setInputParameters() { ... addRemoteDatabaseInput("Obis2Repository", urlParameterName,userParameterName, passwordParameterName, "driver", "dialect"); @Override protected void process() throws Exception { ... String databaseJdbc = getInputParameter(urlParameterName); String databaseUser = getInputParameter(userParameterName); String databasePwd = getInputParameter(passwordParameterName); connection = DriverManager.getConnection(databaseJdbc, databaseUser,databasePwd); ... }
Customize output
The last step is to set and to specify output of procedure.
For this purpose we override the method getOutput()
which return StatisticalType.
First output parameter we instantiate is a PrimitiveType object that wraps a string; so, we set type as string.
We associate name and description to the output value.
We can istantiate a second output as an another PrimitiveType
We set them as a map which will keep the order of the parameter used to store both output.
We add both the output object into the map.
getOutput()
procedure which will invoke Statistical Manager to understand type of the output object and at this point in the ecological engine library the algorithm will be indexed with the name set in the file of property.
String Output
In ordert to have a string as output you have to create a PrimitiveType
as follows:
@Override public StatisticalType getOutput() { …. PrimitiveType val = new PrimitiveType(String.class.getName(), myString , PrimitiveTypes.STRING, stringName, defaultValue); return val; }
Bar Chart Output
In order to create an Histogram Chart you have to fulfill a DafaultCategoryDataser
object and use it to create chart
DefaultCategoryDataset dataset; … dataset.addValue(...); …. @Override public StatisticalType getOutput() { …. HashMap<String, Image> producedImages = new HashMap<String, Image>(); JFreeChart chart = HistogramGraph.createStaticChart(dataset); Image image = ImageTools.toImage(chart.createBufferedImage(680, 420)); producedImages.put("Species Observations", image); … }
Timeseries Chart Output
In order to create an TimeSeries Chart you have to fulfill a DafaultCategoryDataser
object and use it to create chart.
The second parameter of createStatiChart method is the format of time.
DefaultCategoryDataset dataset; … dataset.addValue(...); …. @Override public StatisticalType getOutput() { ... HashMap<String, Image> producedImages = new HashMap<String, Image>(); JFreeChart chart = TimeSeriesGraph.createStaticChart(dataset, "yyyy"); Image image = ImageTools.toImage(chart.createBufferedImage(680, 420)); producedImages.put("TimeSeries chart", image); ... }
File of property
In order to deploy algorithm we must create:
- the war of eclipse project;
- a file of property containing name used to deploy algorithm by statistical manger interface following by classpath of algorithm class.
I-marin will move the algorithm available to the statistical manager and the interface will be automatically generated.
Complete Example with multiple output
public class AbsoluteSpeciesBarChartsAlgorithm extends StandardLocalExternalAlgorithm { LinkedHashMap<String, StatisticalType> map = new LinkedHashMap<String, StatisticalType>(); static String databaseName = "DatabaseName"; static String userParameterName = "DatabaseUserName"; static String passwordParameterName = "DatabasePassword"; static String urlParameterName = "DatabaseURL"; private String firstSpeciesNumber="Species# :"; private String yearStart="Starting year :"; private String yearEnd="Ending year :"; private int speciesNumber; private DefaultCategoryDataset defaultcategorydataset; @Override public void init() throws Exception { AnalysisLogger.getLogger().debug("Initialization"); } @Override public String getDescription() { return "Algorithm returning bar chart of most observed species in a specific years range (with respect to the OBIS database)"; } @Override protected void process() throws Exception { defaultcategorydataset = new DefaultCategoryDataset(); String driverName = "org.postgresql.Driver"; String tmp=getInputParameter(firstSpeciesNumber); speciesNumber = Integer.parseInt(tmp); Class driverClass = Class.forName(driverName); Driver driver = (Driver) driverClass.newInstance(); String databaseJdbc = getInputParameter(urlParameterName); String year_start = getInputParameter(yearStart); String year_end = getInputParameter(yearEnd); String databaseUser = getInputParameter(userParameterName); String databasePwd = getInputParameter(passwordParameterName); Connection connection = null; connection = DriverManager.getConnection(databaseJdbc, databaseUser, databasePwd); Statement stmt = connection.createStatement(); String query = "SELECT tname, sum(count)AS count FROM public.count_species_per_year WHERE year::integer >=" + year_start + "AND year::integer <=" + year_end + "GROUP BY tname ORDER BY count desc;"; ResultSet rs = stmt.executeQuery(query); int i =0; String s = "Species"; while (rs.next()&& i<speciesNumber) { String tname = rs.getString("tname"); String count = rs.getString("count"); int countOcc=Integer.parseInt(count); PrimitiveType val = new PrimitiveType(String.class.getName(), count, PrimitiveTypes.STRING, tname, tname); map.put(tname, val); if(i<16) defaultcategorydataset.addValue(countOcc,s,tname); else break; i++; } connection.close(); } @Override protected void setInputParameters() { addStringInput(firstSpeciesNumber, "Number of shown species", "10"); addStringInput(yearStart, "Starting year of observations", "1800"); addStringInput(yearEnd, "Ending year of observations", "2020"); addRemoteDatabaseInput("Obis2Repository", urlParameterName, userParameterName, passwordParameterName, "driver", "dialect"); } @Override public void shutdown() { AnalysisLogger.getLogger().debug("Shutdown"); } @Override public StatisticalType getOutput() { PrimitiveType p = new PrimitiveType(Map.class.getName(), PrimitiveType.stringMap2StatisticalMap(outputParameters), PrimitiveTypes.MAP, "Discrepancy Analysis",""); AnalysisLogger.getLogger().debug("MapsComparator: Producing Gaussian Distribution for the errors"); //build image: HashMap<String, Image> producedImages = new HashMap<String, Image>(); JFreeChart chart = HistogramGraph.createStaticChart(defaultcategorydataset); Image image = ImageTools.toImage(chart.createBufferedImage(680, 420)); producedImages.put("Species Observations", image); PrimitiveType images = new PrimitiveType(HashMap.class.getName(), producedImages, PrimitiveTypes.IMAGES, "ErrorRepresentation", "Graphical representation of the error spread"); //end build image AnalysisLogger.getLogger().debug("Bar Charts Species Occurrences Produced"); //collect all the outputs map.put("Result", p); map.put("Images", images); //generate a primitive type for the collection PrimitiveType output = new PrimitiveType(HashMap.class.getName(), map, PrimitiveTypes.MAP, "ResultsMap", "Results Map"); return output; } } }