8c908f948b09826c6cb4452ee5b282aca41be85e
galt
Tue Dec 8 21:52:59 2015 -0800
Multi-region (exonMostly). This work allows people to look at virtual chromosomes from a list of regions and then navigate and perform all of the usual functions on it.
diff --git src/hg/hgTracks/imageV2.c src/hg/hgTracks/imageV2.c
index 4dfb61f..96e1ede 100644
--- src/hg/hgTracks/imageV2.c
+++ src/hg/hgTracks/imageV2.c
@@ -3,31 +3,31 @@
/* Copyright (C) 2014 The Regents of the University of California
* See README in this or parent directory for licensing information. */
#include "common.h"
#include "hPrint.h"
#include "chromInfo.h"
#include "hdb.h"
#include "hui.h"
#include "jsHelper.h"
#include "cheapcgi.h"
#include "htmshell.h"
#include "imageV2.h"
#include "hgTracks.h"
#include "hgConfig.h"
#include "regexHelper.h"
-
+// Note: when right-click View image (or pdf output) then theImgBox==NULL, so it will be rendered as a single simple image
struct imgBox *theImgBox = NULL; // Make this global for now to avoid huge rewrite
struct imgTrack *curImgTrack = NULL; // Make this global for now to avoid huge rewrite
/////////////////////////
// FLAT TRACKS
// A simplistic way of flattening the track list before building the image
// NOTE: Strategy is NOT to use imgBox->imgTracks, since this should be independednt of imageV2
/////////////////////////
void flatTracksAdd(struct flatTracks **flatTracks,struct track *track,struct cart *cart)
// Adds one track into the flatTracks list
{
struct flatTracks *flatTrack;
AllocVar(flatTrack);
flatTrack->track = track;
char var[256]; // The whole reason to do this is to reorder tracks/subtracks in the image!
@@ -880,44 +880,44 @@
struct mapSet *map = sliceGetMap(slice,TRUE); // Only one that belongs to slice, not image
if (map != NULL)
mapSetFree(&map);
freeMem(slice->title);
freeMem(slice->link);
freeMem(slice);
*pSlice = NULL;
}
}
/////////////////////// imgTracks
struct imgTrack *imgTrackStart(struct trackDb *tdb, char *name, char *db,
- char *chrom,int chromStart,int chromEnd,boolean plusStrand,
+ char *chrom, long chromStart, long chromEnd, boolean plusStrand,
boolean hasCenterLabel, enum trackVisibility vis, int order)
// Starts an image track which will contain all image slices needed to render one track
// Must completed by adding slices with imgTrackAddSlice()
{
struct imgTrack *imgTrack; // pngTn.forHtml, pixWidth, mapName
AllocVar(imgTrack);
imgTrack->centerLabelSeen = clAlways;
return imgTrackUpdate(imgTrack,tdb,name,db,chrom,chromStart,chromEnd,plusStrand,
hasCenterLabel,vis,order);
}
struct imgTrack *imgTrackUpdate(struct imgTrack *imgTrack, struct trackDb *tdb, char *name,
- char *db,char *chrom,int chromStart,int chromEnd,boolean plusStrand,
+ char *db, char *chrom, long chromStart, long chromEnd, boolean plusStrand,
boolean hasCenterLabel, enum trackVisibility vis, int order)
// Updates an already existing image track
{
if (tdb != NULL && tdb != imgTrack->tdb)
imgTrack->tdb = tdb;
if (name != NULL && differentStringNullOk(imgTrack->name,name))
{
if (imgTrack->name != NULL)
freeMem(imgTrack->name);
imgTrack->name = cloneString(name);
}
if (db != NULL && db != imgTrack->db)
imgTrack->db = db; // NOTE: Not allocated
if (chrom != NULL && chrom != imgTrack->chrom)
imgTrack->chrom = chrom; // NOTE: Not allocated
@@ -1071,31 +1071,33 @@
// slices, the imgTrack is in the best position to determine where to put the map item
// returns count of map items added, which could be 0, 1 or more than one if item spans slices
// NOTE: Precedence is given to first map item when adding items with same coordinates!
{
struct imgSlice *slice;
char *imgFile = NULL; // name of file that hold the image
char *neededId = NULL; // id is only added it it is NOT the trackId.
if (imgTrack->tdb == NULL || differentStringNullOk(id, imgTrack->tdb->track))
neededId = id;
// Trap surprising location s for map items, but only on test machines.
if (hIsPrivateHost())
{
int leftX, topY, rightX, bottomY;
imgTrackCoordinates(imgTrack, &leftX, &topY, &rightX, &bottomY);
- if (topLeftY < topY || bottomRightY > bottomY)
+ //if (topLeftY < topY || bottomRightY > bottomY)
+ // TODO for sideLabels=0, many track item maps are extending down 1 pixel too far. EXISTING BUG.
+ if (topLeftY < topY || bottomRightY > (bottomY + 1)) // DEBUG RESTORE GALT Ignoring problem for now.
{
char * name = (imgTrack->name != NULL ? imgTrack->name
: imgTrack->tdb != NULL ? imgTrack->tdb->track
: imgFile);
warn("imgTrackAddMapItem(%s,%s) mapItem (%d,%d)(%d,%d) spills over track bounds(%d,%d)(%d,%d)",
name,title,topLeftX,topLeftY,bottomRightX,bottomRightY,leftX,topY,rightX,bottomY);
}
}
int count = 0;
for (slice = imgTrack->slices;slice != NULL;slice=slice->next)
{
if (slice->type == stButton) // Buttons don't have maps. Overlap will be ignored!
continue;
if (slice->parentImg != NULL)
@@ -1204,31 +1206,31 @@
return FALSE;
}
if (imgTrack->db == NULL)
{
if (verbose)
{
warn("imgTrack(%s) has no chrom.",name);
imgTrackShow(NULL,imgTrack,0);
}
return FALSE;
}
if (imgTrack->chromStart >= imgTrack->chromEnd)
{
if (verbose)
{
- warn("imgTrack(%s) for %s.%s:%d-%d has bad genome range.",name,
+ warn("imgTrack(%s) for %s.%s:%ld-%ld has bad genome range.",name,
imgTrack->db,imgTrack->chrom,imgTrack->chromStart,imgTrack->chromEnd);
imgTrackShow(NULL,imgTrack,0);
}
return FALSE;
}
if (imgTrack->slices == NULL)
{
if (verbose)
{
warn("imgTrack(%s) has no slices.",name);
imgTrackShow(NULL,imgTrack,0);
}
return FALSE;
}
// Can have no more than one of each type of slice
@@ -1273,145 +1275,155 @@
{
struct imgTrack *imgTrack = *pImgTrack;
struct imgSlice *slice;
while ((slice = slPopHead(&(imgTrack->slices))) != NULL )
sliceFree(&slice);
freeMem(imgTrack->name);
freeMem(imgTrack);
*pImgTrack = NULL;
}
}
/////////////////////// Image Box
-struct imgBox *imgBoxStart(char *db,char *chrom,int chromStart,int chromEnd,boolean plusStrand,
+struct imgBox *imgBoxStart(char *db, char *chrom, long chromStart, long chromEnd, boolean plusStrand,
int sideLabelWidth, int width)
// Starts an imgBox which should contain all info needed to draw the hgTracks image with
// multiple tracks. The image box must be completed using imgBoxImageAdd() and imgBoxTrackAdd()
{
struct imgBox * imgBox; // pngTn.forHtml, pixWidth, mapName
AllocVar(imgBox);
if (db != NULL)
imgBox->db = cloneString(db); // NOTE: Is allocated
if (chrom != NULL)
imgBox->chrom = cloneString(chrom); // NOTE: Is allocated
imgBox->chromStart = chromStart;
imgBox->chromEnd = chromEnd;
imgBox->plusStrand = plusStrand;
imgBox->showSideLabel = (sideLabelWidth != 0);
imgBox->sideLabelWidth = sideLabelWidth;
imgBox->images = NULL;
imgBox->bgImg = NULL;
imgBox->width = width;
imgBox->showPortal = FALSE;
//int oneThird = (chromEnd - chromStart)/3; // TODO: Currently defaulting to 1/3 of image width
imgBox->portalStart = chromStart; // + oneThird;
imgBox->portalEnd = chromEnd; // - oneThird;
imgBox->portalWidth = chromEnd - chromStart;
imgBox->basesPerPixel =
((double)imgBox->chromEnd - imgBox->chromStart)/(imgBox->width - imgBox->sideLabelWidth);
return imgBox;
}
-boolean imgBoxPortalDefine(struct imgBox *imgBox,int *chromStart,int *chromEnd,
+boolean imgBoxPortalDefine(struct imgBox *imgBox, long *chromStart, long *chromEnd,
int *imgWidth,double imageMultiple)
// Defines the portal of the imgBox. The portal is the initial viewable region when dragScroll
// is being used. The new chromStart,chromEnd and imgWidth are returned as OUTs, while the portal
// becomes the initial defined size.
// returns TRUE if successfully defined as having a portal
{
if ( (int)imageMultiple == 0)
imageMultiple = IMAGEv2_DRAG_SCROLL_SZ;
imgBox->portalStart = imgBox->chromStart;
imgBox->portalEnd = imgBox->chromEnd;
imgBox->portalWidth = imgBox->width - imgBox->sideLabelWidth;
imgBox->showPortal = FALSE; // Guilty until proven innocent
-int positionWidth = (int)((imgBox->portalEnd - imgBox->portalStart) * imageMultiple);
-*chromStart = imgBox->portalStart - (int)( ((imageMultiple - 1)/2)
+long positionWidth = (long)((imgBox->portalEnd - imgBox->portalStart) * imageMultiple);
+*chromStart = imgBox->portalStart - (long)( ((imageMultiple - 1)/2)
* (imgBox->portalEnd - imgBox->portalStart));
if (*chromStart < 0)
*chromStart = 0;
*chromEnd = *chromStart + positionWidth;
+// get chrom size
+long virtChromSize = 0;
+if (sameString(imgBox->chrom, "virt"))
+ {
+ virtChromSize = virtSeqBaseCount;
+ }
+else
+ {
struct chromInfo *chrInfo = hGetChromInfo(imgBox->db,imgBox->chrom);
if (chrInfo == NULL)
{
*chromStart = imgBox->chromStart;
*chromEnd = imgBox->chromEnd;
return FALSE;
}
-if (*chromEnd > (int)(chrInfo->size)) // Bound by chrom length
+ virtChromSize = chrInfo->size;
+ }
+if (*chromEnd > virtChromSize) // Bound by chrom length
{
- *chromEnd = (int)(chrInfo->size);
+ *chromEnd = virtChromSize;
*chromStart = *chromEnd - positionWidth;
if (*chromStart < 0)
*chromStart = 0;
}
// TODO: Normalize to power of 10 boundary
// Normalize portal ends
-int diff = *chromStart - imgBox->portalStart;
+long diff = *chromStart - imgBox->portalStart;
if (diff < 10 && diff > -10)
*chromStart = imgBox->portalStart;
diff = *chromEnd - imgBox->portalEnd;
if (diff < 10 && diff > -10)
*chromEnd = imgBox->portalEnd;
double growthOfImage = (*chromEnd - *chromStart)/(imgBox->portalEnd - imgBox->portalStart);
*imgWidth = (imgBox->portalWidth * growthOfImage) + imgBox->sideLabelWidth;
//if (imgBox->portalStart < *chromStart || imgBox->portalEnd > *chromEnd
//|| imgBox->portalWidth > *imgWidth)
// {
// *imgWidth = imgBox->width; // Undo damage
// *chromStart = imgBox->chromStart;
// *chromEnd = imgBox->chromEnd;
// return FALSE;
// }
imgBox->width = *imgWidth;
imgBox->chromStart = *chromStart;
imgBox->chromEnd = *chromEnd;
imgBox->basesPerPixel =
((double)imgBox->chromEnd - imgBox->chromStart)/(imgBox->width - imgBox->sideLabelWidth);
imgBox->showPortal = TRUE;
return imgBox->showPortal;
}
-boolean imgBoxPortalRemove(struct imgBox *imgBox,int *chromStart,int *chromEnd,int *imgWidth)
+boolean imgBoxPortalRemove(struct imgBox *imgBox, long *chromStart, long *chromEnd, int *imgWidth)
// Will redefine the imgBox as the portal dimensions and return the dimensions as OUTs.
// Returns TRUE if a portal was defined in the first place
{
if (imgBox->showPortal == FALSE)
{
*chromStart=imgBox->chromStart; // return to original coordinates
*chromEnd =imgBox->chromEnd;
*imgWidth =imgBox->width;
return FALSE;
}
*chromStart=imgBox->chromStart=imgBox->portalStart; // return to original coordinates
*chromEnd =imgBox->chromEnd =imgBox->portalEnd;
*imgWidth =imgBox->width = (imgBox->portalWidth + imgBox->sideLabelWidth);
imgBox->showPortal = FALSE;
return TRUE;
}
-boolean imgBoxPortalDimensions(struct imgBox *imgBox,int *chromStart,int *chromEnd,
+boolean imgBoxPortalDimensions(struct imgBox *imgBox, long *chromStart, long *chromEnd,
int *imgWidth, int *sideLabelWidth,
- int *portalStart,int *portalEnd,int *portalWidth,
+ long *portalStart, long *portalEnd, int *portalWidth,
double *basesPerPixel)
// returns the imgBox portal dimensions in the OUTs returns TRUE if portal defined
{
if ( chromStart )
*chromStart = imgBox->chromStart;
if ( chromEnd )
*chromEnd = imgBox->chromEnd;
if ( imgWidth )
*imgWidth = imgBox->width;
if ( sideLabelWidth )
*sideLabelWidth = imgBox->sideLabelWidth;
if (imgBox->showPortal)
{
if ( portalStart )
*portalStart = imgBox->portalStart;
@@ -1525,32 +1537,32 @@
//return slRemoveEl(&(imgBox->imgTracks),imgTrack);
//}
void imgBoxTracksNormalizeOrder(struct imgBox *imgBox)
// This routine sorts the imgTracks
{
slSort(&(imgBox->imgTracks), imgTrackOrderCmp);
}
void imgBoxShow(struct dyString **dy,struct imgBox *imgBox,int indent)
// show the imgBox
{
if (imgBox)
{
struct dyString *myDy = addIndent(dy,indent);
- dyStringPrintf(myDy,"imgBox: %s.%s:%d-%d %c width:%d basePer:%g sideLabel:%s w:%d "
- "portal:%s %d-%d w:%d",(imgBox->db ? imgBox->db : ""),
+ dyStringPrintf(myDy,"imgBox: %s.%s:%ld-%ld %c width:%d basePer:%g sideLabel:%s w:%d "
+ "portal:%s %ld-%ld w:%d",(imgBox->db ? imgBox->db : ""),
(imgBox->chrom ? imgBox->chrom : ""),imgBox->chromStart,imgBox->chromEnd,
(imgBox->plusStrand ? '+' : '-'),imgBox->width,imgBox->basesPerPixel,
(imgBox->showSideLabel ? "Yes" : "No"),imgBox->sideLabelWidth,
(imgBox->showPortal ? "Yes" : "No"),
imgBox->portalStart,imgBox->portalEnd,imgBox->portalWidth);
indent++;
struct image *img;
for (img=imgBox->images;img!=NULL;img=img->next)
imgShow(&myDy,img,"data ",indent);
if (imgBox->bgImg)
imgShow(&myDy,imgBox->bgImg,"bgnd ",indent);
if (dy == NULL)
warn("%s",dyStringCannibalize(&myDy));
struct imgTrack *imgTrack = NULL;
@@ -1595,95 +1607,95 @@
if (imgBox->db == NULL)
{
if (verbose)
warn("imgBox has no db.");
return FALSE;
}
if (imgBox->db == NULL)
{
if (verbose)
warn("imgBox has no chrom.");
return FALSE;
}
if (imgBox->chromStart >= imgBox->chromEnd)
{
if (verbose)
- warn("imgBox(%s.%s:%d-%d) has bad genome range.",
+ warn("imgBox(%s.%s:%ld-%ld) has bad genome range.",
imgBox->db,imgBox->chrom,imgBox->chromStart,imgBox->chromEnd);
return FALSE;
}
if (imgBox->portalStart >= imgBox->portalEnd
|| imgBox->portalStart < imgBox->chromStart
|| imgBox->portalEnd > imgBox->chromEnd )
{
if (verbose)
- warn("imgBox(%s.%s:%d-%d) has bad portal range: %d-%d",
+ warn("imgBox(%s.%s:%ld-%ld) has bad portal range: %ld-%ld",
imgBox->db,imgBox->chrom,imgBox->chromStart,imgBox->chromEnd,
imgBox->portalStart,imgBox->portalEnd);
return FALSE;
}
// Must have images
if (imgBox->images == NULL)
{
if (verbose)
- warn("imgBox(%s.%s:%d-%d) has no images",
+ warn("imgBox(%s.%s:%ld-%ld) has no images",
imgBox->db,imgBox->chrom,imgBox->chromStart,imgBox->chromEnd);
return FALSE;
}
// Must have tracks
if (imgBox->imgTracks == NULL)
{
if (verbose)
- warn("imgBox(%s.%s:%d-%d) has no imgTracks",
+ warn("imgBox(%s.%s:%ld-%ld) has no imgTracks",
imgBox->db,imgBox->chrom,imgBox->chromStart,imgBox->chromEnd);
return FALSE;
}
struct imgTrack *imgTrack = imgBox->imgTracks;
while (imgTrack != NULL)
{
if (!imgTrackIsComplete(imgTrack,verbose))
{
if (verbose)
- warn("imgBox(%s.%s:%d-%d) has bad track - being skipped.",
+ warn("imgBox(%s.%s:%ld-%ld) has bad track - being skipped.",
imgBox->db,imgBox->chrom,imgBox->chromStart,imgBox->chromEnd);
slRemoveEl(&(imgBox->imgTracks),imgTrack);
imgTrackFree(&imgTrack);
imgTrack = imgBox->imgTracks; // start over
continue;
//return FALSE;
}
if (differentWord(imgTrack->db, imgBox->db)
|| differentWord(imgTrack->chrom, imgBox->chrom)
|| imgTrack->chromStart != imgBox->chromStart
|| imgTrack->chromEnd != imgBox->chromEnd
|| imgTrack->plusStrand != imgBox->plusStrand)
{
if (verbose)
- warn("imgBox(%s.%s:%d-%d) has inconsistent imgTrack for %s.%s:%d-%d",
+ warn("imgBox(%s.%s:%ld-%ld) has inconsistent imgTrack for %s.%s:%ld-%ld",
imgBox->db, imgBox->chrom, imgBox->chromStart, imgBox->chromEnd,
imgTrack->db,imgTrack->chrom,imgTrack->chromStart,imgTrack->chromEnd);
return FALSE;
}
struct imgSlice *slice = NULL;
for (slice = imgTrack->slices; slice != NULL; slice = slice->next )
{
// Every slice that has an image must point to an image owned by the imgBox
if (slice->parentImg && (slIxFromElement(imgBox->images,slice->parentImg) == -1))
{
if (verbose)
- warn("imgBox(%s.%s:%d-%d) has slice(%s) for unknown image (%s)",
+ warn("imgBox(%s.%s:%ld-%ld) has slice(%s) for unknown image (%s)",
imgBox->db,imgBox->chrom,imgBox->chromStart,imgBox->chromEnd,
sliceTypeToString(slice->type),slice->parentImg->file);
return FALSE;
}
}
imgTrack = imgTrack->next;
}
return TRUE;
}
void imgBoxFree(struct imgBox **pImgBox)
// frees all memory assocated with an imgBox (including images and imgTracks)
{
if (pImgBox != NULL && *pImgBox != NULL)
{
@@ -1760,53 +1772,54 @@
static void imageDraw(struct imgBox *imgBox,struct imgTrack *imgTrack,struct imgSlice *slice,
char *name,int offsetX,int offsetY,boolean useMap)
// writes an image as HTML
{
if (slice->parentImg && slice->parentImg->file != NULL)
{
hPrintf(" parentImg->file,offsetX,offsetY);
// Problem: dragScroll beyond left shows unsightly leftLabel!
// Tried clip:rect() but this only works with position:absolute!
// May need to split image betweeen side label and data!!! That is a big change.
if (useMap)
hPrintf(" usemap='#map_%s'",name);
hPrintf(" class='sliceImg %s",sliceTypeToClass(slice->type));
- if (slice->type==stData && imgBox->showPortal)
+ if (slice->type==stData && imgBox->showPortal) // || slice->type==stCenter will make centerLabels scroll too
hPrintf(" panImg'");
else
hPrintf("'");
if (slice->title != NULL)
hPrintf(" title='%s'", attributeEncode(slice->title) ); // Adds slice wide title
else if (slice->parentImg->title != NULL)
hPrintf("' title='%s'", attributeEncode(slice->parentImg->title) );// Adds image wide title
if (slice->type==stData || slice->type==stCenter)
hPrintf(" ondrag='{return false;}'");
hPrintf(">");
}
else
{
int height = slice->height;
// Adjustment for centerLabel Conditional
if (imgTrack->centerLabelSeen == clNotSeen
&& (slice->type == stSide || slice->type == stButton))
{
struct imgSlice *centerSlice = imgTrackSliceGetByType(imgTrack,stCenter);
if (centerSlice != NULL)
height -= centerSlice->height;
}
+
hPrintf("