1. Attempting to delete old visualization back-end & front-end

This commit is contained in:
cdtank 2011-01-12 19:29:03 +00:00
parent 08e643982a
commit 3b8ac290a7
3 changed files with 0 additions and 1279 deletions

View file

@ -1,220 +0,0 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.visualization.personpubcount;
import java.util.HashSet;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import com.hp.hpl.jena.iri.IRI;
import com.hp.hpl.jena.iri.IRIFactory;
import com.hp.hpl.jena.iri.Violation;
import com.hp.hpl.jena.query.DataSource;
import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.query.Syntax;
import com.hp.hpl.jena.rdf.model.RDFNode;
import edu.cornell.mannlib.vitro.webapp.visualization.constants.QueryConstants;
import edu.cornell.mannlib.vitro.webapp.visualization.constants.QueryFieldLabels;
import edu.cornell.mannlib.vitro.webapp.visualization.exceptions.MalformedQueryParametersException;
import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.BiboDocument;
import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Individual;
import edu.cornell.mannlib.vitro.webapp.visualization.visutils.QueryRunner;
/**
* This query runner is used to execute a sparql query that will fetch all the publications
* defined by bibo:Document property for a particular individual.
*
* @author cdtank
*/
public class PersonPublicationCountQueryRunner implements QueryRunner<Set<BiboDocument>> {
protected static final Syntax SYNTAX = Syntax.syntaxARQ;
private String personURI;
private DataSource dataSource;
private Individual author;
public Individual getAuthor() {
return author;
}
private Log log;
private static final String SPARQL_QUERY_COMMON_SELECT_CLAUSE = ""
+ "SELECT (str(?authorLabel) as ?authorLabelLit) "
+ " (str(?document) as ?documentLit) "
+ " (str(?documentMoniker) as ?documentMonikerLit) "
+ " (str(?documentLabel) as ?documentLabelLit) "
+ " (str(?documentBlurb) as ?documentBlurbLit) "
+ " (str(?publicationYear) as ?publicationYearLit) "
+ " (str(?publicationYearMonth) as ?publicationYearMonthLit) "
+ " (str(?publicationDate) as ?publicationDateLit) "
+ " (str(?documentDescription) as ?documentDescriptionLit) ";
private static final String SPARQL_QUERY_COMMON_WHERE_CLAUSE = ""
+ "?document rdfs:label ?documentLabel ."
+ "OPTIONAL { ?document core:year ?publicationYear } ."
+ "OPTIONAL { ?document core:yearMonth ?publicationYearMonth } ."
+ "OPTIONAL { ?document core:date ?publicationDate } ."
+ "OPTIONAL { ?document vitro:moniker ?documentMoniker } ."
+ "OPTIONAL { ?document vitro:blurb ?documentBlurb } ."
+ "OPTIONAL { ?document vitro:description ?documentDescription }";
public PersonPublicationCountQueryRunner(String personURI,
DataSource dataSource, Log log) {
this.personURI = personURI;
this.dataSource = dataSource;
this.log = log;
}
private Set<BiboDocument> createJavaValueObjects(ResultSet resultSet) {
Set<BiboDocument> authorDocuments = new HashSet<BiboDocument>();
while (resultSet.hasNext()) {
QuerySolution solution = resultSet.nextSolution();
BiboDocument biboDocument = new BiboDocument(
solution.get(QueryFieldLabels.DOCUMENT_URL)
.toString());
RDFNode documentLabelNode = solution.get(QueryFieldLabels.DOCUMENT_LABEL);
if (documentLabelNode != null) {
biboDocument.setDocumentLabel(documentLabelNode.toString());
}
RDFNode documentBlurbNode = solution.get(QueryFieldLabels.DOCUMENT_BLURB);
if (documentBlurbNode != null) {
biboDocument.setDocumentBlurb(documentBlurbNode.toString());
}
RDFNode documentmonikerNode = solution.get(QueryFieldLabels.DOCUMENT_MONIKER);
if (documentmonikerNode != null) {
biboDocument.setDocumentMoniker(documentmonikerNode.toString());
}
RDFNode documentDescriptionNode = solution.get(QueryFieldLabels.DOCUMENT_DESCRIPTION);
if (documentDescriptionNode != null) {
biboDocument.setDocumentDescription(documentDescriptionNode.toString());
}
RDFNode publicationYearNode = solution.get(QueryFieldLabels.DOCUMENT_PUBLICATION_YEAR);
if (publicationYearNode != null) {
biboDocument.setPublicationYear(publicationYearNode.toString());
}
RDFNode publicationYearMonthNode = solution.get(
QueryFieldLabels
.DOCUMENT_PUBLICATION_YEAR_MONTH);
if (publicationYearMonthNode != null) {
biboDocument.setPublicationYearMonth(publicationYearMonthNode.toString());
}
RDFNode publicationDateNode = solution.get(QueryFieldLabels.DOCUMENT_PUBLICATION_DATE);
if (publicationDateNode != null) {
biboDocument.setPublicationDate(publicationDateNode.toString());
}
/*
* Since we are getting publication count for just one author at a time we need
* to create only one "Individual" instance. We test against the null for "author" to
* make sure that it has not already been instantiated.
* */
RDFNode authorURLNode = solution.get(QueryFieldLabels.AUTHOR_URL);
if (authorURLNode != null && author == null) {
author = new Individual(authorURLNode.toString());
RDFNode authorLabelNode = solution.get(QueryFieldLabels.AUTHOR_LABEL);
if (authorLabelNode != null) {
author.setIndividualLabel(authorLabelNode.toString());
}
}
authorDocuments.add(biboDocument);
}
return authorDocuments;
}
private ResultSet executeQuery(String queryURI,
DataSource dataSource) {
QueryExecution queryExecution = null;
// try {
Query query = QueryFactory.create(getSparqlQuery(queryURI), SYNTAX);
// QuerySolutionMap qs = new QuerySolutionMap();
// qs.add("authPerson", queryParam); // bind resource to s
queryExecution = QueryExecutionFactory.create(query, dataSource);
// if (query.isSelectType()) {
return queryExecution.execSelect();
// }
// } finally {
// if (queryExecution != null) {
// queryExecution.close();
// }
// }
// return null;
}
private String getSparqlQuery(String queryURI) {
// Resource uri1 = ResourceFactory.createResource(queryURI);
String sparqlQuery = QueryConstants.getSparqlPrefixQuery()
+ SPARQL_QUERY_COMMON_SELECT_CLAUSE
+ "(str(<" + queryURI + ">) as ?authPersonLit) "
+ "WHERE { "
+ "<" + queryURI + "> rdf:type foaf:Person ;"
+ " rdfs:label ?authorLabel ;"
+ " core:authorInAuthorship ?authorshipNode . "
+ " ?authorshipNode rdf:type core:Authorship ;"
+ " core:linkedInformationResource ?document . "
+ SPARQL_QUERY_COMMON_WHERE_CLAUSE
+ "}";
log.debug("SPARQL query for person pub count -> \n" + sparqlQuery);
return sparqlQuery;
}
public Set<BiboDocument> getQueryResult()
throws MalformedQueryParametersException {
if (StringUtils.isNotBlank(this.personURI)) {
/*
* To test for the validity of the URI submitted.
* */
IRIFactory iRIFactory = IRIFactory.jenaImplementation();
IRI iri = iRIFactory.create(this.personURI);
if (iri.hasViolation(false)) {
String errorMsg = ((Violation) iri.violations(false).next()).getShortMessage();
log.error("Pub Count vis Query " + errorMsg);
throw new MalformedQueryParametersException(
"URI provided for an individual is malformed.");
}
} else {
throw new MalformedQueryParametersException("URL parameter is either null or empty.");
}
ResultSet resultSet = executeQuery(this.personURI,
this.dataSource);
return createJavaValueObjects(resultSet);
}
}

View file

@ -1,370 +0,0 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.visualization.personpubcount;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.skife.csv.CSVWriter;
import org.skife.csv.SimpleWriter;
import com.hp.hpl.jena.query.DataSource;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfWriter;
import edu.cornell.mannlib.vitro.webapp.beans.Portal;
import edu.cornell.mannlib.vitro.webapp.controller.Controllers;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.visualization.VisualizationFrameworkConstants;
import edu.cornell.mannlib.vitro.webapp.visualization.exceptions.MalformedQueryParametersException;
import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.BiboDocument;
import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Individual;
import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.SparklineData;
import edu.cornell.mannlib.vitro.webapp.visualization.visutils.PDFDocument;
import edu.cornell.mannlib.vitro.webapp.visualization.visutils.QueryRunner;
import edu.cornell.mannlib.vitro.webapp.visualization.visutils.UtilityFunctions;
import edu.cornell.mannlib.vitro.webapp.visualization.visutils.VisualizationRequestHandler;
/**
*
* This request handler is used to serve the content related to an individual's
* publications over the years like,
* 1. Sprakline representing this
* 2. An entire page dedicated to the sparkline vis which will also have links to
* download the data using which the sparkline was rendered & its tabular representation etc.
* 3. Downloadable CSV file containing number of publications over the years.
* 4. Downloadable PDf file containing the publications content, among other things.
* Currently this is disabled because the feature is half-baked. We plan to activate this in
* the next major release.
*
* @author cdtank
*/
public class PersonPublicationCountRequestHandler implements VisualizationRequestHandler {
public void generateVisualization(VitroRequest vitroRequest,
HttpServletRequest request,
HttpServletResponse response,
Log log,
DataSource dataSource) {
String peronURI = vitroRequest.getParameter(
VisualizationFrameworkConstants
.INDIVIDUAL_URI_KEY);
String renderMode = vitroRequest.getParameter(
VisualizationFrameworkConstants
.RENDER_MODE_KEY);
String visMode = vitroRequest.getParameter(
VisualizationFrameworkConstants
.VIS_MODE_KEY);
String visContainer = vitroRequest.getParameter(
VisualizationFrameworkConstants
.VIS_CONTAINER_KEY);
QueryRunner<Set<BiboDocument>> queryManager =
new PersonPublicationCountQueryRunner(peronURI, dataSource, log);
try {
Set<BiboDocument> authorDocuments = queryManager.getQueryResult();
/*
* Create a map from the year to number of publications. Use the BiboDocument's
* parsedPublicationYear to populate the data.
* */
Map<String, Integer> yearToPublicationCount =
UtilityFunctions.getYearToPublicationCount(authorDocuments);
Individual author = ((PersonPublicationCountQueryRunner) queryManager).getAuthor();
if (VisualizationFrameworkConstants.DATA_RENDER_MODE
.equalsIgnoreCase(renderMode)) {
prepareDataResponse(author,
authorDocuments,
yearToPublicationCount,
response);
return;
}
/*
* For now we are disabling the capability to render pdf file.
* */
/*
if (VisualizationFrameworkConstants.PDF_RENDER_MODE
.equalsIgnoreCase(renderMode)) {
preparePDFResponse(author,
authorDocuments,
yearToPublicationCount,
response);
return;
}
*/
/*
* Computations required to generate HTML for the sparkline & related context.
* */
PersonPublicationCountVisCodeGenerator visualizationCodeGenerator =
new PersonPublicationCountVisCodeGenerator(vitroRequest.getContextPath(),
peronURI,
visMode,
visContainer,
authorDocuments,
yearToPublicationCount,
log);
SparklineData sparklineData = visualizationCodeGenerator
.getValueObjectContainer();
/*
* This is side-effecting because the response of this method is just to redirect to
* a page with visualization on it.
* */
RequestDispatcher requestDispatcher = null;
if (VisualizationFrameworkConstants.DYNAMIC_RENDER_MODE
.equalsIgnoreCase(renderMode)) {
prepareDynamicResponse(request,
response,
vitroRequest,
sparklineData,
yearToPublicationCount);
requestDispatcher = request.getRequestDispatcher("/templates/page/blankPage.jsp");
} else {
prepareStandaloneResponse(request,
response,
vitroRequest,
sparklineData);
requestDispatcher = request.getRequestDispatcher(Controllers.BASIC_JSP);
}
try {
requestDispatcher.forward(request, response);
} catch (Exception e) {
log.error("EntityEditController could not forward to view.");
log.error(e.getMessage());
log.error(e.getStackTrace());
}
} catch (MalformedQueryParametersException e) {
try {
UtilityFunctions.handleMalformedParameters(
e.getMessage(),
"Visualization Query Error - Individual Publication Count",
vitroRequest,
request,
response,
log);
} catch (ServletException e1) {
log.error(e1.getStackTrace());
} catch (IOException e1) {
log.error(e1.getStackTrace());
}
return;
}
}
private void writePublicationsOverTimeCSV(Map<String, Integer> yearToPublicationCount,
PrintWriter responseWriter) {
CSVWriter csvWriter = new SimpleWriter(responseWriter);
try {
csvWriter.append(new String[]{"Year", "Publications"});
for (Entry<String, Integer> currentEntry : yearToPublicationCount.entrySet()) {
csvWriter.append(new Object[]{currentEntry.getKey(), currentEntry.getValue()});
}
} catch (IOException e) {
e.printStackTrace();
}
responseWriter.flush();
}
/**
* Provides response when csv file containing the publication count over the years
* is requested.
* @param author
* @param authorDocuments
* @param yearToPublicationCount
* @param response
*/
private void prepareDataResponse(
Individual author,
Set<BiboDocument> authorDocuments,
Map<String, Integer> yearToPublicationCount,
HttpServletResponse response) {
String authorName = null;
/*
* To protect against cases where there are no author documents associated with the
* individual.
* */
if (authorDocuments.size() > 0) {
authorName = author.getIndividualLabel();
}
/*
* To make sure that null/empty records for author names do not cause any mischief.
* */
if (StringUtils.isBlank(authorName)) {
authorName = "no-author";
}
String outputFileName = UtilityFunctions.slugify(authorName)
+ "_publications-per-year" + ".csv";
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment;filename=" + outputFileName);
try {
PrintWriter responseWriter = response.getWriter();
/*
* We are side-effecting responseWriter since we are directly manipulating the response
* object of the servlet.
* */
writePublicationsOverTimeCSV(yearToPublicationCount, responseWriter);
responseWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Provides response when an entire page dedicated to publication sparkline is requested.
* @param request
* @param response
* @param vreq
* @param valueObjectContainer
*/
private void prepareStandaloneResponse(HttpServletRequest request,
HttpServletResponse response, VitroRequest vreq,
SparklineData valueObjectContainer) {
Portal portal = vreq.getPortal();
request.setAttribute("sparklineVO", valueObjectContainer);
request.setAttribute("bodyJsp", "/templates/visualization/publication_count.jsp");
request.setAttribute("portalBean", portal);
request.setAttribute("title", "Individual Publication Count visualization");
request.setAttribute("scripts", "/templates/visualization/visualization_scripts.jsp");
}
/**
* Provides response when the publication sparkline has to be rendered in already existing
* page, e.g. profile page.
* @param request
* @param response
* @param vreq
* @param valueObjectContainer
* @param yearToPublicationCount
*/
private void prepareDynamicResponse(
HttpServletRequest request,
HttpServletResponse response,
VitroRequest vreq,
SparklineData valueObjectContainer,
Map<String, Integer> yearToPublicationCount) {
Portal portal = vreq.getPortal();
request.setAttribute("sparklineVO", valueObjectContainer);
if (yearToPublicationCount.size() > 0) {
request.setAttribute("shouldVIVOrenderVis", true);
} else {
request.setAttribute("shouldVIVOrenderVis", false);
}
request.setAttribute("portalBean", portal);
request.setAttribute("bodyJsp", "/templates/visualization/ajax_vis_content.jsp");
}
private void preparePDFResponse(
Individual author,
Set<BiboDocument> authorDocuments,
Map<String, Integer> yearToPublicationCount,
HttpServletResponse response) {
String authorName = null;
/*
* To protect against cases where there are no author documents associated with the
* individual.
* */
if (authorDocuments.size() > 0) {
authorName = author.getIndividualLabel();
}
/*
* To make sure that null/empty records for author names do not cause any mischief.
* */
if (StringUtils.isBlank(authorName)) {
authorName = "no-author";
}
String outputFileName = UtilityFunctions.slugify(authorName) + "_report" + ".pdf";
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment;filename=" + outputFileName);
ServletOutputStream responseOutputStream;
try {
responseOutputStream = response.getOutputStream();
Document document = new Document();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfWriter pdfWriter = PdfWriter.getInstance(document, baos);
document.open();
PDFDocument pdfDocument = new PDFDocument(authorName,
yearToPublicationCount,
document,
pdfWriter);
document.close();
// setting some response headers & content type
response.setHeader("Expires", "0");
response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
response.setHeader("Pragma", "public");
response.setContentLength(baos.size());
// write ByteArrayOutputStream to the ServletOutputStream
baos.writeTo(responseOutputStream);
responseOutputStream.flush();
responseOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
}
}
}

View file

@ -1,689 +0,0 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.visualization.personpubcount;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.Map.Entry;
import org.apache.commons.logging.Log;
import edu.cornell.mannlib.vitro.webapp.controller.visualization.VisualizationController;
import edu.cornell.mannlib.vitro.webapp.controller.visualization.VisualizationFrameworkConstants;
import edu.cornell.mannlib.vitro.webapp.visualization.constants.VOConstants;
import edu.cornell.mannlib.vitro.webapp.visualization.constants.VisConstants;
import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.BiboDocument;
import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.SparklineData;
@SuppressWarnings("serial")
public class PersonPublicationCountVisCodeGenerator {
/*
* There are 2 modes of sparkline that are available via this visualization.
* 1. Short Sparkline - This sparkline will render all the data points (or sparks),
* which in this case are the publications over the years, from the last 10 years.
*
* 2. Full Sparkline - This sparkline will render all the data points (or sparks)
* spanning the career of the person & last 10 years at the minimum, in case if
* the person started his career in the last 10 yeras.
* */
private static final Map<String, String> VIS_DIV_NAMES = new HashMap<String, String>() { {
put("SHORT_SPARK", "pub_count_short_sparkline_vis");
put("FULL_SPARK", "pub_count_full_sparkline_vis");
} };
private static final String VISUALIZATION_STYLE_CLASS = "sparkline_style";
private static final String DEFAULT_VIS_CONTAINER_DIV_ID = "pub_count_vis_container";
private Map<String, Integer> yearToPublicationCount;
private Log log;
private SparklineData sparklineData;
private String contextPath;
private String individualURI;
public PersonPublicationCountVisCodeGenerator(String contextPath,
String individualURIParam,
String visMode,
String visContainer,
Set<BiboDocument> authorDocuments,
Map<String, Integer> yearToPublicationCount,
Log log) {
this.contextPath = contextPath;
this.individualURI = individualURIParam;
this.yearToPublicationCount = yearToPublicationCount;
this.sparklineData = new SparklineData();
this.log = log;
generateVisualizationCode(visMode, visContainer, authorDocuments);
}
/**
* This method is used to generate the visualization code (HMTL, CSS & JavaScript).
* There 2 parts to it - 1. Actual Content Code & 2. Context Code.
* 1. Actual Content code in this case is the sparkline image, text related to
* data and the wrapping tables. This is generated via call to google vis API through
* JavaScript.
* 2. Context code is generally optional but contains code pertaining to tabulated
* data & links to download files etc.
* @param visMode
* @param visContainer
* @param authorDocuments
*/
private void generateVisualizationCode(String visMode,
String visContainer,
Set<BiboDocument> authorDocuments) {
sparklineData.setSparklineContent(getMainVisualizationCode(authorDocuments,
visMode,
visContainer));
sparklineData.setSparklineContext(getVisualizationContextCode(visMode));
}
private String getMainVisualizationCode(Set<BiboDocument> authorDocuments,
String visMode,
String providedVisContainerID) {
int numOfYearsToBeRendered = 0;
int currentYear = Calendar.getInstance().get(Calendar.YEAR);
int shortSparkMinYear = currentYear
- VisConstants.MINIMUM_YEARS_CONSIDERED_FOR_SPARKLINE
+ 1;
/*
* This is required because when deciding the range of years over which the vis
* was rendered we dont want to be influenced by the "DEFAULT_PUBLICATION_YEAR".
* */
Set<String> publishedYears = new HashSet<String>(yearToPublicationCount.keySet());
publishedYears.remove(VOConstants.DEFAULT_PUBLICATION_YEAR);
/*
* We are setting the default value of minPublishedYear to be 10 years before
* the current year (which is suitably represented by the shortSparkMinYear),
* this in case we run into invalid set of published years.
* */
int minPublishedYear = shortSparkMinYear;
String visContainerID = null;
StringBuilder visualizationCode = new StringBuilder();
if (yearToPublicationCount.size() > 0) {
try {
minPublishedYear = Integer.parseInt(Collections.min(publishedYears));
} catch (NoSuchElementException e1) {
log.debug("vis: " + e1.getMessage() + " error occurred for "
+ yearToPublicationCount.toString());
} catch (NumberFormatException e2) {
log.debug("vis: " + e2.getMessage() + " error occurred for "
+ yearToPublicationCount.toString());
}
}
int minPubYearConsidered = 0;
/*
* There might be a case that the author has made his first publication within the
* last 10 years but we want to make sure that the sparkline is representative of
* at least the last 10 years, so we will set the minPubYearConsidered to
* "currentYear - 10" which is also given by "shortSparkMinYear".
* */
if (minPublishedYear > shortSparkMinYear) {
minPubYearConsidered = shortSparkMinYear;
} else {
minPubYearConsidered = minPublishedYear;
}
numOfYearsToBeRendered = currentYear - minPubYearConsidered + 1;
visualizationCode.append("<style type='text/css'>"
+ "." + VISUALIZATION_STYLE_CLASS + " table{"
+ " margin: 0;"
+ " padding: 0;"
+ " width: auto;"
+ " border-collapse: collapse;"
+ " border-spacing: 0;"
+ " vertical-align: inherit;"
+ "}"
+ "table.sparkline_wrapper_table td, th {"
+ " vertical-align: bottom;"
+ "}"
+ ".vis_link a{"
+ " padding-top: 5px;"
+ "}"
+ "td.sparkline_number { text-align:right; "
+ "padding-right:5px; }"
+ "td.sparkline_text {text-align:left;}"
+ ".incomplete-data-holder {"
+ ""
+ "}"
+ "</style>\n");
visualizationCode.append("<script type=\"text/javascript\">\n"
+ "function drawPubCountVisualization(providedSparklineImgTD) "
+ "{\n"
+ "var data = new google.visualization.DataTable();\n"
+ "data.addColumn('string', 'Year');\n"
+ "data.addColumn('number', 'Publications');\n"
+ "data.addRows(" + numOfYearsToBeRendered + ");\n");
int publicationCounter = 0;
/*
* For the purpose of this visualization I have come up with a term "Sparks" which
* essentially means data points.
* Sparks that will be rendered in full mode will always be the one's which have any year
* associated with it. Hence.
* */
int renderedFullSparks = 0;
for (int publicationYear = minPubYearConsidered;
publicationYear <= currentYear;
publicationYear++) {
String stringPublishedYear = String.valueOf(publicationYear);
Integer currentPublications = yearToPublicationCount.get(stringPublishedYear);
if (currentPublications == null) {
currentPublications = 0;
}
visualizationCode.append("data.setValue("
+ publicationCounter
+ ", 0, '"
+ stringPublishedYear
+ "');\n");
visualizationCode.append("data.setValue("
+ publicationCounter
+ ", 1, "
+ currentPublications
+ ");\n");
/*
* Sparks that will be rendered in full mode will always be the one's which has
* any year associated with it. Hence.
* */
renderedFullSparks += currentPublications;
publicationCounter++;
}
/*
* Total publications will also consider publications that have no year associated with
* it. Hence.
* */
Integer unknownYearPublications = 0;
if (yearToPublicationCount.get(VOConstants.DEFAULT_PUBLICATION_YEAR) != null) {
unknownYearPublications = yearToPublicationCount
.get(VOConstants.DEFAULT_PUBLICATION_YEAR);
}
String sparklineDisplayOptions = "{width: 150, height: 30, showAxisLines: false, "
+ "showValueLabels: false, labelPosition: 'none'}";
if (providedVisContainerID != null) {
visContainerID = providedVisContainerID;
} else {
visContainerID = DEFAULT_VIS_CONTAINER_DIV_ID;
}
/*
* By default these represents the range of the rendered sparks. Only in case of
* "short" sparkline mode we will set the Earliest RenderedPublication year to
* "currentYear - 10".
* */
sparklineData.setEarliestRenderedPublicationYear(minPublishedYear);
sparklineData.setLatestRenderedPublicationYear(currentYear);
/*
* The Full Sparkline will be rendered by default. Only if the url has specific mention of
* SHORT_SPARKLINE_MODE_URL_HANDLE then we render the short sparkline and not otherwise.
* */
/*
* Since building StringBuilder objects (which is being used to store the vis code) is
* essentially a side-effecting process, we have both the activators method as side-
* effecting. They both side-effect "visualizationCode"
* */
if (VisualizationFrameworkConstants.SHORT_SPARKLINE_VIS_MODE.equalsIgnoreCase(visMode)) {
sparklineData.setEarliestRenderedPublicationYear(shortSparkMinYear);
generateShortSparklineVisualizationContent(currentYear,
shortSparkMinYear,
visContainerID,
visualizationCode,
unknownYearPublications,
sparklineDisplayOptions);
} else {
generateFullSparklineVisualizationContent(currentYear,
minPubYearConsidered,
visContainerID,
visualizationCode,
unknownYearPublications,
renderedFullSparks,
sparklineDisplayOptions);
}
log.debug(visualizationCode);
return visualizationCode.toString();
}
private void generateShortSparklineVisualizationContent(int currentYear,
int shortSparkMinYear,
String visContainerID,
StringBuilder visualizationCode,
int unknownYearPublications,
String sparklineDisplayOptions) {
/*
* Create a view of the data containing only the column pertaining to publication count.
* */
visualizationCode.append("var shortSparklineView = "
+ "new google.visualization.DataView(data);\n"
+ "shortSparklineView.setColumns([1]);\n");
/*
* For the short view we only want the last 10 year's view of publication count,
* hence we filter the data we actually want to use for render.
* */
visualizationCode.append("shortSparklineView.setRows("
+ "data.getFilteredRows([{column: 0, "
+ "minValue: '" + shortSparkMinYear + "', "
+ "maxValue: '" + currentYear + "'}])"
+ ");\n");
/*
* Create the vis object and draw it in the div pertaining to short-sparkline.
* */
visualizationCode.append("var short_spark = new google.visualization.ImageSparkLine("
+ "providedSparklineImgTD[0]"
+ ");\n"
+ "short_spark.draw(shortSparklineView, "
+ sparklineDisplayOptions + ");\n");
/*
* We want to display how many publication counts were considered, so this is used
* to calculate this.
* */
visualizationCode.append("var shortSparkRows = shortSparklineView.getViewRows();\n"
+ "var renderedShortSparks = 0;\n"
+ "$.each(shortSparkRows, function(index, value) {"
+ "renderedShortSparks += data.getValue(value, 1);"
+ "});\n");
/*
* Generate the text introducing the vis.
* */
String imcompleteDataText = "This information is based solely on publications which "
+ "have been loaded into the VIVO system. "
+ "This may only be a small sample of the person\\'s "
+ "total work.";
visualizationCode.append("$('#" + VIS_DIV_NAMES.get("SHORT_SPARK")
+ " td.sparkline_number').text("
+ "parseInt(renderedShortSparks) "
+ "+ parseInt(" + unknownYearPublications + "));");
visualizationCode.append("var shortSparksText = ''"
+ "+ ' publication(s) within the last 10 years "
+ "<span class=\"incomplete-data-holder\" title=\""
+ imcompleteDataText + "\">incomplete data</span>'"
+ "+ '';"
+ "$('#" + VIS_DIV_NAMES.get("SHORT_SPARK") + " "
+ "td.sparkline_text').html(shortSparksText);");
visualizationCode.append("}\n ");
/*
* Generate the code that will activate the visualization. It takes care of creating
* div elements to hold the actual sparkline image and then calling the
* drawPubCountVisualization function.
* */
visualizationCode.append(generateVisualizationActivator(VIS_DIV_NAMES.get("SHORT_SPARK"),
visContainerID));
}
private void generateFullSparklineVisualizationContent(
int currentYear,
int minPubYearConsidered,
String visContainerID,
StringBuilder visualizationCode,
int unknownYearPublications,
int renderedFullSparks,
String sparklineDisplayOptions) {
String csvDownloadURLHref = "";
try {
if (getCSVDownloadURL() != null) {
csvDownloadURLHref = "<a href=\"" + getCSVDownloadURL()
+ "\" class=\"inline_href\">(.CSV File)</a>";
} else {
csvDownloadURLHref = "";
}
} catch (UnsupportedEncodingException e) {
csvDownloadURLHref = "";
}
visualizationCode.append("var fullSparklineView = "
+ "new google.visualization.DataView(data);\n"
+ "fullSparklineView.setColumns([1]);\n");
visualizationCode.append("var full_spark = new google.visualization.ImageSparkLine("
+ "providedSparklineImgTD[0]"
+ ");\n"
+ "full_spark.draw(fullSparklineView, "
+ sparklineDisplayOptions + ");\n");
visualizationCode.append("$('#" + VIS_DIV_NAMES.get("FULL_SPARK")
+ " td.sparkline_number').text('" + (renderedFullSparks
+ unknownYearPublications) + "').css('font-weight', 'bold');");
visualizationCode.append("var allSparksText = ''"
+ "+ ' <h3>publication(s)</h3> '"
+ "+ ' "
+ "<span class=\"sparkline_range\">"
+ "from " + minPubYearConsidered + " to " + currentYear + ""
+ "</span> '"
+ "+ ' " + csvDownloadURLHref + " ';"
+ "$('#" + VIS_DIV_NAMES.get("FULL_SPARK")
+ " td.sparkline_text').html(allSparksText);");
visualizationCode.append("}\n ");
visualizationCode.append(generateVisualizationActivator(VIS_DIV_NAMES.get("FULL_SPARK"),
visContainerID));
}
private String generateVisualizationActivator(String sparklineID, String visContainerID) {
String sparklineTableWrapper = "\n"
+ "var table = $('<table>');"
+ "table.attr('class', 'sparkline_wrapper_table');"
+ "var row = $('<tr>');"
+ "sparklineImgTD = $('<td>');"
+ "sparklineImgTD.attr('id', '" + sparklineID + "_img');"
+ "sparklineImgTD.attr('width', '65');"
// + "sparklineImgTD.attr('align', 'right');"
+ "sparklineImgTD.attr('class', '" + VISUALIZATION_STYLE_CLASS + "');"
+ "row.append(sparklineImgTD);"
+ "var row2 = $('<tr>');"
+ "var sparklineNumberTD = $('<td>');"
// + "sparklineNumberTD.attr('width', '30');"
// + "sparklineNumberTD.attr('align', 'right');"
+ "sparklineNumberTD.attr('class', 'sparkline_number');"
+ "sparklineNumberTD.css('text-align', 'center');"
+ "row2.append(sparklineNumberTD);"
+ "var row3 = $('<tr>');"
+ "var sparklineTextTD = $('<td>');"
// + "sparklineTextTD.attr('width', '450');"
+ "sparklineTextTD.attr('class', 'sparkline_text');"
+ "row3.append(sparklineTextTD);"
+ "table.append(row);"
+ "table.append(row2);"
+ "table.append(row3);"
+ "table.prependTo('#" + sparklineID + "');\n";
return "$(document).ready(function() {"
+ "var sparklineImgTD; "
/*
* This is a nuclear option (creating the container in which everything goes)
* the only reason this will be ever used is the API user never submitted a
* container ID in which everything goes. The alternative was to let the
* vis not appear in the calling page at all. So now atleast vis appears but
* appended at the bottom of the body.
* */
+ "if ($('#" + visContainerID + "').length === 0) {"
+ " $('<div/>', {'id': '" + visContainerID + "'"
+ " }).appendTo('body');"
+ "}"
+ "if ($('#" + sparklineID + "').length === 0) {"
+ "$('<div/>', {'id': '" + sparklineID + "',"
+ "'class': '" + VISUALIZATION_STYLE_CLASS + "'"
+ "}).prependTo('#" + visContainerID + "');"
+ sparklineTableWrapper
+ "}"
+ "drawPubCountVisualization(sparklineImgTD);"
+ "});"
+ "</script>\n";
}
private String getVisualizationContextCode(String visMode) {
String visualizationContextCode = "";
if (VisualizationFrameworkConstants.SHORT_SPARKLINE_VIS_MODE.equalsIgnoreCase(visMode)) {
visualizationContextCode = generateShortVisContext();
} else {
visualizationContextCode = generateFullVisContext();
}
log.debug(visualizationContextCode);
return visualizationContextCode;
}
private String generateFullVisContext() {
StringBuilder divContextCode = new StringBuilder();
String csvDownloadURLHref = "";
if (yearToPublicationCount.size() > 0) {
try {
if (getCSVDownloadURL() != null) {
csvDownloadURLHref = "Download data as <a href='"
+ getCSVDownloadURL() + "'>.csv</a> file.<br />";
sparklineData.setDownloadDataLink(getCSVDownloadURL());
} else {
csvDownloadURLHref = "";
}
} catch (UnsupportedEncodingException e) {
csvDownloadURLHref = "";
}
} else {
csvDownloadURLHref = "No data available to export.<br />";
}
String tableCode = generateDataTable();
divContextCode.append("<p>" + tableCode + csvDownloadURLHref + "</p>");
sparklineData.setTable(tableCode);
return divContextCode.toString();
}
private String getCSVDownloadURL()
throws UnsupportedEncodingException {
if (yearToPublicationCount.size() > 0) {
String secondaryContextPath = "";
if (!contextPath.contains(VisualizationFrameworkConstants.VISUALIZATION_URL_PREFIX)) {
secondaryContextPath = VisualizationFrameworkConstants.VISUALIZATION_URL_PREFIX;
}
String downloadURL = contextPath
+ secondaryContextPath
+ "?" + VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY
+ "=" + URLEncoder.encode(individualURI,
VisualizationController.URL_ENCODING_SCHEME)
.toString()
+ "&" + VisualizationFrameworkConstants.VIS_TYPE_KEY
+ "=" + URLEncoder.encode(
VisualizationFrameworkConstants
.PERSON_PUBLICATION_COUNT_VIS,
VisualizationController.URL_ENCODING_SCHEME)
.toString()
+ "&" + VisualizationFrameworkConstants.RENDER_MODE_KEY
+ "=" + URLEncoder.encode(VisualizationFrameworkConstants
.DATA_RENDER_MODE,
VisualizationController.URL_ENCODING_SCHEME).toString()
+ "&"
+ VisualizationFrameworkConstants.VIS_MODE_KEY
+ "=" + URLEncoder.encode("coauthorship",
VisualizationController.URL_ENCODING_SCHEME).toString();
return downloadURL;
} else {
return null;
}
}
private String generateShortVisContext() {
StringBuilder divContextCode = new StringBuilder();
try {
String fullTimelineLink, fullTimelineCoPILink;
if (yearToPublicationCount.size() > 0) {
String secondaryContextPath = "";
if (!contextPath.contains(VisualizationFrameworkConstants.VISUALIZATION_URL_PREFIX)) {
secondaryContextPath = VisualizationFrameworkConstants.VISUALIZATION_URL_PREFIX;
}
String fullTimelineNetworkURL = contextPath
+ secondaryContextPath
+ "?"
+ VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY
+ "=" + URLEncoder.encode(individualURI,
VisualizationController.URL_ENCODING_SCHEME).toString()
+ "&"
+ VisualizationFrameworkConstants.VIS_TYPE_KEY
+ "=" + URLEncoder.encode("person_level",
VisualizationController.URL_ENCODING_SCHEME).toString()
+ "&"
+ VisualizationFrameworkConstants.RENDER_MODE_KEY
+ "=" + URLEncoder.encode(VisualizationFrameworkConstants
.STANDALONE_RENDER_MODE,
VisualizationController.URL_ENCODING_SCHEME).toString()
+ "&"
+ VisualizationFrameworkConstants.VIS_MODE_KEY
+ "=" + URLEncoder.encode("coauthorship",
VisualizationController.URL_ENCODING_SCHEME).toString();
fullTimelineLink = "<a href='" + fullTimelineNetworkURL + "'>View all VIVO "
+ "publications and corresponding co-author network.</a>";
sparklineData.setFullTimelineNetworkLink(fullTimelineNetworkURL);
String fullTimelineCoPINetworkURL = contextPath
+ secondaryContextPath
+ "?"
+ VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY
+ "=" + URLEncoder.encode(individualURI,
VisualizationController.URL_ENCODING_SCHEME).toString()
+ "&"
+ VisualizationFrameworkConstants.VIS_TYPE_KEY
+ "=" + URLEncoder.encode("person_level",
VisualizationController.URL_ENCODING_SCHEME).toString()
+ "&"
+ VisualizationFrameworkConstants.RENDER_MODE_KEY
+ "=" + URLEncoder.encode(VisualizationFrameworkConstants
.STANDALONE_RENDER_MODE,
VisualizationController.URL_ENCODING_SCHEME).toString()
+ "&"
+ VisualizationFrameworkConstants.VIS_MODE_KEY
+ "=" + URLEncoder.encode("copi",
VisualizationController.URL_ENCODING_SCHEME).toString();
fullTimelineCoPILink = "<a href='" + fullTimelineCoPINetworkURL + "'>View all "
+ "grants and corresponding co-pi network.</a>";
sparklineData.setFullTimelineCoPINetworkLink(fullTimelineCoPINetworkURL);
} else {
fullTimelineLink = "No data available to render full timeline.<br />";
fullTimelineCoPILink = "No data available to render full timeline.<br />";
}
divContextCode.append("<span class=\"vis_link\">" + fullTimelineLink + "</span>");
divContextCode.append("<br/><br/><span class=\"vis_link_copi\">" + fullTimelineCoPILink + "</span>");
} catch (UnsupportedEncodingException e) {
log.error(e);
}
return divContextCode.toString();
}
private String generateDataTable() {
String csvDownloadURLHref = "";
try {
if (getCSVDownloadURL() != null) {
csvDownloadURLHref = "<a href=\"" + getCSVDownloadURL() + "\">(.CSV File)</a>";
} else {
csvDownloadURLHref = "";
}
} catch (UnsupportedEncodingException e) {
csvDownloadURLHref = "";
}
StringBuilder dataTable = new StringBuilder();
dataTable.append("<table id='sparkline_data_table'>"
+ "<caption>Publications per year " + csvDownloadURLHref + "</caption>"
+ "<thead>"
+ "<tr>"
+ "<th>Year</th>"
+ "<th>Publications</th>"
+ "</tr>"
+ "</thead>"
+ "<tbody>");
for (Entry<String, Integer> currentEntry : yearToPublicationCount.entrySet()) {
dataTable.append("<tr>"
+ "<td>" + currentEntry.getKey() + "</td>"
+ "<td>" + currentEntry.getValue() + "</td>"
+ "</tr>");
}
dataTable.append("</tbody>\n </table>\n");
return dataTable.toString();
}
public SparklineData getValueObjectContainer() {
return sparklineData;
}
}