1. Refactored the vis code geenrators for publication, coauthor, coinvestigator, grants sparklines to remove unused code.

2. Changed logic to not to generate link to csv downloads if there is 0 publication/grant for an individual.
This commit is contained in:
cdtank 2011-02-08 21:22:55 +00:00
parent 4f7d3b8302
commit c2a0816ec1
10 changed files with 189 additions and 1687 deletions

View file

@ -187,9 +187,11 @@
if (totalPubs !== totalPublicationCount) { if (totalPubs !== totalPublicationCount) {
sparksText += ' (' + totalPublicationCount + ' total)'; sparksText += ' (' + totalPublicationCount + ' total)';
} }
if (totalPublicationCount) {
sparksText += ' <br /><a href="${sparklineVO.downloadDataLink}">(.CSV File)</a> ';
}
sparksText += ' <br /><a href="${sparklineVO.downloadDataLink}">(.CSV File)</a> ';
</#if> </#if>
if (!onlyUnknownYearPublications) { if (!onlyUnknownYearPublications) {

View file

@ -189,7 +189,10 @@
sparksText += ' (' + totalGrantCount + ' total)'; sparksText += ' (' + totalGrantCount + ' total)';
} }
sparksText += '<br /> <a href="${sparklineVO.downloadDataLink}">(.CSV File)</a> '; if (totalGrantCount) {
sparksText += '<br /> <a href="${sparklineVO.downloadDataLink}">(.CSV File)</a> ';
}
</#if> </#if>
if (!onlyUnknownYearGrants) { if (!onlyUnknownYearGrants) {

View file

@ -188,10 +188,11 @@
if (totalGrants !== totalGrantCount) { if (totalGrants !== totalGrantCount) {
sparksText += ' (' + totalGrantCount + ' total)'; sparksText += ' (' + totalGrantCount + ' total)';
} }
if (totalGrantCount) {
sparksText += '<br /> <a href="${sparklineVO.downloadDataLink}" >(.CSV File)</a> ';
}
sparksText += '<br /> <a href="${sparklineVO.downloadDataLink}" >(.CSV File)</a> ';
</#if> </#if>
if (!onlyUnknownYearGrants) { if (!onlyUnknownYearGrants) {

View file

@ -189,8 +189,11 @@
if (totalPubs !== totalPublicationCount) { if (totalPubs !== totalPublicationCount) {
sparksText += ' (' + totalPublicationCount + ' total)'; sparksText += ' (' + totalPublicationCount + ' total)';
} }
sparksText += ' <br /><a href="${sparklineVO.downloadDataLink}">(.CSV File)</a> '; if (totalPublicationCount) {
sparksText += ' <br /><a href="${sparklineVO.downloadDataLink}">(.CSV File)</a> ';
}
</#if> </#if>
if (!onlyUnknownYearPublications) { if (!onlyUnknownYearPublications) {

View file

@ -11,21 +11,18 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Set; import java.util.Set;
import java.util.Map.Entry;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap;
import edu.cornell.mannlib.vitro.webapp.controller.visualization.freemarker.VisualizationFrameworkConstants; import edu.cornell.mannlib.vitro.webapp.controller.visualization.freemarker.VisualizationFrameworkConstants;
import edu.cornell.mannlib.vitro.webapp.visualization.constants.VOConstants; 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.constants.VisConstants;
import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.Node; import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.Node;
import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.SparklineData; import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.SparklineData;
import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.YearToEntityCountDataElement; import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.YearToEntityCountDataElement;
import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.UtilityFunctions;
@SuppressWarnings("serial")
public class CoAuthorshipVisCodeGenerator { public class CoAuthorshipVisCodeGenerator {
/* /*
@ -37,22 +34,13 @@ public class CoAuthorshipVisCodeGenerator {
* spanning the career of the person & last 10 years at the minimum, in case if * 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. * 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", "unique_coauthors_short_sparkline_vis");
put("FULL_SPARK", "unique_coauthors_full_sparkline_vis");
} };
private static final String VISUALIZATION_STYLE_CLASS = "sparkline_style";
private static final String DEFAULT_VISCONTAINER_DIV_ID = "unique_coauthors_vis_container"; private static final String DEFAULT_VISCONTAINER_DIV_ID = "unique_coauthors_vis_container";
private Map<String, Set<Node>> yearToUniqueCoauthors; private Map<String, Set<Node>> yearToUniqueCoauthors;
private Log log; private Log log;
private SparklineData sparklineData; private SparklineData sparklineParameterVO;
private String individualURI; private String individualURI;
@ -65,36 +53,22 @@ public class CoAuthorshipVisCodeGenerator {
this.individualURI = individualURI; this.individualURI = individualURI;
this.yearToUniqueCoauthors = yearToUniqueCoauthors; this.yearToUniqueCoauthors = yearToUniqueCoauthors;
this.sparklineData = new SparklineData();
this.log = log; this.log = log;
generateVisualizationCode(visMode, visContainer); this.sparklineParameterVO = setupSparklineParameters(visMode, visContainer);
} }
/** /**
* This method is used to generate the visualization code (HMTL, CSS & JavaScript). * This method is used to setup parameters for the sparkline value object. These parameters
* There 2 parts to it - 1. Actual Content Code & 2. Context Code. * will be used in the template to construct the actual html/javascript 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 visMode
* @param visContainer * @param visContainer
*/ */
private void generateVisualizationCode(String visMode, private SparklineData setupSparklineParameters(String visMode,
String visContainer) {
sparklineData.setSparklineContent(getMainVisualizationCode(visMode,
visContainer));
sparklineData.setSparklineContext(getVisualizationContextCode(visMode));
}
private String getMainVisualizationCode(String visMode,
String providedVisContainerID) { String providedVisContainerID) {
SparklineData sparklineData = new SparklineData();
int numOfYearsToBeRendered = 0; int numOfYearsToBeRendered = 0;
int currentYear = Calendar.getInstance().get(Calendar.YEAR); int currentYear = Calendar.getInstance().get(Calendar.YEAR);
@ -118,8 +92,6 @@ public class CoAuthorshipVisCodeGenerator {
String visContainerID = null; String visContainerID = null;
StringBuilder visualizationCode = new StringBuilder();
if (yearToUniqueCoauthors.size() > 0) { if (yearToUniqueCoauthors.size() > 0) {
try { try {
minPublishedYear = Integer.parseInt(Collections.min(publishedYears)); minPublishedYear = Integer.parseInt(Collections.min(publishedYears));
@ -150,30 +122,6 @@ public class CoAuthorshipVisCodeGenerator {
sparklineData.setNumOfYearsToBeRendered(numOfYearsToBeRendered); sparklineData.setNumOfYearsToBeRendered(numOfYearsToBeRendered);
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;"
+ "}"
+ ".incomplete-data-holder {"
+ ""
+ "}"
+ "td.sparkline_number { text-align:right; "
+ "padding-right:5px; }"
+ "td.sparkline_text {text-align:left;}"
+ "</style>\n");
visualizationCode.append("<script type=\"text/javascript\">\n"
+ "function drawUniqueCoauthorCountVisualization(providedSparklineImgTD) {\n"
+ "var data = new google.visualization.DataTable();\n"
+ "data.addColumn('string', 'Year');\n"
+ "data.addColumn('number', 'Unique co-authors');\n"
+ "data.addRows(" + numOfYearsToBeRendered + ");\n");
int uniqueCoAuthorCounter = 0; int uniqueCoAuthorCounter = 0;
int renderedFullSparks = 0; int renderedFullSparks = 0;
Set<Node> allCoAuthorsWithKnownAuthorshipYears = new HashSet<Node>(); Set<Node> allCoAuthorsWithKnownAuthorshipYears = new HashSet<Node>();
@ -195,18 +143,6 @@ public class CoAuthorshipVisCodeGenerator {
currentUniqueCoAuthors = 0; currentUniqueCoAuthors = 0;
} }
visualizationCode.append("data.setValue("
+ uniqueCoAuthorCounter
+ ", 0, '"
+ publicationYearAsString
+ "');\n");
visualizationCode.append("data.setValue("
+ uniqueCoAuthorCounter
+ ", 1, "
+ currentUniqueCoAuthors
+ ");\n");
yearToUniqueCoauthorsCountDataTable.add(new YearToEntityCountDataElement(uniqueCoAuthorCounter, yearToUniqueCoauthorsCountDataTable.add(new YearToEntityCountDataElement(uniqueCoAuthorCounter,
publicationYearAsString, publicationYearAsString,
currentUniqueCoAuthors)); currentUniqueCoAuthors));
@ -238,9 +174,6 @@ public class CoAuthorshipVisCodeGenerator {
sparklineData.setUnknownYearPublications(unknownYearCoauthors); sparklineData.setUnknownYearPublications(unknownYearCoauthors);
String sparklineDisplayOptions = "{width: 65, height: 30, showAxisLines: false, "
+ "showValueLabels: false, labelPosition: 'none'}";
if (providedVisContainerID != null) { if (providedVisContainerID != null) {
visContainerID = providedVisContainerID; visContainerID = providedVisContainerID;
} else { } else {
@ -262,351 +195,41 @@ public class CoAuthorshipVisCodeGenerator {
* The Full Sparkline will be rendered by default. Only if the url has specific mention of * The Full Sparkline will be rendered by default. Only if the url has specific mention of
* SHORT_SPARKLINE_MODE_KEY then we render the short sparkline and not otherwise. * SHORT_SPARKLINE_MODE_KEY 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)) { if (VisualizationFrameworkConstants.SHORT_SPARKLINE_VIS_MODE.equalsIgnoreCase(visMode)) {
sparklineData.setEarliestRenderedPublicationYear(shortSparkMinYear); sparklineData.setEarliestRenderedPublicationYear(shortSparkMinYear);
sparklineData.setShortVisMode(true); sparklineData.setShortVisMode(true);
generateShortSparklineVisualizationContent(currentYear,
shortSparkMinYear,
visContainerID,
visualizationCode,
unknownYearCoauthors,
sparklineDisplayOptions);
} else { } else {
sparklineData.setShortVisMode(false); sparklineData.setShortVisMode(false);
generateFullSparklineVisualizationContent(currentYear,
minPubYearConsidered,
visContainerID,
visualizationCode,
unknownYearCoauthors,
renderedFullSparks,
sparklineDisplayOptions);
} }
log.debug(visualizationCode);
return visualizationCode.toString();
}
private void generateShortSparklineVisualizationContent(int currentYear,
int shortSparkMinYear,
String visContainerID,
StringBuilder visualizationCode,
int unknownYearCoauthors,
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(" + unknownYearCoauthors + "));");
visualizationCode.append("var shortSparksText = ''"
+ "+ ' co-author(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
* drawUniqueCoauthorCountVisualization function.
* */
visualizationCode.append(generateVisualizationActivator(VIS_DIV_NAMES.get("SHORT_SPARK"),
visContainerID));
}
private void generateFullSparklineVisualizationContent(int currentYear,
int minPubYearConsidered,
String visContainerID,
StringBuilder visualizationCode,
int unknownYearCoauthors,
int renderedFullSparks,
String sparklineDisplayOptions) {
String csvDownloadURLHref = "";
if (getCSVDownloadURL() != null) {
csvDownloadURLHref = "<a href=\"" + getCSVDownloadURL()
+ "\" class=\"inline_href\">(.CSV File)</a>";
} else {
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
+ unknownYearCoauthors) + "');");
visualizationCode.append("var allSparksText = ''"
+ "+ ' co-author(s) from '"
+ "+ ' <span class=\"sparkline_range\">"
+ "" + 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 sparklineNumberTD = $('<td>');"
+ "sparklineNumberTD.attr('width', '30');"
+ "sparklineNumberTD.attr('align', 'right');"
+ "sparklineNumberTD.attr('class', 'sparkline_number');"
+ "row.append(sparklineNumberTD);"
+ "var sparklineTextTD = $('<td>');"
+ "sparklineTextTD.attr('width', '350');"
+ "sparklineTextTD.attr('class', 'sparkline_text');"
+ "row.append(sparklineTextTD);"
+ "table.append(row);"
+ "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
+ "}"
+ "drawUniqueCoauthorCountVisualization(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 (yearToUniqueCoauthors.size() > 0) { if (yearToUniqueCoauthors.size() > 0) {
if (getCSVDownloadURL() != null) { sparklineData.setFullTimelineNetworkLink(UtilityFunctions.getCollaboratorshipNetworkLink(individualURI,
csvDownloadURLHref = "Download data as <a href='"
+ getCSVDownloadURL() + "'>.csv</a> file.<br />";
sparklineData.setDownloadDataLink(getCSVDownloadURL());
} else {
csvDownloadURLHref = "";
}
} else {
csvDownloadURLHref = "No data available to export.<br />";
}
String tableCode = generateDataTable();
divContextCode.append("<p>" + tableCode + csvDownloadURLHref + "</p>");
sparklineData.setTable(tableCode);
Map<String, Integer> yearToUniqueCoauthorsCount = new HashMap<String, Integer>();
for (Map.Entry<String, Set<Node>> currentYear : yearToUniqueCoauthors.entrySet()) {
yearToUniqueCoauthorsCount.put(currentYear.getKey(), currentYear.getValue().size());
}
sparklineData.setYearToActivityCount(yearToUniqueCoauthorsCount);
return divContextCode.toString();
}
private String getCSVDownloadURL(){
if (yearToUniqueCoauthors.size() > 0) {
ParamMap CSVDownloadURLParams = new ParamMap(VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY,
individualURI,
VisualizationFrameworkConstants.VIS_TYPE_KEY,
VisualizationFrameworkConstants.COAUTHORSHIP_VIS,
VisualizationFrameworkConstants.VIS_MODE_KEY,
VisualizationFrameworkConstants.COAUTHORS_COUNT_PER_YEAR_VIS_MODE);
return UrlBuilder.getUrl(VisualizationFrameworkConstants.DATA_VISUALIZATION_SERVICE_URL_PREFIX,
CSVDownloadURLParams);
} else {
return null;
}
}
private String generateShortVisContext() {
StringBuilder divContextCode = new StringBuilder();
String fullTimelineLink;
if (yearToUniqueCoauthors.size() > 0) {
ParamMap fullTimelineNetworkURLParams = new ParamMap(
VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY,
individualURI,
VisualizationFrameworkConstants.VIS_TYPE_KEY,
VisualizationFrameworkConstants.PERSON_LEVEL_VIS, VisualizationFrameworkConstants.PERSON_LEVEL_VIS,
VisualizationFrameworkConstants.VIS_MODE_KEY, VisualizationFrameworkConstants.COAUTHOR_VIS_MODE));
VisualizationFrameworkConstants.COAUTHOR_VIS_MODE);
String fullTimelineNetworkURL = UrlBuilder.getUrl(
VisualizationFrameworkConstants.FREEMARKERIZED_VISUALIZATION_URL_PREFIX,
fullTimelineNetworkURLParams);
fullTimelineLink = "<a href='" + fullTimelineNetworkURL
+ "'>View full timeline and co-author network.</a>";
sparklineData.setFullTimelineNetworkLink(fullTimelineNetworkURL); sparklineData.setDownloadDataLink(UtilityFunctions
.getCSVDownloadURL(
individualURI,
VisualizationFrameworkConstants.COAUTHORSHIP_VIS,
VisualizationFrameworkConstants.COAUTHORS_COUNT_PER_YEAR_VIS_MODE));
} else { Map<String, Integer> yearToUniqueCoauthorsCount = new HashMap<String, Integer>();
fullTimelineLink = "No data available to render full timeline.<br />";
for (Map.Entry<String, Set<Node>> currentYearToCoAuthors : yearToUniqueCoauthors.entrySet()) {
yearToUniqueCoauthorsCount.put(currentYearToCoAuthors.getKey(),
currentYearToCoAuthors.getValue().size());
}
sparklineData.setYearToActivityCount(yearToUniqueCoauthorsCount);
} }
divContextCode.append("<p>" + fullTimelineLink + "</p>");
return divContextCode.toString();
}
private String generateDataTable() {
StringBuilder dataTable = new StringBuilder();
dataTable.append("<table id='sparkline_data_table'>"
+ "<caption>Unique Co-Authors per year</caption>"
+ "<thead>"
+ "<tr>"
+ "<th>Year</th>"
+ "<th>Count</th>"
+ "</tr>"
+ "</thead>"
+ "<tbody>");
for (Entry<String, Set<Node>> currentEntry : yearToUniqueCoauthors.entrySet()) {
dataTable.append("<tr>"
+ "<td>" + currentEntry.getKey() + "</td>"
+ "<td>" + currentEntry.getValue().size() + "</td>"
+ "</tr>");
}
dataTable.append("</tbody>\n </table>\n");
return dataTable.toString();
}
public SparklineData getValueObjectContainer() {
return sparklineData; return sparklineData;
} }
}
public SparklineData getValueObjectContainer() {
return this.sparklineParameterVO;
}
}

View file

@ -9,20 +9,18 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Set; import java.util.Set;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap;
import edu.cornell.mannlib.vitro.webapp.controller.visualization.freemarker.VisualizationFrameworkConstants; import edu.cornell.mannlib.vitro.webapp.controller.visualization.freemarker.VisualizationFrameworkConstants;
import edu.cornell.mannlib.vitro.webapp.visualization.constants.VOConstants; 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.constants.VisConstants;
import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.CoPINode; import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.CoPINode;
import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.SparklineData; import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.SparklineData;
import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.YearToEntityCountDataElement; import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.YearToEntityCountDataElement;
import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.UtilityFunctions;
/** /**
* This class contains code for rendering sparklines and displaying tables for * This class contains code for rendering sparklines and displaying tables for
@ -30,7 +28,6 @@ import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.Ye
* @author bkoniden * @author bkoniden
* Deepak Konidena * Deepak Konidena
*/ */
@SuppressWarnings("serial")
public class CoPIVisCodeGenerator { public class CoPIVisCodeGenerator {
/* /*
@ -42,22 +39,13 @@ public class CoPIVisCodeGenerator {
* spanning the career of the person & last 10 years at the minimum, in case if * spanning the career of the person & last 10 years at the minimum, in case if
* the person started his career in the last 10 years. * the person started his career in the last 10 years.
* */ * */
private static final Map<String, String> VIS_DIV_NAMES = new HashMap<String, String>() { {
put("SHORT_SPARK", "unique_copis_short_sparkline_vis");
put("FULL_SPARK", "unique_copis_full_sparkline_vis");
} };
private static final String VISUALIZATION_STYLE_CLASS = "sparkline_style";
private static final String DEFAULT_VISCONTAINER_DIV_ID = "unique_coinvestigators_vis_container"; private static final String DEFAULT_VISCONTAINER_DIV_ID = "unique_coinvestigators_vis_container";
private Map<String, Set<CoPINode>> yearToUniqueCoPIs; private Map<String, Set<CoPINode>> yearToUniqueCoPIs;
private Log log; private Log log;
private SparklineData sparklineData; private SparklineData sparklineParameterVO;
private String individualURI; private String individualURI;
@ -70,37 +58,23 @@ public class CoPIVisCodeGenerator {
this.individualURI = individualURI; this.individualURI = individualURI;
this.yearToUniqueCoPIs = yearToUniqueCoPIs; this.yearToUniqueCoPIs = yearToUniqueCoPIs;
this.sparklineData = new SparklineData();
this.log = log; this.log = log;
generateVisualizationCode(visMode, visContainer); this.sparklineParameterVO = setupSparklineParameters(visMode, visContainer);
} }
/** /**
* This method is used to generate the visualization code (HMTL, CSS & * This method is used to setup parameters for the sparkline value object. These parameters
* JavaScript). There 2 parts to it - 1. Actual Content Code & 2. Context * will be used in the template to construct the actual html/javascript code.
* 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 visMode
* @param visContainer * @param visContainer
*/ */
private void generateVisualizationCode(String visMode, String visContainer) { private SparklineData setupSparklineParameters(String visMode,
String providedVisContainerID) {
sparklineData.setSparklineContent(getMainVisualizationCode(visMode, SparklineData sparklineData = new SparklineData();
visContainer));
sparklineData.setSparklineContext(getVisualizationContextCode(visMode));
}
private String getMainVisualizationCode(String visMode,
String providedVisContainerID) {
int numOfYearsToBeRendered = 0; int numOfYearsToBeRendered = 0;
int currentYear = Calendar.getInstance().get(Calendar.YEAR); int currentYear = Calendar.getInstance().get(Calendar.YEAR);
@ -126,8 +100,6 @@ public class CoPIVisCodeGenerator {
String visContainerID = null; String visContainerID = null;
StringBuilder visualizationCode = new StringBuilder();
if (yearToUniqueCoPIs.size() > 0) { if (yearToUniqueCoPIs.size() > 0) {
try { try {
minGrantYear = Integer.parseInt(Collections minGrantYear = Integer.parseInt(Collections
@ -160,24 +132,6 @@ public class CoPIVisCodeGenerator {
sparklineData.setNumOfYearsToBeRendered(numOfYearsToBeRendered); sparklineData.setNumOfYearsToBeRendered(numOfYearsToBeRendered);
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;" + "}"
+ ".incomplete-data-holder {" + "" + "}"
+ "td.sparkline_number { text-align:right; "
+ "padding-right:5px; }"
+ "td.sparkline_text {text-align:left;}" + "</style>\n");
visualizationCode
.append("<script type=\"text/javascript\">\n"
+ "function drawUniqueCoPICountVisualization(providedSparklineImgTD) {\n"
+ "var data = new google.visualization.DataTable();\n"
+ "data.addColumn('string', 'Year');\n"
+ "data.addColumn('number', 'Unique Co-PI(s)');\n"
+ "data.addRows(" + numOfYearsToBeRendered + ");\n");
int uniqueCoPICounter = 0; int uniqueCoPICounter = 0;
int renderedFullSparks = 0; int renderedFullSparks = 0;
Set<CoPINode> allCoPIsWithKnownGrantShipYears = new HashSet<CoPINode>(); Set<CoPINode> allCoPIsWithKnownGrantShipYears = new HashSet<CoPINode>();
@ -198,12 +152,6 @@ public class CoPIVisCodeGenerator {
currentUniqueCoPIs = 0; currentUniqueCoPIs = 0;
} }
visualizationCode.append("data.setValue(" + uniqueCoPICounter
+ ", 0, '" + grantYearAsString + "');\n");
visualizationCode.append("data.setValue(" + uniqueCoPICounter
+ ", 1, " + currentUniqueCoPIs + ");\n");
yearToUniqueInvestigatorsCountDataTable.add(new YearToEntityCountDataElement(uniqueCoPICounter, yearToUniqueInvestigatorsCountDataTable.add(new YearToEntityCountDataElement(uniqueCoPICounter,
grantYearAsString, grantYearAsString,
currentUniqueCoPIs)); currentUniqueCoPIs));
@ -234,9 +182,6 @@ public class CoPIVisCodeGenerator {
sparklineData.setUnknownYearGrants(unknownYearGrants); sparklineData.setUnknownYearGrants(unknownYearGrants);
String sparklineDisplayOptions = "{width: 65, height: 30, showAxisLines: false, "
+ "showValueLabels: false, labelPosition: 'none'}";
if (providedVisContainerID != null) { if (providedVisContainerID != null) {
visContainerID = providedVisContainerID; visContainerID = providedVisContainerID;
} else { } else {
@ -259,348 +204,42 @@ public class CoPIVisCodeGenerator {
* specific mention of SHORT_SPARKLINE_MODE_KEY then we render the short * specific mention of SHORT_SPARKLINE_MODE_KEY then we render the short
* sparkline and not otherwise. * 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 if (VisualizationFrameworkConstants.SHORT_SPARKLINE_VIS_MODE
.equalsIgnoreCase(visMode)) { .equalsIgnoreCase(visMode)) {
sparklineData.setEarliestRenderedGrantYear(shortSparkMinYear); sparklineData.setEarliestRenderedGrantYear(shortSparkMinYear);
sparklineData.setShortVisMode(true); sparklineData.setShortVisMode(true);
generateShortSparklineVisualizationContent(currentYear,
shortSparkMinYear, visContainerID, visualizationCode,
unknownYearGrants, sparklineDisplayOptions);
} else { } else {
sparklineData.setShortVisMode(false); sparklineData.setShortVisMode(false);
generateFullSparklineVisualizationContent(currentYear,
minGrantYearConsidered, visContainerID, visualizationCode,
unknownYearGrants, renderedFullSparks,
sparklineDisplayOptions);
} }
log.debug(visualizationCode);
return visualizationCode.toString();
}
private void generateShortSparklineVisualizationContent(int currentYear,
int shortSparkMinYear, String visContainerID,
StringBuilder visualizationCode, int unknownYearGrants,
String sparklineDisplayOptions) {
/*
* Create a view of the data containing only the column pertaining to
* grant 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
* grant 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 grant 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 grants 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("
+ unknownYearGrants + "));");
visualizationCode.append("var shortSparksText = ''"
+ "+ ' grant(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 drawUniqueCoPICountVisualization function.
*/
visualizationCode.append(generateVisualizationActivator(VIS_DIV_NAMES
.get("SHORT_SPARK"), visContainerID));
}
private void generateFullSparklineVisualizationContent(
int currentYear,
int minGrantYearConsidered,
String visContainerID,
StringBuilder visualizationCode,
int unknownYearGrants,
int renderedFullSparks,
String sparklineDisplayOptions) {
String csvDownloadURLHref = "";
if (getCSVDownloadURL() != null) {
csvDownloadURLHref = "<a href=\"" + getCSVDownloadURL()
+ "\" class=\"inline_href\">(.CSV File)</a>";
} else {
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
+ unknownYearGrants) + "');");
visualizationCode.append("var allSparksText = ''"
+ "+ ' Co-Principal Investigator(s) '"
+ "+ ' from "
+ "<span class=\"sparkline_range\">"
+ "" + minGrantYearConsidered + " 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 sparklineNumberTD = $('<td>');"
+ "sparklineNumberTD.attr('width', '30');"
+ "sparklineNumberTD.attr('align', 'right');"
+ "sparklineNumberTD.attr('class', 'sparkline_number');"
+ "row.append(sparklineNumberTD);"
+ "var sparklineTextTD = $('<td>');"
+ "sparklineTextTD.attr('width', '450');"
+ "sparklineTextTD.attr('class', 'sparkline_text');"
+ "row.append(sparklineTextTD);"
+ "table.append(row);"
+ "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
+ "}"
+ "drawUniqueCoPICountVisualization(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 (yearToUniqueCoPIs.size() > 0) { if (yearToUniqueCoPIs.size() > 0) {
if (getCSVDownloadURL() != null) { sparklineData.setFullTimelineNetworkLink(UtilityFunctions.getCollaboratorshipNetworkLink(individualURI,
csvDownloadURLHref = "Download data as <a href='"
+ getCSVDownloadURL() + "'>.csv</a> file.<br />";
sparklineData.setDownloadDataLink(getCSVDownloadURL());
} else {
csvDownloadURLHref = "";
}
} else {
csvDownloadURLHref = "No data available to export.<br />";
}
String tableCode = generateDataTable();
divContextCode.append("<p>" + tableCode + csvDownloadURLHref + "</p>");
sparklineData.setTable(tableCode);
Map<String, Integer> yearToUniqueCoPIsCount = new HashMap<String, Integer>();
for (Map.Entry<String, Set<CoPINode>> currentYear : yearToUniqueCoPIs.entrySet()) {
yearToUniqueCoPIsCount.put(currentYear.getKey(), currentYear.getValue().size());
}
sparklineData.setYearToActivityCount(yearToUniqueCoPIsCount);
return divContextCode.toString();
}
private String getCSVDownloadURL() {
if (yearToUniqueCoPIs.size() > 0) {
ParamMap CSVDownloadURLParams = new ParamMap(VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY,
individualURI,
VisualizationFrameworkConstants.VIS_TYPE_KEY,
VisualizationFrameworkConstants.CO_PI_VIS,
VisualizationFrameworkConstants.VIS_MODE_KEY,
VisualizationFrameworkConstants.COPIS_COUNT_PER_YEAR_VIS_MODE);
return UrlBuilder.getUrl(VisualizationFrameworkConstants.DATA_VISUALIZATION_SERVICE_URL_PREFIX,
CSVDownloadURLParams);
} else {
return null;
}
}
private String generateShortVisContext() {
StringBuilder divContextCode = new StringBuilder();
String fullTimelineLink;
if (yearToUniqueCoPIs.size() > 0) {
ParamMap fullTimelineNetworkURLParams = new ParamMap(
VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY,
individualURI,
VisualizationFrameworkConstants.VIS_TYPE_KEY,
VisualizationFrameworkConstants.PERSON_LEVEL_VIS, VisualizationFrameworkConstants.PERSON_LEVEL_VIS,
VisualizationFrameworkConstants.VIS_MODE_KEY, VisualizationFrameworkConstants.COPI_VIS_MODE));
VisualizationFrameworkConstants.COPI_VIS_MODE);
sparklineData.setDownloadDataLink(UtilityFunctions
.getCSVDownloadURL(
individualURI,
VisualizationFrameworkConstants.CO_PI_VIS,
VisualizationFrameworkConstants.COPIS_COUNT_PER_YEAR_VIS_MODE));
Map<String, Integer> yearToUniqueCoPIsCount = new HashMap<String, Integer>();
for (Map.Entry<String, Set<CoPINode>> currentYearToUniqueCoPIsCount : yearToUniqueCoPIs.entrySet()) {
yearToUniqueCoPIsCount.put(currentYearToUniqueCoPIsCount.getKey(),
currentYearToUniqueCoPIsCount.getValue().size());
}
String fullTimelineNetworkURL = UrlBuilder.getUrl( sparklineData.setYearToActivityCount(yearToUniqueCoPIsCount);
VisualizationFrameworkConstants.FREEMARKERIZED_VISUALIZATION_URL_PREFIX,
fullTimelineNetworkURLParams);
fullTimelineLink = "<a href='" + fullTimelineNetworkURL
+ "'>View full timeline and co-pi network.</a>";
sparklineData.setFullTimelineNetworkLink(fullTimelineNetworkURL);
} else {
fullTimelineLink = "No data available to render full timeline.<br />";
} }
divContextCode.append("<p>" + fullTimelineLink + "</p>");
return divContextCode.toString();
}
private String generateDataTable() {
StringBuilder dataTable = new StringBuilder();
dataTable.append("<table id='sparkline_data_table'>"
+ "<caption>Unique Co-PIs per year</caption>"
+ "<thead>"
+ "<tr>"
+ "<th>Year</th>"
+ "<th>Count</th>"
+ "</tr>"
+ "</thead>"
+ "<tbody>");
for (Entry<String, Set<CoPINode>> currentEntry : yearToUniqueCoPIs.entrySet()) {
dataTable.append("<tr>"
+ "<td>" + currentEntry.getKey() + "</td>"
+ "<td>" + currentEntry.getValue().size() + "</td>"
+ "</tr>");
}
dataTable.append("</tbody>\n </table>\n");
return dataTable.toString();
}
public SparklineData getValueObjectContainer() {
return sparklineData; return sparklineData;
} }
public SparklineData getValueObjectContainer() {
return this.sparklineParameterVO;
}
} }

View file

@ -5,27 +5,23 @@ package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.persongrantcou
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Set; import java.util.Set;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap;
import edu.cornell.mannlib.vitro.webapp.controller.visualization.freemarker.VisualizationFrameworkConstants; import edu.cornell.mannlib.vitro.webapp.controller.visualization.freemarker.VisualizationFrameworkConstants;
import edu.cornell.mannlib.vitro.webapp.visualization.constants.VOConstants; 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.constants.VisConstants;
import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.Grant; import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.Grant;
import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.SparklineData; import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.SparklineData;
import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.YearToEntityCountDataElement; import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.YearToEntityCountDataElement;
import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.UtilityFunctions;
@SuppressWarnings("serial")
public class PersonGrantCountVisCodeGenerator { public class PersonGrantCountVisCodeGenerator {
/* /*
@ -38,22 +34,13 @@ public class PersonGrantCountVisCodeGenerator {
* the person started his career in the last 10 yeras. * 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", "grant_count_short_sparkline_vis");
put("FULL_SPARK", "grant_count_full_sparkline_vis");
} };
private static final String VISUALIZATION_STYLE_CLASS = "sparkline_style";
private static final String DEFAULT_VIS_CONTAINER_DIV_ID = "grant_count_vis_container"; private static final String DEFAULT_VIS_CONTAINER_DIV_ID = "grant_count_vis_container";
private Map<String, Integer> yearToGrantCount; private Map<String, Integer> yearToGrantCount;
private Log log; private Log log;
private SparklineData sparklineData; private SparklineData sparklineParameterVO;
private String individualURI; private String individualURI;
@ -65,43 +52,28 @@ public class PersonGrantCountVisCodeGenerator {
this.individualURI = individualURIParam; this.individualURI = individualURIParam;
this.yearToGrantCount = yearToGrantCount; this.yearToGrantCount = yearToGrantCount;
this.sparklineData = new SparklineData();
sparklineData.setYearToActivityCount(yearToGrantCount);
this.log = log; this.log = log;
this.sparklineParameterVO = setupSparklineParameters(visMode, visContainer, piGrants);
generateVisualizationCode(visMode, visContainer, piGrants);
} }
/** /**
* This method is used to generate the visualization code (HMTL, CSS & JavaScript). * This method is used to setup parameters for the sparkline value object. These parameters
* There 2 parts to it - 1. Actual Content Code & 2. Context Code. * will be used in the template to construct the actual html/javascript 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 visMode
* @param visContainer * @param visContainer
* @param piGrants * @param authorDocuments
* @return
*/ */
private void generateVisualizationCode(String visMode, private SparklineData setupSparklineParameters(String visMode,
String visContainer, String providedVisContainerID,
Set<Grant> piGrants) { Set<Grant> piGrants) {
sparklineData.setSparklineContent(getMainVisualizationCode(piGrants, SparklineData sparklineData = new SparklineData();
visMode, sparklineData.setYearToActivityCount(yearToGrantCount);
visContainer));
sparklineData.setSparklineContext(getVisualizationContextCode(visMode));
}
private String getMainVisualizationCode(Set<Grant> piGrants,
String visMode, String providedVisContainerID) {
int numOfYearsToBeRendered = 0; int numOfYearsToBeRendered = 0;
int currentYear = Calendar.getInstance().get(Calendar.YEAR); int currentYear = Calendar.getInstance().get(Calendar.YEAR);
int shortSparkMinYear = currentYear int shortSparkMinYear = currentYear
@ -112,8 +84,7 @@ public class PersonGrantCountVisCodeGenerator {
* the vis was rendered we dont want to be influenced by the * the vis was rendered we dont want to be influenced by the
* "DEFAULT_GRANT_YEAR". * "DEFAULT_GRANT_YEAR".
*/ */
Set<String> grantYears = new HashSet<String>(yearToGrantCount Set<String> grantYears = new HashSet<String>(yearToGrantCount.keySet());
.keySet());
grantYears.remove(VOConstants.DEFAULT_GRANT_YEAR); grantYears.remove(VOConstants.DEFAULT_GRANT_YEAR);
/* /*
@ -126,8 +97,6 @@ public class PersonGrantCountVisCodeGenerator {
String visContainerID = null; String visContainerID = null;
StringBuilder visualizationCode = new StringBuilder();
if (yearToGrantCount.size() > 0) { if (yearToGrantCount.size() > 0) {
try { try {
minGrantYear = Integer.parseInt(Collections minGrantYear = Integer.parseInt(Collections
@ -160,26 +129,6 @@ public class PersonGrantCountVisCodeGenerator {
sparklineData.setNumOfYearsToBeRendered(numOfYearsToBeRendered); sparklineData.setNumOfYearsToBeRendered(numOfYearsToBeRendered);
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 drawGrantCountVisualization(providedSparklineImgTD) "
+ "{\n" + "var data = new google.visualization.DataTable();\n"
+ "data.addColumn('string', 'Year');\n"
+ "data.addColumn('number', 'Grants');\n"
+ "data.addRows(" + numOfYearsToBeRendered + ");\n");
int grantCounter = 0; int grantCounter = 0;
/* /*
@ -201,12 +150,6 @@ public class PersonGrantCountVisCodeGenerator {
currentGrants = 0; currentGrants = 0;
} }
visualizationCode.append("data.setValue(" + grantCounter
+ ", 0, '" + stringInvestigatedYear + "');\n");
visualizationCode.append("data.setValue(" + grantCounter
+ ", 1, " + currentGrants + ");\n");
yearToGrantCountDataTable yearToGrantCountDataTable
.add(new YearToEntityCountDataElement( .add(new YearToEntityCountDataElement(
grantCounter, stringInvestigatedYear, grantCounter, stringInvestigatedYear,
@ -221,9 +164,7 @@ public class PersonGrantCountVisCodeGenerator {
} }
sparklineData sparklineData.setYearToEntityCountDataTable(yearToGrantCountDataTable);
.setYearToEntityCountDataTable(yearToGrantCountDataTable);
sparklineData.setRenderedSparks(renderedFullSparks); sparklineData.setRenderedSparks(renderedFullSparks);
/* /*
@ -238,9 +179,6 @@ public class PersonGrantCountVisCodeGenerator {
sparklineData.setUnknownYearGrants(unknownYearGrants); sparklineData.setUnknownYearGrants(unknownYearGrants);
String sparklineDisplayOptions = "{width: 65, height: 30, showAxisLines: false, "
+ "showValueLabels: false, labelPosition: 'none'}";
if (providedVisContainerID != null) { if (providedVisContainerID != null) {
visContainerID = providedVisContainerID; visContainerID = providedVisContainerID;
} else { } else {
@ -263,347 +201,35 @@ public class PersonGrantCountVisCodeGenerator {
* specific mention of SHORT_SPARKLINE_MODE_URL_HANDLE then we render * specific mention of SHORT_SPARKLINE_MODE_URL_HANDLE then we render
* the short sparkline and not otherwise. * 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 if (VisualizationFrameworkConstants.SHORT_SPARKLINE_VIS_MODE
.equalsIgnoreCase(visMode)) { .equalsIgnoreCase(visMode)) {
sparklineData.setEarliestRenderedGrantYear(shortSparkMinYear); sparklineData.setEarliestRenderedGrantYear(shortSparkMinYear);
sparklineData.setShortVisMode(true); sparklineData.setShortVisMode(true);
generateShortSparklineVisualizationContent(currentYear,
shortSparkMinYear, visContainerID, visualizationCode,
unknownYearGrants, sparklineDisplayOptions);
} else { } else {
sparklineData.setShortVisMode(false); sparklineData.setShortVisMode(false);
generateFullSparklineVisualizationContent(currentYear,
minGrantYearConsidered, visContainerID, visualizationCode,
unknownYearGrants, renderedFullSparks,
sparklineDisplayOptions);
}
log.debug(visualizationCode);
return visualizationCode.toString();
}
private void generateShortSparklineVisualizationContent(int currentYear,
int shortSparkMinYear, String visContainerID,
StringBuilder visualizationCode, int unknownYearGrants,
String sparklineDisplayOptions) {
/*
* Create a view of the data containing only the column pertaining to
* grant 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
* grant 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 grant 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 grants 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("
+ unknownYearGrants + "));");
visualizationCode.append("var shortSparksText = ''"
+ "+ ' grant(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 drawGrantCountVisualization function.
*/
visualizationCode.append(generateVisualizationActivator(VIS_DIV_NAMES
.get("SHORT_SPARK"), visContainerID));
}
private void generateFullSparklineVisualizationContent(
int currentYear,
int minGrantYearConsidered,
String visContainerID,
StringBuilder visualizationCode,
int unknownYearGrants,
int renderedFullSparks,
String sparklineDisplayOptions) {
String csvDownloadURLHref = "";
if (getCSVDownloadURL() != null) {
csvDownloadURLHref = "<a href=\"" + getCSVDownloadURL()
+ "\" class=\"inline_href\">(.CSV File)</a>";
} else {
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
+ unknownYearGrants) + "');");
visualizationCode.append("var allSparksText = ''"
+ "+ ' grant(s) '"
+ "+ ' from "
+ "<span class=\"sparkline_range\">"
+ "" + minGrantYearConsidered + " 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 sparklineNumberTD = $('<td>');"
+ "sparklineNumberTD.attr('width', '30');"
+ "sparklineNumberTD.attr('align', 'right');"
+ "sparklineNumberTD.attr('class', 'sparkline_number');"
+ "row.append(sparklineNumberTD);"
+ "var sparklineTextTD = $('<td>');"
+ "sparklineTextTD.attr('width', '450');"
+ "sparklineTextTD.attr('class', 'sparkline_text');"
+ "row.append(sparklineTextTD);"
+ "table.append(row);"
+ "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 (yearToGrantCount.size() > 0) { if (yearToGrantCount.size() > 0) {
if (getCSVDownloadURL() != null) { sparklineData.setFullTimelineNetworkLink(UtilityFunctions.getCollaboratorshipNetworkLink(individualURI,
VisualizationFrameworkConstants.PERSON_LEVEL_VIS,
csvDownloadURLHref = "Download data as <a href='" VisualizationFrameworkConstants.COPI_VIS_MODE));
+ getCSVDownloadURL() + "'>.csv</a> file.<br />";
sparklineData.setDownloadDataLink(getCSVDownloadURL()); sparklineData.setDownloadDataLink(UtilityFunctions
.getCSVDownloadURL(
} else { individualURI,
csvDownloadURLHref = ""; VisualizationFrameworkConstants.PERSON_GRANT_COUNT_VIS,
} ""));
} else {
csvDownloadURLHref = "No data available to export.<br />";
} }
String tableCode = generateDataTable(); return sparklineData;
divContextCode.append("<p>" + tableCode + csvDownloadURLHref + "</p>");
sparklineData.setTable(tableCode);
return divContextCode.toString();
}
private String getCSVDownloadURL() {
if (yearToGrantCount.size() > 0) {
ParamMap CSVDownloadURLParams = new ParamMap(VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY,
individualURI,
VisualizationFrameworkConstants.VIS_TYPE_KEY,
VisualizationFrameworkConstants.PERSON_GRANT_COUNT_VIS);
return UrlBuilder.getUrl(VisualizationFrameworkConstants.DATA_VISUALIZATION_SERVICE_URL_PREFIX,
CSVDownloadURLParams);
} else {
return null;
}
}
private String generateShortVisContext() {
StringBuilder divContextCode = new StringBuilder();
String fullTimelineLink;
if (yearToGrantCount.size() > 0) {
// add another parameter for vis_mode
ParamMap fullTimelineNetworkURLParams = new ParamMap(VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY,
individualURI,
VisualizationFrameworkConstants.VIS_TYPE_KEY,
VisualizationFrameworkConstants.PERSON_LEVEL_VIS);
String fullTimelineNetworkURL = UrlBuilder.getUrl(
VisualizationFrameworkConstants.FREEMARKERIZED_VISUALIZATION_URL_PREFIX,
fullTimelineNetworkURLParams);
fullTimelineLink = "<a href='" + fullTimelineNetworkURL + "'>View all VIVO "
+ "grants and corresponding co-pi network.</a>";
sparklineData.setFullTimelineNetworkLink(fullTimelineNetworkURL);
} else {
fullTimelineLink = "No data available to render full timeline.<br />";
}
divContextCode.append("<span class=\"vis_link\">" + fullTimelineLink + "</span>");
return divContextCode.toString();
}
private String generateDataTable() {
String csvDownloadURLHref = "";
if (getCSVDownloadURL() != null) {
csvDownloadURLHref = "<a href=\"" + getCSVDownloadURL() + "\">(.CSV File)</a>";
} else {
csvDownloadURLHref = "";
}
StringBuilder dataTable = new StringBuilder();
dataTable.append("<table id='sparkline_data_table'>"
+ "<caption>Grants per year " + csvDownloadURLHref + "</caption>"
+ "<thead>"
+ "<tr>"
+ "<th>Year</th>"
+ "<th>Grants</th>"
+ "</tr>"
+ "</thead>"
+ "<tbody>");
for (Entry<String, Integer> currentEntry : yearToGrantCount.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() { public SparklineData getValueObjectContainer() {
return sparklineData; return this.sparklineParameterVO;
} }
} }

View file

@ -5,27 +5,23 @@ package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.personpubcount
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Set; import java.util.Set;
import java.util.Map.Entry;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap;
import edu.cornell.mannlib.vitro.webapp.controller.visualization.freemarker.VisualizationFrameworkConstants; import edu.cornell.mannlib.vitro.webapp.controller.visualization.freemarker.VisualizationFrameworkConstants;
import edu.cornell.mannlib.vitro.webapp.visualization.constants.VOConstants; 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.constants.VisConstants;
import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.BiboDocument; import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.BiboDocument;
import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.SparklineData; import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.SparklineData;
import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.YearToEntityCountDataElement; import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.YearToEntityCountDataElement;
import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.UtilityFunctions;
@SuppressWarnings("serial")
public class PersonPublicationCountVisCodeGenerator { public class PersonPublicationCountVisCodeGenerator {
/* /*
@ -37,24 +33,16 @@ public class PersonPublicationCountVisCodeGenerator {
* spanning the career of the person & last 10 years at the minimum, in case if * 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. * 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 static final String DEFAULT_VIS_CONTAINER_DIV_ID = "pub_count_vis_container";
private Map<String, Integer> yearToPublicationCount; private Map<String, Integer> yearToPublicationCount;
private Log log; private Log log;
private SparklineData sparklineData;
private String individualURI; private String individualURI;
private SparklineData sparklineParameterVO;
public PersonPublicationCountVisCodeGenerator(String individualURIParam, public PersonPublicationCountVisCodeGenerator(String individualURIParam,
String visMode, String visMode,
@ -66,44 +54,28 @@ public class PersonPublicationCountVisCodeGenerator {
this.individualURI = individualURIParam; this.individualURI = individualURIParam;
this.yearToPublicationCount = yearToPublicationCount; this.yearToPublicationCount = yearToPublicationCount;
this.sparklineData = new SparklineData();
sparklineData.setYearToActivityCount(yearToPublicationCount);
this.log = log; this.log = log;
generateVisualizationCode(visMode, visContainer, authorDocuments); this.sparklineParameterVO = setupSparklineParameters(visMode, visContainer, authorDocuments);
} }
/** /**
* This method is used to generate the visualization code (HMTL, CSS & JavaScript). * This method is used to setup parameters for the sparkline value object. These parameters
* There 2 parts to it - 1. Actual Content Code & 2. Context Code. * will be used in the template to construct the actual html/javascript 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 visMode
* @param visContainer * @param visContainer
* @param authorDocuments * @param authorDocuments
* @return
*/ */
private void generateVisualizationCode(String visMode, private SparklineData setupSparklineParameters(String visMode,
String visContainer, String providedVisContainerID,
Set<BiboDocument> authorDocuments) { Set<BiboDocument> authorDocuments) {
SparklineData sparklineData = new SparklineData();
sparklineData.setYearToActivityCount(yearToPublicationCount);
sparklineData.setSparklineContent(getMainVisualizationCode(authorDocuments,
visMode,
visContainer));
sparklineData.setSparklineContext(getVisualizationContextCode(visMode));
}
private String getMainVisualizationCode(Set<BiboDocument> authorDocuments,
String visMode,
String providedVisContainerID) {
int numOfYearsToBeRendered = 0; int numOfYearsToBeRendered = 0;
int currentYear = Calendar.getInstance().get(Calendar.YEAR); int currentYear = Calendar.getInstance().get(Calendar.YEAR);
@ -127,8 +99,6 @@ public class PersonPublicationCountVisCodeGenerator {
String visContainerID = null; String visContainerID = null;
StringBuilder visualizationCode = new StringBuilder();
if (yearToPublicationCount.size() > 0) { if (yearToPublicationCount.size() > 0) {
try { try {
minPublishedYear = Integer.parseInt(Collections.min(publishedYears)); minPublishedYear = Integer.parseInt(Collections.min(publishedYears));
@ -159,37 +129,6 @@ public class PersonPublicationCountVisCodeGenerator {
sparklineData.setNumOfYearsToBeRendered(numOfYearsToBeRendered); sparklineData.setNumOfYearsToBeRendered(numOfYearsToBeRendered);
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; int publicationCounter = 0;
/* /*
@ -213,19 +152,10 @@ public class PersonPublicationCountVisCodeGenerator {
currentPublications = 0; currentPublications = 0;
} }
visualizationCode.append("data.setValue(" yearToPublicationCountDataTable.add(new YearToEntityCountDataElement(
+ publicationCounter publicationCounter,
+ ", 0, '" stringPublishedYear,
+ stringPublishedYear currentPublications));
+ "');\n");
visualizationCode.append("data.setValue("
+ publicationCounter
+ ", 1, "
+ currentPublications
+ ");\n");
yearToPublicationCountDataTable.add(new YearToEntityCountDataElement(publicationCounter, stringPublishedYear, currentPublications));
/* /*
* Sparks that will be rendered will always be the one's which has * Sparks that will be rendered will always be the one's which has
@ -237,8 +167,6 @@ public class PersonPublicationCountVisCodeGenerator {
} }
sparklineData.setYearToEntityCountDataTable(yearToPublicationCountDataTable); sparklineData.setYearToEntityCountDataTable(yearToPublicationCountDataTable);
sparklineData.setRenderedSparks(renderedFullSparks); sparklineData.setRenderedSparks(renderedFullSparks);
@ -255,9 +183,6 @@ public class PersonPublicationCountVisCodeGenerator {
sparklineData.setUnknownYearPublications(unknownYearPublications); sparklineData.setUnknownYearPublications(unknownYearPublications);
String sparklineDisplayOptions = "{width: 65, height: 30, showAxisLines: false, "
+ "showValueLabels: false, labelPosition: 'none'}";
if (providedVisContainerID != null) { if (providedVisContainerID != null) {
visContainerID = providedVisContainerID; visContainerID = providedVisContainerID;
} else { } else {
@ -275,350 +200,39 @@ public class PersonPublicationCountVisCodeGenerator {
sparklineData.setEarliestRenderedPublicationYear(minPublishedYear); sparklineData.setEarliestRenderedPublicationYear(minPublishedYear);
sparklineData.setLatestRenderedPublicationYear(currentYear); sparklineData.setLatestRenderedPublicationYear(currentYear);
if (yearToPublicationCount.size() > 0) {
sparklineData.setFullTimelineNetworkLink(UtilityFunctions.getCollaboratorshipNetworkLink(individualURI,
VisualizationFrameworkConstants.PERSON_LEVEL_VIS,
VisualizationFrameworkConstants.COAUTHOR_VIS_MODE));
sparklineData.setDownloadDataLink(UtilityFunctions
.getCSVDownloadURL(
individualURI,
VisualizationFrameworkConstants.PERSON_PUBLICATION_COUNT_VIS,
""));
}
/* /*
* The Full Sparkline will be rendered by default. Only if the url has specific mention of * 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. * 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)) { if (VisualizationFrameworkConstants.SHORT_SPARKLINE_VIS_MODE.equalsIgnoreCase(visMode)) {
sparklineData.setEarliestRenderedPublicationYear(shortSparkMinYear); sparklineData.setEarliestRenderedPublicationYear(shortSparkMinYear);
sparklineData.setShortVisMode(true); sparklineData.setShortVisMode(true);
generateShortSparklineVisualizationContent(currentYear,
shortSparkMinYear,
visContainerID,
visualizationCode,
unknownYearPublications,
sparklineDisplayOptions);
} else { } else {
sparklineData.setShortVisMode(false); sparklineData.setShortVisMode(false);
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 = "";
if (getCSVDownloadURL() != null) {
csvDownloadURLHref = "<a href=\"" + getCSVDownloadURL()
+ "\" class=\"inline_href\">(.CSV File)</a>";
} else {
csvDownloadURLHref = "";
} }
visualizationCode.append("var fullSparklineView = " return sparklineData;
+ "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) + "');");
visualizationCode.append("var allSparksText = ''"
+ "+ ' publication(s) '"
+ "+ ' from "
+ "<span class=\"sparkline_range\">"
+ "" + 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 sparklineNumberTD = $('<td>');"
+ "sparklineNumberTD.attr('width', '30');"
+ "sparklineNumberTD.attr('align', 'right');"
+ "sparklineNumberTD.attr('class', 'sparkline_number');"
+ "row.append(sparklineNumberTD);"
+ "var sparklineTextTD = $('<td>');"
+ "sparklineTextTD.attr('width', '450');"
+ "sparklineTextTD.attr('class', 'sparkline_text');"
+ "row.append(sparklineTextTD);"
+ "table.append(row);"
+ "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) {
if (getCSVDownloadURL() != null) {
csvDownloadURLHref = "Download data as <a href='"
+ getCSVDownloadURL() + "'>.csv</a> file.<br />";
sparklineData.setDownloadDataLink(getCSVDownloadURL());
} else {
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() {
if (yearToPublicationCount.size() > 0) {
ParamMap CSVDownloadURLParams = new ParamMap(VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY,
individualURI,
VisualizationFrameworkConstants.VIS_TYPE_KEY,
VisualizationFrameworkConstants.PERSON_PUBLICATION_COUNT_VIS);
return UrlBuilder.getUrl(VisualizationFrameworkConstants.DATA_VISUALIZATION_SERVICE_URL_PREFIX,
CSVDownloadURLParams);
} else {
return null;
}
}
private String generateShortVisContext() {
StringBuilder divContextCode = new StringBuilder();
String fullTimelineLink;
if (yearToPublicationCount.size() > 0) {
ParamMap fullTimelineNetworkURLParams = new ParamMap(VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY,
individualURI,
VisualizationFrameworkConstants.VIS_TYPE_KEY,
VisualizationFrameworkConstants.PERSON_LEVEL_VIS);
String fullTimelineNetworkURL = UrlBuilder.getUrl(
VisualizationFrameworkConstants.FREEMARKERIZED_VISUALIZATION_URL_PREFIX,
fullTimelineNetworkURLParams);
fullTimelineLink = "<a href='" + fullTimelineNetworkURL + "'>View all VIVO "
+ "publications and corresponding co-author network.</a>";
sparklineData.setFullTimelineNetworkLink(fullTimelineNetworkURL);
} else {
fullTimelineLink = "No data available to render full timeline.<br />";
}
divContextCode.append("<span class=\"vis_link\">" + fullTimelineLink + "</span>");
return divContextCode.toString();
}
private String generateDataTable() {
String csvDownloadURLHref = "";
if (getCSVDownloadURL() != null) {
csvDownloadURLHref = "<a href=\"" + getCSVDownloadURL() + "\">(.CSV File)</a>";
} else {
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() { public SparklineData getValueObjectContainer() {
return sparklineData; return this.sparklineParameterVO;
} }
} }

View file

@ -7,14 +7,6 @@ import java.util.Map;
public class SparklineData { public class SparklineData {
/*
* For now sparklineNumPublicationsText & sparklinePublicationRangeText is left
* as empty but later on we would want to leverage the granularity that this
* provides.
* */
private String sparklineNumPublicationsText = "";
private String sparklinePublicationRangeText = "";
private Integer earliestYearConsidered; private Integer earliestYearConsidered;
private Integer earliestRenderedPublicationYear; private Integer earliestRenderedPublicationYear;
private Integer latestRenderedPublicationYear; private Integer latestRenderedPublicationYear;
@ -25,17 +17,12 @@ public class SparklineData {
private Integer unknownYearPublications; private Integer unknownYearPublications;
private Integer unknownYearGrants; private Integer unknownYearGrants;
private Map<String, Integer> yearToActivityCount; private Map<String, Integer> yearToActivityCount;
private String table = "";
private String downloadDataLink = ""; private String downloadDataLink = "";
private String fullTimelineNetworkLink = ""; private String fullTimelineNetworkLink = "";
private String visContainerDivID = "pub_count_vis_container"; private String visContainerDivID = "pub_count_vis_container";
private String sparklineContent;
private String sparklineContext;
private boolean isShortVisMode = true; private boolean isShortVisMode = true;
@ -43,23 +30,6 @@ public class SparklineData {
private int numOfYearsToBeRendered; private int numOfYearsToBeRendered;
public String getSparklineNumPublicationsText() {
return sparklineNumPublicationsText;
}
public void setSparklineNumPublicationsText(String sparklineNumPublicationsText) {
this.sparklineNumPublicationsText = sparklineNumPublicationsText;
}
public String getSparklinePublicationRangeText() {
return sparklinePublicationRangeText;
}
public void setSparklinePublicationRangeText(
String sparklinePublicationRangeText) {
this.sparklinePublicationRangeText = sparklinePublicationRangeText;
}
public Integer getEarliestRenderedGrantYear() { public Integer getEarliestRenderedGrantYear() {
return earliestRenderedGrantYear; return earliestRenderedGrantYear;
} }
@ -151,14 +121,6 @@ public class SparklineData {
return renderedSparks; return renderedSparks;
} }
public String getTable() {
return table;
}
public void setTable(String table) {
this.table = table;
}
public String getDownloadDataLink() { public String getDownloadDataLink() {
return downloadDataLink; return downloadDataLink;
} }
@ -183,14 +145,6 @@ public class SparklineData {
return visContainerDivID; return visContainerDivID;
} }
public String getSparklineContent() {
return sparklineContent;
}
public void setSparklineContent(String shortSparklineContent) {
this.sparklineContent = shortSparklineContent;
}
public void setShortVisMode(boolean isShortVisMode) { public void setShortVisMode(boolean isShortVisMode) {
this.isShortVisMode = isShortVisMode; this.isShortVisMode = isShortVisMode;
} }
@ -199,11 +153,4 @@ public class SparklineData {
return isShortVisMode; return isShortVisMode;
} }
public String getSparklineContext() {
return sparklineContext;
}
public void setSparklineContext(String shortSparklineContext) {
this.sparklineContext = shortSparklineContext;
}
} }

View file

@ -3,10 +3,8 @@
package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils; package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.TreeMap; import java.util.TreeMap;
@ -20,11 +18,12 @@ import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
import edu.cornell.mannlib.vitro.webapp.beans.Portal; import edu.cornell.mannlib.vitro.webapp.beans.Portal;
import edu.cornell.mannlib.vitro.webapp.controller.Controllers; import edu.cornell.mannlib.vitro.webapp.controller.Controllers;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues;
import edu.cornell.mannlib.vitro.webapp.controller.visualization.freemarker.VisualizationFrameworkConstants; import edu.cornell.mannlib.vitro.webapp.controller.visualization.freemarker.VisualizationFrameworkConstants;
@ -33,8 +32,8 @@ import edu.cornell.mannlib.vitro.webapp.visualization.constants.VisConstants;
import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.BiboDocument; import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.BiboDocument;
import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.CoAuthorshipData; import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.CoAuthorshipData;
import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.CoPIData; import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.CoPIData;
import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.Grant;
import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.CoPINode; import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.CoPINode;
import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.Grant;
import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.Node; import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.Node;
public class UtilityFunctions { public class UtilityFunctions {
@ -276,5 +275,50 @@ public class UtilityFunctions {
* */ * */
return null; return null;
} }
public static String getCSVDownloadURL(String individualURI, String visType, String visMode) {
ParamMap CSVDownloadURLParams = null;
if (StringUtils.isBlank(visMode)) {
CSVDownloadURLParams = new ParamMap(VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY,
individualURI,
VisualizationFrameworkConstants.VIS_TYPE_KEY,
visType);
} else {
CSVDownloadURLParams = new ParamMap(VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY,
individualURI,
VisualizationFrameworkConstants.VIS_TYPE_KEY,
visType,
VisualizationFrameworkConstants.VIS_MODE_KEY,
visMode);
}
String csvDownloadLink = UrlBuilder.getUrl(VisualizationFrameworkConstants.DATA_VISUALIZATION_SERVICE_URL_PREFIX,
CSVDownloadURLParams);
return csvDownloadLink != null ? csvDownloadLink : "" ;
}
public static String getCollaboratorshipNetworkLink(String individualURI, String visType, String visMode) {
ParamMap collaboratorshipNetworkURLParams = new ParamMap(VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY,
individualURI,
VisualizationFrameworkConstants.VIS_TYPE_KEY,
visType,
VisualizationFrameworkConstants.VIS_MODE_KEY,
visMode);
String collaboratorshipNetworkURL = UrlBuilder.getUrl(
VisualizationFrameworkConstants.FREEMARKERIZED_VISUALIZATION_URL_PREFIX,
collaboratorshipNetworkURLParams);
return collaboratorshipNetworkURL != null ? collaboratorshipNetworkURL : "" ;
}
} }