X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fio%2FSequenceAnnotationReport.java;h=3a7ee65defabe116cf0a68a17f606a774e74fb85;hb=b8cd52fe7bed59130e5b080acfd42c3ef2effdbb;hp=96d71f69ba112817c75bb2926fb8fc97399cffbd;hpb=054cc21f3aad9e37c464b1af6c62dbee6ca624b1;p=jalview.git diff --git a/src/jalview/io/SequenceAnnotationReport.java b/src/jalview/io/SequenceAnnotationReport.java index 96d71f6..3a7ee65 100644 --- a/src/jalview/io/SequenceAnnotationReport.java +++ b/src/jalview/io/SequenceAnnotationReport.java @@ -21,16 +21,21 @@ package jalview.io; import jalview.datamodel.DBRefEntry; +import jalview.datamodel.DBRefSource; +import jalview.datamodel.DynamicData; +import jalview.datamodel.PDBEntry; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; +import jalview.io.gff.GffConstants; +import jalview.util.MessageManager; import jalview.util.UrlLink; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; +import java.util.Collection; import java.util.Comparator; -import java.util.Hashtable; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; /** * generate HTML reports for a sequence @@ -39,6 +44,18 @@ import java.util.List; */ public class SequenceAnnotationReport { + private static final String COMMA = ","; + + private static final String ELLIPSIS = "..."; + + private static final int MAX_REFS_PER_SOURCE = 4; + + private static final int MAX_SOURCES = 40; + + private static final String[][] PRIMARY_SOURCES = new String[][] { + DBRefSource.CODINGDBS, DBRefSource.DNACODINGDBS, + DBRefSource.PROTEINDBS }; + final String linkImageURL; /* @@ -46,11 +63,22 @@ public class SequenceAnnotationReport */ private static Comparator comparator = new Comparator() { + @Override public int compare(DBRefEntry ref1, DBRefEntry ref2) { String s1 = ref1.getSource(); String s2 = ref2.getSource(); + boolean s1Primary = isPrimarySource(s1); + boolean s2Primary = isPrimarySource(s2); + if (s1Primary && !s2Primary) + { + return -1; + } + if (!s1Primary && s2Primary) + { + return 1; + } int comp = s1 == null ? -1 : (s2 == null ? 1 : s1 .compareToIgnoreCase(s2)); if (comp == 0) @@ -62,6 +90,21 @@ public class SequenceAnnotationReport } return comp; } + + private boolean isPrimarySource(String source) + { + for (String[] primary : PRIMARY_SOURCES) + { + for (String s : primary) + { + if (source.equals(s)) + { + return true; + } + } + } + return false; + } }; public SequenceAnnotationReport(String linkImageURL) @@ -70,316 +113,235 @@ public class SequenceAnnotationReport } /** - * appends the features at rpos to the given stringbuffer ready for display in - * a tooltip + * Append text for the list of features to the tooltip * - * @param tooltipText - * @param linkImageURL + * @param sb * @param rpos * @param features * @param minmax - * TODO refactor to Jalview 'utilities' somehow. */ - public void appendFeatures(final StringBuilder tooltipText, int rpos, - List features, Hashtable minmax) + public void appendFeatures(final StringBuilder sb, int rpos, + List features, Map minmax) { - String tmpString; if (features != null) { for (SequenceFeature feature : features) { - if (feature.getType().equals("disulfide bond")) + appendFeature(sb, rpos, minmax, feature); + } + } + } + + /** + * Appends the feature at rpos to the given buffer + * + * @param sb + * @param rpos + * @param minmax + * @param feature + */ + void appendFeature(final StringBuilder sb, int rpos, + Map minmax, SequenceFeature feature) + { + if (feature.isContactFeature()) + { + if (feature.getBegin() == rpos || feature.getEnd() == rpos) + { + if (sb.length() > 6) { - if (feature.getBegin() == rpos || feature.getEnd() == rpos) - { - if (tooltipText.length() > 6) - { - tooltipText.append("
"); - } - tooltipText.append("disulfide bond " + feature.getBegin() - + ":" + feature.getEnd()); - } + sb.append("
"); + } + sb.append(feature.getType()).append(" ").append(feature.getBegin()) + .append(":") + .append(feature.getEnd()); + } + } + else + { + if (sb.length() > 6) + { + sb.append("
"); + } + // TODO: remove this hack to display link only features + boolean linkOnly = feature.getValue("linkonly") != null; + if (!linkOnly) + { + sb.append(feature.getType()).append(" "); + if (rpos != 0) + { + // we are marking a positional feature + sb.append(feature.begin); } - else + if (feature.begin != feature.end) { - if (tooltipText.length() > 6) + sb.append(" ").append(feature.end); + } + + if (feature.getDescription() != null + && !feature.description.equals(feature.getType())) + { + String tmpString = feature.getDescription(); + String tmp2up = tmpString.toUpperCase(); + int startTag = tmp2up.indexOf(""); + if (startTag > -1) { - tooltipText.append("
"); + tmpString = tmpString.substring(startTag + 6); + tmp2up = tmp2up.substring(startTag + 6); } - // TODO: remove this hack to display link only features - boolean linkOnly = feature.getValue("linkonly") != null; - if (!linkOnly) + int endTag = tmp2up.indexOf(""); + if (endTag > -1) { - tooltipText.append(feature.getType() + " "); - if (rpos != 0) - { - // we are marking a positional feature - tooltipText.append(feature.begin); - } - if (feature.begin != feature.end) - { - tooltipText.append(" " + feature.end); - } + tmpString = tmpString.substring(0, endTag); + tmp2up = tmp2up.substring(0, endTag); + } + endTag = tmp2up.indexOf(""); + if (endTag > -1) + { + tmpString = tmpString.substring(0, endTag); + } - if (feature.getDescription() != null - && !feature.description.equals(feature.getType())) + if (startTag > -1) + { + sb.append("; ").append(tmpString); + } + else + { + if (tmpString.indexOf("<") > -1 || tmpString.indexOf(">") > -1) { - tmpString = feature.getDescription(); - String tmp2up = tmpString.toUpperCase(); - int startTag = tmp2up.indexOf(""); - if (startTag > -1) - { - tmpString = tmpString.substring(startTag + 6); - tmp2up = tmp2up.substring(startTag + 6); - } - int endTag = tmp2up.indexOf(""); - if (endTag > -1) - { - tmpString = tmpString.substring(0, endTag); - tmp2up = tmp2up.substring(0, endTag); - } - endTag = tmp2up.indexOf(""); - if (endTag > -1) - { - tmpString = tmpString.substring(0, endTag); - } - - if (startTag > -1) - { - tooltipText.append("; " + tmpString); - } - else - { - if (tmpString.indexOf("<") > -1 - || tmpString.indexOf(">") > -1) - { - // The description does not specify html is to - // be used, so we must remove < > symbols - tmpString = tmpString.replaceAll("<", "<"); - tmpString = tmpString.replaceAll(">", ">"); - - tooltipText.append("; "); - tooltipText.append(tmpString); + // The description does not specify html is to + // be used, so we must remove < > symbols + tmpString = tmpString.replaceAll("<", "<"); + tmpString = tmpString.replaceAll(">", ">"); - } - else - { - tooltipText.append("; " + tmpString); - } - } + sb.append("; "); + sb.append(tmpString); } - // check score should be shown - if (!Float.isNaN(feature.getScore())) + else { - float[][] rng = (minmax == null) ? null : ((float[][]) minmax - .get(feature.getType())); - if (rng != null && rng[0] != null && rng[0][0] != rng[0][1]) - { - tooltipText.append(" Score=" + feature.getScore()); - } - } - if (feature.getValue("status") != null) - { - String status = feature.getValue("status").toString(); - if (status.length() > 0) - { - tooltipText.append("; (" + feature.getValue("status") - + ")"); - } + sb.append("; ").append(tmpString); } } } - if (feature.links != null) + // check score should be shown + if (!Float.isNaN(feature.getScore())) { - if (linkImageURL != null) + float[][] rng = (minmax == null) ? null : minmax.get(feature + .getType()); + if (rng != null && rng[0] != null && rng[0][0] != rng[0][1]) { - tooltipText.append(" "); + sb.append(" Score=").append(String.valueOf(feature.getScore())); } - else - { - for (String urlstring : feature.links) - { - try - { - for (String[] urllink : createLinksFrom(null, urlstring)) - { - tooltipText.append("
" - + (urllink[0].toLowerCase().equals( - urllink[1].toLowerCase()) ? urllink[0] - : (urllink[0] + ":" + urllink[1])) - + "
"); - } - } catch (Exception x) - { - System.err.println("problem when creating links from " - + urlstring); - x.printStackTrace(); - } - } - } - + } + String status = (String) feature.getValue("status"); + if (status != null && status.length() > 0) + { + sb.append("; (").append(status).append(")"); + } + String clinSig = (String) feature + .getValue(GffConstants.CLINICAL_SIGNIFICANCE); + if (clinSig != null) + { + sb.append("; ").append(clinSig); } } } } /** + * Format and appends any hyperlinks for the sequence feature to the string + * buffer * - * @param seq - * @param link - * @return String[][] { String[] { link target, link label, dynamic component - * inserted (if any), url }} + * @param sb + * @param feature */ - public String[][] createLinksFrom(SequenceI seq, String link) + void appendLinks(final StringBuffer sb, SequenceFeature feature) { - ArrayList urlSets = new ArrayList(); - ArrayList uniques = new ArrayList(); - UrlLink urlLink = new UrlLink(link); - if (!urlLink.isValid()) - { - System.err.println(urlLink.getInvalidMessage()); - return null; - } - final String target = urlLink.getTarget(); // link.substring(0, - // link.indexOf("|")); - final String label = urlLink.getLabel(); - if (seq != null && urlLink.isDynamic()) + if (feature.links != null) { - - // collect matching db-refs - DBRefEntry[] dbr = jalview.util.DBRefUtils.selectRefs(seq.getDBRefs(), - new String[] { target }); - // collect id string too - String id = seq.getName(); - String descr = seq.getDescription(); - if (descr != null && descr.length() < 1) + if (linkImageURL != null) { - descr = null; + sb.append(" "); } - if (dbr != null) + else { - for (int r = 0; r < dbr.length; r++) + for (String urlstring : feature.links) { - if (id != null && dbr[r].getAccessionId().equals(id)) - { - // suppress duplicate link creation for the bare sequence ID - // string with this link - id = null; - } - // create Bare ID link for this RUL - String[] urls = urlLink.makeUrls(dbr[r].getAccessionId(), true); - if (urls != null) + try { - for (int u = 0; u < urls.length; u += 2) + for (List urllink : createLinksFrom(null, urlstring)) { - String unq = urls[u] + "|" + urls[u + 1]; - if (!uniques.contains(unq)) - { - urlSets.add(new String[] { target, label, urls[u], - urls[u + 1] }); - uniques.add(unq); - } + sb.append("
" + + (urllink.get(0).toLowerCase() + .equals(urllink.get(1).toLowerCase()) ? urllink + .get(0) : (urllink.get(0) + ":" + urllink + .get(1))) + + "
"); } - } - } - } - if (id != null) - { - // create Bare ID link for this RUL - String[] urls = urlLink.makeUrls(id, true); - if (urls != null) - { - for (int u = 0; u < urls.length; u += 2) + } catch (Exception x) { - String unq = urls[u] + "|" + urls[u + 1]; - if (!uniques.contains(unq)) - { - urlSets.add(new String[] { target, label, urls[u], - urls[u + 1] }); - uniques.add(unq); - } - } - } - } - if (descr != null && urlLink.getRegexReplace() != null) - { - // create link for this URL from description only if regex matches - String[] urls = urlLink.makeUrls(descr, true); - if (urls != null) - { - for (int u = 0; u < urls.length; u += 2) - { - String unq = urls[u] + "|" + urls[u + 1]; - if (!uniques.contains(unq)) - { - urlSets.add(new String[] { target, label, urls[u], - urls[u + 1] }); - uniques.add(unq); - } + System.err.println("problem when creating links from " + + urlstring); + x.printStackTrace(); } } } } - else - { - String unq = label + "|" + urlLink.getUrl_prefix(); - if (!uniques.contains(unq)) - { - uniques.add(unq); - // Add a non-dynamic link - urlSets.add(new String[] { target, label, null, - urlLink.getUrl_prefix() }); - } - } - - return urlSets.toArray(new String[][] {}); } - public void createTooltipAnnotationReport(final StringBuilder tip, - SequenceI sequence, boolean showDbRefs, boolean showNpFeats, - Hashtable minmax) + /** + * + * @param seq + * @param link + * @return Collection< List > { List { link target, link + * label, dynamic component inserted (if any), url }} + */ + Collection> createLinksFrom(SequenceI seq, String link) { - int maxWidth = createSequenceAnnotationReport(tip, sequence, - showDbRefs, showNpFeats, minmax, true); - - if (maxWidth > 60) + Map> urlSets = new LinkedHashMap>(); + UrlLink urlLink = new UrlLink(link); + if (!urlLink.isValid()) { - tip.insert(0, "
"); - tip.append("
"); + System.err.println(urlLink.getInvalidMessage()); + return null; } + + urlLink.createLinksFromSeq(seq, urlSets); + + return urlSets.values(); } - public int createSequenceAnnotationReport(final StringBuilder tip, + public void createSequenceAnnotationReport(final StringBuilder tip, SequenceI sequence, boolean showDbRefs, boolean showNpFeats, - Hashtable minmax) + Map minmax) { - return createSequenceAnnotationReport(tip, sequence, showDbRefs, - showNpFeats, minmax, false); + createSequenceAnnotationReport(tip, sequence, showDbRefs, showNpFeats, + minmax, false); } /** - * Adds an html-formatted sequence annotation report to the provided string - * buffer, and returns the longest line length added + * Builds an html formatted report of sequence details and appends it to the + * provided buffer. * * @param sb + * buffer to append report to * @param sequence + * the sequence the report is for * @param showDbRefs - * if true, include database references + * whether to include database references for the sequence * @param showNpFeats - * if true, include non-positional sequence features + * whether to include non-positional sequence features * @param minmax * @param summary - * if true, build a shortened summary report (for tooltip) * @return */ int createSequenceAnnotationReport(final StringBuilder sb, SequenceI sequence, boolean showDbRefs, boolean showNpFeats, - Hashtable minmax, boolean summary) + Map minmax, boolean summary) { String tmp; sb.append(""); @@ -397,15 +359,21 @@ public class SequenceAnnotationReport ds = ds.getDatasetSequence(); } DBRefEntry[] dbrefs = ds.getDBRefs(); - Arrays.sort(dbrefs, comparator); if (showDbRefs && dbrefs != null) { + // note this sorts the refs held on the sequence! + Arrays.sort(dbrefs, comparator); boolean ellipsis = false; + String source = null; String lastSource = null; int countForSource = 0; + int sourceCount = 0; + boolean moreSources = false; + int lineLength = 0; + for (DBRefEntry ref : dbrefs) { - String source = ref.getSource(); + source = ref.getSource(); if (source == null) { // shouldn't happen @@ -414,7 +382,15 @@ public class SequenceAnnotationReport boolean sourceChanged = !source.equals(lastSource); if (sourceChanged) { + lineLength = 0; countForSource = 0; + sourceCount++; + } + if (sourceCount > MAX_SOURCES && summary) + { + ellipsis = true; + moreSources = true; + break; } lastSource = source; countForSource++; @@ -422,34 +398,44 @@ public class SequenceAnnotationReport { sb.append("
"); } - if (countForSource < 3 || !summary) + if (countForSource <= MAX_REFS_PER_SOURCE || !summary) { String accessionId = ref.getAccessionId(); - int len = accessionId.length() + 1; + lineLength += accessionId.length() + 1; if (countForSource > 1 && summary) { sb.append(", ").append(accessionId); - len++; + lineLength++; } else { sb.append(source).append(" ").append(accessionId); - len += source.length(); + lineLength += source.length(); } - maxWidth = Math.max(maxWidth, len); + maxWidth = Math.max(maxWidth, lineLength); } - if (countForSource == 3 && summary) + if (countForSource == MAX_REFS_PER_SOURCE && summary) { - sb.append(", ..."); + sb.append(COMMA).append(ELLIPSIS); ellipsis = true; } } - if (ellipsis) { - sb.append("
(Output Sequence Details to list all database references)"); + if (moreSources) + { + sb.append("
").append(ELLIPSIS).append(COMMA).append(source) + .append(COMMA).append(ELLIPSIS); + } + if (ellipsis) + { + sb.append("
("); + sb.append(MessageManager.getString("label.output_seq_details")); + sb.append(")"); } } - // ADD NON POSITIONAL SEQUENCE INFO + /* + * add non-positional features if wanted + */ SequenceFeature[] features = sequence.getSequenceFeatures(); if (showNpFeats && features != null) { @@ -458,14 +444,92 @@ public class SequenceAnnotationReport if (features[i].begin == 0 && features[i].end == 0) { int sz = -sb.length(); - List tfeat = Collections - .singletonList(features[i]); - appendFeatures(sb, 0, tfeat, minmax); + appendFeature(sb, 0, minmax, features[i]); sz += sb.length(); maxWidth = Math.max(maxWidth, sz); } } } + sb.append("
"); + List pdbEntries = ds.getAllPDBEntries(); + sb.append(getToolTipTextFromPDBEntries(pdbEntries)); return maxWidth; } + + private String getToolTipTextFromPDBEntries(List pdbEntries) + { + String tooltip = ""; + if (pdbEntries.isEmpty()) + { + return tooltip; + } + if (pdbEntries.size() > 1) + { + int x = 0; + PDBEntry bestRanked = null; + for (PDBEntry pdb : pdbEntries) + { + if (pdb.getProperty("DYNAMIC_DATA_PHYRE2") != null) + { + x++; + } + // best ranked entry must be from a Phyre + if (x > 0 && bestRanked == null) + { + bestRanked = pdb; + } + } + tooltip = (x > 0) ? "" + + "
Contains " + + x + + " Phyre2 model structure(s)
Best ranked Phyre2 model is " + + bestRanked.getId() + "
" + : ""; + } + else + { + PDBEntry pdb = pdbEntries.iterator().next(); + if (pdb.getProperty("DYNAMIC_DATA_PHYRE2") != null) + { + tooltip = getPhyreToolTipFromDynamicData((List) pdb + .getProperty("DYNAMIC_DATA_PHYRE2")); + } + } + return tooltip; + } + + private String getPhyreToolTipFromDynamicData( + List dynamicDataList) + { + StringBuilder phyre2InfoBuilder = new StringBuilder(); + phyre2InfoBuilder + .append("") + .append(""); + for (DynamicData data : dynamicDataList) + { + if (data.isDisplay()) + { + phyre2InfoBuilder.append(""); + } + } + phyre2InfoBuilder.append("
Phyre2 Template Info
").append(data.getFieldTitle()) + .append("").append(data.getFieldValue()) + .append("
"); + return phyre2InfoBuilder.toString(); + } + + public void createTooltipAnnotationReport(final StringBuilder tip, + SequenceI sequence, boolean showDbRefs, boolean showNpFeats, + Map minmax) + { + int maxWidth = createSequenceAnnotationReport(tip, sequence, + showDbRefs, showNpFeats, minmax, true); + + if (maxWidth > 60) + { + // ? not sure this serves any useful purpose + // tip.insert(0, "
"); + // tip.append("
"); + } + } }