39e533cc9ffcb46d9c484dc09a387a031a739391 Merge parents 1c86690 f642bab kate Mon Sep 24 16:35:53 2018 -0700 Updating from master diff --cc src/hg/lib/interact.c index 1d74ada,e27d480..43f4404 --- src/hg/lib/interact.c +++ src/hg/lib/interact.c @@@ -1,467 -1,471 +1,565 @@@ /* interact.c was originally generated by the autoSql program, which also * generated interact.h and interact.sql. This module links the database and * the RAM representation of objects. */ #include "common.h" #include "linefile.h" #include "dystring.h" #include "jksql.h" #include "basicBed.h" #include "interact.h" char *interactCommaSepFieldNames = "chrom,chromStart,chromEnd,name,score,value,exp,color,sourceChrom,sourceStart,sourceEnd,sourceName,sourceStrand,targetChrom,targetStart,targetEnd,targetName,targetStrand"; void interactStaticLoad(char **row, struct interact *ret) /* Load a row from interact table into ret. The contents of ret will * be replaced at the next call to this function. */ { ret->chrom = row[0]; ret->chromStart = sqlUnsigned(row[1]); ret->chromEnd = sqlUnsigned(row[2]); ret->name = row[3]; ret->score = sqlUnsigned(row[4]); ret->value = sqlDouble(row[5]); ret->exp = row[6]; ret->color = sqlUnsigned(row[7]); ret->sourceChrom = row[8]; ret->sourceStart = sqlUnsigned(row[9]); ret->sourceEnd = sqlUnsigned(row[10]); ret->sourceName = row[11]; ret->sourceStrand = row[12]; ret->targetChrom = row[13]; ret->targetStart = sqlUnsigned(row[14]); ret->targetEnd = sqlUnsigned(row[15]); ret->targetName = row[16]; ret->targetStrand = row[17]; } struct interact *interactLoadByQuery(struct sqlConnection *conn, char *query) /* Load all interact from table that satisfy the query given. * Where query is of the form 'select * from example where something=something' * or 'select example.* from example, anotherTable where example.something = * anotherTable.something'. * Dispose of this with interactFreeList(). */ { struct interact *list = NULL, *el; struct sqlResult *sr; char **row; sr = sqlGetResult(conn, query); while ((row = sqlNextRow(sr)) != NULL) { el = interactLoad(row); slAddHead(&list, el); } slReverse(&list); sqlFreeResult(&sr); return list; } void interactSaveToDb(struct sqlConnection *conn, struct interact *el, char *tableName, int updateSize) /* Save interact as a row to the table specified by tableName. * As blob fields may be arbitrary size updateSize specifies the approx size * of a string that would contain the entire query. Arrays of native types are * converted to comma separated strings and loaded as such, User defined types are * inserted as NULL. This function automatically escapes quoted strings for mysql. */ { struct dyString *update = newDyString(updateSize); sqlDyStringPrintf(update, "insert into %s values ( '%s',%u,%u,'%s',%u,%g,'%s',%u,'%s',%u,%u,'%s','%s','%s',%u,%u,'%s','%s')", tableName, el->chrom, el->chromStart, el->chromEnd, el->name, el->score, el->value, el->exp, el->color, el->sourceChrom, el->sourceStart, el->sourceEnd, el->sourceName, el->sourceStrand, el->targetChrom, el->targetStart, el->targetEnd, el->targetName, el->targetStrand); sqlUpdate(conn, update->string); freeDyString(&update); } struct interact *interactLoad(char **row) /* Load a interact from row fetched with select * from interact * from database. Dispose of this with interactFree(). */ { struct interact *ret; AllocVar(ret); ret->chrom = cloneString(row[0]); ret->chromStart = sqlUnsigned(row[1]); ret->chromEnd = sqlUnsigned(row[2]); ret->name = cloneString(row[3]); ret->score = sqlUnsigned(row[4]); ret->value = sqlDouble(row[5]); ret->exp = cloneString(row[6]); ret->color = sqlUnsigned(row[7]); ret->sourceChrom = cloneString(row[8]); ret->sourceStart = sqlUnsigned(row[9]); ret->sourceEnd = sqlUnsigned(row[10]); ret->sourceName = cloneString(row[11]); ret->sourceStrand = cloneString(row[12]); ret->targetChrom = cloneString(row[13]); ret->targetStart = sqlUnsigned(row[14]); ret->targetEnd = sqlUnsigned(row[15]); ret->targetName = cloneString(row[16]); ret->targetStrand = cloneString(row[17]); return ret; } struct interact *interactLoadAll(char *fileName) /* Load all interact from a whitespace-separated file. * Dispose of this with interactFreeList(). */ { struct interact *list = NULL, *el; struct lineFile *lf = lineFileOpen(fileName, TRUE); char *row[18]; while (lineFileRow(lf, row)) { el = interactLoad(row); slAddHead(&list, el); } lineFileClose(&lf); slReverse(&list); return list; } struct interact *interactLoadAllByChar(char *fileName, char chopper) /* Load all interact from a chopper separated file. * Dispose of this with interactFreeList(). */ { struct interact *list = NULL, *el; struct lineFile *lf = lineFileOpen(fileName, TRUE); char *row[18]; while (lineFileNextCharRow(lf, chopper, row, ArraySize(row))) { el = interactLoad(row); slAddHead(&list, el); } lineFileClose(&lf); slReverse(&list); return list; } struct interact *interactCommaIn(char **pS, struct interact *ret) /* Create a interact out of a comma separated string. * This will fill in ret if non-null, otherwise will * return a new interact */ { char *s = *pS; if (ret == NULL) AllocVar(ret); ret->chrom = sqlStringComma(&s); ret->chromStart = sqlUnsignedComma(&s); ret->chromEnd = sqlUnsignedComma(&s); ret->name = sqlStringComma(&s); ret->score = sqlUnsignedComma(&s); ret->value = sqlDoubleComma(&s); ret->exp = sqlStringComma(&s); ret->color = sqlUnsignedComma(&s); ret->sourceChrom = sqlStringComma(&s); ret->sourceStart = sqlUnsignedComma(&s); ret->sourceEnd = sqlUnsignedComma(&s); ret->sourceName = sqlStringComma(&s); ret->sourceStrand = sqlStringComma(&s); ret->targetChrom = sqlStringComma(&s); ret->targetStart = sqlUnsignedComma(&s); ret->targetEnd = sqlUnsignedComma(&s); ret->targetName = sqlStringComma(&s); ret->targetStrand = sqlStringComma(&s); *pS = s; return ret; } void interactFree(struct interact **pEl) /* Free a single dynamically allocated interact such as created * with interactLoad(). */ { struct interact *el; if ((el = *pEl) == NULL) return; freeMem(el->chrom); freeMem(el->name); freeMem(el->exp); freeMem(el->sourceChrom); freeMem(el->sourceName); freeMem(el->sourceStrand); freeMem(el->targetChrom); freeMem(el->targetName); freeMem(el->targetStrand); freez(pEl); } void interactFreeList(struct interact **pList) /* Free a list of dynamically allocated interact's */ { struct interact *el, *next; for (el = *pList; el != NULL; el = next) { next = el->next; interactFree(&el); } *pList = NULL; } void interactOutput(struct interact *el, FILE *f, char sep, char lastSep) /* Print out interact. Separate fields with sep. Follow last field with lastSep. */ { if (sep == ',') fputc('"',f); fprintf(f, "%s", el->chrom); if (sep == ',') fputc('"',f); fputc(sep,f); fprintf(f, "%u", el->chromStart); fputc(sep,f); fprintf(f, "%u", el->chromEnd); fputc(sep,f); if (sep == ',') fputc('"',f); fprintf(f, "%s", el->name); if (sep == ',') fputc('"',f); fputc(sep,f); fprintf(f, "%u", el->score); fputc(sep,f); fprintf(f, "%g", el->value); fputc(sep,f); if (sep == ',') fputc('"',f); fprintf(f, "%s", el->exp); if (sep == ',') fputc('"',f); fputc(sep,f); fprintf(f, "%u", el->color); fputc(sep,f); if (sep == ',') fputc('"',f); fprintf(f, "%s", el->sourceChrom); if (sep == ',') fputc('"',f); fputc(sep,f); fprintf(f, "%u", el->sourceStart); fputc(sep,f); fprintf(f, "%u", el->sourceEnd); fputc(sep,f); if (sep == ',') fputc('"',f); fprintf(f, "%s", el->sourceName); if (sep == ',') fputc('"',f); fputc(sep,f); if (sep == ',') fputc('"',f); fprintf(f, "%s", el->sourceStrand); if (sep == ',') fputc('"',f); fputc(sep,f); if (sep == ',') fputc('"',f); fprintf(f, "%s", el->targetChrom); if (sep == ',') fputc('"',f); fputc(sep,f); fprintf(f, "%u", el->targetStart); fputc(sep,f); fprintf(f, "%u", el->targetEnd); fputc(sep,f); if (sep == ',') fputc('"',f); fprintf(f, "%s", el->targetName); if (sep == ',') fputc('"',f); fputc(sep,f); if (sep == ',') fputc('"',f); fprintf(f, "%s", el->targetStrand); if (sep == ',') fputc('"',f); fputc(lastSep,f); } /* -------------------------------- End autoSql Generated Code -------------------------------- */ static char *interactAutoSqlString = "table interact" "\"BED5+13 interaction between two regions\"" " (" " string chrom; \"Chromosome (or contig, scaffold, etc.). For interchromosomal, use 2 records\"" " uint chromStart; \"Start position of lower region. For chromosomal, set to chromStart of this region\"" " uint chromEnd; \"End position of upper region. For interchromsomal, set to chromEnd of this region\"" " string name; \"Name or ID of item. Usually name1/name2 or name1/name2/exp or empty\"" " uint score; \"Score from 0-1000, typically derived from value\"" " double value; \"Strength of interaction or other data value\"" " string exp; \"Experiment name for filtering. Use . if not applicable\"" " uint color; \"Item color, as itemRgb in bed9. Typically based on value or exp\"" " string sourceChrom; \"Chromosome of source region (directional) or lower region. For non-directional interchromosomal, chrom of this region\"" " uint sourceStart; \"Start position of source/lower/this region\"" " uint sourceEnd; \"End position of source/lower/this region\"" " string sourceName; \"Identifier of source/lower/this region. Can be used as link to related table.\"" " string sourceStrand;\"Orientation of source/lower/this region: + or -. Use . if not applicable.\"" " string targetChrom; \"Chromosome of target region (directional) or upper region. For non-directional interchromosomal, chrom of other region\"" " uint targetStart; \"Start position of target/upper/this region\"" " uint targetEnd; \"End position of target/upper/this region\"" " string targetName; \"Identifier of target/upper/this region. Can be used as link to related table.\"" " string targetStrand;\"Orientation of target/upper/this region: + or -. Use . if not applicable.\"" " )" ; #include "asParse.h" struct asObject *interactAsObj() /* Return asObject describing fields of interact object */ { return asParseText(interactAutoSqlString); } char *interactOtherChrom(struct interact *inter) /* Get other chromosome from an interaaction. Return NULL if same chromosome */ { if (sameString(inter->sourceChrom, inter->targetChrom)) return NULL; if (inter->chromStart == inter->sourceStart) return cloneString(inter->targetChrom); return cloneString(inter->sourceChrom); } int interactRegionCenter(int start, int end) /* Return genomic location of center of region */ { return ((double)(end - start + .5) / 2) + start; } int interactRegionDistance(struct interact *inter) /* Return distance between region midpoints. Return -1 for other chromosome */ { if (interactOtherChrom(inter)) return -1; return abs(interactRegionCenter(inter->sourceStart, inter->sourceEnd) - interactRegionCenter(inter->targetStart, inter->targetEnd)); } int interactDistanceCmp(const void *va, const void *vb) /* Compare based on distance between region midpoints */ { struct interact *a = *((struct interact **)va); struct interact *b = *((struct interact **)vb); int aDist = interactRegionDistance(a); int bDist = interactRegionDistance(b); // cross chromosome; always larger than same chrom if (aDist < 0) { if (bDist < 0) return 0; return 1; } if (bDist < 0) return -1; // same chromosome return aDist - bDist; } struct interact *interactLoadAndValidate(char **row) /* Load a interact from row fetched with select * from interact - * from database, validating fields. Dispose of this with interactFree(). */ + * from database, validating fields. Dispose of this with interactFree(). + * This currently differs from auto-gened only by it's handling of color field */ // TODO: more validating { struct interact *ret; AllocVar(ret); ret->chrom = cloneString(row[0]); ret->chromStart = sqlUnsigned(row[1]); ret->chromEnd = sqlUnsigned(row[2]); ret->name = cloneString(row[3]); ret->score = sqlUnsigned(row[4]); ret->value = sqlDouble(row[5]); ret->exp = cloneString(row[6]); - ret->color = bedParseColor(row[7]); + ret->color = bedParseColor(row[7]); // handle #NNNNNN, and HTML color (as well as rgb) ret->sourceChrom = cloneString(row[8]); ret->sourceStart = sqlUnsigned(row[9]); ret->sourceEnd = sqlUnsigned(row[10]); ret->sourceName = cloneString(row[11]); ret->sourceStrand = cloneString(row[12]); ret->targetChrom = cloneString(row[13]); ret->targetStart = sqlUnsigned(row[14]); ret->targetEnd = sqlUnsigned(row[15]); ret->targetName = cloneString(row[16]); ret->targetStrand = cloneString(row[17]); return ret; } +void interactRegionCenters(struct interact *inter, int *sourceCenter, int *targetCenter) +/* Return genomic position of endpoint centers */ +{ +assert(sourceCenter); +assert(targetCenter); +*sourceCenter = interactRegionCenter(inter->sourceStart, inter->sourceEnd); +*targetCenter = interactRegionCenter(inter->targetStart, inter->targetEnd); +} + +struct bed *interactToBed(struct interact *inter) +/* Convert an interact to a BED12 (actually, BED15+label) */ +{ +struct bed *bed = NULL; +AllocVar(bed); + +bed->chrom = inter->chrom; +// expand extents to edges of endpoints +// NOTE: this should be changed in schema defn +//bed->chromStart = inter->chromStart; +bed->chromStart = min(inter->sourceStart, inter->targetStart); +//bed->chromEnd = inter->chromEnd; +bed->chromEnd = max(inter->sourceEnd, inter->targetEnd); +bed->thickStart = bed->chromStart; +bed->thickEnd = bed->chromEnd; +bed->name = inter->name; +bed->score = inter->score; +bed->itemRgb = inter->color; +AllocArray(bed->blockSizes, 2); +AllocArray(bed->chromStarts, 2); + +char *strand = "+"; +if (differentString(inter->sourceChrom, inter->targetChrom)) + { + // inter-chromosomal + bed->blockCount = 1; + bed->blockSizes[0] = inter->chromEnd - inter->chromStart; + bed->chromStarts[0] = 0; + if sameString(bed->chrom, inter->targetChrom) + strand = "-"; + } +else + { + // same chromosome + int sourceCenter, targetCenter; + interactRegionCenters(inter, &sourceCenter, &targetCenter); + if (targetCenter < sourceCenter) + { + strand = "-"; + if (inter->sourceStart <= inter->targetEnd) + { + // overlapping - use thickStart/End to delineate + bed->blockCount = 1; + bed->blockSizes[0] = bed->chromEnd - bed->chromStart; + bed->chromStarts[0] = 0; + bed->thickStart = targetCenter; + bed->thickEnd = sourceCenter; + } + else + { + bed->blockCount = 2; + bed->blockSizes[1] = inter->sourceEnd - inter->sourceStart; + bed->blockSizes[0] = inter->targetEnd - inter->targetStart; + bed->chromStarts[1] = inter->sourceStart - bed->chromStart; + bed->chromStarts[0] = 0; + } + } + else + { + // forward direction + if (inter->targetStart <= inter->sourceEnd) + { + // overlapping - use thickStart/End to delineate + bed->blockCount = 1; + bed->blockSizes[0] = bed->chromEnd - bed->chromStart; + bed->chromStarts[0] = 0; + bed->thickStart = sourceCenter; + bed->thickEnd = targetCenter; + } + else + { + bed->blockCount = 2; + bed->blockSizes[0] = inter->sourceEnd - inter->sourceStart; + bed->blockSizes[1] = inter->targetEnd - inter->targetStart; + bed->chromStarts[0] = 0; + bed->chromStarts[1] = inter->targetStart - bed->chromStart; + } + } + } +strcpy(bed->strand, strand); +bed->label = bed->name; +return bed; +} + + struct interact *interactLoadAllAndValidate(char *fileName) + /* Load all interact from a whitespace-separated file. + * Dispose of this with interactFreeList(). */ + { + struct interact *list = NULL, *el; + struct lineFile *lf = lineFileOpen(fileName, TRUE); + char *row[18]; + while (lineFileRow(lf, row)) + { + el = interactLoadAndValidate(row); + slAddHead(&list, el); + } + lineFileClose(&lf); + slReverse(&list); + return list; + } + + void interactOutputCustom(struct interact *el, FILE *f, char sep, char lastSep) + /* Print out interact. Separate fields with sep. Follow last field with lastSep. + * Differs from auto-gen'ed by printing rgb color */ + { + if (sep == ',') fputc('"',f); + fprintf(f, "%s", el->chrom); + if (sep == ',') fputc('"',f); + fputc(sep,f); + fprintf(f, "%u", el->chromStart); + fputc(sep,f); + fprintf(f, "%u", el->chromEnd); + fputc(sep,f); + if (sep == ',') fputc('"',f); + fprintf(f, "%s", el->name); + if (sep == ',') fputc('"',f); + fputc(sep,f); + fprintf(f, "%u", el->score); + fputc(sep,f); + fprintf(f, "%g", el->value); + fputc(sep,f); + if (sep == ',') fputc('"',f); + fprintf(f, "%s", el->exp); + if (sep == ',') fputc('"',f); + fputc(sep,f); + + // print rgb color + bedOutputRgb(f, el->color); + + fputc(sep,f); + if (sep == ',') fputc('"',f); + fprintf(f, "%s", el->sourceChrom); + if (sep == ',') fputc('"',f); + fputc(sep,f); + fprintf(f, "%u", el->sourceStart); + fputc(sep,f); + fprintf(f, "%u", el->sourceEnd); + fputc(sep,f); + if (sep == ',') fputc('"',f); + fprintf(f, "%s", el->sourceName); + if (sep == ',') fputc('"',f); + fputc(sep,f); + if (sep == ',') fputc('"',f); + fprintf(f, "%s", el->sourceStrand); + if (sep == ',') fputc('"',f); + fputc(sep,f); + if (sep == ',') fputc('"',f); + fprintf(f, "%s", el->targetChrom); + if (sep == ',') fputc('"',f); + fputc(sep,f); + fprintf(f, "%u", el->targetStart); + fputc(sep,f); + fprintf(f, "%u", el->targetEnd); + fputc(sep,f); + if (sep == ',') fputc('"',f); + fprintf(f, "%s", el->targetName); + if (sep == ',') fputc('"',f); + fputc(sep,f); + if (sep == ',') fputc('"',f); + fprintf(f, "%s", el->targetStrand); + if (sep == ',') fputc('"',f); + fputc(lastSep,f); + } + + void interactFixRange(struct interact *inter) + /* Set values for chromStart/chromEnd based on source and target start/ends */ + { + int chromStart = min(inter->sourceStart, inter->targetStart); + int chromEnd = max(inter->sourceEnd, inter->targetEnd); + if (inter->chromStart != chromStart) + { + warn("Fixed chromStart: %d to %d. ", inter->chromStart, chromStart); + inter->chromStart = chromStart; + } + if (inter->chromEnd != chromEnd) + { + warn("Fixed chromEnd: %d to %d. ", inter->chromEnd, chromEnd); + inter->chromEnd = chromEnd; + } + } ++