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;
+}
+
+
+