src/hg/instinct/hgBamBam/drawingCode.c 1.1

1.1 2010/05/25 20:22:44 jsanborn
initial commit
Index: src/hg/instinct/hgBamBam/drawingCode.c
===================================================================
RCS file: src/hg/instinct/hgBamBam/drawingCode.c
diff -N src/hg/instinct/hgBamBam/drawingCode.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/hg/instinct/hgBamBam/drawingCode.c	25 May 2010 20:22:44 -0000	1.1
@@ -0,0 +1,389 @@
+/********************************************************************************/
+/* Copyright 2007-2009 -- The Regents of the University of California           */
+/********************************************************************************/
+
+#include <limits.h>
+#include "common.h"
+#include "bed.h"
+#include "cart.h"
+#include "customTrack.h"
+#include "errCatch.h"
+#include "genoLay.h"
+#include "trackLayout.h"
+#include "hash.h"
+#include "hdb.h"
+#include "hgColors.h"
+#include "hPrint.h"
+#include "htmshell.h"
+#include "jsHelper.h"
+#include "psGfx.h"
+#include "trashDir.h"
+#include "vGfx.h"
+#include "hvGfx.h"
+#include "web.h"
+#include "hgBamBam.h"
+
+#define MIN_LABEL_SIZE 100 // minimum size of labels 
+#define TEXT_BUFFER 5 // pixels to put between text and heatmap
+
+struct trackLayout tl;           /* Dimensions of things, fonts, etc. */
+
+/***** BEGIN HELPER *****/
+
+#define CLIP(p,limit) if (p < 0) p = 0; if (p >= (limit)) p = (limit)-1;
+void verticalTextLeft(struct vGfx *vg, int x, int y,
+		      int width, int height, int colorIx, int fontHeight, 
+		      MgFont *font, char *string)
+{
+/*      don't let this run wild */
+//CLIP(width, vg->width);
+//CLIP(height, vg->height);
+
+if ((width <= 0) || (height <= 0))
+    return;
+
+struct vGfx *vgHoriz;
+int i, j;
+/*  reversed meanings of width and height here since this is going
+ *  to rotate 90 degrees
+ */
+
+int offset = round((double) (width - fontHeight) / 2.0);
+if (offset < 0)
+    offset = 0;
+vgHoriz = vgOpenGif(height, width, "/dev/null", FALSE);
+vgText(vgHoriz, 0, offset, colorIx, font, string);
+
+/*  now, blit from the horizontal to the vertical, rotate -90 (CCW) */
+for (i = 0; i < height; i++)        /* xSrc -> yDest */
+    {
+    int yDest = height - (i + 1);
+    for (j = 0; j < width; j++)     /* ySrc -> xDest */
+	vgDot(vg, x + (j+1), y + yDest, vgGetDot(vgHoriz, i, j));
+    }
+vgClose(&vgHoriz);
+}
+
+
+void vgMakeColorGradient(struct vGfx *vg,
+			 struct rgbColor *start, struct rgbColor *end,
+			 int steps, Color *colorIxs)
+/* Make a color gradient that goes smoothly from start
+ * to end colors in given number of steps.  Put indicesLis
+ * in color table in colorIxs */
+{
+double scale = 0, invScale;
+double invStep;
+int i; int r,g,b;
+
+steps -= 1;     /* Easier to do the calculation in an inclusive way. */
+invStep = 1.0/steps;
+for (i=0; i<=steps; ++i)
+    {
+    invScale = 1.0 - scale;
+    r = invScale * start->r + scale * end->r;
+    g = invScale * start->g + scale * end->g;
+    b = invScale * start->b + scale * end->b;
+    colorIxs[i] = vgFindColorIx(vg, r, g, b);
+    scale += invStep;
+    }
+}
+
+char *cartSettingsString(char *prefix, char *functionName)
+{
+if (!prefix || !functionName)
+    return NULL;
+
+struct hashEl *hEl = cartFindPrefix(cart, prefix);
+if (!hEl)
+    return NULL;
+
+struct dyString *dy = newDyString(1000);
+while (hEl)
+    {
+    char *name = hEl->name;
+    char *val = hEl->val;
+    dyStringPrintf(dy, "%s=%s,", name, val);
+
+    hEl = hEl->next;
+    }
+dyStringPrintf(dy, "%s,%s", functionName, VERSION);
+
+char *str = dyStringCannibalize(&dy);
+return str;
+}
+
+void drawBackgroundLines(struct vGfx *vg, int startX, int startY, int width, int height)
+{
+int x, spacing = 20;
+
+Color lightBlue = vgFindColorIx(vg, 220, 220, 255);
+vgSetClip(vg, startX, startY, width, height);
+for (x = startX; x < (startX + width); x += spacing)
+    vgBox(vg, x, startY, 1, height, lightBlue);
+vgUnclip(vg);
+}
+
+
+/***** END HELPER *****/
+
+void drawBreaks(struct vGfx *vg, struct breaks *breaks, 
+		struct settings *settings)
+{
+
+
+}
+
+char *breaksGif(struct sqlConnection *conn, struct breaks *breaks, 
+		struct settings *settings)
+/* Create genome GIF file and HT that includes it. */
+{
+if (!breaks || !settings)
+    return NULL;
+
+if (settings->height <= 0 || settings->width <= 0)
+    return NULL;
+
+struct hvGfx *vg;
+struct tempName md5Tn;
+char *strToHash = cartSettingsString(bbPrefix, "breaks");
+trashDirMD5File(&md5Tn, "hgg", ".gif", strToHash);
+
+off_t size = fileSize(md5Tn.forCgi);
+if (!fileExists(md5Tn.forCgi) || (size == 0) || DEBUG)
+    {
+    vg = hvGfxOpenGif(settings->width, settings->height, md5Tn.forCgi, FALSE);
+
+    drawBreaks(vg->vg, breaks, settings);
+
+    hvGfxClose(&vg);
+    }
+
+char *filename = replaceChars(md5Tn.forHtml, "..", "");
+return filename;
+}
+
+
+
+void drawCopyNumber(struct vGfx *vg, struct bed *bedList,
+		    struct settings *settings, float medVal, Color col)
+{
+int x1, x2, y, w;
+float val;
+
+struct bed *bed;
+struct chromLay *cl = NULL;
+
+char *prevChrom = NULL;
+
+struct hash *pixelHash = hashNew(0);
+struct hmPixel *hm, *hmList = NULL;
+
+char pixelStr[256];
+struct hashEl *el;
+for (bed = bedList; bed; bed = bed->next)
+    {
+    if (!cl || !sameString(bed->chrom, prevChrom))
+	{
+	el = hashLookup(settings->layoutHash, bed->chrom);
+	if (!el)
+	    errAbort("couldn't find chrom %s in layout", bed->chrom);
+	cl = el->val;
+	prevChrom = bed->chrom;
+	}
+
+    if (bed->chromStart > cl->baseEnd || bed->chromEnd < cl->baseStart)
+	continue;
+
+    x1 = round( cl->pxStart + cl->pxWidth * ((float) (bed->chromStart - cl->baseStart) / cl->baseWidth) );
+    if (x1 < 0)
+	x1 = 0;
+    if (x1 > settings->width)
+	x1 = settings->width;
+
+    x2 = round( cl->pxStart + cl->pxWidth * ((float) (bed->chromEnd - cl->baseStart) / cl->baseWidth) );
+    if (x2 < 0)
+	x2 = 0;
+    if (x2 > settings->width)
+	x2 = settings->width;
+
+    w  = (x2 - x1 > 0) ? x2 - x1 : 1;
+    val = sqlFloat(bed->name);
+    
+    safef(pixelStr,sizeof (pixelStr), "%d", x1);
+    el = hashLookup(pixelHash, pixelStr);
+    if (!el)
+	{
+	hm = AllocA(struct hmPixel);
+	hm->x = x1;
+	hm->y = 0;
+	hm->w = w;
+	hm->h = 0;
+	hm->val = 0.0;
+	hm->count = 0;
+	slAddHead(&hmList, hm);
+	hashAdd(pixelHash, pixelStr, hm);
+	}
+    else
+	hm = el->val;
+    
+    if (x2 - hm->x > hm->w)
+	hm->w = x2 - hm->x;
+
+    hm->val += val;
+    hm->count += 1;
+    }
+
+struct rgbColor rgb = vgColorIxToRgb(vg, col);
+int r = rgb.r + floor((float) (255 - rgb.r) * 0.8);
+int g = rgb.g + floor((float) (255 - rgb.g) * 0.8);
+int b = rgb.b + floor((float) (255 - rgb.b) * 0.8);
+Color fillCol = vgFindColorIx(vg, r, g, b);
+
+medVal = medVal / (settings->maxVal - settings->minVal);
+if (medVal > 1.0)
+    medVal = 1.0;
+int medY = round((float) settings->height * (1.0 - medVal) );
+
+for (hm = hmList; hm ; hm = hm->next)
+    {
+    val = hm->val / hm->count;
+    val = val / (settings->maxVal - settings->minVal);
+    if (val > 1.0)
+	val = 1.0;
+    
+    y = round((float) settings->height * (1.0 - val) );
+
+    if (y > medY)
+	vgBox(vg, hm->x, medY, hm->w, y - medY, fillCol);
+    else
+	vgBox(vg, hm->x, y, hm->w, medY - y, fillCol);
+
+    vgBox(vg, hm->x, y-1, hm->w, 1, col);
+    }
+
+}
+
+char *copyNumberGif(struct sqlConnection *conn, struct bed *bed, 
+		    struct settings *settings, char *suffix, float medVal, Color col)
+/* Create genome GIF file and HT that includes it. */
+{
+if (!bed || !settings)
+    return NULL;
+
+if (settings->height <= 0 || settings->width <= 0)
+    return NULL;
+
+struct hvGfx *vg;
+struct tempName md5Tn;
+char *strToHash = cartSettingsString(bbPrefix, suffix);
+trashDirMD5File(&md5Tn, "hgg", ".gif", strToHash);
+
+off_t size = fileSize(md5Tn.forCgi);
+if (!fileExists(md5Tn.forCgi) || (size == 0) || DEBUG)
+    {
+    vg = hvGfxOpenGif(settings->width, settings->height, md5Tn.forCgi, FALSE);
+
+    drawCopyNumber(vg->vg, bed, settings, medVal, col);
+
+    hvGfxClose(&vg);
+    }
+
+char *filename = replaceChars(md5Tn.forHtml, "..", "");
+return filename;
+}
+
+
+struct settings *initSettings(struct sqlConnection *conn, 
+			      char *pos, int width, int height, float minVal, float maxVal)
+{
+struct settings *settings = AllocA(struct settings);
+
+trackLayoutInit(&tl, cart);
+settings->fontHeight = tl.fontHeight;
+settings->font = tl.font;
+
+settings->width  = width;
+settings->height = height;
+
+settings->minVal = minVal;
+settings->maxVal = maxVal;
+
+char *chrom = NULL;
+int start = 0;
+int stop = 0;
+
+if (pos)
+    {
+    if (!hgParseChromRange(NULL, pos, &chrom, &start, &stop))
+	return NULL;
+    }
+
+settings->totalBases = 0.0;
+
+struct genoLayChrom *gl, *glList = genoLayDbChroms(conn, FALSE);
+
+slSort(&glList, genoLayChromCmpName);
+
+for (gl = glList; gl; gl = gl->next)
+    {
+    if (!chrom)
+	settings->totalBases += gl->size;
+    else if (chrom && sameString(chrom, gl->fullName))
+	{
+	settings->totalBases += (float) (stop - start);
+	break;
+	}
+    }
+
+if (settings->totalBases == 0.0)
+    settings->totalBases = 1.0;
+
+float cbases = 0.0;
+struct chromLay *cl;
+settings->layoutHash = hashNew(0);
+settings->layoutList = NULL;
+for (gl = glList; gl; gl = gl->next)
+    {
+    if (!chrom)
+	{
+	AllocVar(cl);
+	cl->chrom     = cloneString(gl->fullName);
+	cl->baseStart = 0.0;
+	cl->baseEnd   = (float) gl->size;
+	cl->baseWidth = cl->baseEnd - cl->baseStart;
+	cl->pxWidth   = (float) width * cl->baseWidth / settings->totalBases;
+	cl->pxStart   = (float) width * cbases / settings->totalBases;
+
+	//cl->pxStart += 1.0;
+	//cl->pxWidth -= 2.0;
+
+	hashAdd(settings->layoutHash, cl->chrom, cl);
+	slAddHead(&settings->layoutList, cl);
+	cbases += (float) gl->size;
+	}
+    else if (chrom && sameString(chrom, gl->fullName))
+	{
+	AllocVar(cl);
+	cl->chrom = cloneString(gl->fullName);
+	cl->baseStart = (float) start;
+	cl->baseEnd   = (float) stop;
+	cl->baseWidth = cl->baseEnd - cl->baseStart;
+	cl->pxWidth   = (float) width;
+	cl->pxStart   = 0.0;
+
+	//cl->pxStart += 1.0;
+	//cl->pxWidth -= 2.0;
+
+	hashAdd(settings->layoutHash, cl->chrom, cl);
+	slAddHead(&settings->layoutList, cl);
+	break;
+	}
+    }
+slReverse(&settings->layoutList);
+
+return settings;
+}
+
+
+