0513e85cc01843ecc411b86dfce9180a8d1acf37 max Thu Mar 22 17:40:16 2012 -0700 make individual sequences for publications track clickable, show alignments, correct mouseOvers // Also changs text that is shown for PDF Output in hgTracks (see email with Ann/Donna/Brian) diff --git src/hg/hgTracks/simpleTracks.c src/hg/hgTracks/simpleTracks.c index f714f64..16b6743 100644 --- src/hg/hgTracks/simpleTracks.c +++ src/hg/hgTracks/simpleTracks.c @@ -2,30 +2,31 @@ * hgTracks.c allows a standalone main to make track images. */ /* NOTE: This code was imported from hgTracks.c 1.1469, May 19 2008, * so a lot of revision history has been obscured. To see code history * from before this file was created, run this: * cvs ann -r 1.1469 hgTracks.c | less +Gp */ #include "common.h" #include "spaceSaver.h" #include "portable.h" #include "bed.h" #include "psl.h" #include "web.h" #include "hdb.h" +#include "hgFind.h" #include "hCommon.h" #include "hgColors.h" #include "trackDb.h" #include "bedCart.h" #include "wiggle.h" #include "lfs.h" #include "grp.h" #include "chromColors.h" #include "hgTracks.h" #include "subText.h" #include "cds.h" #include "mafTrack.h" #include "wigCommon.h" #include "hui.h" #include "imageV2.h" @@ -12133,31 +12134,31 @@ { track->visibility = tvDense; track->limitedVis = tvDense; track->limitedVisSet = TRUE; } track->nextItemButtonable = track->nextExonButtonable = FALSE; track->nextPrevItem = NULL; track->nextPrevExon = NULL; } char* pubsArticleTable(struct track *tg) /* return the name of the pubs articleTable, either * the value from the trackDb statement 'articleTable' * or the default value: Article */ { -char *articleTable = trackDbSetting(tg->tdb, "pubsArticleTable"); +char *articleTable = trackDbSettingClosestToHome(tg->tdb, "pubsArticleTable"); if (isEmpty(articleTable)) { char buf[256]; safef(buf, sizeof(buf), "%sArticle", tg->track); articleTable = cloneString(buf); } return articleTable; } static char *makeMysqlMatchStr(char *str) { // return a string with all words prefixed with a '+' to force a boolean AND query; // we also strip leading/trailing spaces. char *matchStr = needMem(strlen(str) * 2 + 1); int i = 0; @@ -12165,70 +12166,74 @@ ; while(*str) { matchStr[i++] = '+'; for(; *str && !isspace(*str);str++) matchStr[i++] = *str; for(;*str && isspace(*str);str++) ; } matchStr[i++] = 0; return matchStr; } struct pubsExtra /* additional info needed for publication blat linked features: author+year and title */ { - char* authorYear; - char* title; + char* label; + char* mouseOver; }; -static char* pubsGetFirstAuthor(char* authors) -/* return first author from author field */ +static char* pubsFeatureLabel(char* authors, char* year) +/* create label given authors and year strings */ { +char* authorYear = NULL; + char* author = firstWordInLine(authors); stripChar(author, ','); stripChar(author, ';'); if (isEmpty(author)) author = "NoAuthor"; -return author; +if (isEmpty(year)) + year = "NoYear"; +authorYear = catTwoStrings(author, year); + +return authorYear; } static struct pubsExtra *pubsMakeExtra(char* articleTable, struct sqlConnection* conn, struct linkedFeatures* lf) { char query[LARGEBUF]; safef(query, sizeof(query), "SELECT authors, year, title FROM %s WHERE articleId = '%s'", articleTable, lf->name); struct sqlResult *sr = NULL; char **row = NULL; sr = sqlGetResult(conn, query); struct pubsExtra *extra = NULL; if ((row = sqlNextRow(sr)) != NULL) { - char* author = pubsGetFirstAuthor(row[0]); + char* authors = row[0]; char* year = row[1]; char* title = row[2]; - if (isEmpty(year)) - year = "NoYear"; extra = needMem(sizeof(struct pubsExtra)); - extra->authorYear = catTwoStrings(author, year); + extra->label = pubsFeatureLabel(authors, year); if (isEmpty(title)) - extra->title = extra->authorYear; + extra->mouseOver = extra->label; else - extra->title = cloneString(title); + extra->mouseOver = cloneString(title); } sqlFreeResult(&sr); return extra; } static void pubsLookupAuthors(struct track *tg) /* add authorYear and title to all linkedFeatures->extra */ { enum trackVisibility vis = tg->visibility; if (vis == tvDense || vis == tvSquish) return; char *articleTable = pubsArticleTable(tg); if(isEmpty(articleTable)) @@ -12241,172 +12246,318 @@ { struct pubsExtra* extra = pubsMakeExtra(articleTable, conn, lf); lf->extra = extra; } hFreeConn(&conn); } static void pubsLoadKeywordYearItems(struct track *tg) /* load items that fulfill keyword and year filter */ { struct sqlConnection *conn = hAllocConn(database); char *keywords = cartOptionalString(cart, "pubsKeywords"); char *yearFilter = cartOptionalString(cart, "pubsYear"); char *articleTable = pubsArticleTable(tg); -if(yearFilter != NULL && sameWord(yearFilter, "anytime")) +if(yearFilter == NULL || sameWord(yearFilter, "anytime")) yearFilter = NULL; + if(isNotEmpty(keywords)) keywords = makeMysqlMatchStr(sqlEscapeString(keywords)); if(isEmpty(yearFilter) && isEmpty(keywords)) +{ loadGappedBed(tg); +} else { + char* oldLabel = tg->longLabel; + tg->longLabel = catTwoStrings(oldLabel, " (filter activated)"); + freeMem(oldLabel); + char extra[2048], yearWhere[256], keywordsWhere[1024], prefix[256]; char **row; - int rowOffset; struct linkedFeatures *lfList = NULL; struct trackDb *tdb = tg->tdb; int scoreMin = atoi(trackDbSettingClosestToHomeOrDefault(tdb, "scoreMin", "0")); int scoreMax = atoi(trackDbSettingClosestToHomeOrDefault(tdb, "scoreMax", "1000")); boolean useItemRgb = bedItemRgb(tdb); safef(prefix, sizeof(prefix), "name IN (SELECT articleId FROM %s WHERE", articleTable); if(isNotEmpty(keywords)) - safef(keywordsWhere, sizeof(keywordsWhere), "MATCH (citation, title, authors, abstract) AGAINST ('%s' IN BOOLEAN MODE)", keywords); + safef(keywordsWhere, sizeof(keywordsWhere), \ + "MATCH (citation, title, authors, abstract) AGAINST ('%s' IN BOOLEAN MODE)", keywords); if(isNotEmpty(yearFilter)) safef(yearWhere, sizeof(yearWhere), "year >= '%s'", sqlEscapeString(yearFilter)); if(isEmpty(keywords)) safef(extra, sizeof(extra), "%s %s)", prefix, yearWhere); else if(isEmpty(yearFilter)) safef(extra, sizeof(extra), "%s %s)", prefix, keywordsWhere); else safef(extra, sizeof(extra), "%s %s AND %s)", prefix, yearWhere, keywordsWhere); + + int rowOffset = 0; struct sqlResult *sr = hExtendedRangeQuery(conn, tg->table, chromName, winStart, winEnd, extra, FALSE, NULL, &rowOffset); while ((row = sqlNextRow(sr)) != NULL) { struct bed *bed = bedLoad12(row+rowOffset); slAddHead(&lfList, bedMungToLinkedFeatures(&bed, tdb, 12, scoreMin, scoreMax, useItemRgb)); } sqlFreeResult(&sr); slReverse(&lfList); slSort(&lfList, linkedFeaturesCmp); tg->items = lfList; } hFreeConn(&conn); } +#define PUBSFILTERNAME "pubsFilterArticleId" + +static void activatePslTrackIfCgi(struct track *tg) +/* the publications hgc creates links back to the browser with + * the cgi param pubsFilterArticleId to show only a single type + * of feature for the pubsBlatPsl track. + * If the parameter was supplied, we save this parameter here + * into the cart and activate the track. + */ +{ +char *articleId = cgiOptionalString(PUBSFILTERNAME); +//if (articleId==NULL) + //articleId = cartOptionalString(cart, PUBSFILTERNAME); + +if (articleId!=NULL) +{ + cartSetString(cart, PUBSFILTERNAME, articleId); + tdbSetCartVisibility(tg->tdb, cart, hCarefulTrackOpenVis(database, tg->track)); + tg->visibility=tvPack; +} +} + static void pubsLoadItems(struct track *tg) /* filter items and stuff item data from other tables (author name, title) into extra field */ { pubsLoadKeywordYearItems(tg); pubsLookupAuthors(tg); } char *pubsItemName(struct track *tg, void *item) /* get author/year from extra field */ { struct linkedFeatures *lf = item; struct pubsExtra* extra = lf->extra; if (extra!=NULL) - return extra->authorYear; + return extra->label; else return lf->name; } static void pubsMapItem(struct track *tg, struct hvGfx *hvg, void *item, char *itemName, char *mapItemName, int start, int end, int x, int y, int width, int height) /* create mouse over with title for pubs blat features. */ { if (!theImgBox || tg->limitedVis != tvDense || !tdbIsCompositeChild(tg->tdb)) { struct linkedFeatures *lf = item; char* mouseOver = NULL; if (lf->extra != NULL) { struct pubsExtra *extra = lf->extra; - mouseOver = extra->title; + mouseOver = extra->mouseOver; } else mouseOver = itemName; mapBoxHc(hvg, start, end, x, y, width, height, tg->track, mapItemName, mouseOver); } } +static void pubsLoadMarkerItem (struct track *tg) +/* copy item names into extra field */ +{ +//loadSimpleBed(tg); +loadSimpleBedAsLinkedFeaturesPerBase(tg); +//tg->items = simpleBedListToLinkedFeatures(tg->items, tg->bedSize, TRUE, FALSE); +//if (! (hashFindVal(tdb->settingsHash, "pubsMarkerTable"))) +enum trackVisibility vis = tg->visibility; +if (vis == tvDense || vis == tvSquish) + return; + +struct linkedFeatures *lf = NULL; +for (lf = tg->items; lf != NULL; lf = lf->next) + lf->extra = lf->name; +} + char *pubsMarkerItemName(struct track *tg, void *item) /* retrieve article count from score field and return.*/ { -struct bed *bed = item; +//struct bed *bed = item; +struct linkedFeatures *lf = item; char newName[64]; -safef(newName, sizeof(newName), "%d articles", (int) bed->score); +safef(newName, sizeof(newName), "%d articles", (int) lf->score); return cloneString(newName); } static void pubsMarkerMapItem(struct track *tg, struct hvGfx *hvg, void *item, char *itemName, char *mapItemName, int start, int end, int x, int y, int width, int height) /* use previously saved itemName for the mouseOver */ { +struct linkedFeatures *lf = item; genericMapItem(tg, hvg, item, - itemName, mapItemName, start, end, + lf->extra, lf->extra, start, end, x, y, width, height); } +static struct hash* pubsLookupSequences(struct track *tg, struct sqlConnection* conn, char* articleId, bool getSnippet) +/* create a hash with a mapping annotId -> snippet or annotId -> shortSeq for an articleId*/ +{ + char query[LARGEBUF]; + char *sequenceTable = trackDbRequiredSetting(tg->tdb, "pubsSequenceTable"); + char *selectValSql = NULL; + if (getSnippet) + selectValSql = "replace(replace(snippet, \"\", \"-->\"), \"\", \"<--\")"; + else + selectValSql = "concat(substr(sequence,1,4),\"...\",substr(sequence,-4))"; + + safef(query, sizeof(query), "SELECT annotId, %s FROM %s WHERE articleId='%s' ", + selectValSql, sequenceTable, articleId); + struct hash *seqIdHash = sqlQuickHash(conn, query); + //freeMem(sequenceTable); // XX Why does this crash?? + return seqIdHash; +} + +static char *pubsArticleDispId(struct track *tg, struct sqlConnection *conn, char* articleId) +/* given an articleId, lookup author and year and create label for it */ +{ +char* dispLabel = NULL; +char *articleTable = pubsArticleTable(tg); +char query[LARGEBUF]; +safef(query, sizeof(query), "SELECT authors, year FROM %s WHERE articleId = '%s'", + articleTable, articleId); +struct sqlResult *sr = sqlGetResult(conn, query); +if (sr!=NULL) +{ + char **row = NULL; + row = sqlNextRow(sr); + dispLabel = pubsFeatureLabel(row[0], row[1]); +} +else + dispLabel = articleId; +sqlFreeResult(&sr); +return dispLabel; +} + +static void pubsPslLoadItems(struct track *tg) +/* load only psl items from a single article */ +{ +// get articleId to filter on +char *articleId = cartOptionalString(cart, PUBSFILTERNAME); +if (articleId==NULL) + return; + +struct sqlConnection *conn = hAllocConn(database); +char* dispLabel = pubsArticleDispId(tg, conn, articleId); +struct hash *idToSnip = pubsLookupSequences(tg, conn, articleId, TRUE); +struct hash *idToSeq = pubsLookupSequences(tg, conn, articleId, FALSE); + +// change track label +char* oldLabel = tg->longLabel; +tg->longLabel = catTwoStrings("Individual matches for article ", dispLabel); +freeMem(oldLabel); + +// filter and load items for this articleId +char where[256]; +safef(where, sizeof(where), " articleId=%s ", articleId); + +int rowOffset = 0; +struct sqlResult *sr = NULL; +sr = hRangeQuery(conn, tg->table, chromName, winStart, winEnd, where, &rowOffset); + +struct linkedFeatures *lfList = NULL; +char **row = NULL; +while ((row = sqlNextRow(sr)) != NULL) +{ + struct psl *psl = pslLoad(row+rowOffset); + slAddHead(&lfList, lfFromPsl(psl, TRUE)); + char* shortSeq = hashFindVal(idToSeq, lfList->name); + char* snip = hashFindVal(idToSnip, lfList->name); + struct pubsExtra *extra = needMem(sizeof(struct pubsExtra)); + extra->mouseOver=snip; + extra->label=shortSeq; + lfList->extra = extra; +} +sqlFreeResult(&sr); +slReverse(&lfList); +slSort(&lfList, linkedFeaturesCmp); +tg->items = lfList; +hFreeConn(&conn); +} + +static void pubsBlatPslMethods(struct track *tg) +/* a track that shows only the indiv matches for one single article */ +{ + activatePslTrackIfCgi(tg); + tg->loadItems = pubsPslLoadItems; + tg->itemName = pubsItemName; + tg->mapItem = pubsMapItem; +} + static void pubsBlatMethods(struct track *tg) /* publication blat tracks are bed12+2 tracks of sequences in text, mapped with BLAT */ { tg->loadItems = pubsLoadItems; tg->itemName = pubsItemName; tg->mapItem = pubsMapItem; } static void pubsMarkerMethods(struct track *tg) -/* publication marker tracks are bed5 tracks of genome marker occurences like rsXXXX found in text*/ +/* publication marker tracks are bed4 tracks of genome marker occurences like rsXXXX found in text*/ { + tg->loadItems= pubsLoadMarkerItem; tg->mapItem = pubsMarkerMapItem; tg->itemName = pubsMarkerItemName; } void fillInFromType(struct track *track, struct trackDb *tdb) /* Fill in various function pointers in track from type field of tdb. */ { char *typeLine = tdb->type, *words[8], *type; int wordCount; if (typeLine == NULL) return; wordCount = chopLine(cloneString(typeLine), words); if (wordCount <= 0) return; type = words[0]; #ifndef GBROWSE if (sameWord(type, "bed")) { complexBedMethods(track, tdb, FALSE, wordCount, words); /* bed.h includes genePred.h so should be able to use these trackDb settings. */ if (trackDbSetting(track->tdb, GENEPRED_CLASS_TBL) !=NULL) track->itemColor = genePredItemClassColor; - if (hashFindVal(tdb->settingsHash, "pubsMarkerTable")) + // XX this might not be the right place / right way to set methods here + // XX should I introduce a track type ? (MaxH) + if (trackDbSettingClosestToHome(track->tdb, "pubsMarkerTable") !=NULL) pubsMarkerMethods(track); - if (hashFindVal(tdb->settingsHash, "pubsSequenceTable")) + if (trackDbSettingClosestToHome(track->tdb, "pubsSequenceTable") !=NULL) pubsBlatMethods(track); } /* else if (sameWord(type, "bedLogR")) { wordCount++; words[1] = "9"; complexBedMethods(track, tdb, FALSE, wordCount, words); //track->bedSize = 10; } */ else if (sameWord(type, "bigBed")) { bigBedMethods(track, tdb, wordCount, words); if (trackShouldUseAjaxRetrieval(track)) @@ -12443,30 +12594,34 @@ track->loadItems = loadGenePred; track->colorShades = NULL; if (track->itemAttrTbl != NULL) track->itemColor = genePredItemAttrColor; else if (trackDbSetting(track->tdb, GENEPRED_CLASS_TBL) !=NULL) track->itemColor = genePredItemClassColor; } else if (sameWord(type, "logo")) { logoMethods(track, tdb, wordCount, words); } #endif /* GBROWSE */ else if (sameWord(type, "psl")) { pslMethods(track, tdb, wordCount, words); + + // XX what is the right way to do this? new track type? + if (trackDbSettingClosestToHome(track->tdb, "pubsArticleTable") !=NULL) + pubsBlatPslMethods(track); } else if (sameWord(type, "snake")) { snakeMethods(track, tdb, wordCount, words); } else if (sameWord(type, "chain")) { chainMethods(track, tdb, wordCount, words); } else if (sameWord(type, "netAlign")) { netMethods(track); } else if (sameWord(type, "maf")) {