Commit 54768777 authored by Matija Obreza's avatar Matija Obreza

PDCIStatistics for FaoInstitute

parent 5732b972
...@@ -24,6 +24,7 @@ import javax.persistence.FetchType; ...@@ -24,6 +24,7 @@ import javax.persistence.FetchType;
import javax.persistence.JoinColumn; import javax.persistence.JoinColumn;
import javax.persistence.OneToOne; import javax.persistence.OneToOne;
import javax.persistence.PrePersist; import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import javax.persistence.Table; import javax.persistence.Table;
import javax.persistence.Transient; import javax.persistence.Transient;
...@@ -77,6 +78,7 @@ public class PDCI extends VersionedModel { ...@@ -77,6 +78,7 @@ public class PDCI extends VersionedModel {
private int cropName = 0; private int cropName = 0;
@PrePersist @PrePersist
@PreUpdate
protected void prePersist() { protected void prePersist() {
this.score = calculateScore(); this.score = calculateScore();
this.scoreHist = (float) (Math.ceil(this.score * 2) / 2); this.scoreHist = (float) (Math.ceil(this.score * 2) / 2);
......
/**
* Copyright 2015 Global Crop Diversity Trust
*
* 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 org.genesys2.server.model.genesys;
import java.io.Serializable;
import java.util.List;
/**
* Institute PDCI statistics
*/
public class PDCIStatistics implements Serializable {
private Float min = null;
private Float max = null;
private Double avg = null;
private long[] histogram = new long[21];
private Long count;
public void setMin(Float value) {
this.min = value;
}
public Float getMin() {
return min;
}
public void setMax(Float value) {
this.max = value;
}
public Float getMax() {
return max;
}
public void setAvg(Double value) {
this.avg = value;
}
public Double getAvg() {
return avg;
}
public void setCount(Long value) {
this.count = value;
}
public Long getCount() {
return count;
}
public long[] getHistogram() {
return histogram;
}
/**
* Converts {@link #histogram} to flot.categories compatible JSON
*
* @return
*/
public String getHistogramJson() {
StringBuffer sb = new StringBuffer();
sb.append("[ ");
for (int i = 0; i < histogram.length; i++) {
if (i > 0)
sb.append(", ");
sb.append("['").append(i / 2.0).append("', ").append(histogram[i]).append("]");
}
sb.append(" ]");
return sb.toString();
}
/**
* Fill {@link #histogram} with data
*
* @param hist
*/
public void makeHistogram(List<Object[]> hist) {
for (Object[] h : hist) {
// Determining JPA data types
// System.err.println("Hist " + h[0].getClass() + " " +
// h[1].getClass());
int index = (int) (((Float) h[0]) * 2);
long count = (Long) h[1];
// System.err.println("Index for " + h[0] + " = " + index +
// " count=" + count);
histogram[index] = count;
}
}
}
...@@ -16,7 +16,10 @@ ...@@ -16,7 +16,10 @@
package org.genesys2.server.persistence.domain; package org.genesys2.server.persistence.domain;
import java.util.List;
import org.genesys2.server.model.genesys.PDCI; import org.genesys2.server.model.genesys.PDCI;
import org.genesys2.server.model.impl.FaoInstitute;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
...@@ -25,4 +28,25 @@ public interface PDCIRepository extends JpaRepository<PDCI, Long> { ...@@ -25,4 +28,25 @@ public interface PDCIRepository extends JpaRepository<PDCI, Long> {
@Query("select pdci from PDCI pdci where pdci.accession.id=?1") @Query("select pdci from PDCI pdci where pdci.accession.id=?1")
PDCI findByAccessionId(Long accessionId); PDCI findByAccessionId(Long accessionId);
/**
* Gets [ min(pdci.score), max(pdci.score), avg(pdci.score), count(pdci) ]
* for PDCI of {@link FaoInstitute}
*
* @param faoInstitute
* @return [ Float min(pdci.score), Float max(pdci.score), Double
* avg(pdci.score), Long count(pdci) ]
*/
@Query("select min(pdci.score), max(pdci.score), avg(pdci.score), count(pdci) from Accession a join a.accessionId.pdci pdci where a.institute = ?1")
Object statistics(FaoInstitute faoInstitute);
/**
* Get PDCI histogram for {@link FaoInstitute} by
* {@link PDCI#getScoreHist()}
*
* @param faoInstitute
* @return List of [ scoreHist, count ]
*/
@Query("select pdci.scoreHist, count(pdci) from Accession a join a.accessionId.pdci pdci where a.institute = ?1 group by pdci.scoreHist")
List<Object[]> histogram(FaoInstitute faoInstitute);
} }
...@@ -40,6 +40,7 @@ import org.genesys2.server.model.genesys.ExperimentTrait; ...@@ -40,6 +40,7 @@ import org.genesys2.server.model.genesys.ExperimentTrait;
import org.genesys2.server.model.genesys.Metadata; import org.genesys2.server.model.genesys.Metadata;
import org.genesys2.server.model.genesys.Method; import org.genesys2.server.model.genesys.Method;
import org.genesys2.server.model.genesys.PDCI; import org.genesys2.server.model.genesys.PDCI;
import org.genesys2.server.model.genesys.PDCIStatistics;
import org.genesys2.server.model.genesys.SvalbardData; import org.genesys2.server.model.genesys.SvalbardData;
import org.genesys2.server.model.genesys.Taxonomy2; import org.genesys2.server.model.genesys.Taxonomy2;
import org.genesys2.server.model.impl.AccessionIdentifier3; import org.genesys2.server.model.impl.AccessionIdentifier3;
...@@ -232,4 +233,6 @@ public interface GenesysService { ...@@ -232,4 +233,6 @@ public interface GenesysService {
PDCI loadPDCI(Long accessionId); PDCI loadPDCI(Long accessionId);
PDCIStatistics statisticsPDCI(FaoInstitute faoInstitute);
} }
...@@ -16,6 +16,9 @@ ...@@ -16,6 +16,9 @@
package org.genesys2.server.service; package org.genesys2.server.service;
import org.genesys2.server.model.genesys.PDCIStatistics;
import org.genesys2.server.model.impl.FaoInstitute;
public interface StatisticsService { public interface StatisticsService {
long numberOfCountries(); long numberOfCountries();
...@@ -24,4 +27,6 @@ public interface StatisticsService { ...@@ -24,4 +27,6 @@ public interface StatisticsService {
long numberOfAccessions(); long numberOfAccessions();
PDCIStatistics statisticsPDCI(FaoInstitute faoInstitute);
} }
...@@ -61,6 +61,7 @@ import org.genesys2.server.model.genesys.ExperimentTrait; ...@@ -61,6 +61,7 @@ import org.genesys2.server.model.genesys.ExperimentTrait;
import org.genesys2.server.model.genesys.Metadata; import org.genesys2.server.model.genesys.Metadata;
import org.genesys2.server.model.genesys.Method; import org.genesys2.server.model.genesys.Method;
import org.genesys2.server.model.genesys.PDCI; import org.genesys2.server.model.genesys.PDCI;
import org.genesys2.server.model.genesys.PDCIStatistics;
import org.genesys2.server.model.genesys.SelfCopy; import org.genesys2.server.model.genesys.SelfCopy;
import org.genesys2.server.model.genesys.SvalbardData; import org.genesys2.server.model.genesys.SvalbardData;
import org.genesys2.server.model.genesys.Taxonomy2; import org.genesys2.server.model.genesys.Taxonomy2;
...@@ -1557,6 +1558,7 @@ public class GenesysServiceImpl implements GenesysService, DatasetService { ...@@ -1557,6 +1558,7 @@ public class GenesysServiceImpl implements GenesysService, DatasetService {
@Override @Override
@Transactional @Transactional
@CacheEvict(value = "statistics", allEntries = true)
public PDCI updatePDCI(Long accessionId) { public PDCI updatePDCI(Long accessionId) {
if (pdciCalculator == null) { if (pdciCalculator == null) {
return null; return null;
...@@ -1569,4 +1571,31 @@ public class GenesysServiceImpl implements GenesysService, DatasetService { ...@@ -1569,4 +1571,31 @@ public class GenesysServiceImpl implements GenesysService, DatasetService {
} }
return repoPdci.save(pdciCalculator.updatePdci(pdci, accessionId)); return repoPdci.save(pdciCalculator.updatePdci(pdci, accessionId));
} }
@Override
public PDCIStatistics statisticsPDCI(FaoInstitute faoInstitute) {
PDCIStatistics stats = new PDCIStatistics();
Object[] overall = (Object[]) repoPdci.statistics(faoInstitute);
if (overall == null) {
LOG.warn("No PDCI statistics for " + faoInstitute);
return null;
}
// Determining JPA data types
// System.err.println(overall[0].getClass());
// System.err.println(overall[1].getClass());
// System.err.println(overall[2].getClass());
// System.err.println(overall[3].getClass());
stats.setMin((Float) overall[0]);
stats.setMax((Float) overall[1]);
stats.setAvg((Double) overall[2]);
stats.setCount((Long) overall[3]);
List<Object[]> hist = repoPdci.histogram(faoInstitute);
stats.makeHistogram(hist);
return stats;
}
} }
...@@ -16,6 +16,10 @@ ...@@ -16,6 +16,10 @@
package org.genesys2.server.service.impl; package org.genesys2.server.service.impl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.genesys2.server.model.genesys.PDCIStatistics;
import org.genesys2.server.model.impl.FaoInstitute;
import org.genesys2.server.service.GenesysService; import org.genesys2.server.service.GenesysService;
import org.genesys2.server.service.GeoService; import org.genesys2.server.service.GeoService;
import org.genesys2.server.service.InstituteService; import org.genesys2.server.service.InstituteService;
...@@ -28,6 +32,8 @@ import org.springframework.transaction.annotation.Transactional; ...@@ -28,6 +32,8 @@ import org.springframework.transaction.annotation.Transactional;
@Service @Service
@Transactional(readOnly = true) @Transactional(readOnly = true)
public class StatisticsServiceImpl implements StatisticsService { public class StatisticsServiceImpl implements StatisticsService {
public static final Log LOG = LogFactory.getLog(StatisticsServiceImpl.class);
@Autowired @Autowired
private GeoService geoService; private GeoService geoService;
...@@ -54,4 +60,13 @@ public class StatisticsServiceImpl implements StatisticsService { ...@@ -54,4 +60,13 @@ public class StatisticsServiceImpl implements StatisticsService {
public long numberOfAccessions() { public long numberOfAccessions() {
return genesysService.countAll(); return genesysService.countAll();
} }
@Override
@Cacheable(unless = "#result == null", value = "statistics", key = "'stats.' + #root.methodName + '-' + #faoInstitute.id")
public PDCIStatistics statisticsPDCI(FaoInstitute faoInstitute) {
if (LOG.isInfoEnabled()) {
LOG.info("Regenerating PDCI statistics for " + faoInstitute);
}
return genesysService.statisticsPDCI(faoInstitute);
}
} }
...@@ -94,12 +94,6 @@ public class ElasticUpdater { ...@@ -94,12 +94,6 @@ public class ElasticUpdater {
* @param ids * @param ids
*/ */
public void update(Class<?> clazz, Long id) { public void update(Class<?> clazz, Long id) {
// If Accession, update PDCI
if (Accession.class.equals(clazz) && id !=null) {
genesysService.updatePDCI(id);
}
ElasticNode node = new ElasticNode(clazz, id); ElasticNode node = new ElasticNode(clazz, id);
elasticRemoveQueue.remove(node); elasticRemoveQueue.remove(node);
......
...@@ -8,7 +8,9 @@ import javax.annotation.Resource; ...@@ -8,7 +8,9 @@ import javax.annotation.Resource;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.genesys2.server.model.genesys.Accession;
import org.genesys2.server.service.ElasticService; import org.genesys2.server.service.ElasticService;
import org.genesys2.server.service.GenesysService;
import org.genesys2.server.service.worker.ElasticUpdater.ElasticNode; import org.genesys2.server.service.worker.ElasticUpdater.ElasticNode;
import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
...@@ -41,6 +43,9 @@ class ElasticUpdaterProcessor implements Runnable, InitializingBean, DisposableB ...@@ -41,6 +43,9 @@ class ElasticUpdaterProcessor implements Runnable, InitializingBean, DisposableB
@Resource @Resource
private IQueue<ElasticNode> elasticUpdateQueue; private IQueue<ElasticNode> elasticUpdateQueue;
@Autowired
private GenesysService genesysService;
private long indexDelay = 5000; private long indexDelay = 5000;
private HashMap<String, Set<Long>> buckets = new HashMap<String, Set<Long>>(); private HashMap<String, Set<Long>> buckets = new HashMap<String, Set<Long>>();
...@@ -130,6 +135,12 @@ class ElasticUpdaterProcessor implements Runnable, InitializingBean, DisposableB ...@@ -130,6 +135,12 @@ class ElasticUpdaterProcessor implements Runnable, InitializingBean, DisposableB
return; return;
String className = toUpdate.getClassName(); String className = toUpdate.getClassName();
// If Accession, update PDCI
if (Accession.class.getName().equals(className)) {
genesysService.updatePDCI(toUpdate.getId());
}
Set<Long> bucket = buckets.get(className); Set<Long> bucket = buckets.get(className);
if (bucket == null) { if (bucket == null) {
buckets.put(className, bucket = new HashSet<Long>()); buckets.put(className, bucket = new HashSet<Long>());
......
...@@ -30,6 +30,7 @@ import org.genesys2.server.service.DSService; ...@@ -30,6 +30,7 @@ import org.genesys2.server.service.DSService;
import org.genesys2.server.service.FilterConstants; import org.genesys2.server.service.FilterConstants;
import org.genesys2.server.service.GenesysService; import org.genesys2.server.service.GenesysService;
import org.genesys2.server.service.InstituteService; import org.genesys2.server.service.InstituteService;
import org.genesys2.server.service.StatisticsService;
import org.genesys2.server.service.TaxonomyService; import org.genesys2.server.service.TaxonomyService;
import org.genesys2.server.service.TraitService; import org.genesys2.server.service.TraitService;
import org.genesys2.server.service.impl.NonUniqueAccessionException; import org.genesys2.server.service.impl.NonUniqueAccessionException;
...@@ -69,6 +70,9 @@ public class AccessionController extends BaseController { ...@@ -69,6 +70,9 @@ public class AccessionController extends BaseController {
@Autowired(required = false) @Autowired(required = false)
private PDCICalculator pdciCalculator; private PDCICalculator pdciCalculator;
@Autowired
private StatisticsService statisticsService;
@RequestMapping("/id/{accessionId}") @RequestMapping("/id/{accessionId}")
public String view(ModelMap model, @PathVariable(value = "accessionId") long accessionId) { public String view(ModelMap model, @PathVariable(value = "accessionId") long accessionId) {
_logger.debug("Viewing ACN " + accessionId); _logger.debug("Viewing ACN " + accessionId);
...@@ -118,6 +122,7 @@ public class AccessionController extends BaseController { ...@@ -118,6 +122,7 @@ public class AccessionController extends BaseController {
} }
model.addAttribute("pdci", pdci); model.addAttribute("pdci", pdci);
model.addAttribute("institutePDCI", statisticsService.statisticsPDCI(accession.getInstitute()));
} catch (Throwable e) { } catch (Throwable e) {
_logger.warn(e.getMessage(), e); _logger.warn(e.getMessage(), e);
......
...@@ -37,6 +37,7 @@ import org.genesys2.server.service.GenesysService; ...@@ -37,6 +37,7 @@ import org.genesys2.server.service.GenesysService;
import org.genesys2.server.service.GeoService; import org.genesys2.server.service.GeoService;
import org.genesys2.server.service.InstituteService; import org.genesys2.server.service.InstituteService;
import org.genesys2.server.service.OrganizationService; import org.genesys2.server.service.OrganizationService;
import org.genesys2.server.service.StatisticsService;
import org.genesys2.server.service.TaxonomyService; import org.genesys2.server.service.TaxonomyService;
import org.genesys2.server.service.impl.FilterHandler; import org.genesys2.server.service.impl.FilterHandler;
import org.genesys2.server.service.impl.FilterHandler.AppliedFilter; import org.genesys2.server.service.impl.FilterHandler.AppliedFilter;
...@@ -83,6 +84,9 @@ public class WiewsController extends BaseController { ...@@ -83,6 +84,9 @@ public class WiewsController extends BaseController {
@Autowired @Autowired
private DownloadService downloadService; private DownloadService downloadService;
@Autowired
private StatisticsService statisticsService;
@RequestMapping("/") @RequestMapping("/")
public String view(ModelMap model, @RequestParam(value = "page", required = false, defaultValue = "1") int page) { public String view(ModelMap model, @RequestParam(value = "page", required = false, defaultValue = "1") int page) {
model.addAttribute("pagedData", instituteService.listPGRInstitutes(new PageRequest(page - 1, 50, new Sort("code")))); model.addAttribute("pagedData", instituteService.listPGRInstitutes(new PageRequest(page - 1, 50, new Sort("code"))));
...@@ -128,6 +132,7 @@ public class WiewsController extends BaseController { ...@@ -128,6 +132,7 @@ public class WiewsController extends BaseController {
model.addAttribute("statisticsGenus", genesysService.statisticsGenusByInstitute(faoInstitute, new PageRequest(0, 30))); model.addAttribute("statisticsGenus", genesysService.statisticsGenusByInstitute(faoInstitute, new PageRequest(0, 30)));
model.addAttribute("statisticsTaxonomy", genesysService.statisticsSpeciesByInstitute(faoInstitute, new PageRequest(0, 30))); model.addAttribute("statisticsTaxonomy", genesysService.statisticsSpeciesByInstitute(faoInstitute, new PageRequest(0, 30)));
model.addAttribute("statisticsPDCI", statisticsService.statisticsPDCI(faoInstitute));
return "/wiews/details"; return "/wiews/details";
} }
......
...@@ -622,7 +622,8 @@ admin.kpi.execution.page=KPI Execution ...@@ -622,7 +622,8 @@ admin.kpi.execution.page=KPI Execution
admin.kpi.executionrun.page=Execution run details admin.kpi.executionrun.page=Execution run details
accession.pdci=Passport Data Completeness Index accession.pdci=Passport Data Completeness Index
accession.pdci.jumbo=PDCI Score: {0} of 10.0 accession.pdci.jumbo=PDCI Score: {0,number,0.00} of 10.0
accession.pdci.institute-avg=Average PDCI score for this institute is {0,number,0.00}
accession.pdci.about-link=Read about Passport Data Completeness Index accession.pdci.about-link=Read about Passport Data Completeness Index
accession.pdci.independent-items=Independent of the population type accession.pdci.independent-items=Independent of the population type
accession.pdci.dependent-items=Depending on the population type accession.pdci.dependent-items=Depending on the population type
......
...@@ -11,7 +11,7 @@ var GenesysMaps = { ...@@ -11,7 +11,7 @@ var GenesysMaps = {
this.lng = lng; this.lng = lng;
this.noWrap = true; this.noWrap = true;
}, },
loaded : false, loaded : false,
queue : [], queue : [],
loadedMaps : [], loadedMaps : [],
...@@ -89,6 +89,27 @@ GenesysMaps.BoundingBox.prototype.getBounds = function() { ...@@ -89,6 +89,27 @@ GenesysMaps.BoundingBox.prototype.getBounds = function() {
}; };
var GenesysChart = { var GenesysChart = {
histogram : function(placeholder, data) {
$.plot(placeholder, [ {
data : data,
color : '#88ba42'
} ], {
series : {
bars : {
show : true,
barWidth : 0.4,
fill : 1,
lineWidth : 0,
align : 'center'
}
},
xaxis : {
tickLength : 0
}
});
},
chart : function(placeholder, url, options, labelCallback, clickCallback) { chart : function(placeholder, url, options, labelCallback, clickCallback) {
var defaultOptions = { var defaultOptions = {
...@@ -328,7 +349,7 @@ var GenesysFilterUtil = { ...@@ -328,7 +349,7 @@ var GenesysFilterUtil = {
fe.toggleClass('edit-filter'); fe.toggleClass('edit-filter');
fe.find('.filter-values').parent().toggleClass('col-lg-9').toggleClass('col-lg-4'); fe.find('.filter-values').parent().toggleClass('col-lg-9').toggleClass('col-lg-4');
}, },
normKey: function(key) { normKey : function(key) {
return key.replace(/\./g, '-').replace(/:/g, '_'); return key.replace(/\./g, '-').replace(/:/g, '_');
} }
}; };
......
...@@ -645,7 +645,27 @@ ...@@ -645,7 +645,27 @@
<security:authorize access="isAuthenticated()"> <security:authorize access="isAuthenticated()">
<c:if test="${pdci ne null}"> <c:if test="${pdci ne null}">
<local:pdci value="${pdci}" /> <div class="crop-details">
<h4>
<spring:message code="accession.pdci" />
</h4>
<div class="jumbotron pdci-score">
<div>
<h3>
<spring:message code="accession.pdci.jumbo" arguments="${pdci.score}" />
</h3>
<small> <c:if test="${institutePDCI ne null}">
<spring:message code="accession.pdci.institute-avg" arguments="${institutePDCI.avg}" />
</c:if> <a href="<c:url value="/content/passport-data-completeness-index" />"><spring:message
code="accession.pdci.about-link"
/></a></small>
</div>
</div>
<local:pdci value="${pdci}" />
</div>
</c:if> </c:if>
</security:authorize>