fbdc691703e4bc2d98fcdb2014fe6fa19771c104 braney Fri Feb 10 17:05:10 2017 -0800 make building a custom track with blat results an option on the hgBlat page. Add some features to bigPsl click support to get the same kind of UI that hgBlat provides. diff --git src/hg/hgBlat/hgBlat.c src/hg/hgBlat/hgBlat.c index fbb2ec7..829dcba 100644 --- src/hg/hgBlat/hgBlat.c +++ src/hg/hgBlat/hgBlat.c @@ -32,31 +32,30 @@ boolean orgChange = FALSE; boolean dbChange = FALSE; struct serverTable /* Information on a server. */ { char *db; /* Database name. */ char *genome; /* Genome name. */ boolean isTrans; /* Is tranlated to protein? */ char *host; /* Name of machine hosting server. */ char *port; /* Port that hosts server. */ char *nibDir; /* Directory of sequence files. */ }; char *typeList[] = {"BLAT's guess", "DNA", "protein", "translated RNA", "translated DNA"}; -char *sortList[] = {"query,score", "query,start", "chrom,score", "chrom,start", "score"}; char *outputList[] = {"hyperlink", "psl", "psl no header"}; #ifdef LOWELAB int minMatchShown = 14; #else int minMatchShown = 20; #endif static struct serverTable *trackHubServerTable(char *db, boolean isTrans) /* Find out if database is a track hub with a blat server */ { char *host, *port; if (!trackHubGetBlatParams(db, isTrans, &host, &port)) return NULL; @@ -203,214 +202,148 @@ ++same; } return same; } boolean allDigits(char *s) /* Return TRUE if s is all digits */ { char c; while ((c = *s++) != 0) if (!isdigit(c)) return FALSE; return TRUE; } -int cmpChrom(char *a, char *b) -/* Compare two chromosomes. */ -{ -return cmpStringsWithEmbeddedNumbers(a, b); -} - -int pslCmpTargetScore(const void *va, const void *vb) -/* Compare to sort based on target then score. */ -{ -const struct psl *a = *((struct psl **)va); -const struct psl *b = *((struct psl **)vb); -int diff = cmpChrom(a->tName, b->tName); -if (diff == 0) - diff = pslScore(b) - pslScore(a); -return diff; -} - -int pslCmpTargetStart(const void *va, const void *vb) -/* Compare to sort based on target start. */ -{ -const struct psl *a = *((struct psl **)va); -const struct psl *b = *((struct psl **)vb); -int diff = cmpChrom(a->tName, b->tName); -if (diff == 0) - diff = a->tStart - b->tStart; -return diff; -} - void printLuckyRedirect(char *browserUrl, struct psl *psl, char *database, char *pslName, char *faName, char *uiState, char *unhideTrack) /* Print out a very short page that redirects us. */ { char url[1024]; safef(url, sizeof(url), "%s?position=%s:%d-%d&db=%s&ss=%s+%s&%s%s", browserUrl, psl->tName, psl->tStart + 1, psl->tEnd, database, pslName, faName, uiState, unhideTrack); /* htmlStart("Redirecting"); */ /* Odd it appears that we've already printed the Content-Typ:text/html line but I can't figure out where... */ htmStart(stdout, "Redirecting"); char javascript[1024]; safef(javascript, sizeof javascript, "location.replace('%s');", url); jsInline(javascript); printf("", url); htmlEnd(); } -static char *replaceSuffix(char *input, char *newSuffix) -/* Given a filename with a suffix, replace existing suffix with a new suffix. */ -{ -char buffer[4096]; -safecpy(buffer, sizeof buffer, input); -char *dot = strrchr(buffer, '.'); -safecpy(dot+1, sizeof buffer - 1 - (dot - buffer), newSuffix); -return cloneString(buffer); -} -static void makeBigPsl(char *pslName, char *faName, char *db, char *outputBigBed) -/* Make a bigPsl with the blat results. */ -{ -char *bigPslFile = replaceSuffix(outputBigBed, "bigPsl"); - -char cmdBuffer[4096]; -safef(cmdBuffer, sizeof(cmdBuffer), "loader/pslToBigPsl %s -fa=%s stdout | sort -k1,1 -k2,2n > %s", pslName, faName, bigPslFile); -system(cmdBuffer); -char buf[4096]; -char *twoBitDir; -if (trackHubDatabase(db)) - { - struct trackHubGenome *genome = trackHubGetGenome(db); - twoBitDir = genome->twoBitPath; - } -else - { - safef(buf, sizeof(buf), "/gbdb/%s", db); - twoBitDir = hReplaceGbdbSeqDir(buf, db); - safef(buf, sizeof(buf), "%s%s.2bit", twoBitDir, db); - twoBitDir = buf; - } - -safef(cmdBuffer, sizeof(cmdBuffer), "loader/bedToBigBed -verbose=0 -udcDir=%s -extraIndex=name -sizesIs2Bit -tab -as=loader/bigPsl.as -type=bed9+16 %s %s %s", - udcDefaultDir(), bigPslFile, twoBitDir, outputBigBed); -system(cmdBuffer); -unlink(bigPslFile); -} +/* forward declaration to reduce churn */ +static void getCustomName(char *database, struct cart *cart, struct psl *psl, char **pName, char **pDescription); void showAliPlaces(char *pslName, char *faName, char *customText, char *database, enum gfType qType, enum gfType tType, char *organism, boolean feelingLucky) /* Show all the places that align. */ { +boolean useBigPsl = cfgOptionBooleanDefault("useBlatBigPsl", FALSE); struct lineFile *lf = pslFileOpen(pslName); struct psl *pslList = NULL, *psl; char *browserUrl = hgTracksName(); char *hgcUrl = hgcName(); char uiState[64]; char *vis; char unhideTrack[64]; -char *sort = cartUsualString(cart, "sort", sortList[0]); +char *sort = cartUsualString(cart, "sort", pslSortList[0]); char *output = cartUsualString(cart, "output", outputList[0]); boolean pslOut = startsWith("psl", output); boolean isStraightNuc = (qType == gftRna || qType == gftDna); int minThreshold = (isStraightNuc ? minMatchShown : 0); sprintf(uiState, "%s=%s", cartSessionVarName(), cartSessionId(cart)); /* If user has hidden BLAT track, add a setting that will unhide the track if user clicks on a browser link. */ vis = cartOptionalString(cart, "hgUserPsl"); if (vis != NULL && sameString(vis, "hide")) snprintf(unhideTrack, sizeof(unhideTrack), "&hgUserPsl=dense"); else unhideTrack[0] = 0; while ((psl = pslNext(lf)) != NULL) { if (psl->match >= minThreshold) slAddHead(&pslList, psl); } lineFileClose(&lf); if (pslList == NULL) { puts("

Sorry, no matches found
"); return; } -if (sameString(sort, "query,start")) - { - slSort(&pslList, pslCmpQuery); - } -else if (sameString(sort, "query,score")) - { - slSort(&pslList, pslCmpQueryScore); - } -else if (sameString(sort, "score")) - { - slSort(&pslList, pslCmpScore); - } -else if (sameString(sort, "chrom,start")) - { - slSort(&pslList, pslCmpTargetStart); - } -else if (sameString(sort, "chrom,score")) - { - slSort(&pslList, pslCmpTargetScore); - } -else - { - slSort(&pslList, pslCmpQueryScore); - } +pslSortListByVar(&pslList, sort); + if(feelingLucky) { /* If we found something jump browser to there. */ if(slCount(pslList) > 0) printLuckyRedirect(browserUrl, pslList, database, pslName, faName, uiState, unhideTrack); /* Otherwise call ourselves again not feeling lucky to print empty results. */ else { cartWebStart(cart, database, "%s BLAT Results", trackHubSkipHubName(organism)); showAliPlaces(pslName, faName, customText, database, qType, tType, organism, FALSE); cartWebEnd(); } } else if (pslOut) { printf("
");
     if (!sameString(output, "psl no header"))
 	pslxWriteHead(stdout, qType, tType);
     for (psl = pslList; psl != NULL; psl = psl->next)
 	pslTabOut(psl, stdout);
     printf("
"); } else { printf("

BLAT Search Results

"); char* posStr = cartOptionalString(cart, "position"); if (posStr != NULL) printf("

Go back to %s on the Genome Browser.

\n", browserUrl, posStr); + if (useBigPsl) + { + char *trackName = NULL; + char *trackDescription = NULL; + getCustomName(database, cart, pslList, &trackName, &trackDescription); + psl = pslList; + printf("", + hgcUrl, psl->tStart, psl->tEnd,cgiEncode(trackName), cgiEncode(trackDescription), pslName, cgiEncode(faName), psl->qName, psl->tName, + psl->tStart, psl->tEnd, database, uiState); + + //printf( + //"
\n"); + printf("

Build a custom track with these results. Track will be called %s ", trackDescription); + //printf("Description: %s\n", trackDescription); + //printf("\n"); + //printf("

"); + } + printf("
");
     printf("   ACTIONS      QUERY           SCORE START  END QSIZE IDENTITY CHRO STRAND  START    END      SPAN\n");
     printf("---------------------------------------------------------------------------------------------------\n");
     for (psl = pslList; psl != NULL; psl = psl->next)
 	{
         if (customText)
             printf("",
                 browserUrl, psl->tName, psl->tStart + 1, psl->tEnd, database, 
                 customText, uiState, unhideTrack);
         else
             printf("",
                 browserUrl, psl->tName, psl->tStart + 1, psl->tEnd, database, 
                 pslName, faName, uiState, unhideTrack);
 	printf("browser ");
 	printf("", 
@@ -605,68 +538,33 @@
 else if (count == 2)
     {
     safef(shortName, sizeof shortName, "blat %s+%d", names->name, count - 1);
     safef(description, sizeof description, "blat on %d queries (%s, %s)", count, names->name, names->next->name);
     }
 else
     {
     safef(shortName, sizeof shortName, "blat %s+%d", names->name, count - 1);
     safef(description, sizeof description, "blat on %d queries (%s, %s, ...)", count, names->name, names->next->name);
     }
 
 *pName = makeNameUnique(shortName, database, cart);
 *pDescription = cloneString(description);
 }
 
-static char *outBigPsl(char *db, struct psl *pslList, char *pslFilename, char *faFilename, boolean isProt)
-// Make a bigPsl from a list of psls and return its name.
-{
-struct tempName bigBedTn;
-trashDirDateFile(&bigBedTn, "hgBlat", "bp", ".bb");
-char *bigBedFile = bigBedTn.forCgi;
-makeBigPsl(pslFilename, faFilename, db, bigBedFile);
-char *customTextFile = replaceSuffix(bigBedFile, "txt");
-FILE *fp = fopen(customTextFile, "w");
-char* host = getenv("HTTP_HOST");
-char* reqUrl = getenv("REQUEST_URI");
-// remove everything after / in URL
-char *e = strrchr(reqUrl, '/');
-if (e) *e = 0;
-
-char *trackName = NULL;
-char *trackDescription = NULL;
-
-getCustomName(db, cart, pslList, &trackName, &trackDescription);
-char *customTextTemplate = "track type=bigPsl indelDoubleInsert=on indelQueryInsert=on  pslFile=%s visibility=pack showAll=on htmlUrl=http://%s/goldenPath/help/hgUserPsl.html %s bigDataUrl=http://%s%s/%s name=\"%s\" description=\"%s\"\n";
-char *extraForMismatch = "showDiffBasesAllScales=. baseColorUseSequence=lfExtra baseColorDefault=diffBases"; 
-
-if (isProt)
-    extraForMismatch = "";
-fprintf(fp, customTextTemplate, bigBedTn.forCgi, host, extraForMismatch, host, reqUrl, bigBedTn.forCgi, trackName, trackDescription);
-fclose(fp);
-
-char buffer[4096];
-safef(buffer, sizeof buffer, "http://%s%s/%s", host, reqUrl, customTextFile);
-
-return cloneString(buffer);
-}
-    
 void blatSeq(char *userSeq, char *organism, char *database)
 /* Blat sequence user pasted in. */
 {
-boolean doHyper = sameString(cartUsualString(cart, "output", outputList[0]), "hyperlink");;
-boolean useBigPsl = cfgOptionBooleanDefault("useBlatBigPsl", FALSE) && doHyper;
 FILE *f;
 struct dnaSeq *seqList = NULL, *seq;
 struct tempName pslTn, faTn;
 int maxSingleSize, maxTotalSize, maxSeqCount;
 int minSingleSize = minMatchShown;
 char *genome, *db;
 char *type = cgiString("type");
 char *seqLetters = cloneString(userSeq);
 struct serverTable *serve;
 int conn;
 int oneSize, totalSize = 0, seqCount = 0;
 boolean isTx = FALSE;
 boolean isTxTx = FALSE;
 boolean txTxBoth = FALSE;
 struct gfOutput *gvo;
@@ -842,48 +740,32 @@
 	    {
 	    gfAlignTrans(&conn, serve->nibDir, seq, 5, tFileCache, gvo);
 	    }
 	}
     else
 	{
 	gfAlignStrand(&conn, serve->nibDir, seq, FALSE, minMatchShown, tFileCache, gvo);
 	reverseComplement(seq->dna, seq->size);
 	conn = gfConnect(serve->host, serve->port);
 	gfAlignStrand(&conn, serve->nibDir, seq, TRUE, minMatchShown, tFileCache, gvo);
 	}
     gfOutputQuery(gvo, f);
     }
 carefulClose(&f);
 
-if (useBigPsl)
-    {
-    struct psl *pslList = pslLoadAll(pslTn.forCgi);
-
-    if (pslList != NULL)
-        {
-        char *customTrack = outBigPsl(database, pslList, pslTn.forCgi, faTn.forCgi, qIsProt);
-        showAliPlaces(pslTn.forCgi, faTn.forCgi, customTrack, serve->db, qType, tType, 
-          organism, feelingLucky);
-        }
-    else
-        puts("

Sorry, no matches found
"); - } -else - { showAliPlaces(pslTn.forCgi, faTn.forCgi, NULL, serve->db, qType, tType, organism, feelingLucky); - } if(!feelingLucky) cartWebEnd(); gfFileCacheFree(&tFileCache); } void askForSeq(char *organism, char *db) /* Put up a little form that asks for sequence. * Call self.... */ { /* ignore struct serverTable* return, but can error out if not found */ findServer(db, FALSE); /* JavaScript to update form when org changes */ char *onChangeText = "" "document.mainForm.changeInfo.value='orgChange';" @@ -903,31 +785,31 @@ printf("Query type:"); printf("Sort output:"); printf("Output type:"); printf(" "); printf("\n\n"); printf("\n"); printBlatGenomeListHtml(db, "change", onChangeText); printf("\n"); printf("\n"); printBlatAssemblyListHtml(db); printf("\n"); printf("\n"); cgiMakeDropList("type", typeList, ArraySize(typeList), NULL); printf("\n"); printf("\n"); -cgiMakeDropList("sort", sortList, ArraySize(sortList), cartOptionalString(cart, "sort")); +cgiMakeDropList("sort", pslSortList, ArraySize(pslSortList), cartOptionalString(cart, "sort")); printf("\n"); printf("\n"); cgiMakeDropList("output", outputList, ArraySize(outputList), cartOptionalString(cart, "output")); printf("\n"); printf("\n\n"); userSeq = cartUsualString(cart, "userSeq", ""); printf("\n"); htmlPrintf("\n", userSeq); printf("\n"); printf("\n\n"); printf("\n"); printf("\n"); printf("\n"); printf("\n"); printf("\n");