44ccfacbe3a3d4b300f80d48651c77837a4b571e galt Tue Apr 26 11:12:02 2022 -0700 SQL INJECTION Prevention Version 2 - this improves our methods by making subclauses of SQL that get passed around be both easy and correct to use. The way that was achieved was by getting rid of the obscure and not well used functions sqlSafefFrag and sqlDyStringPrintfFrag and replacing them with the plain versions of those functions, since these are not needed anymore. The new version checks for NOSQLINJ in unquoted %-s which is used to include SQL clauses, and will give an error the NOSQLINJ clause is not present, and this will automatically require the correct behavior by developers. sqlDyStringPrint is a very useful function, however because it was not enforced, users could use various other dyString functions and they operated without any awareness or checking for SQL correct use. Now those dyString functions are prohibited and it will produce an error if you try to use a dyString function on a SQL string, which is simply detected by the presence of the NOSQLINJ prefix. diff --git src/hg/hgTracks/wigMafTrack.c src/hg/hgTracks/wigMafTrack.c index f426b04..23eb470 100644 --- src/hg/hgTracks/wigMafTrack.c +++ src/hg/hgTracks/wigMafTrack.c @@ -1,2789 +1,2789 @@ /* wigMafTrack - display multiple alignment files with score wiggle * and base-level alignment, or else density plot of pairwise alignments * (zoomed out) */ /* Copyright (C) 2014 The Regents of the University of California * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */ #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 "hCommon.h" #include "hgMaf.h" #include "mafTrack.h" #include "customTrack.h" #include "mafSummary.h" #include "mafFrames.h" #include "phyloTree.h" #include "soTerm.h" #include "bigBed.h" #include "hubConnect.h" #include "chromAlias.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, struct hash *labelHash) /* Allocate and initialize a maf item. Species param can be a db or name */ { struct wigMafItem *mi; char *val; AllocVar(mi); if (labelHash) { mi->db = cloneString(hubConnectSkipHubPrefix(s)); mi->name = hashFindVal(labelHash, mi->db); } if (mi->name == NULL) { if ((val = hGenome(s)) != NULL) { /* it's a database name */ mi->db = cloneString(hubConnectSkipHubPrefix(s)); mi->name = val; } else { mi->db = cloneString(s); mi->name = cloneString(s); } } mi->name = hgDirForOrg(mi->name); if (lowerFirstChar && labelHash == NULL ) *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 */ { char *species[MAX_SP_SIZE]; char *groups[20]; char *defaultOff[MAX_SP_SIZE]; char sGroup[MAX_SP_SIZE]; int group; int i; int speciesCt = 0, groupCt = 1; int speciesOffCt = 0; struct hash *speciesOffHash = newHash(0); char *speciesUseFile = trackDbSetting(track->tdb, SPECIES_USE_FILE); /* 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); struct hash *labelHash = mafGetLabelHash(track->tdb); bool lowerFirstChar = TRUE; char *firstCase; firstCase = trackDbSetting(track->tdb, ITEM_FIRST_CHAR_CASE); if (firstCase != NULL) { if (sameWord(firstCase, "noChange")) lowerFirstChar = FALSE; } if (speciesOrder == NULL && speciesGroup == NULL && speciesUseFile == NULL && labelHash == 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"); 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); } /* Make up items for other organisms by scanning through group & species track settings */ struct wigMafItem *mi = NULL, *miList = NULL; 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); } speciesCt = chopLine(cloneString(speciesOrder), species); for (i = 0; i < speciesCt; i++) { boolean defaultOn = (hashLookup(speciesOffHash, species[i]) == NULL); if (cartUsualBooleanClosestToHome(cart, track->tdb, FALSE, species[i],defaultOn)) { mi = newMafItem(species[i], group, lowerFirstChar, labelHash); mi->height = height; slAddHead(&miList, mi); } } } 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 (inSummaryMode(cart, track->tdb, winBaseCount)) return; int begin = winStart - 2; if (begin < 0) begin = 0; if (track->isBigBed) { struct bbiFile *bbi = fetchBbiForTrack(track); mp->list = bigMafLoadInRegion(bbi, chromName, begin, winEnd+2); bbiFileClose(&bbi); track->bbiFile = NULL; } else if (mp->ct) { /* 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). */ char *fileName = getCustomMafFile(track); conn = hAllocConn(CUSTOM_TRASH); conn2 = hAllocConn(CUSTOM_TRASH); mp->list = wigMafLoadInRegion(conn, conn2, mp->ct->dbTableName, chromName, begin, 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, begin, 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; } struct hash *labelHash = mafGetLabelHash(track->tdb); 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, labelHash); 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 !inSummaryMode(cart, track->tdb, winBaseCount) || 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; char *snpTable = trackDbSetting(track->tdb, "snpTable"); boolean doSnpTable = FALSE; if ( (track->limitedVis == tvPack) && (snpTable != NULL) && cartOrTdbBoolean(cart, track->tdb, MAF_SHOW_SNP,FALSE)) doSnpTable = TRUE; // the maf's only get loaded if we're not in summary or snpTable views if (!doSnpTable && !inSummaryMode(cart, track->tdb, winBaseCount)) { /* "close in" display uses actual alignments from file */ struct mafPriv *mp = getMafPriv(track); struct sqlConnection *conn, *conn2; if (track->isBigBed) { struct bbiFile *bbi = fetchBbiForTrack(track); mp->list = bigMafLoadInRegion(fetchBbiForTrack(track), chromName, winStart, winEnd); bbiFileClose(&bbi); track->bbiFile = NULL; } else 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 (inSummaryMode(cart, track->tdb, winBaseCount) && isCustomTrack(track->table)) track->limitedVis = tvDense; /* Load up mafs and store in track so drawer doesn't have * to do it again. */ char *defaultOn = trackDbSetting(track->tdb, "speciesDefaultOn"); char *defaultMaf = trackDbSetting(track->tdb, "defaultMaf"); // check to see if all species that are on are in defaultMaf if (defaultOn && defaultMaf && hTableExists(database, defaultMaf)) { struct wigMafItem *speciesList = newSpeciesItems(track, tl.fontHeight), *wmi; struct slName *defaultNames = slNameListFromString(defaultOn, ' '); boolean allOnInDefault = TRUE; for(wmi = speciesList; wmi; wmi = wmi->next) { if (!slNameInList(defaultNames, wmi->db)) allOnInDefault = FALSE; } if (allOnInDefault) track->table = defaultMaf; } /* 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 (!inSummaryMode(cart, track->tdb, winBaseCount)) 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 (!inSummaryMode(cart, track->tdb, winBaseCount)) #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 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 hubConnectSkipHubPrefix(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 drawScoreOverviewBig( struct track *track, 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. */ { struct lm *lm = lmInit(0); char *fileName = trackDbSetting(track->tdb, "summary"); if (fileName == NULL) { warn("cannot find summary information in trackDb for track '%s'", track->track); return; } struct bbiFile *bbi = bigBedFileOpenAlias(fileName, chromAliasFindAliases); struct bigBedInterval *bb, *bbList = bigBedIntervalQuery(bbi, chromName, seqStart, seqEnd, 0, lm); char *bedRow[7]; char startBuf[16], endBuf[16]; double scale = scaleForPixels(width); for (bb = bbList; bb != NULL; bb = bb->next) { bigBedIntervalToRow(bb, chromName, startBuf, endBuf, bedRow, ArraySize(bedRow)); struct mafSummary *ms; ms = mafSummaryLoad(bedRow); drawScore(ms->score, ms->chromStart, ms->chromEnd, seqStart, scale, hvg, xOff, yOff, height, color, vis); } } 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 drawPairsFromSnpTable(struct track *track, char *snpTable, int seqStart, int seqEnd, struct hvGfx *hvg, int xOff, int yOff, int width, MgFont *font, Color color, enum trackVisibility vis) /* use trackDb variable "snpTable" bed to draw this mode */ { struct wigMafItem *miList = track->items, *mi = miList; struct sqlConnection *conn; struct sqlResult *sr = NULL; char **row = NULL; int rowOffset = 0; struct hash *componentHash = newHash(6); struct hashEl *hel; struct dyString *where = dyStringNew(256); char *whereClause = NULL; if (miList == NULL) return FALSE; if (snpTable == NULL) return FALSE; /* Create SQL where clause that will load up just the * beds for the species that we are including. */ conn = hAllocConn(database); dyStringAppend(where, "name 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,"name in ()")) whereClause = where->string; sr = hOrderedRangeQuery(conn, snpTable, chromName, seqStart, seqEnd, whereClause, &rowOffset); /* Loop through result creating a hash of lists of beds . * The hash is keyed by species. */ while ((row = sqlNextRow(sr)) != NULL) { struct bed *bed = bedLoadN(&row[1], 5); /* prune to fit in window bounds */ if (bed->chromStart < seqStart) bed->chromStart = seqStart; if (bed->chromEnd > seqEnd) bed->chromEnd = seqEnd; if ((hel = hashLookup(componentHash, bed->name)) == NULL) hashAdd(componentHash, bed->name, bed); else slAddHead(&(hel->val), bed); } sqlFreeResult(&sr); hFreeConn(&conn); /* display pairwise items */ Color yellow = hvGfxFindRgb(hvg, &undefinedYellowColor); for (mi = miList; mi != NULL; mi = mi->next) { if (mi->ix < 0) /* ignore item for the score */ continue; struct bed *bedList = (struct bed *)hashFindVal(componentHash, mi->db); if (bedList == NULL) bedList = (struct bed *)hashFindVal(componentHash, mi->name); if (bedList != NULL) { hvGfxSetClip(hvg, xOff, yOff, width, mi->height); struct bed *bed = bedList; double scale = scaleForPixels(width); for(; bed; bed = bed->next) { int x1 = round((bed->chromStart - seqStart)*scale); int x2 = round((bed->chromEnd - seqStart)*scale); int w = x2-x1+1; int height1 = mi->height-1; int color = MG_BLACK; switch(bed->score) { case 222: // place holder for heterozygous nonsynonymous color = 0xff000000; break; case 111: // place holder for heterozygous synonymous color = 0xffd0e040; break; case 0: color = yellow; break; case _5_prime_UTR_variant: case _3_prime_UTR_variant: case coding_sequence_variant: case intron_variant: case intergenic_variant: color = MG_BLUE; break; case synonymous_variant: color = MG_GREEN; break; case missense_variant: color = MG_RED; break; // non-syn BLOSUM62 > 1 case 1579: color = 0xffe0e0ff; break; // non-syn BLOSUM62 > -1 but less than 1 case 1581: color = 0xffb0b0ff; break; } hvGfxBox(hvg, x1 + xOff, yOff, w, height1, color); } hvGfxUnclip(hvg); } yOff += mi->height; } return TRUE; } 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; if (miList == NULL) return FALSE; /* 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; } if (track->isBigBed) { struct lm *lm = lmInit(0); char *fileName = trackDbSetting(track->tdb, "summary"); struct bbiFile *bbi = bigBedFileOpenAlias(fileName, chromAliasFindAliases); struct bigBedInterval *bb, *bbList = bigBedIntervalQuery(bbi, chromName, seqStart, seqEnd, 0, lm); char *bedRow[7]; char startBuf[16], endBuf[16]; for (bb = bbList; bb != NULL; bb = bb->next) { bigBedIntervalToRow(bb, chromName, startBuf, endBuf, bedRow, ArraySize(bedRow)); ms = mafSummaryLoad(bedRow); if ((hel = hashLookup(componentHash, ms->src)) == NULL) hashAdd(componentHash, ms->src, ms); else slAddHead(&(hel->val), ms); } bbiFileClose(&bbi); } else { /* 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 ("); + sqlDyStringPrintf(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); + sqlDyStringPrintf(where, "'%s'", mi->db); if (mi->next != NULL) - dyStringAppend(where, ","); + sqlDyStringPrintf(where, ","); } - dyStringAppend(where, ")"); + sqlDyStringPrintf(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); if (!track->isBigBed) 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) { // sometimes the summary table has the other database without a dot even if it has one char *tryNoDot = cloneString(mi->db); char *dot = strchr(tryNoDot, '.'); if (dot != NULL) { *dot = 0; summaryList = (struct mafSummary *)hashFindVal(componentHash, tryNoDot); } } 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; boolean doSnpMode = (vis == tvPack) &&(trackDbSetting(track->tdb, "snpMode") != NULL); 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; } 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, hubConnectSkipHubPrefix(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, doSnpMode); 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 (inSummaryMode(cart, track->tdb, winBaseCount) && summarySetting(track)) return drawPairsFromSummary(track, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, vis); char *snpTable = trackDbSetting(track->tdb, "snpTable"); if ( (track->limitedVis == tvPack) && (snpTable != NULL)) return drawPairsFromSnpTable(track, snpTable, 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; } struct sqlClosure { char *mafFile; struct sqlConnection *conn2; struct sqlConnection *conn3; char *tableName; }; struct bbClosure { struct bbiFile *bbi; }; typedef struct mafAli * (*mafRetrieveFunc)(void *closure, char *chrom, int start, int end); static struct mafAli *mafLoadFromBb(void *closure, char *chrom, int start, int end) /* Retrieve maf blocks from a bigBed file. */ { struct bbClosure *bbClosure = closure; return bigMafLoadInRegion( bbClosure->bbi, chrom, start, end); } static struct mafAli *mafLoadFromSql(void *closure, char *chrom, int start, int end) /* Retrieve maf blocks from an SQL table. */ { struct sqlClosure *sqlClosure = closure; return mafLoadInRegion2(sqlClosure->conn2, sqlClosure->conn3, sqlClosure->tableName, chrom, start, end, sqlClosure->mafFile ); } static void translateCodons(mafRetrieveFunc func, void *closure, 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) { 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", hubConnectSkipHubPrefix(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 = func(closure, chromName, prevEnd , prevEnd + 1); 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 = func(closure, chromName, prevEnd , prevEnd + 2); if (ali != NULL) sub = mafSubset(ali, masterChrom, prevEnd, prevEnd + 2 ); } else { ali = func(closure, chromName, prevEnd - 1 , prevEnd + 1); 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 = func(closure, chromName, nextStart - 2 + length, nextStart + 1); if (ali != NULL) sub = mafSubset(ali, masterChrom, nextStart - 2 + length, nextStart + 1); } else { ali = func(closure, chromName, nextStart , nextStart + 2); 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 struct mafFrames *getFramesFromSql( char *framesTable, char *chromName, int seqStart, int seqEnd, char *extra, boolean newTableType) { struct mafFrames *mfList = NULL; int rowOffset; struct sqlResult *sr; struct mafFrames *mf; char **row; struct sqlConnection *conn = hAllocConn(database); sr = hRangeQuery(conn, framesTable, chromName, seqStart, seqEnd, extra, &rowOffset); while ((row = sqlNextRow(sr)) != NULL) { if (newTableType) mf = mafFramesLoad(row + rowOffset); else mf = mafFramesLoadOld(row + rowOffset); slAddHead(&mfList, mf); } sqlFreeResult(&sr); hFreeConn(&conn); return mfList; } static struct mafFrames *getFramesFromBb( char *framesTable, char *chromName, int seqStart, int seqEnd, char *component) { struct lm *lm = lmInit(0); struct bbiFile *bbi = bigBedFileOpenAlias(framesTable, chromAliasFindAliases); struct bigBedInterval *bb, *bbList = bigBedIntervalQuery(bbi, chromName, seqStart, seqEnd, 0, lm); char *bedRow[11]; char startBuf[16], endBuf[16]; struct mafFrames *mfList = NULL, *mf; for (bb = bbList; bb != NULL; bb = bb->next) { bigBedIntervalToRow(bb, chromName, startBuf, endBuf, bedRow, ArraySize(bedRow)); if (sameString(bedRow[3], component)) { mf = mafFramesLoad( bedRow ); slAddHead(&mfList, mf); } } bbiFileClose(&bbi); slReverse(&mfList); return mfList; } 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; 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]; 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 mafOrigOffset = 0; struct mafPriv *mp = getMafPriv(track); char *mafFile = NULL; struct sqlConnection *conn2 = NULL; struct sqlConnection *conn3 = NULL; char *tableName = NULL; if (mp->ct != NULL) { conn2 = hAllocConn(CUSTOM_TRASH); conn3 = hAllocConn(CUSTOM_TRASH); tableName = mp->ct->dbTableName; mafFile = getCustomMafFile(track); } else if (!track->isBigBed) { conn2 = hAllocConn(database); conn3 = hAllocConn(database); tableName = track->table; mafFile = getTrackMafFile(track); // optional } 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; } } 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) { if (track->isBigBed) newTableType = TRUE; else 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; } /* 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. */ 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", hubConnectSkipHubPrefix(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); + struct dyString *label = dyStringNew(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); 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)); } if (genomeIsRna) toRna(line); /* draw sequence letters for alignment */ hvGfxSetClip(hvg, x, y-1, width, mi->height); /* having these static here will allow the option 'codonDefault' * to run rapidly through the display without extra calls to SQL * for the same answer over and over. For other codon modes, it * will still need to query the Frames table repeatedly. * This was found to speed up dramatically by adding an index to * the table: * hgsql staAur2 -e 'CREATE INDEX src on multiz369wayFrames (src, bin);' */ static char * extraPrevious = NULL; static struct mafFrames *mfList = NULL, *mf; static boolean found = FALSE; if (framesTable != NULL) { char extra[512]; if (sameString("codonDefault", codonTransMode)) { - safef(extra, sizeof(extra), "src='%s'",defaultCodonSpecies); + sqlSafef(extra, sizeof(extra), "src='%s'",defaultCodonSpecies); found = TRUE; } else if (sameString("codonFrameDef", codonTransMode)) { - safef(extra, sizeof(extra), "src='%s'",mi->db); + sqlSafef(extra, sizeof(extra), "src='%s'",mi->db); found = FALSE; } else if (sameString("codonFrameNone", codonTransMode)) { - safef(extra, sizeof(extra), "src='%s'",mi->db); + sqlSafef(extra, sizeof(extra), "src='%s'",mi->db); found = TRUE; } else errAbort("unknown codon translation mode %s",codonTransMode); tryagain: if (differentStringNullOk(extraPrevious, extra)) { if (track->isBigBed) { char *species = mi->db; if (sameString("codonDefault", codonTransMode)) species = defaultCodonSpecies; mfList = getFramesFromBb( framesTable, chromName, seqStart, seqEnd, species); } else mfList = getFramesFromSql( framesTable, chromName, seqStart, seqEnd, extra, newTableType); } extraPrevious = cloneString(extra); if (mfList != NULL) found = TRUE; for(mf = mfList; mf; mf = mf->next) { int start, end, w; int frame; 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; void *closure; mafRetrieveFunc func; struct sqlClosure sqlClosure; struct bbClosure bbClosure; if (track->isBigBed) { func = mafLoadFromBb; closure = &bbClosure; bbClosure.bbi = fetchBbiForTrack(track); } else { func = mafLoadFromSql; closure = &sqlClosure; sqlClosure.conn2 = conn2; sqlClosure.conn3 = conn3; sqlClosure.mafFile = mafFile; sqlClosure.tableName = tableName; } translateCodons(func, closure, mi->db, line, start, w, frame, mf->strand[0],mf->prevFramePos,mf->nextFramePos, complementBases, x, y, width, mi->height, hvg); } if (!found) { /* try the default species */ - safef(extra, sizeof(extra), "src='%s'",defaultCodonSpecies); + sqlSafef(extra, sizeof(extra), "src='%s'",defaultCodonSpecies); found = TRUE; /* don't try again */ goto tryagain; } } 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) { boolean doSnpMode = (vis == tvPack) &&(trackDbSetting(track->tdb, "snpMode") != 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, doSnpMode); } 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*/ if (differentString(track->tdb->type, "bigMaf")) drawScoreOverview(track->table, height, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, color, scoreVis); else drawScoreOverviewBig(track, 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); + wigType = dyStringNew(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); } }