src/hg/instinct/hgBamBam/hgAnnotations.c 1.3
1.3 2010/05/31 00:02:34 jsanborn
big update
Index: src/hg/instinct/hgBamBam/hgAnnotations.c
===================================================================
RCS file: /projects/compbio/cvsroot/kent/src/hg/instinct/hgBamBam/hgAnnotations.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -b -B -U 1000000 -r1.2 -r1.3
--- src/hg/instinct/hgBamBam/hgAnnotations.c 26 May 2010 05:20:33 -0000 1.2
+++ src/hg/instinct/hgBamBam/hgAnnotations.c 31 May 2010 00:02:34 -0000 1.3
@@ -1,929 +1,1413 @@
/********************************************************************************/
/* Copyright 2007-2009 -- The Regents of the University of California */
/********************************************************************************/
/* hgAnnotations.c
* Work in progress -- to draw small region to full genome annotation tracks (i.e. RefSeq)
* in concise space.
*/
#define EXPR_DATA_SHADES 16
#define DEFAULT_MAX_DEVIATION 0.7
#define COLOR_SCALE 1
#define GENE_HEIGHT 10
#include <limits.h>
#include "common.h"
#include "cart.h"
#include "vGfx.h"
#include "hvGfx.h"
#include "hCommon.h"
#include "hdb.h"
#include "cytoBand.h"
#include "hCytoBand.h"
#include "spaceSaver.h"
#include "hgBamBam.h"
+#include "chromColors.h"
static char const rcsid[] = "$Id$";
static char *heatMapDbProfile = "localDb"; // database profile to use
struct bed *getTable(struct sqlConnection *conn, char *tableName, char *chromName)
{
char **row = NULL;
char query[256];
if (chromName)
safef(query, sizeof(query), "select * from %s where chrom = \"%s\"",
tableName, chromName);
else
safef(query, sizeof(query), "select * from %s", tableName);
if (!sqlExists(conn, query))
return NULL;
struct sqlResult *sr = sqlGetResult(conn, query);
struct bed *tuple = NULL;
struct bed *tupleList = NULL;
while ((row = sqlNextRow(sr)) != NULL)
{
struct genePred *gp = genePredLoad(row+1);
tuple = bedFromGenePred(gp);
if (row[12])
tuple->name = cloneString(row[12]); // switch to name2;
genePredFree(&gp);
slAddHead(&tupleList, tuple);
}
sqlFreeResult(&sr);
return tupleList;
}
+struct bed *getSNPs(struct sqlConnection *conn, char *tableName, char *chromName,
+ int start, int stop)
+{
+char **row = NULL;
+char query[256];
+if (chromName)
+ safef(query, sizeof(query),
+ "select * from %s where chrom = \"%s\" and chromStart > %d and chromEnd <= %d",
+ tableName, chromName, start, stop);
+else
+ safef(query, sizeof(query), "select * from %s", tableName);
+
+if (!sqlExists(conn, query))
+ return NULL;
+
+struct sqlResult *sr = sqlGetResult(conn, query);
+struct bed *bed = NULL;
+struct bed *bedList = NULL;
+
+while ((row = sqlNextRow(sr)) != NULL)
+ {
+ AllocVar(bed);
+ bed->chrom = cloneString(row[0]);
+ bed->chromStart = atoi(row[1]);
+ bed->chromEnd = atoi(row[2]);
+ bed->thickStart = bed->chromStart;
+ bed->thickEnd = bed->chromEnd;
+ bed->name = cloneString(row[4]);
+ slAddHead(&bedList, bed);
+ }
+
+sqlFreeResult(&sr);
+return bedList;
+}
+
int hmPixelCmpCount(const void *va, const void *vb)
/* Compare to sort columns based on priority. */
{
const struct hmPixel *a = *((struct hmPixel **)va);
const struct hmPixel *b = *((struct hmPixel **)vb);
float dif = a->count - b->count;
if (dif < 0)
return -1;
else if (dif > 0)
return 1;
else
return 0;
}
void drawBox(struct vGfx *vg, double x1, double x2, int pStart, int y, int h, Color valCol)
{
int x = round(x1) + pStart;
int w = round(x2) - round(x1);
if (w == 0)
w = 1;
vgBox(vg, x, y, w, h, valCol);
}
void addHmPixel(struct hmPixel **hmList, struct hash *pixelHash,
char mod, double x1, double x2, int pStart, int y, int h)
{
/* calculate starting position and width of box to draw */
int x = round(x1) + pStart;
int w = round(x2) - round(x1);
if (w == 0)
w = 1;
char pixelStr[32];
safef(pixelStr, sizeof(pixelStr), "%d,%c", x, mod);
struct hmPixel *hm;
struct hashEl *el = hashLookup(pixelHash, pixelStr);
if (!el)
{
hm = AllocA(struct hmPixel);
hm->x = x;
hm->y = y;
hm->w = w;
hm->h = h;
hm->val = 0.0;
hm->count = 0;
slAddHead(hmList, hm);
hashAdd(pixelHash, pixelStr, hm);
}
else
hm = el->val;
if (w > hm->w)
hm->w = w;
hm->count += 1;
}
void drawTable(struct vGfx *vg, struct settings *settings,
- char *db, char *tableName, int height)
+ char *db, char *tableName, char *profile, int height)
/* Draw chromosome graph on all chromosomes in layout at given
* y offset and height. */
{
if (!settings)
return;
/* get remote database connection */
-struct sqlConnection *conn = hAllocConn(db);
+struct sqlConnection *conn;
+if (!profile)
+ conn = hAllocConn(db);
+else
+ conn = hAllocConnProfile(profile, db);
struct bed *nb, *ghBed = NULL;
-double pixPerBase = (double) settings->width / (double) settings->totalBases;
+double pixPerBase = (double) settings->dataWidth / (double) settings->totalBases;
Color upShades[EXPR_DATA_SHADES];
static struct rgbColor zeroColor = {0, 0, 0}; // black
static struct rgbColor highColor = {255, 0, 0}; // red
vgMakeColorGradient(vg, &zeroColor, &highColor, EXPR_DATA_SHADES, upShades);
struct hash *pixelHash = hashNew(0);
struct hmPixel *hm, *hmList = NULL;
struct chromLay *cl;
for(cl = settings->layoutList; cl; cl = cl->next)
{
ghBed = getTable(conn, tableName, cl->chrom);
if (!ghBed)
continue;
struct bed *filterList =
bedFilterListInRange(ghBed, NULL, cl->chrom, cl->baseStart, cl->baseEnd);
int pStart = cl->pxStart;
int baseStart = cl->baseStart;
for(nb = filterList; nb; nb = nb->next)
{
int cStart = nb->chromStart;
int cEnd = nb->chromEnd;
double x1, x2;
int baseline = cStart - baseStart;
x1 = pixPerBase * (double) (cStart - baseStart);
x2 = pixPerBase * (double) (cEnd - baseStart);
if ( (x2 - x1) > 2.0)
{ /* width > two pixels, attempt to draw exon/utr structure
* similar to genome browser */
addHmPixel(&hmList, pixelHash, 'i', x1, x2, pStart, 4, 1);
int tStart = nb->thickStart - nb->chromStart;
int tEnd = nb->thickEnd - nb->chromStart;
int i, bStart, bEnd;
for (i = 0; i < nb->blockCount; i++)
{
bStart = nb->chromStarts[i];
bEnd = bStart + nb->blockSizes[i];
if (bStart < tStart)
{ /* 5' utr region */
x1 = pixPerBase * (double) (bStart + baseline);
if (bEnd < tStart)
x2 = pixPerBase * (double) (bEnd + baseline);
else
x2 = pixPerBase * (double) (tStart + baseline);
addHmPixel(&hmList, pixelHash, 'u', x1, x2, pStart, 2, 5);
if (bEnd > tEnd)
{ /* coding region inside single block */
x1 = pixPerBase * (double) (tStart + baseline);
x2 = pixPerBase * (double) (tEnd + baseline);
addHmPixel(&hmList, pixelHash, 'c', x1, x2, pStart, 0, 9);
x1 = pixPerBase * (double) (tEnd + baseline);
x2 = pixPerBase * (double) (bEnd + baseline);
addHmPixel(&hmList, pixelHash, 'u', x1, x2, pStart, 2, 5);
}
else if (bEnd > tStart)
{ /* coding region downstream of 5' utr */
x1 = pixPerBase * (double) (tStart + baseline);
x2 = pixPerBase * (double) (bEnd + baseline);
addHmPixel(&hmList, pixelHash, 'c', x1, x2, pStart, 0, 9);
}
}
else if (bEnd > tEnd)
{ /* 3' utr region */
if (bStart > tEnd)
x1 = pixPerBase * (double) (bStart + baseline);
else
x1 = pixPerBase * (double) (tEnd + baseline);
x2 = pixPerBase * (double) (bEnd + baseline);
addHmPixel(&hmList, pixelHash, 'u', x1, x2, pStart, 2, 5);
if (bStart < tEnd)
{ /* coding region upstream of 3' utr */
x1 = pixPerBase * (double) (bStart + baseline);
x2 = pixPerBase * (double) (tEnd + baseline);
addHmPixel(&hmList, pixelHash, 'c', x1, x2, pStart, 0, 9);
}
}
else
{ /* block is all coding region, no utr */
x1 = pixPerBase * (double) (bStart + baseline);
x2 = pixPerBase * (double) (bEnd + baseline);
addHmPixel(&hmList, pixelHash, 'c', x1, x2, pStart, 0, 9);
}
}
}
else
{ /* width < 2 pixels -- gene too dense, so just draw one large block */
x1 = pixPerBase * (double) (cStart - baseStart);
x2 = pixPerBase * (double) (cEnd - baseStart);
addHmPixel(&hmList, pixelHash, 'f', x1, x2, pStart, 0, 9);
}
}
bedFreeList(&ghBed);
}
hFreeConn(&conn);
if (!hmList) // nothing to draw.
return;
slSort(&hmList, hmPixelCmpCount);
struct hmPixel *last = slLastEl(hmList);
int maxVal = last->count;
+vgSetClip(vg, settings->dataOffsetX, 0, settings->dataWidth, settings->height);
+
Color valCol;
for (hm = hmList; hm ; hm = hm->next)
{
double val = (double) hm->count / (double) maxVal;
int colorIndex = (int)(val * (EXPR_DATA_SHADES-1.0) );
/* Clip color index to fit inside of array, since we may have brightened it. */
if (colorIndex < 0) colorIndex = 0;
if (colorIndex >= EXPR_DATA_SHADES)
colorIndex = EXPR_DATA_SHADES-1;
valCol = upShades[colorIndex];
- vgBox(vg, hm->x, hm->y, hm->w, hm->h, valCol);
+ vgBox(vg, hm->x, hm->y + settings->dataOffsetY, hm->w, hm->h, valCol);
}
+
+vgUnclip(vg);
}
struct spaceSaver *bedToSS(struct settings *settings, char *db,
char *tableName, boolean drawLabels)
{
if (!settings)
return NULL;
/* get remote database connection */
struct sqlConnection *conn = hAllocConn(db);
struct bed *nb, *ghBed = NULL;
struct chromLay *cl = settings->layoutList;
ghBed = getTable(conn, tableName, cl->chrom);
if (!ghBed)
return NULL;
struct bed *filterList =
bedFilterListInRange(ghBed, NULL, cl->chrom, cl->baseStart, cl->baseEnd);
struct spaceSaver *ss = spaceSaverNew(cl->pxStart, cl->pxStart + cl->pxWidth, 100);
-double pixPerBase = (double) settings->width / (double) settings->totalBases;
+double pixPerBase = (double) cl->pxWidth / (double) settings->totalBases;
int baseStart = cl->baseStart;
for(nb = filterList; nb; nb = nb->next)
{
int cStart = nb->chromStart;
int cEnd = nb->chromEnd;
- int x1 = round(pixPerBase * (double) (cStart - baseStart));
- int x2 = round(pixPerBase * (double) (cEnd - baseStart));
+ int x1 = round(pixPerBase * (double) (cStart - baseStart)) + cl->pxStart;
+ int x2 = round(pixPerBase * (double) (cEnd - baseStart)) + cl->pxStart;
+
+ if (drawLabels)
+ x1 -= mgFontStringWidth(settings->font, nb->name) + 4;
+ spaceSaverAdd(ss, x1, x2, nb);
+ }
+spaceSaverFinish(ss);
+
+return ss;
+}
+
+struct spaceSaver *snpsToSS(struct settings *settings, char *db,
+ char *tableName, boolean drawLabels)
+{
+if (!settings)
+ return NULL;
+
+/* get remote database connection */
+struct sqlConnection *conn = hAllocConnProfile(heatMapDbProfile, db);
+
+struct bed *nb, *ghBed = NULL;
+
+struct chromLay *cl = settings->layoutList;
+
+ghBed = getSNPs(conn, tableName, cl->chrom, cl->baseStart, cl->baseEnd);
+if (!ghBed)
+ return NULL;
+
+struct spaceSaver *ss = spaceSaverNew(cl->pxStart, cl->pxStart + cl->pxWidth, 100);
+
+double pixPerBase = (double) settings->dataWidth / (double) settings->totalBases;
+
+int baseStart = cl->baseStart;
+
+for(nb = ghBed; nb; nb = nb->next)
+ {
+ int cStart = nb->chromStart;
+ int cEnd = nb->chromEnd;
+
+ int x1 = round(pixPerBase * (double) (cStart - baseStart)) + cl->pxStart;
+ int x2 = round(pixPerBase * (double) (cEnd - baseStart)) + cl->pxStart;
if (drawLabels)
x1 -= mgFontStringWidth(settings->font, nb->name) + 4;
spaceSaverAdd(ss, x1, x2, nb);
}
spaceSaverFinish(ss);
return ss;
}
void drawBedTable(struct vGfx *vg, struct settings *settings,
struct spaceSaver *ss, boolean drawLabels)
/* Draw chromosome graph on all chromosomes in layout at given
* y offset and height. */
{
-double pixPerBase = (double) settings->width / (double) settings->totalBases;
+double pixPerBase = (double) settings->dataWidth / (double) settings->totalBases;
Color upShades[EXPR_DATA_SHADES];
static struct rgbColor zeroColor = {0, 0, 0}; // black
static struct rgbColor highColor = {255, 0, 0}; // red
vgMakeColorGradient(vg, &zeroColor, &highColor, EXPR_DATA_SHADES, upShades);
struct chromLay *cl = settings->layoutList;
int pStart = cl->pxStart;
int baseStart = cl->baseStart;
+vgSetClip(vg, settings->dataOffsetX, 0, settings->dataWidth, settings->height);
+
struct spaceNode *sn;
for (sn = ss->nodeList; sn; sn = sn->next)
{
- int row = sn->row * GENE_HEIGHT;
+ int row = sn->row * GENE_HEIGHT + settings->dataOffsetY;
struct bed *nb = (struct bed *) sn->val;
int cStart = nb->chromStart;
int cEnd = nb->chromEnd;
double x1, x2;
int baseline = cStart - baseStart;
x1 = pixPerBase * (double) (cStart - baseStart);
x2 = pixPerBase * (double) (cEnd - baseStart);
if (drawLabels)
- vgTextRight(vg, 0, row, x1-2, settings->fontHeight,
+ vgTextRight(vg, 0, row, x1-2+pStart, settings->fontHeight,
MG_BLACK, settings->font, nb->name);
if ( (x2 - x1) > 2.0)
{ /* width > two pixels, attempt to draw exon/utr structure
* similar to genome browser */
drawBox(vg, x1, x2, pStart, 4 + row, 1, MG_BLACK);
int tStart = nb->thickStart - nb->chromStart;
int tEnd = nb->thickEnd - nb->chromStart;
int i, bStart, bEnd;
for (i = 0; i < nb->blockCount; i++)
{
bStart = nb->chromStarts[i];
bEnd = bStart + nb->blockSizes[i];
if (bStart < tStart)
{ /* 5' utr region */
x1 = pixPerBase * (double) (bStart + baseline);
if (bEnd < tStart)
x2 = pixPerBase * (double) (bEnd + baseline);
else
x2 = pixPerBase * (double) (tStart + baseline);
drawBox(vg, x1, x2, pStart, 2 + row, 5, MG_BLACK);
if (bEnd > tEnd)
{ /* coding region inside single block */
x1 = pixPerBase * (double) (tStart + baseline);
x2 = pixPerBase * (double) (tEnd + baseline);
drawBox(vg, x1, x2, pStart, 0 + row, 9, MG_BLACK);
x1 = pixPerBase * (double) (tEnd + baseline);
x2 = pixPerBase * (double) (bEnd + baseline);
drawBox(vg, x1, x2, pStart, 0 + row, 9, MG_BLACK);
}
else if (bEnd > tStart)
{ /* coding region downstream of 5' utr */
x1 = pixPerBase * (double) (tStart + baseline);
x2 = pixPerBase * (double) (bEnd + baseline);
drawBox(vg, x1, x2, pStart, 0 + row, 9, MG_BLACK);
}
}
else if (bEnd > tEnd)
{ /* 3' utr region */
if (bStart > tEnd)
x1 = pixPerBase * (double) (bStart + baseline);
else
x1 = pixPerBase * (double) (tEnd + baseline);
x2 = pixPerBase * (double) (bEnd + baseline);
drawBox(vg, x1, x2, pStart, 2 + row, 5, MG_BLACK);
if (bStart < tEnd)
{ /* coding region upstream of 3' utr */
x1 = pixPerBase * (double) (bStart + baseline);
x2 = pixPerBase * (double) (tEnd + baseline);
drawBox(vg, x1, x2, pStart, 0 + row, 9, MG_BLACK);
}
}
else
{ /* block is all coding region, no utr */
x1 = pixPerBase * (double) (bStart + baseline);
x2 = pixPerBase * (double) (bEnd + baseline);
drawBox(vg, x1, x2, pStart, 0 + row, 9, MG_BLACK);
}
}
}
else
{ /* width < 2 pixels -- gene too dense, so just draw one large block */
x1 = pixPerBase * (double) (cStart - baseStart);
x2 = pixPerBase * (double) (cEnd - baseStart);
drawBox(vg, x1, x2, pStart, 0 + row, 9, MG_BLACK);
}
}
+vgUnclip(vg);
+spaceSaverFree(&ss);
+}
+
+void drawSnpTable(struct vGfx *vg, struct settings *settings,
+ struct spaceSaver *ss, boolean drawLabels)
+/* Draw chromosome graph on all chromosomes in layout at given
+ * y offset and height. */
+{
+if (!settings | !ss)
+ return;
+
+double pixPerBase = (double) settings->dataWidth / (double) settings->totalBases;
+
+Color upShades[EXPR_DATA_SHADES];
+static struct rgbColor zeroColor = {0, 0, 0}; // black
+static struct rgbColor highColor = {255, 0, 0}; // red
+vgMakeColorGradient(vg, &zeroColor, &highColor, EXPR_DATA_SHADES, upShades);
+
+struct chromLay *cl = settings->layoutList;
+int pStart = cl->pxStart;
+int baseStart = cl->baseStart;
+
+struct spaceNode *sn;
+for (sn = ss->nodeList; sn; sn = sn->next)
+ {
+ int row = sn->row * GENE_HEIGHT + settings->dataOffsetY;
+ struct bed *nb = (struct bed *) sn->val;
+
+ int cStart = nb->chromStart;
+ int cEnd = nb->chromEnd;
+
+ double x1, x2;
+
+ x1 = pixPerBase * (double) (cStart - baseStart);
+ x2 = pixPerBase * (double) (cEnd - baseStart);
+
+ if (drawLabels)
+ vgTextRight(vg, 0, row, x1-2, settings->fontHeight,
+ MG_BLACK, settings->font, nb->name);
+
+ x1 = pixPerBase * (double) (cStart - baseStart);
+ x2 = pixPerBase * (double) (cEnd - baseStart);
+ drawBox(vg, x1, x2, pStart, 0 + row, 9, MG_BLACK);
+ }
spaceSaverFree(&ss);
}
char *annotationWholeGenome(struct settings *settings, char *db, char *tableName)
{
int width = settings->width;
int height = settings->height; // was set to 10
if (width * height == 0)
return NULL;
struct tempName md5Tn;
char *strToHash = cartSettingsString(bbPrefix, "annotationGif");
trashDirMD5File(&md5Tn, "hgh", ".gif", strToHash);
off_t size = fileSize(md5Tn.forCgi);
if (!fileExists(md5Tn.forCgi) || (size == 0) || DEBUG)
{
struct hvGfx *vg = hvGfxOpenGif(width, height, md5Tn.forCgi, FALSE);
- drawTable(vg->vg, settings, db, tableName, height);
+ prepareImage(vg->vg, settings);
+
+ drawTable(vg->vg, settings, db, tableName, NULL, height);
hvGfxClose(&vg);
}
char *filename = replaceChars(md5Tn.forHtml, "..", "");
return filename;
}
char *annotationSingleGenome(struct settings *settings, char *db, char *tableName)
{
struct chromLay *cl = settings->layoutList;
boolean drawLabels = TRUE;
if (cl->baseEnd - cl->baseStart > 50000000)
drawLabels = FALSE;
struct spaceSaver *ss = bedToSS(settings, db, tableName, drawLabels);
int maxRow = -1;
struct spaceNode *sn;
for (sn = ss->nodeList; sn; sn = sn->next)
{
if (sn->row > maxRow)
maxRow = sn->row;
}
if (maxRow == -1)
return NULL;
-settings->height = (maxRow + 1) * GENE_HEIGHT;
-
+settings->dataHeight = (maxRow + 1) * GENE_HEIGHT;
+settings->height = settings->dataHeight + TITLE_HEIGHT;
struct tempName md5Tn;
char *strToHash = cartSettingsString(bbPrefix, "annotationGif");
trashDirMD5File(&md5Tn, "hgh", ".gif", strToHash);
off_t size = fileSize(md5Tn.forCgi);
if (!fileExists(md5Tn.forCgi) || (size == 0) || DEBUG)
{
struct hvGfx *vg = hvGfxOpenGif(settings->width, settings->height, md5Tn.forCgi, FALSE);
+ prepareImage(vg->vg, settings);
+
drawBedTable(vg->vg, settings, ss, drawLabels);
hvGfxClose(&vg);
}
char *filename = replaceChars(md5Tn.forHtml, "..", "");
return filename;
}
char *annotationGif(struct settings *settings, char *tableName)
/* Create genome GIF file and HT that includes it. */
{
if (!settings || !tableName)
return NULL;
char *db = "hg18";
if (slCount(settings->layoutList) > 1)
return annotationWholeGenome(settings, db, tableName);
else
return annotationSingleGenome(settings, db, tableName);
}
+
+char *snpsWholeGenome(struct settings *settings, char *db, char *tableName)
+{
+int width = settings->width;
+int height = 10; // was set to 10
+
+if (width * height == 0)
+ return NULL;
+
+struct tempName md5Tn;
+char *strToHash = cartSettingsString(bbPrefix, "snpsGif");
+trashDirMD5File(&md5Tn, "hgh", ".gif", strToHash);
+
+off_t size = fileSize(md5Tn.forCgi);
+if (!fileExists(md5Tn.forCgi) || (size == 0) || DEBUG)
+ {
+ struct hvGfx *vg = hvGfxOpenGif(width, height, md5Tn.forCgi, FALSE);
+
+ drawTable(vg->vg, settings, db, tableName, heatMapDbProfile, height);
+
+ hvGfxClose(&vg);
+ }
+
+char *filename = replaceChars(md5Tn.forHtml, "..", "");
+return filename;
+}
+
+char *snpsSingleGenome(struct settings *settings, char *db, char *tableName)
+{
+if (!settings)
+ return NULL;
+
+struct chromLay *cl = settings->layoutList;
+
+boolean drawLabels = TRUE;
+if (cl->baseEnd - cl->baseStart > 500000)
+ drawLabels = FALSE;
+
+struct spaceSaver *ss = snpsToSS(settings, db, tableName, drawLabels);
+if (!ss)
+ return NULL;
+
+int maxRow = -1;
+struct spaceNode *sn;
+for (sn = ss->nodeList; sn; sn = sn->next)
+ {
+ if (sn->row > maxRow)
+ maxRow = sn->row;
+ }
+if (maxRow == -1)
+ return NULL;
+
+settings->dataHeight = (maxRow + 1) * GENE_HEIGHT;
+settings->height = settings->dataHeight + TITLE_HEIGHT;
+
+struct tempName md5Tn;
+char *strToHash = cartSettingsString(bbPrefix, "snpsGif");
+trashDirMD5File(&md5Tn, "hgh", ".gif", strToHash);
+
+off_t size = fileSize(md5Tn.forCgi);
+if (!fileExists(md5Tn.forCgi) || (size == 0) || DEBUG)
+ {
+ struct hvGfx *vg = hvGfxOpenGif(settings->width, settings->height, md5Tn.forCgi, FALSE);
+
+ prepareImage(vg->vg, settings);
+
+ drawSnpTable(vg->vg, settings, ss, drawLabels);
+
+ hvGfxClose(&vg);
+ }
+
+char *filename = replaceChars(md5Tn.forHtml, "..", "");
+return filename;
+}
+
+char *snpsGif(struct settings *settings, char *tableName)
+/* Create genome GIF file and HT that includes it. */
+{
+if (!settings || !tableName)
+ return NULL;
+
+char *db = "pdata";
+
+if (slCount(settings->layoutList) > 1)
+ return NULL; // don't do whole genome yet. snpsWholeGenome(settings, db, tableName);
+else
+ {
+ struct chromLay *cl = settings->layoutList;
+ if (!cl)
+ return NULL;
+ if ((cl->baseEnd - cl->baseStart) > 5000000) // large region, compress.
+ return NULL; // snpsWholeGenome(settings, db, tableName);
+ else
+ return snpsSingleGenome(settings, db, tableName);
+ }
+return NULL;
+}
+
double basesInScale(double numBases)
{
double exp = floor(log(numBases)/log(10.0));
if (exp < 0.0)
exp = 0.0;
double divisor = pow(10.0, exp);
double rescaledBases = numBases / divisor;
double maxBases = rescaledBases / 2.0;
double bases = 0.0;
if (maxBases >= 5.0)
bases = 5.0 * divisor;
else if (maxBases >= 2.0)
bases = 2.0 * divisor;
else if (maxBases >= 1.0)
bases = 1.0 * divisor;
else if (maxBases >= 0.5)
bases = 0.5 * divisor;
else if (maxBases >= 0.2)
bases = 0.2 * divisor;
else if (maxBases >= 0.1)
bases = 0.1 * divisor;
bases = floor(bases);
return bases;
}
struct hash *getCytoBandHash(struct sqlConnection *conn)
{
if (!sqlTableExists(conn, "cytoBand"))
return NULL;
char **row;
char query[128];
safef(query, sizeof(query), "select * from cytoBand");
struct hash *cbHash = hashNew(0);
struct sqlResult *sr = sqlGetResult(conn, query);
while ((row = sqlNextRow(sr)) != NULL)
{
struct cytoBand *cb = cytoBandLoad(row);
struct hashEl *el = hashLookup(cbHash, cb->chrom);
struct cytoBand *cbList = NULL;
if (el)
cbList = el->val;
slAddTail(&cbList, cb);
if (!el) // add first member of list to hash
hashAdd(cbHash, cb->chrom, cbList);
}
sqlFreeResult(&sr);
return cbHash;
}
-void drawIdeogram(struct hvGfx *hvg, struct settings *settings, int yOff)
+void drawIdeogram(struct hvGfx *hvg, struct settings *settings, struct chromLay *clList, int yOff)
{
if (!settings)
return;
struct vGfx *vg = hvg->vg;
struct sqlConnection *conn = hAllocConnProfile(heatMapDbProfile, "hg18");
struct hash *cbHash = getCytoBandHash(conn);
hFreeConn(&conn);
if (!cbHash)
return;
/* Make grayscale for bands */
int maxShade = 9;
Color shadesOfGray[10+1];
static struct rgbColor black = {0, 0, 0};
static struct rgbColor white = {255, 255, 255};
vgMakeColorGradient(vg, &white, &black, 10, shadesOfGray);
shadesOfGray[10] = MG_RED; // to check for overflow, should never see red.
-int width = settings->width;
-
struct chromLay *cl;
-vgSetClip(vg, 0, yOff, width, CYTO_HEIGHT);
+vgSetClip(vg, settings->dataOffsetX, 0, settings->dataWidth, settings->height);
-for (cl = settings->layoutList; cl; cl = cl->next)
+for (cl = clList; cl; cl = cl->next)
{
struct hashEl *el = hashLookup(cbHash, cl->chrom);
if (!el)
continue;
struct cytoBand *cb, *cbList = el->val;
int pixStart = cl->pxStart;
int pixEnd = cl->pxStart + cl->pxWidth;
int pixSize = cl->pxWidth;
unsigned bStart = cl->baseStart;
unsigned bEnd = cl->baseEnd;
unsigned bSize = bEnd - bStart;
double basesPerPixel = (double) bSize / (double) pixSize;
int xBuffer = 0; //Start = pixStart;
if (pixStart == 0)
xBuffer = 0;
/* Draw box around cytoband */
vgBox(vg, pixStart+1, yOff, pixSize-1, 1, MG_BLACK);
vgBox(vg, pixStart+1, yOff + CYTO_HEIGHT-1, pixSize-1, 1, MG_BLACK);
unsigned minBand = INT_MAX;
unsigned maxBand = 0;
for (cb = cbList; cb; cb = cb->next)
{
unsigned start = cb->chromStart; // our bases start at 1 TODO: FIX!
unsigned stop = cb->chromEnd;
if ((stop < bStart) || (start > bEnd)) // out of scope
continue;
int pStart = round(((double) start - (double) bStart) / basesPerPixel) + pixStart;
if (pStart < pixStart)
pStart = pixStart;
if (pStart <= 0)
pStart = 1;
int pEnd = round(((double) stop - (double) bStart) / basesPerPixel) + pixStart;
if (pEnd >= pixEnd)
pEnd = pixEnd;
Color col = hCytoBandColor(cb, hvg, FALSE, MG_BLACK, MG_WHITE,
shadesOfGray, maxShade);
vgBox(vg, pStart, yOff+1, (pEnd - pStart), CYTO_HEIGHT-2, col);
Color textCol = hvGfxContrastingColor(hvg, col);
char *pt = cb->name;
int fullWidth = mgFontStringWidth(settings->font, pt);
int shortWidth = mgFontStringWidth(settings->font, pt+1);
if (fullWidth < (pEnd - pStart))
vgTextCentered(vg, pStart, yOff+1, (pEnd - pStart), CYTO_HEIGHT-2,
textCol, settings->font, pt);
else if (shortWidth < (pEnd - pStart))
vgTextCentered(vg, pStart, yOff+1, (pEnd - pStart), CYTO_HEIGHT-2,
textCol, settings->font, pt+1);
if (start < minBand)
minBand = start;
if (stop > maxBand)
maxBand = stop;
}
/* If very near left/right edges, if we see the chromosome edge */
if (abs(minBand - bStart) < 100)
vgBox(vg, pixStart, yOff+1, 1, CYTO_HEIGHT-2, MG_BLACK);
if (abs(maxBand- bEnd) < 100)
vgBox(vg, pixEnd-1, yOff+1, 1, CYTO_HEIGHT-2, MG_BLACK);
for (cb = cbList; cb; cb = cb->next)
{
/* If centromere do some drawing. */
if(!sameString(cb->gieStain, "acen"))
continue;
int cenLeft, cenRight, cenTop, cenBottom;
/* Get the coordinates of the edges of the centromere. */
cenLeft = round(((double) cb->chromStart - (double) bStart) / basesPerPixel) + pixStart;
cenRight = round(((double) cb->next->chromEnd - (double) bStart)/basesPerPixel) + pixStart;
cenTop = yOff + CYTO_HEIGHT;
cenBottom = yOff;
if (cenLeft < 0 && cenRight < 0)
break;
if (cenLeft > pixEnd || cenRight < pixStart)
break;
/* Draw centromere itself. */
hCytoBandDrawCentromere(hvg, cenLeft, yOff, cenRight - cenLeft,
CYTO_HEIGHT, MG_WHITE, hCytoBandCentromereColor(hvg));
break;
}
}
}
-void drawChromLabels(struct vGfx *vg, struct settings *settings)
+Color getChromColor(struct vGfx *vg, char *chrom)
+{
+if (!chrom)
+ return MG_BLACK;
+
+int r, g, b;
+switch (chromToInt(chrom))
+ {
+ case 1:
+ r = CHROM_1_R;
+ g = CHROM_1_G;
+ b = CHROM_1_B;
+ break;
+ case 2:
+ r = CHROM_2_R;
+ g = CHROM_2_G;
+ b = CHROM_2_B;
+ break;
+ case 3:
+ r = CHROM_3_R;
+ g = CHROM_3_G;
+ b = CHROM_3_B;
+ break;
+ case 4:
+ r = CHROM_4_R;
+ g = CHROM_4_G;
+ b = CHROM_4_B;
+ break;
+ case 5:
+ r = CHROM_5_R;
+ g = CHROM_5_G;
+ b = CHROM_5_B;
+ break;
+ case 6:
+ r = CHROM_6_R;
+ g = CHROM_6_G;
+ b = CHROM_6_B;
+ break;
+ case 7:
+ r = CHROM_7_R;
+ g = CHROM_7_G;
+ b = CHROM_7_B;
+ break;
+ case 8:
+ r = CHROM_8_R;
+ g = CHROM_8_G;
+ b = CHROM_8_B;
+ break;
+ case 9:
+ r = CHROM_9_R;
+ g = CHROM_9_G;
+ b = CHROM_9_B;
+ break;
+ case 10:
+ r = CHROM_10_R;
+ g = CHROM_10_G;
+ b = CHROM_10_B;
+ break;
+ case 11:
+ r = CHROM_11_R;
+ g = CHROM_11_G;
+ b = CHROM_11_B;
+ break;
+ case 12:
+ r = CHROM_12_R;
+ g = CHROM_12_G;
+ b = CHROM_12_B;
+ break;
+ case 13:
+ r = CHROM_13_R;
+ g = CHROM_13_G;
+ b = CHROM_13_B;
+ break;
+ case 14:
+ r = CHROM_14_R;
+ g = CHROM_14_G;
+ b = CHROM_14_B;
+ break;
+ case 15:
+ r = CHROM_15_R;
+ g = CHROM_15_G;
+ b = CHROM_15_B;
+ break;
+ case 16:
+ r = CHROM_16_R;
+ g = CHROM_16_G;
+ b = CHROM_16_B;
+ break;
+ case 17:
+ r = CHROM_17_R;
+ g = CHROM_17_G;
+ b = CHROM_17_B;
+ break;
+ case 18:
+ r = CHROM_18_R;
+ g = CHROM_18_G;
+ b = CHROM_18_B;
+ break;
+ case 19:
+ r = CHROM_19_R;
+ g = CHROM_19_G;
+ b = CHROM_19_B;
+ break;
+ case 20:
+ r = CHROM_20_R;
+ g = CHROM_20_G;
+ b = CHROM_20_B;
+ break;
+ case 21:
+ r = CHROM_21_R;
+ g = CHROM_21_G;
+ b = CHROM_21_B;
+ break;
+ case 22:
+ r = CHROM_22_R;
+ g = CHROM_22_G;
+ b = CHROM_22_B;
+ break;
+ case 23:
+ r = CHROM_X_R;
+ g = CHROM_X_G;
+ b = CHROM_X_B;
+ break;
+ case 24:
+ r = CHROM_Y_R;
+ g = CHROM_Y_G;
+ b = CHROM_Y_B;
+ break;
+ default:
+ r = 0;
+ g = 0;
+ b = 0;
+ }
+
+return vgFindColorIx(vg, r, g, b);
+}
+
+
+void drawColorIdeogram(struct hvGfx *hvg, struct settings *settings,
+ struct chromLay *clList, int yOff)
+{
+if (!settings)
+ return;
+
+struct vGfx *vg = hvg->vg;
+
+struct sqlConnection *conn = hAllocConnProfile(heatMapDbProfile, "hg18");
+struct hash *cbHash = getCytoBandHash(conn);
+hFreeConn(&conn);
+
+if (!cbHash)
+ return;
+
+/* Make grayscale for bands */
+struct chromLay *cl;
+vgSetClip(vg, 0, 0, settings->width, settings->height);
+
+for (cl = clList; cl; cl = cl->next)
+ {
+ struct hashEl *el = hashLookup(cbHash, cl->chrom);
+ if (!el)
+ continue;
+ struct cytoBand *cb, *cbList = el->val;
+
+ int pixStart = cl->pxStart;
+ int pixEnd = cl->pxStart + cl->pxWidth;
+ int pixSize = cl->pxWidth;
+
+ unsigned bStart = cl->baseStart;
+ unsigned bEnd = cl->baseEnd;
+ unsigned bSize = bEnd - bStart;
+
+ double basesPerPixel = (double) bSize / (double) pixSize;
+
+ int xBuffer = 0; //Start = pixStart;
+ if (pixStart == 0)
+ xBuffer = 0;
+
+ Color col = getChromColor(vg, cl->chrom);
+
+ /* Draw box around cytoband */
+ vgBox(vg, pixStart+1, yOff, pixSize-1, 1, MG_BLACK);
+ vgBox(vg, pixStart+1, yOff + CYTO_HEIGHT-1, pixSize-1, 1, MG_BLACK);
+
+ unsigned minBand = INT_MAX;
+ unsigned maxBand = 0;
+ for (cb = cbList; cb; cb = cb->next)
+ {
+ unsigned start = cb->chromStart; // our bases start at 1 TODO: FIX!
+ unsigned stop = cb->chromEnd;
+ if ((stop < bStart) || (start > bEnd)) // out of scope
+ continue;
+
+ int pStart = round(((double) start - (double) bStart) / basesPerPixel) + pixStart;
+ if (pStart < pixStart)
+ pStart = pixStart;
+ if (pStart <= 0)
+ pStart = 1;
+
+ int pEnd = round(((double) stop - (double) bStart) / basesPerPixel) + pixStart;
+ if (pEnd >= pixEnd)
+ pEnd = pixEnd;
+
+ vgBox(vg, pStart, yOff+1, (pEnd - pStart), CYTO_HEIGHT-2, col);
+
+ if (start < minBand)
+ minBand = start;
+ if (stop > maxBand)
+ maxBand = stop;
+ }
+
+ /* If very near left/right edges, if we see the chromosome edge */
+ if (abs(minBand - bStart) < 100)
+ vgBox(vg, pixStart, yOff+1, 1, CYTO_HEIGHT-2, MG_BLACK);
+ if (abs(maxBand- bEnd) < 100)
+ vgBox(vg, pixEnd-1, yOff+1, 1, CYTO_HEIGHT-2, MG_BLACK);
+
+ for (cb = cbList; cb; cb = cb->next)
+ {
+ /* If centromere do some drawing. */
+ if(!sameString(cb->gieStain, "acen"))
+ continue;
+ int cenLeft, cenRight, cenTop, cenBottom;
+
+ /* Get the coordinates of the edges of the centromere. */
+ cenLeft = round(((double) cb->chromStart - (double) bStart) / basesPerPixel) + pixStart;
+ cenRight = round(((double) cb->next->chromEnd - (double) bStart)/basesPerPixel) + pixStart;
+ cenTop = yOff + CYTO_HEIGHT;
+ cenBottom = yOff;
+
+ if (cenLeft < 0 && cenRight < 0)
+ break;
+ if (cenLeft > pixEnd || cenRight < pixStart)
+ break;
+
+ /* Draw centromere itself. */
+ hCytoBandDrawCentromere(hvg, cenLeft, yOff, cenRight - cenLeft,
+ CYTO_HEIGHT, MG_WHITE, hCytoBandCentromereColor(hvg));
+ break;
+ }
+ char *name = cl->chrom;
+ Color textCol = MG_BLACK; //hvGfxContrastingColor(hvg, col);
+ vgTextCentered(vg, pixStart,
+ settings->dataOffsetY + DEFAULT_LABEL_HEIGHT - settings->fontHeight,
+ (pixEnd - pixStart), DEFAULT_LABEL_HEIGHT, textCol, settings->font, name);
+
+ }
+}
+
+void drawChromLabels(struct vGfx *vg, struct settings *settings, struct chromLay *clList)
{
if (!settings)
return;
int width = settings->width;
int labelHeight = DEFAULT_LABEL_HEIGHT;
struct chromLay *cl;
-vgSetClip(vg, 0, 0, width, labelHeight);
+vgSetClip(vg, settings->dataOffsetX, 0, settings->dataWidth, settings->height);
boolean singleChrom = FALSE;
if (slCount(settings->layoutList) == 1)
singleChrom = TRUE;
-for(cl = settings->layoutList; cl; cl = cl->next)
+for(cl = clList; cl; cl = cl->next)
{
int chromWidth = cl->pxWidth;
int leftX = cl->pxStart;
if (leftX < 0)
leftX = 0;
int rightX = leftX + chromWidth;
if (rightX > width - 1)
rightX = width - 1;
vgBox(vg, leftX, 0, 1, labelHeight, MG_GRAY);
vgBox(vg, rightX, 0, 1, labelHeight, MG_GRAY);
int strWidth;
if (!singleChrom)
{
char *pt = cl->chrom;
strWidth = mgFontStringWidth(settings->font, pt);
if (strWidth < chromWidth)
vgTextCentered(vg, cl->pxStart, 0, chromWidth, labelHeight,
MG_BLACK, settings->font, pt);
else
{
pt = cl->chrom + 3;
strWidth = mgFontStringWidth(settings->font, pt);
if (strWidth < chromWidth)
vgTextCentered(vg, cl->pxStart, 0, chromWidth, labelHeight,
MG_BLACK, settings->font, pt);
}
}
else
{
char str[128];
unsigned long x;
int y = labelHeight/2 - settings->fontHeight/4;
vgText(vg, cl->pxStart + 3, y, MG_BLACK, settings->font, cl->chrom);
int minX = cl->pxStart + mgFontStringWidth(settings->font, cl->chrom);
double numBases = cl->baseEnd - cl->baseStart;
if (numBases == 1)
{
safef(str, sizeof(str), "%lu", (unsigned long int) cl->baseStart);
strWidth = mgFontStringWidth(settings->font, str);
vgText(vg, rightX - strWidth, y, MG_BLACK, settings->font, str);
continue;
}
unsigned long tickBases = (unsigned long) ceil(0.5 * basesInScale(settings->totalBases));
int tickPixels = round(tickBases/settings->totalBases * (double) chromWidth);
if (tickBases == 0)
continue;
int buffer = 10;
unsigned long firstX = floor(cl->baseStart / tickBases) * tickBases;
for (x = firstX; x <= cl->baseEnd; x += tickBases)
{
int tickX = round((x - cl->baseStart + 1) / settings->totalBases * (double) chromWidth)
+ cl->pxStart;
if (tickX <= minX || tickX > rightX)
continue;
int tickY = labelHeight/2 - settings->fontHeight/2 - 1;
vgBox(vg, tickX, tickY, 1, settings->fontHeight+1, MG_BLACK);
safef(str, sizeof(str), "%lu", x);
strWidth = mgFontStringWidth(settings->font, str);
if ((strWidth < tickPixels - buffer) && (tickX - strWidth > minX + buffer))
vgText(vg, tickX - strWidth - 1, y, MG_BLACK, settings->font, str);
}
}
}
vgUnclip(vg);
}
char *genomeLabelsGif(struct sqlConnection *conn, struct settings *settings)
/* Create genome label GIF file and HT that includes it. */
{
if (!settings)
return NULL;
struct hvGfx *vg;
int width = settings->width;
int height = settings->height;
if (width * height == 0)
return NULL;
struct tempName md5Tn;
char *strToHash = cartSettingsString(bbPrefix, "genomeLabelsGif");
trashDirMD5File(&md5Tn, "hgh", ".gif", strToHash);
off_t size = fileSize(md5Tn.forCgi);
if (!fileExists(md5Tn.forCgi) || (size == 0) || DEBUG)
{
vg = hvGfxOpenGif(width, height, md5Tn.forCgi, FALSE);
- drawChromLabels(vg->vg, settings);
- drawIdeogram(vg, settings, DEFAULT_LABEL_HEIGHT);
+ prepareImage(vg->vg, settings);
+
+ drawChromLabels(vg->vg, settings, settings->layoutList);
+
+ drawIdeogram(vg, settings, settings->layoutList, DEFAULT_LABEL_HEIGHT);
hvGfxClose(&vg);
}
char *filename = replaceChars(md5Tn.forHtml, "..", "");
return filename;
}
double basesInScaleAndString(double numBases, char **scaleStr)
{
double bases = basesInScale(numBases);
double divisor = 1.0;
char *suffix = NULL;
if (bases == 1.0)
{
divisor = 1.0;
suffix = "base";
}
else if (bases < 10.0)
{
divisor = 1.0;
suffix = "bases";
}
else if (bases < 1000.0)
{
divisor = 1.0;
suffix = "bp";
}
else if (bases < 1000000.0)
{
divisor = 1000.0;
suffix = "Kb";
}
else if (bases < 1000000000.0)
{
divisor = 1000000.0;
suffix = "Mb";
}
else if (bases < 1000000000000.0)
{
divisor = 1000000000.0;
suffix = "Gb";
}
char str[128];
safef(str, sizeof(str), "%d %s", (int) floor(bases/divisor), suffix);
*scaleStr = cloneString(str);
return bases;
}
void drawGenomeScale(struct vGfx *vg, struct settings *settings,
int width, int height, double numBases)
{
char *scaleStr;
double scaleBases = basesInScaleAndString(numBases, &scaleStr);
if (!scaleStr)
return;
-vgSetClip(vg, 0, 0, width, height);
-vgBox(vg, 0, 0, width, height, MG_WHITE);
+vgSetClip(vg, settings->dataOffsetX, 0, settings->dataWidth, height);
int midY = height / 2;
int buffer = 3;
int scaleWidth = round(((double) width) * scaleBases / numBases);
int startX = round((double)width / 2.0) - scaleWidth / 2;
int dashTop = (height - settings->fontHeight)/2;
/* draw line on left/right side */
vgBox(vg, startX, dashTop, 1, settings->fontHeight, MG_BLACK);
vgBox(vg, startX+scaleWidth, dashTop, 1, settings->fontHeight, MG_BLACK);
/* draw line connecting */
vgBox(vg, startX, midY, scaleWidth, 1, MG_BLACK);
int textY = midY - settings->fontHeight/2;
vgTextRight(vg, 0, textY, startX - buffer, settings->fontHeight,
MG_BLACK, settings->font, scaleStr);
vgUnclip(vg);
}
char *genomeScaleGif(struct settings *settings)
/* Create genome GIF file and HT that includes it. */
{
if (!settings || settings->totalBases < 1)
return NULL;
int totalW = settings->width;
int totalH = settings->height;
struct tempName md5Tn;
char *strToHash = cartSettingsString(bbPrefix, "genomeScaleGif");
trashDirMD5File(&md5Tn, "hgh", ".gif", strToHash);
off_t size = fileSize(md5Tn.forCgi);
if (!fileExists(md5Tn.forCgi) || (size == 0) || DEBUG)
{
struct hvGfx *vg = hvGfxOpenGif(totalW, totalH, md5Tn.forCgi, FALSE);
+ prepareImage(vg->vg, settings);
+
drawGenomeScale(vg->vg, settings, totalW, totalH, settings->totalBases);
hvGfxClose(&vg);
}
char *filename = replaceChars(md5Tn.forHtml, "..", "");
return filename;
}