65490776b922ad5a6ba63214bc015c3f61c5fad2
jcasper
Wed Jun 12 14:56:14 2019 -0700
Adding custom track support for hic plus a couple cosmetic changes, refs #18842
diff --git src/hg/lib/customFactory.c src/hg/lib/customFactory.c
index 6ca66a9..cec2e36 100644
--- src/hg/lib/customFactory.c
+++ src/hg/lib/customFactory.c
@@ -35,30 +35,31 @@
#include "bigWig.h"
#include "bigBed.h"
#include "hgBam.h"
#include "vcf.h"
#include "makeItemsItem.h"
#include "bedDetail.h"
#include "pgSnp.h"
#include "regexHelper.h"
#include "chromInfo.h"
#include "trackHub.h"
#include "bedTabix.h"
#include "barChartBed.h"
#include "barChartUi.h"
#include "interact.h"
#include "interactUi.h"
+#include "hic.h"
#include "cgiApoptosis.h"
// placeholder when custom track uploaded file name is not known
#define CT_NO_FILE_NAME "custom track"
static boolean doExtraChecking = FALSE;
/*** Utility routines used by many factories. ***/
char *customFactoryNextTilTrack(struct customPp *cpp)
/* Return next line. Return NULL at end of input or at line starting with
* "track." */
{
char *line = customPpNext(cpp);
if (line != NULL && startsWithWord("track", line))
@@ -132,30 +133,107 @@
{
if (a == NULL && b == NULL)
errAbort("sameType should not be called when both inputs are NULL.");
else if (a == NULL || b == NULL)
return FALSE;
char *aCopy = cloneString(a);
char *bCopy = cloneString(b);
char *aWord = firstWordInLine(aCopy);
char *bWord = firstWordInLine(bCopy);
boolean same = sameString(aWord, bWord);
freeMem(aCopy);
freeMem(bCopy);
return same;
}
+boolean isValidBigDataUrl(char *url, boolean doAbort)
+/* return True if the URL is a valid bigDataUrl.
+ * It can be a local filename if this is allowed by udc.localDir
+ */
+{
+if ((startsWith("http://", url)
+ || startsWith("https://", url)
+ || startsWith("ftp://", url)))
+return TRUE;
+
+// we allow bigDataUrl's to point to trash (or sessionDataDir, if configured)
+char *sessionDataDir = cfgOption("sessionDataDir");
+char *sessionDataDirOld = cfgOption("sessionDataDirOld");
+if (startsWith(trashDir(), url) ||
+ (isNotEmpty(sessionDataDir) && startsWith(sessionDataDir, url)) ||
+ (isNotEmpty(sessionDataDirOld) && startsWith(sessionDataDirOld, url)))
+ return TRUE;
+
+char *prefix = cfgOption("udc.localDir");
+if (prefix == NULL)
+ {
+ if (doAbort)
+ errAbort("Only network protocols http, https, or ftp allowed in bigDataUrl: '%s'", url);
+ return FALSE;
+ }
+
+if (!startsWith(prefix, url))
+ {
+ if (doAbort)
+ errAbort("bigDataUrl '%s' on local file system has to start with '%s' (see udc.localDir directive in cgi-bin/hg.conf)", url, prefix);
+ return FALSE;
+ }
+
+return TRUE;
+}
+
+static void checkAllowedBigDataUrlProtocols(char *url)
+/* Abort if url is not using one of the allowed bigDataUrl network protocols.
+ * In particular, do not allow a local file reference, unless explicitely
+ * allowed by hg.conf's udc.localDir directive. */
+{
+isValidBigDataUrl(url, TRUE);
+}
+
+static char *bigDataDocPath(char *type)
+/* If type is a bigData type, provide a relative path to its custom track/format doc page. */
+{
+char *docUrl = NULL;
+if (sameString(type, "bigWig"))
+ docUrl = "../goldenPath/help/bigWig.html";
+else if (sameString(type, "bigBed"))
+ docUrl = "../goldenPath/help/bigBed.html";
+else if (sameString(type, "bam"))
+ docUrl = "../goldenPath/help/bam.html";
+else if (sameString(type, "vcfTabix"))
+ docUrl = "../goldenPath/help/vcf.html";
+return docUrl;
+}
+
+static void requireBigDataUrl(char *bigDataUrl, char *type, char *trackName)
+/* If bigDataUrl is empty, errAbort with helpful message about bigDataUrl requirement */
+{
+if (isEmpty(bigDataUrl))
+ {
+ struct dyString *doc = dyStringNew(0);
+ char *docUrl = bigDataDocPath(type);
+ if (docUrl != NULL)
+ dyStringPrintf(doc, " For more information about the bigDataUrl setting, see "
+ "%s custom track documentation.",
+ docUrl, type);
+ errAbort("Missing bigDataUrl setting from track of type=%s (%s). "
+ "Please check for case and spelling and that there is no new-line "
+ "between the 'track' and the 'bigDataUrl' if the bigDataUrl appears to be there."
+ "%s",
+ type, trackName, doc->string);
+ }
+}
/*** BED Factory ***/
static boolean rowIsBed(char **row, int wordCount, char *db, struct dyString *reason)
/* Return TRUE if row is consistent with BED format. If it's not BED and reason is not NULL,
* append reason for failure. */
{
if (wordCount < 3)
{
if (reason)
dyStringAppend(reason, "Too few fields (need at least 3)");
return FALSE;
}
if (wordCount > bedKnownFields)
{
if (reason)
@@ -1551,30 +1629,74 @@
slAddHead(&itemList, item);
}
slReverse(&itemList);
return interactFinish(track, itemList);
}
struct customFactory interactFactory =
/* Factory for interact tracks */
{
NULL,
"interact",
interactRecognizer,
interactLoader,
};
+
+/*********************/
+/**** hic Factory ****/
+
+static boolean hicRecognizer(struct customFactory *fac,
+ struct customPp *cpp, char *type,
+ struct customTrack *track)
+/* Return TRUE if looks like we're handling a hic track */
+{
+return (sameType(type, "hic"));
+}
+
+static struct customTrack *hicLoader(struct customFactory *fac,
+ struct hash *chromHash,
+ struct customPp *cpp, struct customTrack *track, boolean dbRequested)
+/* Load up hic data until get next track line. */
+{
+struct hash *settings = track->tdb->settingsHash;
+char *bigDataUrl = hashFindVal(settings, "bigDataUrl");
+requireBigDataUrl(bigDataUrl, fac->name, track->tdb->shortLabel);
+checkAllowedBigDataUrlProtocols(bigDataUrl);
+
+if (doExtraChecking)
+ {
+ struct hicMeta *meta;
+ char *hicErrMsg = hicLoadHeader(bigDataUrl, &meta);
+ if (hicErrMsg != NULL)
+ {
+ track->networkErrMsg = cloneString(hicErrMsg);
+ }
+ }
+return track;
+}
+
+struct customFactory hicFactory =
+/* Factory for Hi-C tracks */
+{
+ NULL,
+ "hic",
+ hicRecognizer,
+ hicLoader,
+ };
+
+
/*** GFF/GTF Factory - converts to BED ***/
static boolean rowIsGff(char *db, char **row, int wordCount, char *type, struct lineFile *lf)
/* Return TRUE if format of this row is consistent with being a .gff */
{
boolean isGff = FALSE;
if (wordCount >= 8 && wordCount <= 9)
{
/* Check that strand is + - or . */
char *strand = row[6];
char c = strand[0];
if ((c == '.' || c == '+' || c == '-') && strand[1] == 0)
{
// check chrom name
char *officialChrom = hgOfficialChromName(db, row[0]);
@@ -2548,108 +2670,30 @@
struct hash *settings = track->tdb->settingsHash;
if (hashLookup(settings, "viewLimits") == NULL)
{
struct bbiSummaryElement sum = bbiTotalSummary(track->bbiFile);
if (sum.minVal == sum.maxVal)
{
sum.minVal += 1;
sum.maxVal -= 1;
}
char text[1024];
safef(text, sizeof(text), "%f:%f", sum.minVal, sum.maxVal);
hashAdd(settings, "viewLimits", cloneString(text));
}
}
-boolean isValidBigDataUrl(char *url, boolean doAbort)
-/* return True if the URL is a valid bigDataUrl.
- * It can be a local filename if this is allowed by udc.localDir
- */
-{
-if ((startsWith("http://", url)
- || startsWith("https://", url)
- || startsWith("ftp://", url)))
-return TRUE;
-
-// we allow bigDataUrl's to point to trash (or sessionDataDir, if configured)
-char *sessionDataDir = cfgOption("sessionDataDir");
-char *sessionDataDirOld = cfgOption("sessionDataDirOld");
-if (startsWith(trashDir(), url) ||
- (isNotEmpty(sessionDataDir) && startsWith(sessionDataDir, url)) ||
- (isNotEmpty(sessionDataDirOld) && startsWith(sessionDataDirOld, url)))
- return TRUE;
-
-char *prefix = cfgOption("udc.localDir");
-if (prefix == NULL)
- {
- if (doAbort)
- errAbort("Only network protocols http, https, or ftp allowed in bigDataUrl: '%s'", url);
- return FALSE;
- }
-
-if (!startsWith(prefix, url))
- {
- if (doAbort)
- errAbort("bigDataUrl '%s' on local file system has to start with '%s' (see udc.localDir directive in cgi-bin/hg.conf)", url, prefix);
- return FALSE;
- }
-
-return TRUE;
-}
-
-static void checkAllowedBigDataUrlProtocols(char *url)
-/* Abort if url is not using one of the allowed bigDataUrl network protocols.
- * In particular, do not allow a local file reference, unless explicitely
- * allowed by hg.conf's udc.localDir directive. */
-{
-isValidBigDataUrl(url, TRUE);
-}
-
-static char *bigDataDocPath(char *type)
-/* If type is a bigData type, provide a relative path to its custom track/format doc page. */
-{
-char *docUrl = NULL;
-if (sameString(type, "bigWig"))
- docUrl = "../goldenPath/help/bigWig.html";
-else if (sameString(type, "bigBed"))
- docUrl = "../goldenPath/help/bigBed.html";
-else if (sameString(type, "bam"))
- docUrl = "../goldenPath/help/bam.html";
-else if (sameString(type, "vcfTabix"))
- docUrl = "../goldenPath/help/vcf.html";
-return docUrl;
-}
-
-static void requireBigDataUrl(char *bigDataUrl, char *type, char *trackName)
-/* If bigDataUrl is empty, errAbort with helpful message about bigDataUrl requirement */
-{
-if (isEmpty(bigDataUrl))
- {
- struct dyString *doc = dyStringNew(0);
- char *docUrl = bigDataDocPath(type);
- if (docUrl != NULL)
- dyStringPrintf(doc, " For more information about the bigDataUrl setting, see "
- "%s custom track documentation.",
- docUrl, type);
- errAbort("Missing bigDataUrl setting from track of type=%s (%s). "
- "Please check for case and spelling and that there is no new-line "
- "between the 'track' and the 'bigDataUrl' if the bigDataUrl appears to be there."
- "%s",
- type, trackName, doc->string);
- }
-}
-
static struct customTrack *bigWigLoader(struct customFactory *fac,
struct hash *chromHash,
struct customPp *cpp, struct customTrack *track, boolean dbRequested)
/* Load up wiggle data until get next track line. */
{
/* Not much to this. A bigWig has nothing here but a track line. */
struct hash *settings = track->tdb->settingsHash;
char *bigDataUrl = hashFindVal(settings, "bigDataUrl");
requireBigDataUrl(bigDataUrl, fac->name, track->tdb->shortLabel);
checkAllowedBigDataUrlProtocols(bigDataUrl);
/* protect against temporary network error */
struct errCatch *errCatch = errCatchNew();
if (errCatchStart(errCatch))
{
@@ -3431,30 +3475,31 @@
slAddTail(&factoryList, &bigBedFactory);
slAddTail(&factoryList, &bedGraphFactory);
slAddTail(&factoryList, µarrayFactory);
slAddTail(&factoryList, &coloredExonFactory);
slAddTail(&factoryList, &encodePeakFactory);
slAddTail(&factoryList, &bedDetailFactory);
slAddTail(&factoryList, &adjacencyFactory);
slAddTail(&factoryList, &bamFactory);
slAddTail(&factoryList, &vcfTabixFactory);
slAddTail(&factoryList, &makeItemsFactory);
slAddTail(&factoryList, &bigDataOopsFactory);
slAddTail(&factoryList, &barChartFactory);
slAddTail(&factoryList, &bigBarChartFactory);
slAddTail(&factoryList, &interactFactory);
slAddTail(&factoryList, &bigInteractFactory);
+ slAddTail(&factoryList, &hicFactory);
}
}
struct customFactory *customFactoryFind(char *genomeDb, struct customPp *cpp,
char *type, struct customTrack *track)
/* Figure out factory that can handle this track. The track is
* loaded from the track line if any, and type is the type element
* if any from that track. */
{
struct customFactory *fac;
customFactoryInit();
for (fac = factoryList; fac != NULL; fac = fac->next)
if (fac->recognizer(fac, cpp, type, track))
break;
return fac;