Cumulative publications graph
This commit is contained in:
parent
5449579543
commit
9e2f8439ef
5 changed files with 275 additions and 16 deletions
|
@ -0,0 +1,144 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.visualization.personpubcount;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.AuthorizationRequest;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.visualization.exceptions.MalformedQueryParametersException;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Activity;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.visualization.visutils.QueryRunner;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.visualization.visutils.VisualizationRequestHandler;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.jena.query.Dataset;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
public class CumulativeCountRequestHandler implements VisualizationRequestHandler {
|
||||||
|
@Override
|
||||||
|
public AuthorizationRequest getRequiredPrivileges() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseValues generateStandardVisualization(VitroRequest vitroRequest, Log log, Dataset dataSource) throws MalformedQueryParametersException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseValues generateVisualizationForShortURLRequests(Map<String, String> parameters, VitroRequest vitroRequest, Log log, Dataset dataSource) throws MalformedQueryParametersException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object generateAjaxVisualization(VitroRequest vitroRequest, Log log, Dataset dataSource) throws MalformedQueryParametersException {
|
||||||
|
String personURI = vitroRequest.getParameter("uri");
|
||||||
|
|
||||||
|
QueryRunner<Set<Activity>> queryManager = new PersonPublicationCountQueryRunner(
|
||||||
|
personURI,
|
||||||
|
vitroRequest.getRDFService(),
|
||||||
|
log);
|
||||||
|
|
||||||
|
Set<Activity> authorDocuments = queryManager.getQueryResult();
|
||||||
|
|
||||||
|
Map<Integer, Map<String, Integer>> yearToTypeCount = new TreeMap<Integer, Map<String, Integer>>();
|
||||||
|
for (Activity currentActivity : authorDocuments) {
|
||||||
|
String activityYearStr = currentActivity.getParsedActivityYear();
|
||||||
|
Integer activityYear;
|
||||||
|
try {
|
||||||
|
activityYear = Integer.parseInt(activityYearStr, 10);
|
||||||
|
} catch (NumberFormatException nfe) {
|
||||||
|
activityYear = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Integer> typeCounts;
|
||||||
|
if (yearToTypeCount.containsKey(activityYear)) {
|
||||||
|
typeCounts = yearToTypeCount.get(activityYear);
|
||||||
|
} else {
|
||||||
|
typeCounts = new TreeMap<String, Integer>();
|
||||||
|
yearToTypeCount.put(activityYear, typeCounts);
|
||||||
|
}
|
||||||
|
|
||||||
|
String activityType = currentActivity.getActivityType();
|
||||||
|
if (StringUtils.isEmpty(activityType)) {
|
||||||
|
activityType = "http://purl.org/ontology/bibo/Document";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeCounts.containsKey(activityType)) {
|
||||||
|
typeCounts.put(activityType, typeCounts.get(activityType) + 1);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
typeCounts.put(activityType, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder csv = new StringBuilder();
|
||||||
|
|
||||||
|
csv.append("Year,Previous,Other,Books,Articles\n");
|
||||||
|
|
||||||
|
int currentYear = Calendar.getInstance().get(Calendar.YEAR);
|
||||||
|
|
||||||
|
List<Integer> years = new ArrayList<Integer>(yearToTypeCount.keySet());
|
||||||
|
for (int year = currentYear - 9; year < currentYear + 1; year++) {
|
||||||
|
if (!years.contains(year)) {
|
||||||
|
years.add(year);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Collections.sort(years);
|
||||||
|
int publicationCount = 0;
|
||||||
|
for (Integer year : years) {
|
||||||
|
if (year < currentYear - 9) {
|
||||||
|
if (yearToTypeCount.containsKey(year)) {
|
||||||
|
Map<String, Integer> typeCounts = yearToTypeCount.get(year);
|
||||||
|
for (Map.Entry<String, Integer> entry : typeCounts.entrySet()) {
|
||||||
|
publicationCount += entry.getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int articleCount = 0;
|
||||||
|
int bookCount = 0;
|
||||||
|
int otherCount = 0;
|
||||||
|
|
||||||
|
if (yearToTypeCount.containsKey(year)) {
|
||||||
|
Map<String, Integer> typeCounts = yearToTypeCount.get(year);
|
||||||
|
for (Map.Entry<String, Integer> entry : typeCounts.entrySet()) {
|
||||||
|
if ("http://purl.org/ontology/bibo/AcademicArticle".equalsIgnoreCase(entry.getKey()) ||
|
||||||
|
"http://purl.org/ontology/bibo/Article".equalsIgnoreCase(entry.getKey()) ) {
|
||||||
|
articleCount += entry.getValue();
|
||||||
|
} else if ("http://purl.org/ontology/bibo/Book".equalsIgnoreCase(entry.getKey()) ||
|
||||||
|
"http://purl.org/ontology/bibo/BookSection".equalsIgnoreCase(entry.getKey()) ||
|
||||||
|
"http://purl.org/ontology/bibo/Chapter".equalsIgnoreCase(entry.getKey()) ||
|
||||||
|
"http://purl.org/ontology/bibo/EditedBook".equalsIgnoreCase(entry.getKey()) ) {
|
||||||
|
bookCount += entry.getValue();
|
||||||
|
} else {
|
||||||
|
otherCount += entry.getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
csv.append(year).append(",")
|
||||||
|
.append(publicationCount).append(",")
|
||||||
|
.append(otherCount).append(",")
|
||||||
|
.append(bookCount).append(",")
|
||||||
|
.append(articleCount).append("\n");
|
||||||
|
|
||||||
|
publicationCount += articleCount + bookCount + otherCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return csv.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, String> generateDataVisualization(VitroRequest vitroRequest, Log log, Dataset dataset) throws MalformedQueryParametersException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -75,6 +75,7 @@ public class PersonPublicationCountQueryRunner implements QueryRunner<Set<Activi
|
||||||
+ "{\n"
|
+ "{\n"
|
||||||
+ " <" + queryURI + "> rdfs:label ?authorName .\n"
|
+ " <" + queryURI + "> rdfs:label ?authorName .\n"
|
||||||
+ " <" + queryURI + "> core:authorOf ?document .\n"
|
+ " <" + queryURI + "> core:authorOf ?document .\n"
|
||||||
|
+ " ?document vitro:mostSpecificType ?publicationType .\n"
|
||||||
+ " ?document core:publicationDate ?publicationDate .\n"
|
+ " ?document core:publicationDate ?publicationDate .\n"
|
||||||
+ "}\n"
|
+ "}\n"
|
||||||
+ "WHERE"
|
+ "WHERE"
|
||||||
|
@ -86,7 +87,8 @@ public class PersonPublicationCountQueryRunner implements QueryRunner<Set<Activi
|
||||||
+ " ?authorshipNode rdf:type core:Authorship ; \n"
|
+ " ?authorshipNode rdf:type core:Authorship ; \n"
|
||||||
+ " core:relates ?document . \n"
|
+ " core:relates ?document . \n"
|
||||||
+ " ?document rdf:type bibo:Document ; \n"
|
+ " ?document rdf:type bibo:Document ; \n"
|
||||||
+ " rdfs:label ?documentLabel .\n"
|
+ " rdfs:label ?documentLabel ;\n"
|
||||||
|
+ " vitro:mostSpecificType ?publicationType .\n"
|
||||||
+ " } UNION {\n"
|
+ " } UNION {\n"
|
||||||
+ " <" + queryURI + "> rdf:type foaf:Person ;\n"
|
+ " <" + queryURI + "> rdf:type foaf:Person ;\n"
|
||||||
+ " core:relatedBy ?authorshipNode . \n"
|
+ " core:relatedBy ?authorshipNode . \n"
|
||||||
|
@ -106,9 +108,10 @@ public class PersonPublicationCountQueryRunner implements QueryRunner<Set<Activi
|
||||||
private String getSparqlQuery(String queryURI) {
|
private String getSparqlQuery(String queryURI) {
|
||||||
|
|
||||||
String sparqlQuery = QueryConstants.getSparqlPrefixQuery()
|
String sparqlQuery = QueryConstants.getSparqlPrefixQuery()
|
||||||
+ "SELECT ?document ?publicationDate\n"
|
+ "SELECT ?document ?publicationType ?publicationDate\n"
|
||||||
+ "WHERE { \n"
|
+ "WHERE { \n"
|
||||||
+ " <" + queryURI + "> core:authorOf ?document . \n"
|
+ " <" + queryURI + "> core:authorOf ?document . \n"
|
||||||
|
+ " OPTIONAL { ?document vitro:mostSpecificType ?publicationType . } .\n"
|
||||||
+ " OPTIONAL { ?document core:publicationDate ?publicationDate . } .\n"
|
+ " OPTIONAL { ?document core:publicationDate ?publicationDate . } .\n"
|
||||||
+ "}\n";
|
+ "}\n";
|
||||||
|
|
||||||
|
@ -172,6 +175,11 @@ public class PersonPublicationCountQueryRunner implements QueryRunner<Set<Activi
|
||||||
biboDocument.setActivityDate(publicationDateNode.asLiteral().getString());
|
biboDocument.setActivityDate(publicationDateNode.asLiteral().getString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RDFNode publicationType = qs.get("publicationType");
|
||||||
|
if (publicationType != null) {
|
||||||
|
biboDocument.setActivityType(publicationType.asResource().getURI());
|
||||||
|
}
|
||||||
|
|
||||||
authorDocuments.add(biboDocument);
|
authorDocuments.add(biboDocument);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ import edu.cornell.mannlib.vitro.webapp.visualization.visutils.UtilityFunctions;
|
||||||
public class Activity extends Individual {
|
public class Activity extends Individual {
|
||||||
|
|
||||||
private String activityDate;
|
private String activityDate;
|
||||||
|
private String activityType;
|
||||||
|
|
||||||
public Activity(String activityURI) {
|
public Activity(String activityURI) {
|
||||||
super(activityURI);
|
super(activityURI);
|
||||||
|
@ -31,6 +32,10 @@ public class Activity extends Individual {
|
||||||
this.setIndividualLabel(activityLabel);
|
this.setIndividualLabel(activityLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getActivityType() { return this.activityType; }
|
||||||
|
|
||||||
|
public void setActivityType(String activityType) { this.activityType = activityType; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method will be called to get the final/inferred year for the publication.
|
* This method will be called to get the final/inferred year for the publication.
|
||||||
* The 2 choices, in order, are,
|
* The 2 choices, in order, are,
|
||||||
|
|
|
@ -12,6 +12,9 @@
|
||||||
<bean id="capability_map"
|
<bean id="capability_map"
|
||||||
class="edu.cornell.mannlib.vitro.webapp.visualization.capabilitymap.CapabilityMapRequestHandler" />
|
class="edu.cornell.mannlib.vitro.webapp.visualization.capabilitymap.CapabilityMapRequestHandler" />
|
||||||
|
|
||||||
|
<bean id="cumulative_pub_count"
|
||||||
|
class="edu.cornell.mannlib.vitro.webapp.visualization.personpubcount.CumulativeCountRequestHandler" />
|
||||||
|
|
||||||
<bean id="person_pub_count"
|
<bean id="person_pub_count"
|
||||||
class="edu.cornell.mannlib.vitro.webapp.visualization.personpubcount.PersonPublicationCountRequestHandler" />
|
class="edu.cornell.mannlib.vitro.webapp.visualization.personpubcount.PersonPublicationCountRequestHandler" />
|
||||||
|
|
||||||
|
@ -53,6 +56,10 @@
|
||||||
<ref bean="capability_map"></ref>
|
<ref bean="capability_map"></ref>
|
||||||
</entry>
|
</entry>
|
||||||
|
|
||||||
|
<entry key="cumulative_pub_count">
|
||||||
|
<ref bean="cumulative_pub_count"></ref>
|
||||||
|
</entry>
|
||||||
|
|
||||||
<entry key="person_pub_count">
|
<entry key="person_pub_count">
|
||||||
<ref bean="person_pub_count"></ref>
|
<ref bean="person_pub_count"></ref>
|
||||||
</entry>
|
</entry>
|
||||||
|
|
|
@ -18,16 +18,120 @@
|
||||||
<#assign standardVisualizationURLRoot ="/visualization">
|
<#assign standardVisualizationURLRoot ="/visualization">
|
||||||
|
|
||||||
<#if isAuthor>
|
<#if isAuthor>
|
||||||
|
${scripts.add('<script type="text/javascript" src="${urls.base}/js/d3.min.js"></script>')}
|
||||||
|
|
||||||
<#assign coAuthorIcon = "${urls.images}/visualization/coauthorship/co_author_icon.png">
|
<#assign coAuthorIcon = "${urls.images}/visualization/coauthorship/co_author_icon.png">
|
||||||
<#assign mapOfScienceIcon = "${urls.images}/visualization/mapofscience/scimap_icon.png">
|
<#assign mapOfScienceIcon = "${urls.images}/visualization/mapofscience/scimap_icon.png">
|
||||||
<#assign coAuthorVisUrl = individual.coAuthorVisUrl()>
|
<#assign coAuthorVisUrl = individual.coAuthorVisUrl()>
|
||||||
<#assign mapOfScienceVisUrl = individual.mapOfScienceUrl()>
|
<#assign mapOfScienceVisUrl = individual.mapOfScienceUrl()>
|
||||||
|
|
||||||
<#assign googleJSAPI = "https://www.google.com/jsapi?autoload=%7B%22modules%22%3A%5B%7B%22name%22%3A%22visualization%22%2C%22version%22%3A%221%22%2C%22packages%22%3A%5B%22imagesparkline%22%5D%7D%5D%7D">
|
<span id="publicationsHeading">${i18n().publications_in_vivo}</span>
|
||||||
|
|
||||||
<span id="sparklineHeading">${i18n().publications_in_vivo}</span>
|
<svg width="360" height="200" id="publicationsChart" onload="renderPublicationsChart()">
|
||||||
|
</svg>
|
||||||
|
|
||||||
<div id="vis_container_coauthor"> </div>
|
<script>
|
||||||
|
var dataUrl = '${urls.base}/visualizationAjax?vis=cumulative_pub_count&uri=${individual.uri?url}';
|
||||||
|
|
||||||
|
function renderPublicationsChart() {
|
||||||
|
var svg = d3.select("#publicationsChart"),
|
||||||
|
margin = {top: 30, right: 20, bottom: 30, left: 40},
|
||||||
|
width = +svg.attr("width") - margin.left - margin.right,
|
||||||
|
height = +svg.attr("height") - margin.top - margin.bottom,
|
||||||
|
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
|
||||||
|
|
||||||
|
var x = d3.scaleBand()
|
||||||
|
.rangeRound([0, width])
|
||||||
|
.paddingInner(0.05)
|
||||||
|
.align(0.1);
|
||||||
|
|
||||||
|
var y = d3.scaleLinear()
|
||||||
|
.rangeRound([height, 0]);
|
||||||
|
|
||||||
|
var z = d3.scaleOrdinal()
|
||||||
|
.range(["#777777", "#1f77b4", "#aec7e8", "#ff7f0e"]);
|
||||||
|
|
||||||
|
d3.csv(dataUrl, function (d, i, columns) {
|
||||||
|
for (i = 1, t = 0; i < columns.length; ++i) t += d[columns[i]] = +d[columns[i]];
|
||||||
|
d.total = t;
|
||||||
|
return d;
|
||||||
|
}, function (error, data) {
|
||||||
|
if (error) throw error;
|
||||||
|
|
||||||
|
var keys = data.columns.slice(1);
|
||||||
|
|
||||||
|
x.domain(data.map(function (d) {
|
||||||
|
return d.Year;
|
||||||
|
}));
|
||||||
|
y.domain([0, d3.max(data, function (d) {
|
||||||
|
return d.total;
|
||||||
|
})]).nice();
|
||||||
|
z.domain(keys);
|
||||||
|
|
||||||
|
g.append("g")
|
||||||
|
.selectAll("g")
|
||||||
|
.data(d3.stack().keys(keys)(data))
|
||||||
|
.enter().append("g")
|
||||||
|
.attr("fill", function (d) {
|
||||||
|
return z(d.key);
|
||||||
|
})
|
||||||
|
.selectAll("rect")
|
||||||
|
.data(function (d) {
|
||||||
|
return d;
|
||||||
|
})
|
||||||
|
.enter().append("rect")
|
||||||
|
.attr("x", function (d) {
|
||||||
|
return x(d.data.Year);
|
||||||
|
})
|
||||||
|
.attr("y", function (d) {
|
||||||
|
return y(d[1]);
|
||||||
|
})
|
||||||
|
.attr("height", function (d) {
|
||||||
|
return y(d[0]) - y(d[1]);
|
||||||
|
})
|
||||||
|
.attr("width", x.bandwidth());
|
||||||
|
|
||||||
|
g.append("g")
|
||||||
|
.attr("class", "axis")
|
||||||
|
.attr("transform", "translate(0," + height + ")")
|
||||||
|
.call(d3.axisBottom(x));
|
||||||
|
|
||||||
|
g.append("g")
|
||||||
|
.attr("class", "axis")
|
||||||
|
.call(d3.axisLeft(y).ticks(null, "s"))
|
||||||
|
.append("text")
|
||||||
|
.attr("x", 2)
|
||||||
|
.attr("y", y(y.ticks().pop()) + 0.5)
|
||||||
|
.attr("dy", "0.32em")
|
||||||
|
.attr("fill", "#000");
|
||||||
|
|
||||||
|
var legend = g.append("g")
|
||||||
|
.attr("font-family", "sans-serif")
|
||||||
|
.attr("font-size", 10)
|
||||||
|
.attr("text-anchor", "end")
|
||||||
|
.selectAll("g")
|
||||||
|
.data(keys.slice(1,4).reverse())
|
||||||
|
.enter().append("g")
|
||||||
|
.attr("transform", function (d, i) {
|
||||||
|
return "translate(-" + (200 - i * 80) +",-25)";
|
||||||
|
});
|
||||||
|
|
||||||
|
legend.append("rect")
|
||||||
|
.attr("x", width - 19)
|
||||||
|
.attr("width", 19)
|
||||||
|
.attr("height", 19)
|
||||||
|
.attr("fill", z);
|
||||||
|
|
||||||
|
legend.append("text")
|
||||||
|
.attr("x", width - 24)
|
||||||
|
.attr("y", 9.5)
|
||||||
|
.attr("dy", "0.32em")
|
||||||
|
.text(function (d) {
|
||||||
|
return d;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
<div id="coauthorship_link_container" class="collaboratorship-link-container">
|
<div id="coauthorship_link_container" class="collaboratorship-link-container">
|
||||||
<a href="${coAuthorVisUrl}" title="${i18n().co_author_network}" class="btn btn-info" role="button">
|
<a href="${coAuthorVisUrl}" title="${i18n().co_author_network}" class="btn btn-info" role="button">
|
||||||
|
@ -42,15 +146,6 @@
|
||||||
${i18n().map_of_science_capitalized}
|
${i18n().map_of_science_capitalized}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
${scripts.add('<script type="text/javascript" src="${googleJSAPI}"></script>',
|
|
||||||
'<script type="text/javascript" src="${urls.base}/js/visualization/visualization-helper-functions.js"></script>',
|
|
||||||
'<script type="text/javascript" src="${urls.base}/js/visualization/sparkline.js"></script>')}
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
var visualizationUrl = '${urls.base}/visualizationAjax?uri=${individual.uri?url}&template=${visRequestingTemplate!}';
|
|
||||||
var infoIconSrc = '${urls.images}/iconInfo.png';
|
|
||||||
</script>
|
|
||||||
</#if>
|
</#if>
|
||||||
|
|
||||||
<#if isInvestigator>
|
<#if isInvestigator>
|
||||||
|
|
Loading…
Add table
Reference in a new issue