5b97c90762187cf1993742fe8c422308e08d082c tdreszer Wed Jul 11 17:08:55 2012 -0700 Next batch of many checkins as dictated by Jim. Formatting if and limiting lines to 100 chars. Changes limited to lines last touched by tdreszer (git blame) so as not to ruin history. None of these changes should affect executables in any way. diff --git src/hg/hgTracks/wigMafTrack.c src/hg/hgTracks/wigMafTrack.c index c993ab0..46c14c6 100644 --- src/hg/hgTracks/wigMafTrack.c +++ src/hg/hgTracks/wigMafTrack.c @@ -1,2539 +1,2541 @@ /* wigMafTrack - display multiple alignment files with score wiggle * and base-level alignment, or else density plot of pairwise alignments * (zoomed out) */ #include "common.h" #include "hash.h" #include "linefile.h" #include "jksql.h" #include "hdb.h" #include "hgTracks.h" #include "maf.h" #include "scoredRef.h" #include "wiggle.h" #include "hCommon.h" #include "hgMaf.h" #include "mafTrack.h" #include "customTrack.h" #include "mafSummary.h" #include "mafFrames.h" #include "phyloTree.h" #define GAP_ITEM_LABEL "Gaps" #define MAX_SP_SIZE 2000 struct wigMafItem /* A maf track item -- * a line of bases (base level) or pairwise density gradient (zoomed out). */ { struct wigMafItem *next; char *name; /* Common name */ char *db; /* Database */ int group; /* number of species group/clade */ int ix; /* Position in list. */ int height; /* Pixel height of item. */ int inserts[128]; int insertsSize; int seqEnds[128]; int seqEndsSize; int brackStarts[128]; int brackStartsSize; int brackEnds[128]; int brackEndsSize; }; static void wigMafItemFree(struct wigMafItem **pEl) /* Free up a wigMafItem. */ { struct wigMafItem *el = *pEl; if (el != NULL) { freeMem(el->name); freeMem(el->db); freez(pEl); } } void wigMafItemFreeList(struct wigMafItem **pList) /* Free a list of dynamically allocated wigMafItem's */ { struct wigMafItem *el, *next; for (el = *pList; el != NULL; el = next) { next = el->next; wigMafItemFree(&el); } *pList = NULL; } Color wigMafItemLabelColor(struct track *tg, void *item, struct hvGfx *hvg) /* Return color to draw a maf item based on the species group it is in */ { struct wigMafItem *mi = (struct wigMafItem *)item; if (sameString(mi->name, GAP_ITEM_LABEL)) return getOrangeColor(); return (((struct wigMafItem *)item)->group % 2 ? tg->ixAltColor : tg->ixColor); } static struct mafAli *wigMafLoadInRegion(struct sqlConnection *conn, struct sqlConnection *conn2, char *table, char *chrom, int start, int end, char *file) /* Load mafs from region */ { return mafLoadInRegion2(conn, conn2, table, chrom, start, end, file); } static struct wigMafItem *newMafItem(char *s, int g, boolean lowerFirstChar) /* Allocate and initialize a maf item. Species param can be a db or name */ { struct wigMafItem *mi; char *val; AllocVar(mi); if ((val = hGenome(s)) != NULL) { /* it's a database name */ mi->db = cloneString(s); mi->name = val; } else { mi->db = cloneString(s); mi->name = cloneString(s); } mi->name = hgDirForOrg(mi->name); if (lowerFirstChar) *mi->name = tolower(*mi->name); mi->height = tl.fontHeight; mi->group = g; return mi; } struct wigMafItem *getSpeciesFromMaf(struct track *track, int height) { struct wigMafItem *mi = NULL, *miList = NULL; struct hash *hash = newHash(8); /* keyed by database. */ struct mafPriv *mp = getMafPriv(track); struct mafAli *maf; char buf[64]; char *otherOrganism; if (mp->list == (struct mafAli *)-1) return NULL; for (maf = mp->list; maf != NULL; maf = maf->next) { struct mafComp *mc; for (mc = maf->components; mc != NULL; mc = mc->next) { mafSrcDb(mc->src, buf, sizeof(buf)); if (sameString(buf, database)) continue; if (hashLookup(hash, buf) == NULL) { AllocVar(mi); mi->db = cloneString(buf); otherOrganism = hOrganism(mi->db); mi->name = (otherOrganism == NULL ? cloneString(buf) : otherOrganism); mi->height = tl.fontHeight; slAddHead(&miList, mi); hashAdd(hash, mi->db, mi); } } } hashFree(&hash); return miList; } struct wigMafItem *newSpeciesItems(struct track *track, int height) /* Make up item list for all species configured in track settings */ { struct dyString *order = dyStringNew(256); char option[MAX_SP_SIZE]; char *species[MAX_SP_SIZE]; char *groups[20]; char *defaultOff[MAX_SP_SIZE]; char sGroup[24]; struct wigMafItem *mi = NULL, *miList = NULL; int group; int i; int speciesCt = 0, groupCt = 1; int speciesOffCt = 0; struct hash *speciesOffHash = newHash(0); #define BRANEY_SAYS_USETARG_IS_OBSOLETE #ifndef BRANEY_SAYS_USETARG_IS_OBSOLETE char *speciesTarget = trackDbSetting(track->tdb, SPECIES_TARGET_VAR); char *speciesTree = trackDbSetting(track->tdb, SPECIES_TREE_VAR); bool useTarg; /* use phyloTree to find shortest path */ struct phyloTree *tree = NULL; #endif///ndef BRANEY_SAYS_USETARG_IS_OBSOLETE char *speciesUseFile = trackDbSetting(track->tdb, SPECIES_USE_FILE); char *msaTable = NULL; /* either speciesOrder or speciesGroup is specified in trackDb */ char *speciesOrder = trackDbSetting(track->tdb, SPECIES_ORDER_VAR); char *speciesGroup = trackDbSetting(track->tdb, SPECIES_GROUP_VAR); char *speciesOff = trackDbSetting(track->tdb, SPECIES_DEFAULT_OFF_VAR); bool lowerFirstChar = TRUE; char *firstCase; firstCase = trackDbSetting(track->tdb, ITEM_FIRST_CHAR_CASE); if (firstCase != NULL) { if (sameWord(firstCase, "noChange")) lowerFirstChar = FALSE; } #ifndef BRANEY_SAYS_USETARG_IS_OBSOLETE char buffer[128]; -safef(buffer, sizeof(buffer), "%s.vis",track->track); // According to Tim, this makes no sense as "vis" +// According to Tim, this makes no sense as ".vis" +safef(buffer, sizeof(buffer), "%s.vis",track->track); if (!cartVarExists(cart, buffer) && (speciesTarget != NULL)) useTarg = TRUE; else { char *val; val = cartUsualString(cart, buffer, "useCheck"); useTarg = sameString("useTarg",val); } if (useTarg && (tree = phyloParseString(speciesTree)) == NULL) useTarg = FALSE; #endif///ndef BRANEY_SAYS_USETARG_IS_OBSOLETE if (speciesOrder == NULL && speciesGroup == NULL && speciesUseFile == NULL) return getSpeciesFromMaf(track, height); if (speciesGroup) groupCt = chopLine(cloneString(speciesGroup), groups); if (speciesUseFile) { if ((speciesGroup != NULL) || (speciesOrder != NULL)) errAbort("Can't specify speciesUseFile and speciesGroup or speciesOrder"); if (hIsGsidServer()) { msaTable = trackDbSetting(track->tdb, "msaTable"); if (msaTable != NULL) { speciesOrder = cartGetOrderFromFileAndMsaTable(database, cart, speciesUseFile, msaTable); } else { speciesOrder = cartGetOrderFromFile(database, cart, speciesUseFile); } } else { speciesOrder = cartGetOrderFromFile(database, cart, speciesUseFile); } speciesOff = NULL; } /* keep track of species configured off initially for track */ if (speciesOff) { speciesOffCt = chopLine(cloneString(speciesOff), defaultOff); for (i = 0; i < speciesOffCt; i++) hashAdd(speciesOffHash, defaultOff[i], NULL); } char *prefix = track->track; // use when setting things to the cart if (tdbIsContainerChild(track->tdb)) prefix = tdbGetContainer(track->tdb)->track; /* Make up items for other organisms by scanning through group & species track settings */ for (group = 0; group < groupCt; group++) { if (groupCt != 1 || !speciesOrder) { safef(sGroup, sizeof sGroup, "%s%s", SPECIES_GROUP_PREFIX, groups[group]); speciesOrder = trackDbRequiredSetting(track->tdb, sGroup); } #ifndef BRANEY_SAYS_USETARG_IS_OBSOLETE if (useTarg) { warn("BRANEY_SAYS useTarg should never be TRUE!"); char *ptr, *path; struct hash *orgHash = newHash(0); int numNodes, ii; char *nodeNames[512]; char *species = NULL; char *lowerString; path = phyloNodeNames(tree); numNodes = chopLine(path, nodeNames); for(ii=0; ii < numNodes; ii++) { if ((ptr = hOrganism(nodeNames[ii])) != NULL) { ptr[0] = tolower(ptr[0]); hashAdd(orgHash, ptr, nodeNames[ii]); } else { hashAdd(orgHash, nodeNames[ii], nodeNames[ii]); } } lowerString = cartUsualString(cart, SPECIES_HTML_TARGET,speciesTarget); lowerString[0] = tolower(lowerString[0]); species = hashFindVal(orgHash, lowerString); if ((ptr = phyloFindPath(tree, database, species)) != NULL) speciesOrder = ptr; } #endif///ndef BRANEY_SAYS_USETARG_IS_OBSOLETE speciesCt = chopLine(cloneString(speciesOrder), species); for (i = 0; i < speciesCt; i++) { #ifndef BRANEY_SAYS_USETARG_IS_OBSOLETE if (!useTarg) #endif///ndef BRANEY_SAYS_USETARG_IS_OBSOLETE { /* skip this species if UI checkbox was unchecked */ if (!cartVarExistsAnyLevel(cart, track->tdb,FALSE,species[i])) { if (hashLookup(speciesOffHash, species[i])) { safef(option, sizeof(option), "%s.%s", prefix, species[i]); cartSetBoolean(cart, option, FALSE); } } if (!cartUsualBooleanClosestToHome(cart, track->tdb, FALSE, species[i],TRUE)) continue; } mi = newMafItem(species[i], group, lowerFirstChar); slAddHead(&miList, mi); } } slReverse(&miList); for (mi = miList; mi != NULL; mi = mi->next) { mi->height = height; dyStringPrintf(order, "%s ",mi->db); } safef(option, sizeof(option), "%s.speciesOrder", prefix); cartSetString(cart, option, order->string); slReverse(&miList); return miList; } static struct wigMafItem *scoreItem(int scoreHeight, char *label) /* Make up item that will show the score */ { struct wigMafItem *mi; AllocVar(mi); mi->name = cloneString(label); mi->height = scoreHeight; return mi; } struct mafPriv *getMafPriv(struct track *track) { struct mafPriv *mp = track->customPt; if (mp == NULL) { AllocVar(mp); track->customPt = mp; } return mp; } char *getTrackMafFile(struct track *track) /* look up MAF file name in track setting, return NULL if not found */ { return hashFindVal(track->tdb->settingsHash, "mafFile"); } char *getCustomMafFile(struct track *track) { char *fileName = getTrackMafFile(track); if (fileName == NULL) errAbort("cannot find custom maf setting"); return fileName; } static void loadMafsToTrack(struct track *track) /* load mafs in region to track custom pointer */ { struct sqlConnection *conn; struct sqlConnection *conn2; struct mafPriv *mp = getMafPriv(track); if (winBaseCount > MAF_SUMMARY_VIEW) return; /* we open two connections to the database * that has the maf track in it. One is * for the scoredRefs, the other to access * the extFile database. We could get away * with just one connection, but then we'd * have to allocate more memory to hold * the scoredRefs (whereas now we just use * one statically loaded scoredRef). */ if (mp->ct) { char *fileName = getCustomMafFile(track); conn = hAllocConn(CUSTOM_TRASH); conn2 = hAllocConn(CUSTOM_TRASH); mp->list = wigMafLoadInRegion(conn, conn2, mp->ct->dbTableName, chromName, winStart - 2 , winEnd + 2, fileName); hFreeConn(&conn); hFreeConn(&conn2); } else { char *fileName = getTrackMafFile(track); // optional conn = hAllocConn(database); conn2 = hAllocConn(database); mp->list = wigMafLoadInRegion(conn, conn2, track->table, chromName, winStart - 2 , winEnd + 2, fileName); hFreeConn(&conn); hFreeConn(&conn2); } } static struct wigMafItem *loadBaseByBaseItems(struct track *track) /* Make up base-by-base track items. */ { struct wigMafItem *miList = NULL, *speciesList = NULL, *mi; int scoreHeight = 0; bool lowerFirstChar = TRUE; char *firstCase; firstCase = trackDbSetting(track->tdb, ITEM_FIRST_CHAR_CASE); if (firstCase != NULL) { if (sameWord(firstCase, "noChange")) lowerFirstChar = FALSE; } loadMafsToTrack(track); /* NOTE: we are building up the item list backwards */ /* Add items for conservation wiggles */ struct track *wigTrack = track->subtracks; if (wigTrack) { enum trackVisibility wigVis = (wigTrack->limitedVis == tvDense ? tvDense : tvFull); while (wigTrack != NULL) { scoreHeight = wigTotalHeight(wigTrack, wigVis); mi = scoreItem(scoreHeight, wigTrack->shortLabel); slAddHead(&miList, mi); wigTrack = wigTrack->next; } } /* Make up item that will show gaps in this organism. */ AllocVar(mi); mi->name = GAP_ITEM_LABEL; mi->height = tl.fontHeight; slAddHead(&miList, mi); /* Make up item for this organism. */ mi = newMafItem(database, 0, lowerFirstChar); slAddHead(&miList, mi); speciesList = newSpeciesItems(track, tl.fontHeight); /* Make items for other species */ miList = slCat(speciesList, miList); slReverse(&miList); return miList; } static char *summarySetting(struct track *track) /* Return the setting for the MAF summary table * or NULL if none set */ { return trackDbSetting(track->tdb, SUMMARY_VAR); } static char *pairwiseSuffix(struct track *track) /* Return the suffix for the wiggle tables for the pairwise alignments, * or NULL if none set */ { char *suffix = trackDbSetting(track->tdb, PAIRWISE_VAR); if (suffix != NULL) suffix = firstWordInLine(cloneString(suffix)); return suffix; } static int pairwiseWigHeight(struct track *track) /* Return the height of a pairwise wiggle for this track, or 0 if n/a * NOTE: set one pixel smaller than we actually want, to * leave a border at the bottom of the wiggle. */ { char *words[2]; int wordCount; char *settings; struct track *wigTrack = track->subtracks; int pairwiseHeight = tl.fontHeight; int consWigHeight = 0; settings = cloneString(trackDbSetting(track->tdb, PAIRWISE_HEIGHT)); if (settings != NULL) return(atoi(firstWordInLine(settings))); if (wigTrack) { consWigHeight = wigTotalHeight(wigTrack, tvFull); pairwiseHeight = max(consWigHeight/3 - 1, pairwiseHeight); } settings = cloneString(trackDbSetting(track->tdb, PAIRWISE_VAR)); if (settings == NULL) return pairwiseHeight; /* get height for pairwise wiggles */ if ((wordCount = chopLine(settings, words)) > 1) { int settingsHeight = atoi(words[1]); if (settingsHeight < tl.fontHeight) pairwiseHeight = tl.fontHeight; else if (settingsHeight > consWigHeight && consWigHeight > 0) pairwiseHeight = consWigHeight; else pairwiseHeight = settingsHeight; } freez(&settings); return pairwiseHeight; } static char *getWigTablename(char *species, char *suffix) /* generate tablename for wiggle pairwise: "<species>_<table>_wig" */ { char table[64]; safef(table, sizeof(table), "%s_%s_wig", species, suffix); return cloneString(table); } static char *getMafTablename(char *species, char *suffix) /* generate tablename for wiggle maf: "<species>_<table>" */ { char table[64]; safef(table, sizeof(table), "%s_%s", species, suffix); return cloneString(table); } static boolean displayPairwise(struct track *track) /* determine if tables are present for pairwise display */ { return winBaseCount < MAF_SUMMARY_VIEW || isCustomTrack(track->table) || pairwiseSuffix(track) || summarySetting(track); } static boolean displayZoomedIn(struct track *track) /* determine if mafs are loaded -- zoomed in display */ { struct mafPriv *mp = getMafPriv(track); return mp->list != (char *)-1; } static void markNotPairwiseItem(struct wigMafItem *mi) { mi->ix = -1; } static boolean isPairwiseItem(struct wigMafItem *mi) { return mi->ix != -1; } static struct wigMafItem *loadPairwiseItems(struct track *track) /* Make up items for modes where pairwise data are shown. First an item for the score wiggle, then a pairwise item for each "other species" in the multiple alignment. These may be density plots (pack) or wiggles (full). Return item list. Also set customPt with mafList if zoomed in */ { struct wigMafItem *miList = NULL, *speciesItems = NULL, *mi; struct track *wigTrack = track->subtracks; int scoreHeight = tl.fontHeight * 4; if (winBaseCount < MAF_SUMMARY_VIEW) { /* "close in" display uses actual alignments from file */ struct mafPriv *mp = getMafPriv(track); struct sqlConnection *conn, *conn2; if (mp->ct) { char *fileName = getCustomMafFile(track); conn = hAllocConn(CUSTOM_TRASH); conn2 = hAllocConn(CUSTOM_TRASH); mp->list = wigMafLoadInRegion(conn, conn2, mp->ct->dbTableName, chromName, winStart, winEnd, fileName); hFreeConn(&conn); hFreeConn(&conn2); } else { char *fileName = getTrackMafFile(track); // optional conn = hAllocConn(database); conn2 = hAllocConn(database); mp->list = wigMafLoadInRegion(conn, conn2, track->table, chromName, winStart, winEnd, fileName); hFreeConn(&conn); hFreeConn(&conn2); } #ifdef DEBUG slSort(&mp->list, mafCmp); #endif } while (wigTrack != NULL) { /* display score graph along with pairs only if a wiggle * is provided */ scoreHeight = wigTotalHeight(wigTrack, tvFull); mi = scoreItem(scoreHeight, wigTrack->shortLabel); /* mark this as not a pairwise item */ markNotPairwiseItem(mi); slAddHead(&miList, mi); wigTrack = wigTrack->next; } if (displayPairwise(track)) /* make up items for other organisms by scanning through * all mafs and looking at database prefix to source. */ { speciesItems = newSpeciesItems(track, track->limitedVis == tvFull ? pairwiseWigHeight(track) : tl.fontHeight); miList = slCat(speciesItems, miList); } slReverse(&miList); return miList; } static struct wigMafItem *loadWigMafItems(struct track *track, boolean isBaseLevel) /* Load up items */ { struct wigMafItem *miList = NULL, *mi; int scoreHeight = tl.fontHeight * 4; struct track *wigTrack = track->subtracks; struct mafPriv *mp = getMafPriv(track); mp->list = (char *)-1; /* no maf's loaded or attempted to load */ /* if we're out in summary view and rendering a custom * track we force dense mode since we don't have * a summary table (yet). */ if ((winBaseCount >= MAF_SUMMARY_VIEW) && isCustomTrack(track->table)) track->limitedVis = tvDense; /* Load up mafs and store in track so drawer doesn't have * to do it again. */ /* Make up tracks for display. */ if (track->limitedVis == tvFull || track->limitedVis == tvPack) { if (isBaseLevel) { miList = loadBaseByBaseItems(track); } /* zoomed out */ else { miList = loadPairwiseItems(track); } } else if (track->limitedVis == tvSquish) { if (!wigTrack) { scoreHeight = tl.fontHeight * 4; if (winBaseCount < MAF_SUMMARY_VIEW) loadMafsToTrack(track); /* not a real meausre of conservation, so don't label it so */ miList = scoreItem(scoreHeight, ""); } else while (wigTrack) { /* have a wiggle */ scoreHeight = wigTotalHeight(wigTrack, tvFull); mi = scoreItem(scoreHeight, wigTrack->shortLabel); slAddTail(&miList, mi); wigTrack = wigTrack->next; } } else { /* dense mode, zoomed out - show density plot, with track label */ if (!wigTrack) { /* no wiggle -- use mafs if close in */ if (winBaseCount < MAF_SUMMARY_VIEW) #ifndef NOTYET loadMafsToTrack(track); AllocVar(miList); miList->name = cloneString(track->shortLabel); miList->height = tl.fontHeight; #else miList = loadPairwiseItems(track); /* remove components that aren't selected */ struct wigMafItem *mil = miList; struct hash *nameHash = newHash(5); for(;mil; mil = mil->next) hashStore(nameHash, mil->name); struct mafPriv *mp = getMafPriv(track); struct mafAli *mafList = mp->list; struct mafComp *mc; for(; mafList; mafList = mafList->next) { struct mafComp *prev = mafList->components; /* start after the master component */ for(mc = mafList->components->next; mc; mc = mc->next) { char *ptr = strchr(mc->src, '.'); if (ptr) *ptr = 0; char *ptr2 = hOrganism(mc->src); *ptr2 = tolower(*ptr2); if (!hashLookup(nameHash, ptr2)) /* delete this component */ prev->next = mc->next; else { if (ptr) *ptr = '.'; prev = mc; } } } /* label with the track name */ miList->name = cloneString(track->shortLabel); miList->next = NULL; #endif /* NOTYET */ } else while (wigTrack) { AllocVar(mi); mi->name = cloneString(wigTrack->shortLabel); mi->height = tl.fontHeight + 1; slAddTail(&miList, mi); wigTrack = wigTrack->next; } } return miList; } static void wigMafLoad(struct track *track) /* Load up maf tracks. What this will do depends on * the zoom level and the display density. */ { struct wigMafItem *miList = NULL; struct track *wigTrack = track->subtracks; // Make sure visibility takes into account any composite track with multi-views track->limitedVis = tvMin(track->visibility,limitedVisFromComposite(track)); track->limitedVisSet = (track->limitedVis != tvHide && track->visibility != track->limitedVis); miList = loadWigMafItems(track, zoomedToBaseLevel); track->items = miList; while (wigTrack != NULL) // load wiggle subtrack items { /* update track visibility from parent track, * since hgTracks will update parent vis before loadItems */ wigTrack->visibility = track->visibility; wigTrack->limitedVis = track->limitedVis; wigTrack->loadItems(wigTrack); wigTrack = wigTrack->next; } } static int wigMafTotalHeight(struct track *track, enum trackVisibility vis) /* Return total height of maf track. */ { struct wigMafItem *mi; int total = 0,count=0; for (mi = track->items; mi != NULL; mi = mi->next) { total += mi->height; count++; } track->height = total; if (track->limitedVis == tvDense) - track->height=(tl.fontHeight+1)*count; // Evidence that track-height comes in as 9 but should be 10! + track->height=(tl.fontHeight+1)*count; // Evidence that track->height is 9 but should be 10! return track->height; } static int wigMafItemHeight(struct track *track, void *item) /* Return total height of maf track. */ { struct wigMafItem *mi = item; return mi->height; } static void wigMafFree(struct track *track) /* Free up maf items. */ { struct mafPriv *mp = getMafPriv(track); if (mp->list != NULL && mp->list != (char *)-1) mafAliFreeList((struct mafAli **)&mp->list); if (track->items != NULL) wigMafItemFreeList((struct wigMafItem **)&track->items); } static char *wigMafItemName(struct track *track, void *item) /* Return name of maf level track. */ { struct wigMafItem *mi = item; return mi->name; } static void processInserts(char *text, struct mafAli *maf, struct hash *itemHash, int insertCounts[], int baseCount) /* Make up insert line from sequence of reference species. It has a gap count at each displayed base position, and is generated by counting up '-' chars in the sequence, where */ { int i, baseIx = 0; struct mafComp *mc; char c; for (i=0; i < maf->textSize && baseIx < baseCount - 1; i++) { c = text[i]; if (c == '-') { for (mc = maf->components; mc != NULL; mc = mc->next) { char buf[64]; mafSrcDb(mc->src, buf, sizeof buf); if (hashLookup(itemHash, buf) == NULL) continue; if (mc->text == NULL) /* empty row annotation */ continue; if (mc->text[i] != '-') { insertCounts[baseIx]++; break; } } } else baseIx++; } } static int processSeq(char *text, char *masterText, int textSize, char *outLine, int offset, int outSize, int *inserts, int insertCounts) /* Add text to outLine, suppressing copy where there are dashes * in masterText. This effectively projects the alignment onto * the master genome. * If no dash exists in this sequence, count up size * of the insert and save in the line. */ { int i, outIx = 0, outPositions = 0; int insertSize = 0, previousInserts = 0; int previousBreaks = 0; outLine = outLine + offset + previousBreaks + (previousInserts * 2); for (i=0; i < textSize /*&& outPositions < outSize*/; i++) { if (masterText[i] != '-') { if (insertSize != 0) { inserts[insertCounts++] = offset + outIx + 1; insertSize = 0; } outLine[outIx++] = text[i]; outPositions++; } else { /* gap in master (reference) sequence but not in this species */ switch(text[i]) { case 'N': case '-': case '=': case ' ': break; default: insertSize++; } } } if (insertSize != 0) { inserts[insertCounts++] = offset + outIx + 1; } return insertCounts; } static int drawScore(float score, int chromStart, int chromEnd, int seqStart, double scale, struct hvGfx *hvg, int xOff, int yOff, int height, Color color, enum trackVisibility vis) /* Draw density plot or graph based on score. Return last X drawn */ { int x1,x2,y,w; int height1 = height-1; x1 = round((chromStart - seqStart)*scale); x2 = round((chromEnd - seqStart)*scale); w = x2-x1+1; if (vis == tvFull) { y = score * height1; hvGfxBox(hvg, x1 + xOff, yOff + height1 - y, w, y+1, color); } else { Color c; int shade = (score * maxShade) + 1; if (shade < 0) shade = 0; else if (shade > maxShade) shade = maxShade; c = shadesOfGray[shade]; hvGfxBox(hvg, x1 + xOff, yOff, w, height1, c); } return xOff + x1 + w - 1; } static void drawScoreSummary(struct mafSummary *summaryList, int height, int seqStart, int seqEnd, struct hvGfx *hvg, int xOff, int yOff, int width, MgFont *font, Color color, Color altColor, enum trackVisibility vis, boolean chainBreaks) /* Draw density plot or graph for summary maf scores */ { struct mafSummary *ms; double scale = scaleForPixels(width); boolean isDouble = FALSE; int x1, x2; int w = 0; int chromStart = seqStart; int lastX; /* draw chain before first alignment */ ms = summaryList; if (chainBreaks && ms->chromStart > chromStart) { if (isContigOrTandem(ms->leftStatus[0]) || ms->leftStatus[0] == MAF_INSERT_STATUS) { isDouble = (ms->leftStatus[0] == MAF_INSERT_STATUS); x1 = xOff; x2 = round((double)((int)ms->chromStart-1 - seqStart) * scale) + xOff; w = x2 - x1; if (w > 0) drawMafChain(hvg, x1, yOff, w, height, isDouble); } else if (ms->leftStatus[0] == MAF_MISSING_STATUS ) { Color fuzz = shadesOfGray[1]; x1 = xOff; x2 = round((double)((int)ms->chromStart-1 - seqStart) * scale) + xOff; w = x2 - x1; hvGfxBox(hvg, x1, yOff, w, height, fuzz); } } for (ms = summaryList; ms != NULL; ms = ms->next) { lastX = drawScore(ms->score, ms->chromStart, ms->chromEnd, seqStart, scale, hvg, xOff, yOff, height, color, vis); /* draw chain after alignment */ if (chainBreaks && ms->chromEnd < seqEnd && ms->next != NULL) { if (isContigOrTandem(ms->rightStatus[0]) || ms->rightStatus[0] == MAF_INSERT_STATUS) { isDouble = (ms->rightStatus[0] == MAF_INSERT_STATUS); x1 = round((double)((int)ms->chromEnd+1 - seqStart) * scale) + xOff; x2 = round((double)((int)ms->next->chromStart-1 - seqStart) * scale) + xOff; w = x2 - x1; if (w == 1 && x1 == lastX) continue; if (w > 0); drawMafChain(hvg, x1, yOff, w, height, isDouble); } else if (ms->rightStatus[0] == MAF_MISSING_STATUS ) { Color fuzz = shadesOfGray[2]; x1 = round((double)((int)ms->chromEnd+1 - seqStart) * scale) + xOff; x2 = round((double)((int)ms->next->chromStart-1 - seqStart) * scale) + xOff ; w = x2 - x1; if (w == 1 && x1 == lastX) continue; if (w > 0) hvGfxBox(hvg, x1, yOff, w, height, fuzz); } } } } static void drawScoreOverviewC(struct sqlConnection *conn, char *tableName, int height, int seqStart, int seqEnd, struct hvGfx *hvg, int xOff, int yOff, int width, MgFont *font, Color color, Color altColor, enum trackVisibility vis) /* Draw density plot or graph for overall maf scores rather than computing * by sections, for speed. Don't actually load the mafs -- just * the scored refs from the table. * TODO: reuse code in mafTrack.c */ { char **row; int rowOffset; struct sqlResult *sr = hRangeQuery(conn, tableName, chromName, seqStart, seqEnd, NULL, &rowOffset); double scale = scaleForPixels(width); while ((row = sqlNextRow(sr)) != NULL) { struct scoredRef ref; scoredRefStaticLoad(row + rowOffset, &ref); drawScore(ref.score, ref.chromStart, ref.chromEnd, seqStart, scale, hvg, xOff, yOff, height, color, vis); } sqlFreeResult(&sr); } static void drawScoreOverview(char *tableName, int height, int seqStart, int seqEnd, struct hvGfx *hvg, int xOff, int yOff, int width, MgFont *font, Color color, Color altColor, enum trackVisibility vis) { struct sqlConnection *conn = hAllocConn(database); drawScoreOverviewC(conn, tableName, height, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, altColor, vis); hFreeConn(&conn); } static void drawScoreOverviewCT(char *tableName, int height, int seqStart, int seqEnd, struct hvGfx *hvg, int xOff, int yOff, int width, MgFont *font, Color color, Color altColor, enum trackVisibility vis) { struct sqlConnection *conn = hAllocConn(CUSTOM_TRASH); drawScoreOverviewC(conn, tableName, height, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, altColor, vis); hFreeConn(&conn); } static boolean drawPairsFromSummary(struct track *track, int seqStart, int seqEnd, struct hvGfx *hvg, int xOff, int yOff, int width, MgFont *font, Color color, enum trackVisibility vis) { /* Draw pairwise display for this multiple alignment */ char *summary; struct wigMafItem *miList = track->items, *mi = miList; struct sqlConnection *conn; struct sqlResult *sr = NULL; char **row = NULL; int rowOffset = 0; struct mafSummary *ms, *summaryList; struct hash *componentHash = newHash(6); struct hashEl *hel; struct hashCookie cookie; struct dyString *where = dyStringNew(256); char *whereClause = NULL; boolean useIrowChains = TRUE; char option[64]; if (miList == NULL) return FALSE; char *prefix = track->track; // use when setting things to the cart if (tdbIsContainerChild(track->tdb)) prefix = tdbGetContainer(track->tdb)->track; /* get summary table name from trackDb */ if ((summary = summarySetting(track)) == NULL) return FALSE; if (cartVarExistsAnyLevel(cart, track->tdb,FALSE,MAF_CHAIN_VAR)) useIrowChains = cartUsualBooleanClosestToHome(cart, track->tdb, FALSE, MAF_CHAIN_VAR,TRUE); else { char *irowString = trackDbSetting(track->tdb, "irows"); if (irowString && sameString(irowString, "off")) useIrowChains = FALSE; safef(option, sizeof(option), "%s.%s", prefix, MAF_CHAIN_VAR); cartSetBoolean(cart, option, useIrowChains); } /* Create SQL where clause that will load up just the * summaries for the species that we are including. */ conn = hAllocConn(database); dyStringAppend(where, "src in ("); for (mi = miList; mi != NULL; mi = mi->next) { if (!isPairwiseItem(mi)) /* exclude non-species items (e.g. conservation wiggle */ continue; dyStringPrintf(where, "'%s'", mi->db); if (mi->next != NULL) dyStringAppend(where, ","); } dyStringAppend(where, ")"); /* check for empty where clause */ if (!sameString(where->string,"src in ()")) whereClause = where->string; sr = hOrderedRangeQuery(conn, summary, chromName, seqStart, seqEnd, whereClause, &rowOffset); boolean hasFieldLeftStatus = hHasField(database, summary, "leftStatus"); /* Loop through result creating a hash of lists of maf summary blocks. * The hash is keyed by species. */ while ((row = sqlNextRow(sr)) != NULL) { if (hasFieldLeftStatus) ms = mafSummaryLoad(row + rowOffset); else /* previous table schema didn't have status fields */ ms = mafSummaryMiniLoad(row + rowOffset); /* prune to fit in window bounds */ if (ms->chromStart < seqStart) ms->chromStart = seqStart; if (ms->chromEnd > seqEnd) ms->chromEnd = seqEnd; if ((hel = hashLookup(componentHash, ms->src)) == NULL) hashAdd(componentHash, ms->src, ms); else slAddHead(&(hel->val), ms); } sqlFreeResult(&sr); /* reverse summary lists */ cookie = hashFirst(componentHash); while ((hel = hashNext(&cookie)) != NULL) slReverse(&hel->val); hFreeConn(&conn); /* display pairwise items */ for (mi = miList; mi != NULL; mi = mi->next) { if (mi->ix < 0) /* ignore item for the score */ continue; summaryList = (struct mafSummary *)hashFindVal(componentHash, mi->db); if (summaryList == NULL) summaryList = (struct mafSummary *)hashFindVal(componentHash, mi->name); if (summaryList != NULL) { if (vis == tvFull) { hvGfxSetClip(hvg, xOff, yOff, width, 16); drawScoreSummary(summaryList, mi->height, seqStart, seqEnd, hvg, xOff, yOff, width, font, track->ixAltColor, track->ixAltColor, tvFull, useIrowChains); hvGfxUnclip(hvg); } else { /* pack */ /* get maf table, containing pairwise alignments for this organism */ /* display pairwise alignments in this region in dense format */ hvGfxSetClip(hvg, xOff, yOff, width, mi->height); drawScoreSummary(summaryList, mi->height, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, color, tvDense, useIrowChains); hvGfxUnclip(hvg); } } yOff += mi->height; } return TRUE; } static boolean drawPairsFromPairwiseMafScores(struct track *track, int seqStart, int seqEnd, struct hvGfx *hvg, int xOff, int yOff, int width, MgFont *font, Color color, enum trackVisibility vis) /* Draw pairwise display for this multiple alignment */ { char *suffix; char *tableName; Color pairColor; struct track *wigTrack = track->subtracks; int pairwiseHeight = pairwiseWigHeight(track); struct wigMafItem *miList = track->items, *mi = miList; if (miList == NULL) return FALSE; /* get pairwise table suffix from trackDb */ suffix = pairwiseSuffix(track); if (vis == tvFull && !isCustomTrack(track->table)) { double minY = 50.0; double maxY = 100.0; /* NOTE: later, remove requirement for wiggle */ if (wigTrack == NULL) return FALSE; /* swap colors for pairwise wiggles */ pairColor = wigTrack->ixColor; wigTrack->ixColor = wigTrack->ixAltColor; wigTrack->ixAltColor = pairColor; wigSetCart(wigTrack, MIN_Y, (void *)&minY); wigSetCart(wigTrack, MAX_Y, (void *)&maxY); } /* display pairwise items */ for (mi = miList; mi != NULL; mi = mi->next) { if (mi->ix < 0) /* ignore item for the score */ continue; if (isCustomTrack(track->table)) { struct mafPriv *mp = getMafPriv(track); drawScoreOverviewCT(mp->ct->dbTableName, mi->height, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, color, vis); hvGfxUnclip(hvg); } else if (vis == tvFull) { /* get wiggle table, of pairwise for example, percent identity */ tableName = getWigTablename(mi->name, suffix); if (!hTableExists(database, tableName)) tableName = getWigTablename(mi->db, suffix); if (hTableExists(database, tableName)) { /* reuse the wigTrack for pairwise tables */ wigTrack->track = tableName; wigTrack->table = tableName; wigTrack->loadItems(wigTrack); wigTrack->height = wigTrack->lineHeight = wigTrack->heightPer = pairwiseHeight - 1; /* clip, but leave 1 pixel border */ hvGfxSetClip(hvg, xOff, yOff, width, wigTrack->height); wigTrack->drawItems(wigTrack, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, tvFull); hvGfxUnclip(hvg); } else { /* no wiggle table for this -- compute a graph on-the-fly from mafs */ hvGfxSetClip(hvg, xOff, yOff, width, mi->height); tableName = getMafTablename(mi->name, suffix); if (!hTableExists(database, tableName)) tableName = getMafTablename(mi->db, suffix); if (hTableExists(database, tableName)) drawScoreOverview(tableName, mi->height, seqStart, seqEnd, hvg, xOff, yOff, width, font, track->ixAltColor, track->ixAltColor, tvFull); hvGfxUnclip(hvg); } /* need to add extra space between wiggles (for now) */ mi->height = pairwiseHeight; } else { /* pack */ /* get maf table, containing pairwise alignments for this organism */ /* display pairwise alignments in this region in dense format */ hvGfxSetClip(hvg, xOff, yOff, width, mi->height); tableName = getMafTablename(mi->name, suffix); if (!hTableExists(database, tableName)) tableName = getMafTablename(mi->db, suffix); if (hTableExists(database, tableName)) drawScoreOverview(tableName, mi->height, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, color, tvDense); hvGfxUnclip(hvg); } yOff += mi->height; } return TRUE; } static boolean drawPairsFromMultipleMaf(struct track *track, int seqStart, int seqEnd, struct hvGfx *hvg, int xOff, int yOff, int width, MgFont *font, Color color, enum trackVisibility vis) /* Draw pairwise display from maf of multiple alignment. * Extract pairwise alignments from maf and rescore. * This is used only when zoomed-in. */ { struct wigMafItem *miList = track->items, *mi = miList; int graphHeight = 0; Color pairColor = (vis == tvFull ? track->ixAltColor : color); boolean useIrowChains = TRUE; char option[64]; char *prefix = track->track; // use when setting things to the cart if (tdbIsContainerChild(track->tdb)) prefix = track->tdb->parent->track; struct mafPriv *mp = getMafPriv(track); if (miList == NULL || mp->list == NULL) return FALSE; if (cartVarExistsAnyLevel(cart, track->tdb,FALSE,MAF_CHAIN_VAR)) useIrowChains = cartUsualBooleanClosestToHome(cart, track->tdb, FALSE, MAF_CHAIN_VAR,TRUE); else { char *irowString = trackDbSetting(track->tdb, "irows"); if (irowString && sameString(irowString, "off")) useIrowChains = FALSE; safef(option, sizeof(option), "%s.%s", prefix, MAF_CHAIN_VAR); cartSetBoolean(cart, option, useIrowChains); } if (vis == tvFull) graphHeight = pairwiseWigHeight(track); /* display pairwise items */ for (mi = miList; mi != NULL; mi = mi->next) { struct mafAli *mafList = NULL, *maf, *pairMaf; struct mafComp *mcThis, *mcPair = NULL, *mcMaster = NULL; if (mi->ix < 0) /* ignore item for the score */ continue; /* using maf sequences from file */ /* create pairwise maf list from the multiple maf */ struct mafPriv *mp = getMafPriv(track); for (maf = mp->list; maf != NULL; maf = maf->next) { if ((mcThis = mafMayFindCompSpecies(maf, mi->db, '.')) == NULL) continue; //if (mcPair->srcSize != 0) // TODO: replace with a cloneMafComp() AllocVar(mcPair); mcPair->src = cloneString(mcThis->src); mcPair->srcSize = mcThis->srcSize; mcPair->strand = mcThis->strand; mcPair->start = mcThis->start; mcPair->size = mcThis->size; mcPair->text = cloneString(mcThis->text); mcPair->leftStatus = mcThis->leftStatus; mcPair->leftLen = mcThis->leftLen; mcPair->rightStatus = mcThis->rightStatus; mcPair->rightLen = mcThis->rightLen; mcThis = mafFindCompSpecies(maf, database, '.'); AllocVar(mcMaster); mcMaster->src = cloneString(mcThis->src); mcMaster->srcSize = mcThis->srcSize; mcMaster->strand = mcThis->strand; mcMaster->start = mcThis->start; mcMaster->size = mcThis->size; mcMaster->text = cloneString(mcThis->text); mcMaster->next = mcPair; AllocVar(pairMaf); pairMaf->components = mcMaster; pairMaf->textSize = maf->textSize; slAddHead(&mafList, pairMaf); } slReverse(&mafList); /* compute a graph or density on-the-fly from mafs */ hvGfxSetClip(hvg, xOff, yOff, width, mi->height); drawMafRegionDetails(mafList, mi->height, seqStart, seqEnd, hvg, xOff, yOff, width, font, pairColor, pairColor, vis, FALSE, useIrowChains); hvGfxUnclip(hvg); /* need to add extra space between graphs ?? (for now) */ if (vis == tvFull) mi->height = graphHeight; yOff += mi->height; mafAliFreeList(&mafList); } return TRUE; } static boolean wigMafDrawPairwise(struct track *track, int seqStart, int seqEnd, struct hvGfx *hvg, int xOff, int yOff, int width, MgFont *font, Color color, enum trackVisibility vis) /* Draw pairwise display for this multiple alignment * When zoomed in, use on-the-fly scoring of alignments extracted from multiple * When zoomed out: * if "pairwise" setting is on, use pairwise tables (maf or wiggle) * <species>_<suffix> for maf, <species>_<suffix>_wig for wiggle * For full mode, display graph. * for pack mode, display density plot. * if "summary" setting is on, use maf summary table * (saves space, and performs better) */ { if (displayZoomedIn(track)) return drawPairsFromMultipleMaf(track, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, vis); if (isCustomTrack(track->table) || pairwiseSuffix(track)) return drawPairsFromPairwiseMafScores(track, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, vis); if (summarySetting(track)) return drawPairsFromSummary(track, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, vis); return FALSE; } static void alternateBlocksBehindChars(struct hvGfx *hvg, int x, int y, int width, int height, int charWidth, int charCount, int stripeCharWidth, Color a, Color b) /* Draw blocks that alternate between color a and b. */ { int x1,x2 = x + width; int color = a; int i; for (i=0; i<charCount; i += stripeCharWidth) { x1 = i * width / charCount; x2 = (i+stripeCharWidth) * width/charCount; hvGfxBox(hvg, x1+x, y, x2-x1, height, color); if (color == a) color = b; else color = a; } } void alignSeqToUpperN(char *line) /* force base chars to upper, ignoring insert counts */ { int i; for (i=0; line[i] != 0; i++) line[i] = toupper(line[i]); } void complementUpperAlignSeq(DNA *dna, int size) /* Complement DNA (not reverse), ignoring insert counts. * Assumed to be all upper case bases */ { int i; for (i = 0; i < size; i++, dna++) { if (*dna == 'A') *dna = 'T'; else if (*dna == 'C') *dna = 'G'; else if (*dna == 'G') *dna = 'C'; else if (*dna == 'T') *dna = 'A'; } } void reverseForStrand(DNA *dna, int length, char strand, bool alreadyComplemented) { if (strand == '-') { if (alreadyComplemented) reverseBytes(dna, length); else reverseComplement(dna, length); } else { if (alreadyComplemented) complement(dna, length); } } #define ISGAP(x) (((x) == '=') || (((x) == '-'))) #define ISN(x) ((x) == 'N') #define ISSPACE(x) ((x) == ' ') #define ISGAPSPACEORN(x) (ISSPACE(x) || ISGAP(x) || ISN(x)) static AA lookupAndCheckCodon(char *codon) { AA retValue; if ((retValue = lookupCodon(codon)) == 0) return '*'; return retValue; } static void translateCodons(struct sqlConnection *conn, struct sqlConnection *conn2, char *tableName, char *compName, DNA *dna, int start, int length, int frame, char strand, int prevEnd, int nextStart, bool alreadyComplemented, int x, int y, int width, int height, struct hvGfx *hvg, char *mafFile) { int size = length; DNA *ptr; int color; int end = start + length; int x1; char masterChrom[128]; struct mafAli *ali, *sub = NULL; struct mafComp *comp = NULL; int mult = 1; char codon[4]; int fillBox = FALSE; safef(masterChrom, sizeof(masterChrom), "%s.%s", database, chromName); dna += start; reverseForStrand(dna, length, strand, alreadyComplemented); ptr = dna; color = shadesOfSea[0]; mult = 0; if (frame && (prevEnd == -1)) { switch(frame) { case 1: if (0)//!( ISGAPSPACEORN(ptr[0]) ||ISGAPSPACEORN(ptr[1]))) { fillBox = TRUE; *ptr++ = 'X'; *ptr++ = 'X'; mult = 2; } else { reverseForStrand(ptr, 2, strand, alreadyComplemented); ptr +=2; } length -=2; break; case 2: if (0)//!( ISGAPSPACEORN(ptr[0]))) { fillBox = TRUE; *ptr++ = 'X'; length -=1; mult = 1; } else { reverseForStrand(ptr, 1, strand, alreadyComplemented); ptr++; } length -=1; break; } } else if (frame && (prevEnd != -1)) { memset(codon, 0, sizeof(codon)); switch(frame) { case 1: ali = mafLoadInRegion2(conn, conn2, tableName, chromName, prevEnd , prevEnd + 1, mafFile ); if (ali != NULL) { sub = mafSubset(ali, masterChrom, prevEnd , prevEnd + 1 ); comp = mafMayFindCompSpecies(sub, compName, '.'); } if (comp && comp->text && (!(ISGAPSPACEORN(comp->text[0]) ||ISGAPSPACEORN(ptr[0]) ||ISGAPSPACEORN(ptr[1])))) { if (strand == '-') complement(comp->text, 1); codon[0] = comp->text[0]; codon[1] = ptr[0]; codon[2] = ptr[1]; fillBox = TRUE; mult = 2; *ptr++ = ' '; *ptr++ = lookupAndCheckCodon(codon); } else ptr+=2; length -= 2; break; case 2: if (strand == '-') { ali = mafLoadInRegion2(conn, conn2, tableName, chromName, prevEnd, prevEnd + 2, mafFile); if (ali != NULL) sub = mafSubset(ali, masterChrom, prevEnd, prevEnd + 2 ); } else { ali = mafLoadInRegion2(conn, conn2, tableName, chromName, prevEnd - 1, prevEnd + 1, mafFile); if (ali != NULL) sub = mafSubset(ali, masterChrom, prevEnd - 1, prevEnd + 1); } if (sub != NULL) comp = mafMayFindCompSpecies(sub, compName, '.'); if (comp && comp->text && (!(ISGAPSPACEORN(comp->text[0])||ISGAPSPACEORN(comp->text[1]) ||ISGAPSPACEORN(*ptr)))) { if (strand == '-') reverseComplement(comp->text, 2); codon[0] = comp->text[0]; codon[1] = comp->text[1]; codon[2] = *ptr; fillBox = TRUE; mult = 1; *ptr++ = lookupAndCheckCodon(codon); } else ptr++; length -= 1; break; } } if (fillBox) { if (strand == '-') { x1 = x + ( end - ( 5 - frame) ) * width / winBaseCount; } else { x1 = x + (start - 2) * width / winBaseCount; } hvGfxBox(hvg, x1, y, mult*width/winBaseCount + 1 , height, color); } for (;length > 2; ptr +=3 , length -=3) { if (!(ISGAPSPACEORN(ptr[0]) || ISGAPSPACEORN(ptr[1]) || ISGAPSPACEORN(ptr[2]) )) { ptr[1] = lookupAndCheckCodon(ptr); ptr[0] = ' '; ptr[2] = ' '; if (strand == '-') { x1 = x + ( start + length - 3 - 2) * width / winBaseCount; } else { x1 = x + (end - length - 2) * width / winBaseCount; } if (color == shadesOfSea[0]) color = shadesOfSea[1]; else color = shadesOfSea[0]; hvGfxBox(hvg, x1, y, 3*width/winBaseCount + 1 , height, color); } } if (length && (nextStart != -1)) { char codon[4]; int mult = 1; boolean fillBox = FALSE; memset(codon, 0, sizeof(codon)); sub = NULL; if (strand == '-') { ali = mafLoadInRegion2(conn, conn2, tableName, chromName, nextStart - 2 + length, nextStart + 1, mafFile ); if (ali != NULL) sub = mafSubset(ali, masterChrom, nextStart - 2 + length, nextStart + 1); } else { ali = mafLoadInRegion2(conn, conn2, tableName, chromName, nextStart , nextStart + 2, mafFile ); if (ali != NULL) sub = mafSubset(ali, masterChrom, nextStart , nextStart + 2); } if (sub != NULL) comp = mafMayFindCompSpecies(sub, compName, '.'); if (sub && comp && comp->text) { switch(length) { case 2: if (strand == '-') complement(comp->text, 1); codon[0] = *ptr; codon[1] = *(1 + ptr); codon[2] = *comp->text; if (!(ISGAPSPACEORN(codon[0]) ||ISGAPSPACEORN(codon[1]) ||ISGAPSPACEORN(codon[2]))) { fillBox = TRUE; *ptr++ = ' '; *ptr++ = lookupAndCheckCodon(codon); mult = 2; } break; case 1: if (strand == '-') reverseComplement(comp->text, 2); codon[0] = *ptr; codon[1] = comp->text[0]; codon[2] = comp->text[1]; if (!(ISGAPSPACEORN(codon[0]) ||ISGAPSPACEORN(codon[1]) ||ISGAPSPACEORN(codon[2]))) { *ptr++ = lookupAndCheckCodon(codon); fillBox = TRUE; } break; } if (fillBox) { if (strand == '-') { x1 = x + ( start - 2 ) * width / winBaseCount; } else { x1 = x + (end - length - 2) * width / winBaseCount; } if (color == shadesOfSea[0]) color = shadesOfSea[1]; else color = shadesOfSea[0]; hvGfxBox(hvg, x1, y, mult*width/winBaseCount + 1 , height, color); } } } else if (length) /* broken frame, just show nucs */ { if (strand == '-') { if (!alreadyComplemented) complement(ptr, length); } else { if (alreadyComplemented) complement(ptr, length); } } if (strand == '-') reverseBytes(dna, size); } static int wigMafDrawBases(struct track *track, int seqStart, int seqEnd, struct hvGfx *hvg, int xOff, int yOff, int width, MgFont *font, Color color, enum trackVisibility vis, struct wigMafItem *miList) /* Draw base-by-base view, return new Y offset. */ { struct wigMafItem *mi; struct mafAli *mafList, *maf, *sub; struct mafComp *mc, *mcMaster; int lineCount = slCount(miList); char **lines = NULL, *selfLine, *insertLine; int *insertCounts; int i, x = xOff, y = yOff; struct dnaSeq *seq = NULL; struct hash *miHash = newHash(9); struct hash *srcHash = newHash(0); char dbChrom[64]; char option[64]; int alignLineLength = winBaseCount * 2; /* doubled to allow space for insert counts */ boolean complementBases = cartUsualBooleanDb(cart, database, COMPLEMENT_BASES_VAR, FALSE); bool dots = FALSE; /* configuration option */ /* this line must be longer than the longest base-level display */ char noAlignment[2000]; boolean useIrowChains = TRUE; int offset; char *framesTable = NULL; char *defaultCodonSpecies = cartUsualString(cart, SPECIES_CODON_DEFAULT, NULL); char *codonTransMode = NULL; boolean startSub2 = FALSE; int mafOrig = 0; int mafOrigOffset = 0; char query[256]; struct mafPriv *mp = getMafPriv(track); char *mafFile = NULL; struct sqlConnection *conn2 = NULL; struct sqlConnection *conn3 = NULL; char *tableName = NULL; char *prefix = track->track; // use when setting things to the cart if (tdbIsContainerChild(track->tdb)) prefix = tdbGetContainer(track->tdb)->track; if (mp->ct != NULL) { conn2 = hAllocConn(CUSTOM_TRASH); conn3 = hAllocConn(CUSTOM_TRASH); tableName = mp->ct->dbTableName; mafFile = getCustomMafFile(track); } else { conn2 = hAllocConn(database); conn3 = hAllocConn(database); tableName = track->table; mafFile = getTrackMafFile(track); // optional } if (hIsGsidServer()) { /* decide the value of mafOrigOffset to be used to display xxAaMaf tracks. */ struct sqlConnection *conn = hAllocConn(database); safef(query, sizeof(query), "select chromStart from %s", track->table); mafOrig = atoi(sqlNeedQuickString(conn, query)); mafOrigOffset = (mafOrig % 3) - 1; /* offset has to be non-negative */ if (mafOrigOffset < 0) mafOrigOffset = mafOrigOffset +3; hFreeConn(&conn); } if (defaultCodonSpecies == NULL) defaultCodonSpecies = trackDbSetting(track->tdb, "speciesCodonDefault"); if (defaultCodonSpecies == NULL) defaultCodonSpecies = database; if (seqStart > 2) { startSub2 = TRUE; seqStart -=2; } seqEnd +=2; if (seqEnd > seqBaseCount) seqEnd = seqBaseCount; if (cartVarExistsAnyLevel(cart, track->tdb,FALSE,MAF_DOT_VAR)) dots = cartUsualBooleanClosestToHome(cart, track->tdb, FALSE, MAF_DOT_VAR,TRUE); else { char *dotString = trackDbSetting(track->tdb, MAF_DOT_VAR); if (dotString && sameString(dotString, "on")) { dots = TRUE; safef(option, sizeof(option), "%s.%s", prefix, MAF_DOT_VAR); cartSetBoolean(cart, option, TRUE); } } if (cartVarExistsAnyLevel(cart, track->tdb,FALSE,"frames")) framesTable = cartOptionalStringClosestToHome(cart, track->tdb,FALSE,"frames"); else framesTable = trackDbSetting(track->tdb, "frames"); if (framesTable) { codonTransMode = cartUsualStringClosestToHome(cart, track->tdb,FALSE,"codons", "codonDefault"); if (sameString("codonNone", codonTransMode)) framesTable = NULL; } boolean newTableType = FALSE; if (framesTable != NULL) newTableType = hHasField(database, framesTable, "isExonStart"); /* initialize "no alignment" string to o's */ for (i = 0; i < sizeof noAlignment - 1; i++) noAlignment[i] = UNALIGNED_SEQ; if (cartVarExistsAnyLevel(cart, track->tdb,FALSE,MAF_CHAIN_VAR)) useIrowChains = cartUsualBooleanClosestToHome(cart, track->tdb, FALSE, MAF_CHAIN_VAR,TRUE); else { char *irowString = trackDbSetting(track->tdb, "irows"); if (irowString && sameString(irowString, "off")) useIrowChains = FALSE; safef(option, sizeof(option), "%s.%s", prefix, MAF_CHAIN_VAR); cartSetBoolean(cart, option, useIrowChains); } /* Allocate a line of characters for each item. */ AllocArray(lines, lineCount); lines[0] = needMem(alignLineLength); for (i=1; i<lineCount; ++i) { lines[i] = needMem(alignLineLength); memset(lines[i], ' ', alignLineLength - 1); } /* Give nice names to first two. */ insertLine = lines[0]; selfLine = lines[1]; /* Allocate a line for recording gap sizes in reference */ AllocArray(insertCounts, alignLineLength); /* Load up self-line with DNA */ seq = hChromSeqMixed(database, chromName, seqStart , seqEnd); memcpy(selfLine, seq->dna, winBaseCount + 4); //toUpperN(selfLine, winBaseCount); freeDnaSeq(&seq); /* Make hash of species items keyed by database. */ i = 0; for (mi = miList; mi != NULL; mi = mi->next) { mi->ix = i++; if (mi->db != NULL) hashAdd(miHash, mi->db, mi); } /* Go through the mafs saving relevant info in lines. */ mafList = mp->list; safef(dbChrom, sizeof(dbChrom), "%s.%s", database, chromName); for (maf = mafList; maf != NULL; maf = maf->next) { int mafStart; /* get info about sequences from full alignment, for use later, when determining if sequence is unaligned or missing */ for (mc = maf->components; mc != NULL; mc = mc->next) if (!hashFindVal(srcHash, mc->src)) hashAdd(srcHash, mc->src, maf); mcMaster = mafFindComponent(maf, dbChrom); mafStart = mcMaster->start; /* get portion of maf in this window */ if (startSub2) sub = mafSubset(maf, dbChrom, winStart - 2, winEnd + 2); else sub = mafSubset(maf, dbChrom, winStart , winEnd + 2); if (sub != NULL) { int subStart,subEnd; int lineOffset, subSize; int startInserts = 0; char *ptr; /* process alignment for reference ("master") species */ for(ptr = mcMaster->text; *ptr == '-'; ptr++) startInserts++; mcMaster = mafFindComponent(sub, dbChrom); if (mcMaster->strand == '-') mafFlipStrand(sub); subStart = mcMaster->start; subEnd = subStart + mcMaster->size; subSize = subEnd - subStart; lineOffset = subStart - seqStart; processInserts(mcMaster->text, sub, miHash, &insertCounts[lineOffset], subSize); insertCounts[lineOffset] = max(insertCounts[lineOffset],startInserts); /* fill in bases for each species */ for (mi = miList; mi != NULL; mi = mi->next) { char *seq; bool needToFree = FALSE; int size = sub->textSize; if (mi->ix == 1) /* reference */ continue; if (mi->db == NULL) /* not a species line -- it's the gaps line, or... */ continue; if ((mc = mafMayFindCompSpecies(sub, mi->db, '.')) == NULL) continue; if (mafStart == subStart) { if (mc->size && mc->leftStatus == MAF_INSERT_STATUS && (*mc->text != '-') && !((lineOffset) && (((lines[mi->ix][lineOffset-1]) == '=') || (lines[mi->ix][lineOffset-1]) == '-'))) { insertCounts[lineOffset] = max(insertCounts[lineOffset],mc->leftLen); mi->inserts[mi->insertsSize] = (subStart - seqStart)+ 1; mi->insertsSize++; } } if (startInserts) { struct mafComp *mc1; if (((mc1 = mafMayFindCompSpecies(maf, mi->db, '.')) != NULL) && ((mc1->text) && (countNonDash(mc1->text, startInserts) > 0))) { mi->inserts[mi->insertsSize] = (subStart - seqStart)+ 1; mi->insertsSize++; } } seq = mc->text; if ( mc->text == NULL ) { /* if no alignment here, but MAF annotation indicates continuity * of flanking alignments, fill with dashes or ='s */ if (!useIrowChains) continue; if (isContigOrTandem(mc->leftStatus) && isContigOrTandem(mc->rightStatus)) { char fill = '-'; seq = needMem(size+1); needToFree = TRUE; memset(seq, fill, size); } else if (mc->leftStatus == MAF_INSERT_STATUS && mc->rightStatus == MAF_INSERT_STATUS) { char fill = MAF_DOUBLE_GAP; seq = needMem(size+1); needToFree = TRUE; memset(seq, fill, size); } else if (mc->leftStatus == MAF_MISSING_STATUS && mc->rightStatus == MAF_MISSING_STATUS) { char fill = 'N'; seq = needMem(size+1); needToFree = TRUE; memset(seq, fill, size); } else continue; } if (((mc->leftStatus == MAF_NEW_STATUS || mc->rightStatus == MAF_NEW_STATUS ) || (mc->leftStatus == MAF_NEW_NESTED_STATUS || mc->rightStatus == MAF_NEW_NESTED_STATUS ))) { int i; char *p; seq = needMem(size+1); needToFree = TRUE; for (p = seq, i = 0; i < size; p++, i++) *p = ' '; p = seq; if (mc->text != NULL) strcpy(p, mc->text); if (mc->leftStatus == MAF_NEW_STATUS) { char *m = mcMaster->text; if (mafStart == subStart) mi->seqEnds[mi->seqEndsSize] = (subStart - seqStart) + 1; while(*p == '-') { if ((*m++ != '-') && (mafStart == subStart)) mi->seqEnds[mi->seqEndsSize]++; *p++ = ' '; } if (mafStart == subStart) mi->seqEndsSize++; } if (mc->leftStatus == MAF_NEW_NESTED_STATUS) { char *m = mcMaster->text; if (mafStart == subStart) mi->brackStarts[mi->brackStartsSize] = (subStart - seqStart)+ 1; while(*p == '-') { *p++ = '='; if ((*m++ != '-') && (mafStart == subStart)) mi->brackStarts[mi->brackStartsSize]++; } if (mafStart == subStart) mi->brackStartsSize++; } if (mc->rightStatus == MAF_NEW_NESTED_STATUS) { char *p = seq + size - 1; char *m = mcMaster->text + size - 1; if (subEnd <= seqEnd) mi->brackEnds[mi->brackEndsSize] = (subStart - seqStart)+ subSize + 1; while(*p == '-') { if ((*m-- != '-') && (subEnd <= seqEnd)) mi->brackEnds[mi->brackEndsSize]--; *p-- = '='; } if (subEnd <= seqEnd) mi->brackEndsSize++; } if (mc->rightStatus == MAF_NEW_STATUS) { char *p = seq + size - 1; char *m = mcMaster->text + size - 1; if (mc->size && ((subEnd <= seqEnd))) mi->seqEnds[mi->seqEndsSize] = (subStart - seqStart)+ subSize + 1; while(*p == '-') { if ((*m-- != '-') && (mc->size && (subEnd <= seqEnd))) mi->seqEnds[mi->seqEndsSize]--; *p-- = ' '; } if (mc->size && ((subEnd <= seqEnd))) mi->seqEndsSize++; } } if (mc->text && ((mc->leftStatus == MAF_MISSING_STATUS))) { char *p = seq; while(*p == '-') *p++ = 'N'; } if (mc->text && ((mc->leftStatus == MAF_INSERT_STATUS))) { char *p = seq; while(*p == '-') *p++ = '='; } if (mc->text && ((mc->rightStatus == MAF_MISSING_STATUS))) { char *p = seq + size - 1; while(*p == '-') *p-- = 'N'; } if (mc->text && ((mc->rightStatus == MAF_INSERT_STATUS))) { char *m = mcMaster->text + size - 1; char *p = seq + size - 1; while((*p == '-') || (*m == '-')) { *p-- = '='; m--; } } mi->insertsSize = processSeq(seq, mcMaster->text, size, lines[mi->ix], lineOffset, subSize, mi->inserts, mi->insertsSize); if (needToFree) freeMem(seq); } } mafAliFree(&sub); } /* draw inserts line */ mi = miList; for(offset=startSub2*2; (offset < alignLineLength) && (offset < winBaseCount + startSub2 * 2); offset++) { int x1, x2; x1 = (offset - startSub2 * 2) * width/winBaseCount; x2 = ((offset - startSub2 * 2)+1) * width/winBaseCount - 1; if (insertCounts[offset] != 0) { struct dyString *label = newDyString(20); int haveRoomFor = (width/winBaseCount)/tl.mWidth; /* calculate number of AAs instead of bases if it is wigMafProt */ if (strstr(track->tdb->type, "wigMafProt")) { dyStringPrintf(label, "%d",insertCounts[offset]/3); } else { dyStringPrintf(label, "%d",insertCounts[offset]); } if (label->stringSize > haveRoomFor) { dyStringClear(label); dyStringPrintf(label, "%c",(insertCounts[offset] % 3) == 0 ? '*' : '+'); } hvGfxTextCentered(hvg, x1+x - (width/winBaseCount)/2, y, x2-x1, mi->height, getOrangeColor(), font, label->string); dyStringFree(&label); } } y += mi->height; /* draw alternating colors behind base-level alignments */ { int alternateColorBaseCount, alternateColorBaseOffset; - alternateColorBaseCount = cartUsualIntClosestToHome(cart, track->tdb, FALSE, BASE_COLORS_VAR, 0); - alternateColorBaseOffset = cartUsualIntClosestToHome(cart, track->tdb, FALSE, BASE_COLORS_OFFSET_VAR, 0); + alternateColorBaseCount = + cartUsualIntClosestToHome(cart, track->tdb, FALSE, BASE_COLORS_VAR, 0); + alternateColorBaseOffset = + cartUsualIntClosestToHome(cart, track->tdb, FALSE, BASE_COLORS_OFFSET_VAR, 0); if (alternateColorBaseCount != 0) { int baseWidth = spreadStringCharWidth(width, winBaseCount); int colorX = x + alternateColorBaseOffset * baseWidth; alternateBlocksBehindChars(hvg, colorX, y-1, width, mi->height*(lineCount-1), tl.mWidth, winBaseCount, alternateColorBaseCount, shadesOfSea[0], MG_WHITE); } } /* draw base-level alignments */ for (mi = miList->next, i=1; mi != NULL && mi->db != NULL; mi = mi->next, i++) { char *line; line = lines[i]; /* TODO: leave lower case in to indicate masking ? * NOTE: want to make sure that all sequences are soft-masked * if we do this */ /* HAVE DONE: David doesn't like lower case by default * TODO: casing based on quality values ?? */ alignSeqToUpperN(line); if (complementBases) { complement(line, strlen(line)); } /* draw sequence letters for alignment */ hvGfxSetClip(hvg, x, y-1, width, mi->height); if (framesTable != NULL) { int rowOffset; char **row; struct sqlConnection *conn = hAllocConn(database); struct sqlResult *sr; char extra[512]; boolean found = FALSE; if (sameString("codonDefault", codonTransMode)) { safef(extra, sizeof(extra), "src='%s'",defaultCodonSpecies); found = TRUE; } else if (sameString("codonFrameDef", codonTransMode)) { safef(extra, sizeof(extra), "src='%s'",mi->db); found = FALSE; } else if (sameString("codonFrameNone", codonTransMode)) { safef(extra, sizeof(extra), "src='%s'",mi->db); found = TRUE; } else errAbort("unknown codon translation mode %s",codonTransMode); tryagain: sr = hRangeQuery(conn, framesTable, chromName, seqStart, seqEnd, extra, &rowOffset); while ((row = sqlNextRow(sr)) != NULL) { struct mafFrames mf; int start, end, w; int frame; found = TRUE; if (newTableType) mafFramesStaticLoad(row + rowOffset, &mf); else mafFramesStaticLoadOld(row + rowOffset, &mf); if (mf.chromStart < seqStart) start = 0; else start = mf.chromStart-seqStart; frame = mf.frame; if (mf.strand[0] == '-') { if (mf.chromEnd > seqEnd) frame = (frame + mf.chromEnd-seqEnd ) % 3; } else { if (mf.chromStart < seqStart) frame = (frame + seqStart-mf.chromStart ) % 3; } end = mf.chromEnd > seqEnd ? seqEnd - seqStart : mf.chromEnd - seqStart; w= end - start; translateCodons(conn2, conn3, tableName, mi->db, line, start , w, frame, mf.strand[0],mf.prevFramePos,mf.nextFramePos, complementBases, x, y, width, mi->height, hvg, mafFile); - } sqlFreeResult(&sr); if (!found) { /* try the default species */ safef(extra, sizeof(extra), "src='%s'",defaultCodonSpecies); found = TRUE; /* don't try again */ goto tryagain; } hFreeConn(&conn); } if (startSub2) { if (strstr(track->tdb->type, "wigMafProt")) { spreadAlignStringProt(hvg, x, y, width, mi->height-1, color, font, &line[2], &selfLine[2], winBaseCount, dots, FALSE, seqStart, mafOrigOffset); } else { /* make sure we have bases to display before printing them */ if (strlen(line) > 2) spreadAlignString(hvg, x, y, width, mi->height-1, color, font, &line[2], &selfLine[2], winBaseCount, dots, FALSE); } } else spreadAlignString(hvg, x, y, width, mi->height-1, color, font, line, selfLine, winBaseCount, dots, FALSE); for(offset = 0; offset < mi->seqEndsSize; offset++) { int x1; x1 = x + (mi->seqEnds[offset] -1 - startSub2 * 2) * width/winBaseCount; hvGfxBox(hvg, x1, y-1, 1, mi->height-1, getChromBreakBlueColor()); } for(offset = 0; offset < mi->insertsSize; offset++) { int x1; x1 = x + (mi->inserts[offset] -1 - startSub2 * 2) * width/winBaseCount; hvGfxBox(hvg, x1, y-1, 1, mi->height-1, getOrangeColor()); } for(offset = 0; offset < mi->brackStartsSize; offset++) { int x1; x1 = x + (mi->brackStarts[offset] -1- startSub2 * 2) * width/winBaseCount; hvGfxBox(hvg, x1, y-1, 2, 1, getChromBreakGreenColor()); hvGfxBox(hvg, x1, y-1, 1, mi->height-1, getChromBreakGreenColor()); hvGfxBox(hvg, x1, y + mi->height-3, 2, 1, getChromBreakGreenColor()); } for(offset = 0; offset < mi->brackEndsSize; offset++) { int x1; x1 = x + (mi->brackEnds[offset] -1- startSub2 * 2) * width/winBaseCount; hvGfxBox(hvg, x1-1, y-1, 2, 1, getChromBreakGreenColor()); hvGfxBox(hvg, x1, y-1, 1, mi->height-1, getChromBreakGreenColor()); hvGfxBox(hvg, x1-1, y + mi->height-3, 2, 1, getChromBreakGreenColor()); } hvGfxUnclip(hvg); y += mi->height; } /* Clean up */ /* for (i=0; i<lineCount-1; ++i) freeMem(lines[i]); freez(&lines); */ hFreeConn(&conn2); hFreeConn(&conn3); hashFree(&miHash); return y; } static int wigMafDrawScoreGraph(struct track *track, int seqStart, int seqEnd, struct hvGfx *hvg, int xOff, int yOff, int width, MgFont *font, Color color, enum trackVisibility vis) { /* Draw routine for score graph, returns new Y offset */ struct track *wigTrack = track->subtracks; enum trackVisibility scoreVis; scoreVis = (vis == tvDense ? tvDense : tvFull); if (wigTrack == NULL) { /* no wiggle */ int height = tl.fontHeight * 4; if (vis == tvFull || vis == tvPack) /* suppress graph if other items displayed (bases or pairs) */ return yOff; else if (vis == tvDense) height = track->height; // Evidence that track-height comes in as 9 but should be 10! /* draw some kind of graph from multiple alignment */ struct mafPriv *mp = getMafPriv(track); if (mp->list != (char *)-1 && mp->list != NULL) { /* use mafs */ drawMafRegionDetails(mp->list, height, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, color, scoreVis, FALSE, FALSE); } else if (mp->ct != NULL) { /* use or scored refs from maf table*/ drawScoreOverviewCT(mp->ct->dbTableName, height, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, color, scoreVis); yOff++; } else { /* use or scored refs from maf table*/ drawScoreOverview(track->table, height, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, color, scoreVis); yOff++; } yOff += height; } else { Color wigColor = 0; while (wigTrack != NULL) { /* draw conservation wiggles */ if (!wigColor) wigColor = hvGfxFindRgb(hvg, &wigTrack->color); else wigColor = slightlyLighterColor(hvg, wigColor); wigTrack->ixColor = wigColor; wigTrack->ixAltColor = hvGfxFindRgb(hvg, &wigTrack->altColor); hvGfxSetClip(hvg, xOff, yOff, width, wigTotalHeight(wigTrack, scoreVis) - 1); wigTrack->drawItems(wigTrack, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, scoreVis); hvGfxUnclip(hvg); yOff += wigTotalHeight(wigTrack, scoreVis); wigTrack = wigTrack->next; } } return yOff; } static void wigMafDraw(struct track *track, int seqStart, int seqEnd, struct hvGfx *hvg, int xOff, int yOff, int width, MgFont *font, Color color, enum trackVisibility vis) /* Draw routine for wigmaf type tracks */ { int y = yOff; y = wigMafDrawScoreGraph(track, seqStart, seqEnd, hvg, xOff, y, width, font, color, vis); if (vis == tvFull || vis == tvPack) { if (zoomedToBaseLevel) { struct wigMafItem *wiList = track->items; /* skip over cons wiggles */ struct track *wigTrack = track->subtracks; while (wigTrack) { wiList = wiList->next; wigTrack = wigTrack->next; } y = wigMafDrawBases(track, seqStart, seqEnd, hvg, xOff, y, width, font, color, vis, wiList); //MG_RED, vis, wiList); } else wigMafDrawPairwise(track, seqStart, seqEnd, hvg, xOff, y, width, font, color, vis); } mapBoxHc(hvg, seqStart, seqEnd, xOff, yOff, width, track->height, track->track, track->track, NULL); } void wigMafMethods(struct track *track, struct trackDb *tdb, int wordCount, char *words[]) /* Make track for maf multiple alignment. */ { struct track *wigTrack; int i; struct dyString *wigType; struct consWiggle *consWig, *consWigList = NULL; track->loadItems = wigMafLoad; track->freeItems = wigMafFree; track->drawItems = wigMafDraw; track->itemName = wigMafItemName; track->mapItemName = wigMafItemName; track->totalHeight = wigMafTotalHeight; track->itemHeight = wigMafItemHeight; track->itemStart = tgItemNoStart; track->itemEnd = tgItemNoEnd; track->itemLabelColor = wigMafItemLabelColor; track->mapsSelf = TRUE; //track->canPack = TRUE; /* deal with conservation wiggle(s) */ consWigList = wigMafWiggles(database, tdb); if (consWigList == NULL) return; /* determine which conservation wiggles to use -- from cart, or if none there, use first entry in trackDb setting */ boolean first = TRUE; for (consWig = consWigList; consWig != NULL; consWig = consWig->next) { if (differentString(consWig->leftLabel, DEFAULT_CONS_LABEL)) { char *wigVarSuffix = NULL; (void)wigMafWiggleVar(tdb->track, consWig,&wigVarSuffix); if (!cartUsualBooleanClosestToHome(cart, tdb, FALSE, wigVarSuffix, first)) continue; } first = FALSE; // Manufacture and initialize wiggle subtrack, both tdb and track struct trackDb *wigTdb = CloneVar(tdb); wigType = newDyString(64); dyStringPrintf(wigType, "type wig "); for (i = 1; i < wordCount; i++) dyStringPrintf(wigType, "%s ", words[i]); wigTdb->type = cloneString(wigType->string); wigTdb->track = consWig->table; wigTdb->table= consWig->table; /* Tweak wiggle left labels: replace underscore with space and * append 'Cons' */ struct dyString *ds = dyStringNew(0); dyStringAppend(ds, consWig->leftLabel); if (differentString(consWig->leftLabel, DEFAULT_CONS_LABEL)) dyStringAppend(ds, " Cons"); wigTdb->shortLabel = dyStringCannibalize(&ds); subChar(wigTdb->shortLabel, '_', ' '); wigTrack = trackFromTrackDb(wigTdb); /* setup wiggle methods in subtrack */ wigMethods(wigTrack, tdb, wordCount, words); wigTrack->mapsSelf = FALSE; wigTrack->drawLeftLabels = NULL; wigTrack->next = NULL; slAddTail(&track->subtracks, wigTrack); dyStringFree(&wigType); } }