9007158bac3746b1eb7f76513c8e8631e1ca1ca2 braney Fri Mar 21 13:18:22 2025 -0700 add decipher SQL tracks to quickLift support diff --git src/hg/hgTracks/simpleTracks.c src/hg/hgTracks/simpleTracks.c index 66c014c0027..79b4b07e6df 100644 --- src/hg/hgTracks/simpleTracks.c +++ src/hg/hgTracks/simpleTracks.c @@ -5995,54 +5995,81 @@ } #endif /* GBROWSE */ // The following few functions are shared by GAD, OMIM, DECIPHER, Superfamily. // Those tracks need an extra label derived from item name -- the extra label // is used as mouseover text for each item, and appears to the immediate left // of the feature in full mode. struct bedPlusLabel { struct bed bed; // inline, so struct bedPlusLabel * can be cast to struct bed *. char *label; }; -typedef char *labelFromNameFunction(char *name); +typedef char *labelFromNameFunction(char *db, char *name); static void bedPlusLabelLoad(struct track *tg, labelFromNameFunction func) /* Load items from a bed table; if vis is pack or full, add extra label derived from item name. */ +{ +char *liftDb = cloneString(trackDbSetting(tg->tdb, "quickLiftDb")); + +if (liftDb == NULL) { struct bedPlusLabel *itemList = NULL; struct sqlConnection *conn = hAllocConn(database); int rowOffset = 0; struct sqlResult *sr = hRangeQuery(conn, tg->table, chromName, winStart, winEnd, NULL, &rowOffset); char **row = NULL; while ((row = sqlNextRow(sr)) != NULL) { struct bed *bed = bedLoad(row+rowOffset); struct bedPlusLabel *item = needMoreMem(bed, sizeof(struct bed), sizeof(struct bedPlusLabel)); if (tg->visibility == tvPack || tg->visibility == tvFull) - item->label = cloneString(func(item->bed.name)); + item->label = cloneString(func(database, item->bed.name)); slAddHead(&itemList, item); } sqlFreeResult(&sr); hFreeConn(&conn); slReverse(&itemList); slSort(&itemList, bedCmp); tg->items = itemList; } +else + { + /* if we're quicklifting get normal beds then add label */ + loadSimpleBedWithLoader(tg, bedLoad); + struct bed *beds = tg->items; + struct bedPlusLabel *bedLabels = NULL; + + struct bed *nextBed; + for(; beds; beds = nextBed) + { + nextBed = beds->next; + + struct bedPlusLabel *bedLabel; + AllocVar(bedLabel); + + bedLabel->bed = *beds; + bedLabel->label = cloneString(func(liftDb, bedLabel->bed.name)); + slAddHead(&bedLabels, bedLabel); + } + slSort(&bedLabels, bedCmp); + tg->items = bedLabels; + } +} void bedPlusLabelDrawAt(struct track *tg, void *item, struct hvGfx *hvg, int xOff, int y, double scale, MgFont *font, Color color, enum trackVisibility vis) /* Draw a single bed item at position. If vis is full, draw the associated label to the left * of the item. */ { struct bedPlusLabel *bpl = item; struct bed *bed = item; int heightPer = tg->heightPer; int s = max(bed->chromStart, winStart), e = min(bed->chromEnd, winEnd); if (s > e) return; int x1 = round((s-winStart)*scale) + xOff; int x2 = round((e-winStart)*scale) + xOff; int w = x2 - x1; @@ -6064,39 +6091,39 @@ static void bedPlusLabelMapItem(struct track *tg, struct hvGfx *hvg, void *item, char *itemName, char *mapItemName, int start, int end, int x, int y, int width, int height) /* Special mouseover text from item->label. (derived from genericMapItem) */ { // Don't bother if we are imageV2 and a dense child. if(!theImgBox || tg->limitedVis != tvDense || !tdbIsCompositeChild(tg->tdb)) { struct bedPlusLabel *bpl = item;; char *mouseOverText = isEmpty(bpl->label) ? bpl->bed.name : bpl->label; mapBoxHc(hvg, start, end, x, y, width, height, tg->track, mapItemName, mouseOverText); } } -static char *collapseRowsFromQuery(char *query, char *sep, int limit) +static char *collapseRowsFromQuery(char *db, char *query, char *sep, int limit) /* Return a string that is the concatenation of (up to limit) row[0]'s returned from query, * separated by sep. Don't free the return value! */ { static struct dyString *dy = NULL; if (dy == NULL) dy = dyStringNew(0); dyStringClear(dy); -struct sqlConnection *conn = hAllocConn(database); +struct sqlConnection *conn = hAllocConn(db); struct sqlResult *sr = sqlMustGetResult(conn, query); int i = 0; char **row = NULL; while ((row = sqlNextRow(sr)) != NULL) { eraseTrailingSpaces(row[0]); if (i != 0) dyStringAppend(dy, sep); dyStringAppend(dy, row[0]); if (i == limit) { dyStringAppend(dy, " ..."); break; } i++; @@ -7182,138 +7209,140 @@ } else { proteinName = cloneString(""); } } } } name = cloneString(proteinName); hFreeConn(&conn); return(name); } -static char *superfamilyNameLong(char *name) +static char *superfamilyNameLong(char *db, char *name) /* Return domain names of an entry of a Superfamily track item, each item may have multiple names due to possibility of multiple domains. */ { char query[256]; sqlSafef(query, sizeof(query), "select description from sfDescription where name='%s';", name); -return collapseRowsFromQuery(query, "; ", 100); +return collapseRowsFromQuery(db, query, "; ", 100); } static void superfamilyLoad(struct track *tg) /* Load superfamily items; in addition to items, store long description for mouseover/full mode. */ { bedPlusLabelLoad(tg, superfamilyNameLong); } void superfamilyMethods(struct track *tg) /* Fill in methods for (simple) bed tracks. */ { tg->loadItems = superfamilyLoad; tg->drawItemAt = bedPlusLabelDrawAt; tg->mapItem = bedPlusLabelMapItem; tg->itemName = superfamilyName; tg->mapItemName = superfamilyName; tg->nextPrevExon = simpleBedNextPrevEdge; } -static char *gadDiseaseClassList(char *name) +static char *gadDiseaseClassList(char *db, char *name) /* Return list of diseases associated with a GAD entry */ { char query[256]; sqlSafef(query, sizeof(query), "select distinct diseaseClassCode from gadAll " "where geneSymbol='%s' and association = 'Y' order by diseaseClassCode", name); -return collapseRowsFromQuery(query, ",", 20); +return collapseRowsFromQuery(db, query, ",", 20); } -static char *gadDiseaseList(char *name) +static char *gadDiseaseList(char *db, char *name) /* Return list of diseases associated with a GAD entry */ { char query[256]; sqlSafef(query, sizeof(query), "select distinct broadPhen from gadAll where geneSymbol='%s' and association = 'Y' " "order by broadPhen", name); -return collapseRowsFromQuery(query, "; ", 20); +return collapseRowsFromQuery(db, query, "; ", 20); } static void gadLoad(struct track *tg) /* Load GAD items as bed + label (used for mouseover; different label in draw routine!) */ { bedPlusLabelLoad(tg, gadDiseaseList); } static void gadDrawAt(struct track *tg, void *item, struct hvGfx *hvg, int xOff, int y, double scale, MgFont *font, Color color, enum trackVisibility vis) /* Draw a single GAD item at position with extra label in full mode. * This is almost identical to bedPlusLabelDrawAt, but uses yet another function * to derive extra text in full mode. */ { struct bed *bed = item; int heightPer = tg->heightPer; int x1 = round((double)((int)bed->chromStart-winStart)*scale) + xOff; int x2 = round((double)((int)bed->chromEnd-winStart)*scale) + xOff; int w; w = x2-x1; if (w < 1) w = 1; hvGfxBox(hvg, x1, y, w, heightPer, color); if (vis == tvFull) { // New text for label in full mode: - char *sDiseaseClasses = gadDiseaseClassList(bed->name); + char *liftDb = cloneString(trackDbSetting(tg->tdb, "quickLiftDb")); + char *db = (liftDb == NULL) ? database : liftDb; + char *sDiseaseClasses = gadDiseaseClassList(db, bed->name); int textWidth = mgFontStringWidth(font, sDiseaseClasses); hvGfxTextRight(hvg, x1-textWidth-2, y, textWidth, heightPer, MG_BLACK, font, sDiseaseClasses); } } -static char *decipherCnvsPhenotypeList(char *name) +static char *decipherCnvsPhenotypeList(char *db, char *name) /* Return list of diseases associated with a DECIPHER CNVs entry */ { char query[256]; static char list[4096]; struct sqlConnection *conn = hAllocConn(database); if (sqlFieldIndex(conn, "decipherRaw", "phenotypes") >= 0) { list[0] = '\0'; sqlSafef(query, sizeof(query), "select phenotypes from decipherRaw where id='%s'", name); struct sqlResult *sr = sqlMustGetResult(conn, query); char **row = sqlNextRow(sr); if ((row != NULL) && strlen(row[0]) >= 1) { char *prettyResult = replaceChars(row[0], "|", "; "); safecpy(list, sizeof(list), prettyResult); // freeMem(prettyResult); } sqlFreeResult(&sr); } else { sqlSafef(query, sizeof(query), "select distinct phenotype from decipherRaw where id='%s' order by phenotype", name); hFreeConn(&conn); - return collapseRowsFromQuery(query, "; ", 20); + return collapseRowsFromQuery(db, query, "; ", 20); } hFreeConn(&conn); return list; } void decipherCnvsLoad(struct track *tg) /* Load DECIPHER CNVs items with extra labels from decipherPhenotypeList. */ { bedPlusLabelLoad(tg, decipherCnvsPhenotypeList); } Color decipherCnvsColor(struct track *tg, void *item, struct hvGfx *hvg) /* Return color to draw DECIPHER CNVs entry */ { struct bed *bed = item; @@ -7356,97 +7385,101 @@ { col = MG_BLUE; } else { col = MG_RED; } } sqlFreeResult(&sr); } } hFreeConn(&conn); return(col); } -static char *decipherSnvsPhenotypeList(char *name) +static char *decipherSnvsPhenotypeList(char *db, char *name) /* Return list of diseases associated with a DECIPHER SNVs entry */ { char query[256]; static char list[4096]; -struct sqlConnection *conn = hAllocConn(database); +struct sqlConnection *conn = hAllocConn(db); if (sqlFieldIndex(conn, "decipherSnvsRaw", "phenotypes") >= 0) { list[0] = '\0'; sqlSafef(query, sizeof(query), "select phenotypes from decipherSnvsRaw where id='%s'", name); struct sqlResult *sr = sqlMustGetResult(conn, query); char **row = sqlNextRow(sr); if ((row != NULL) && strlen(row[0]) >= 1) { char *prettyResult = replaceChars(row[0], "|", "; "); safecpy(list, sizeof(list), prettyResult); // freeMem(prettyResult); } sqlFreeResult(&sr); } else { sqlSafef(query, sizeof(query), "select distinct phenotype from decipherSnvsRaw where id='%s' order by phenotype", name); hFreeConn(&conn); - return collapseRowsFromQuery(query, "; ", 20); + return collapseRowsFromQuery(db, query, "; ", 20); } hFreeConn(&conn); return list; } void decipherSnvsLoad(struct track *tg) /* Load DECIPHER SNVs items with extra labels from decipherSnvsPhenotypeList. */ { bedPlusLabelLoad(tg, decipherSnvsPhenotypeList); } Color decipherSnvsColor(struct track *tg, void *item, struct hvGfx *hvg) /* Return color to draw DECIPHER SNV entry */ { struct bed *bed = item; int col = tg->ixColor; -struct sqlConnection *conn = hAllocConn(database); +char *db = database; +char *liftDb = cloneString(trackDbSetting(tg->tdb, "quickLiftDb")); +if (liftDb != NULL) + db = liftDb; +struct sqlConnection *conn = hAllocConn(db); struct sqlResult *sr; char **row; char query[256]; char cond_str[256]; char *decipherId = NULL; /* So far, we can just remove "chr" from UCSC chrom names to get DECIPHER names */ char *decipherChrom = bed->chrom; if (startsWithNoCase("chr", bed->chrom)) decipherChrom += 3; /* color scheme: BLACK: If the entry is likely or definitely pathogenic DARK GRAY: If the entry is uncertain or unknown LIGHT GRAY: If the entry is likely or definitely benign */ sqlSafef(cond_str, sizeof(cond_str),"name='%s' ", bed->name); -decipherId = sqlGetField(database, "decipherSnvs", "name", cond_str); +decipherId = sqlGetField(db, "decipherSnvs", "name", cond_str); if (decipherId != NULL) { - if (hTableExists(database, "decipherSnvsRaw")) + if (hTableExists(db, "decipherSnvsRaw")) { sqlSafef(query, sizeof(query), "select pathogenicity from decipherSnvsRaw where " "id = '%s' and chr = '%s' and start = '%d' and end = '%d'", decipherId, decipherChrom, bed->chromStart+1, bed->chromEnd); sr = sqlGetResult(conn, query); col = MG_GRAY; if ((row = sqlNextRow(sr)) != NULL) { char *ucPathogenicity = cloneString(row[0]); strUpper(ucPathogenicity); if (endsWith(ucPathogenicity, "PATHOGENIC")) { col = MG_BLACK; } else if (endsWith(ucPathogenicity, "BENIGN")) @@ -13290,31 +13323,31 @@ else if (sameString(mode, "X-linked dominant")) dyStringAppend(dy, "XLD"); else if (sameString(mode, "X-linked recessive")) dyStringAppend(dy, "XLR"); else if (sameString(mode, "Y-linked")) dyStringAppend(dy, "YL"); else if (!isEmpty(mode)) dyStringAppend(dy, mode); if (modes->next) dyStringAppend(dy, "/"); } return dy->string; } -static char *omimGene2DisorderList(char *name) +static char *omimGene2DisorderList(char *db, char *name) /* Return list of disorders associated with a OMIM entry. Do not free result! */ { static struct dyString *dy = NULL; struct sqlConnection *conn; char query[4096]; if (dy == NULL) dy = dyStringNew(0); dyStringClear(dy); // get gene symbol(s) first conn = hAllocConn(database); sqlSafef(query,sizeof(query), "select geneSymbol from omimGeneMap2 where omimId =%s", name); char buf[4096]; @@ -13699,31 +13732,31 @@ geneSymbol = sqlQuickString(conn, query); if (geneSymbol && differentString(geneSymbol, "0")) { // pick the first one, if multiple gene symbols exist chp = strstr(geneSymbol, ","); if (chp != NULL) *chp = '\0'; dyStringAppend(name, geneSymbol); } } } hFreeConn(&conn); return(name->string); } -static char *cosmicTissueList(char *name) +static char *cosmicTissueList(char *db, char *name) /* Return list of tumor tissues associated with a COSMIC entry. Do not free result! */ { static struct dyString *dy = NULL; struct sqlConnection *conn = hAllocConn(database); if (dy == NULL) dy = dyStringNew(0); dyStringClear(dy); char query[256]; sqlSafef(query,sizeof(query), "select concat(gene_name,' ',mut_syntax_aa) from cosmicRaw where cosmic_mutation_id ='%s'", name); char buf[256]; char *ret = sqlQuickQuery(conn, query, buf, sizeof(buf)); @@ -13762,31 +13795,31 @@ if ((chp != NULL) && (strlen(chp) > 3)) { chp++; chp++; chp++; chp++; *chp = '\0'; } dyStringAppend(dy, " ("); dyStringAppend(dy, ret); dyStringAppend(dy, "\%)"); } sqlSafef(query,sizeof(query), "select tumour_site from cosmicRaw where cosmic_mutation_id ='%s' order by tumour_site", name); -char *disorders = collapseRowsFromQuery(query, ",", 4); +char *disorders = collapseRowsFromQuery(db, query, ",", 4); if (isNotEmpty(disorders)) { dyStringAppend(dy, " "); dyStringAppend(dy, disorders); } hFreeConn(&conn); return(dy->string); } static void cosmicLoad(struct track *tg) /* Load COSMIC items, storing long label from cosmicTissueList */ { bedPlusLabelLoad(tg, cosmicTissueList); } @@ -13799,31 +13832,31 @@ tg->nextPrevExon = simpleBedNextPrevEdge; } void omimGene2Methods (struct track *tg) /* Methods for version 2 of OMIM Genes track. */ { tg->loadItems = omimGene2Load; tg->itemColor = omimGene2Color; tg->itemName = omimGene2Name; tg->itemNameColor = omimGene2Color; tg->drawItemAt = bedPlusLabelDrawAt; tg->mapItem = bedPlusLabelMapItem; tg->nextPrevExon = simpleBedNextPrevEdge; } -static char *omimAvSnpAaReplacement(char *name) +static char *omimAvSnpAaReplacement(char *db, char *name) /* Return replacement string associated with a OMIM AV (Allelic Variant) entry */ { static char omimAvSnpBuffer[256]; struct sqlConnection *conn; char query[256]; struct sqlResult *sr; char **row; omimAvSnpBuffer[0] = '\0'; conn = hAllocConn(database); sqlSafef(query,sizeof(query), "select repl2, dbSnpId, description from omimAv where avId='%s'", name); sr = sqlMustGetResult(conn, query); row = sqlNextRow(sr); @@ -13842,31 +13875,31 @@ /* Load OMIM AV items, storing long label from omimAvSnpAaReplacement. */ { bedPlusLabelLoad(tg, omimAvSnpAaReplacement); } void omimAvSnpMethods (struct track *tg) /* Methods for OMIM AV (Allelic Variant) SNPs. */ { tg->loadItems = omimAvSnpLoad; tg->drawItemAt = bedPlusLabelDrawAt; tg->mapItem = bedPlusLabelMapItem; tg->nextPrevExon = simpleBedNextPrevEdge; } -static char *omimLocationDescription(char *name) +static char *omimLocationDescription(char *db, char *name) /* Return description of an OMIM entry */ { static char omimLocationBuffer[512]; struct sqlConnection *conn; char query[256]; omimLocationBuffer[0] = '\0'; conn = hAllocConn(database); sqlSafef(query,sizeof(query), "select geneName from omimGeneMap2 where omimId=%s", name); (void)sqlQuickQuery(conn, query, omimLocationBuffer, sizeof(omimLocationBuffer)); hFreeConn(&conn); return(omimLocationBuffer); } @@ -14066,38 +14099,38 @@ /* set the color to red if the entry is listed in morbidmap */ sqlSafef(query, sizeof(query), "select geneSymbols from omimMorbidMap where omimId=%s", el->name); geneSymbols = sqlQuickString(conn, query); hFreeConn(&conn); if (geneSymbols != NULL) { return hvGfxFindColorIx(hvg, 255, 0, 0); } else { return hvGfxFindColorIx(hvg, 0, 0, 200); } } -static char *omimGeneDiseaseList(char *name) +static char *omimGeneDiseaseList(char *db, char *name) /* Return list of diseases associated with a OMIM entry */ { char query[256]; sqlSafef(query,sizeof(query), "select distinct description from omimMorbidMap, omimGene " "where name='%s' and name=cast(omimId as char) order by description", name); -return collapseRowsFromQuery(query, "; ", 20); +return collapseRowsFromQuery(db, query, "; ", 20); } static void omimGeneLoad(struct track *tg) /* Load OMIM Genes, storing long label from omimGeneDiseaseList. */ { bedPlusLabelLoad(tg, omimGeneDiseaseList); } void omimGeneMethods (struct track *tg) /* Methods for original OMIM Genes track. */ { tg->loadItems = omimGeneLoad; tg->itemColor = omimGeneColor; tg->itemNameColor = omimGeneColor; tg->itemName = omimGeneName;