src/hg/instinct/hgHeatmap2/hgCircleMaps.c 1.7
1.7 2009/02/27 21:26:46 jsanborn
updated hgcirclemaps
Index: src/hg/instinct/hgHeatmap2/hgCircleMaps.c
===================================================================
RCS file: /projects/compbio/cvsroot/kent/src/hg/instinct/hgHeatmap2/hgCircleMaps.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -b -B -U 4 -r1.6 -r1.7
--- src/hg/instinct/hgHeatmap2/hgCircleMaps.c 28 Jan 2009 22:44:18 -0000 1.6
+++ src/hg/instinct/hgHeatmap2/hgCircleMaps.c 27 Feb 2009 21:26:46 -0000 1.7
@@ -42,8 +42,9 @@
double median; /* median value for ring */
boolean drawSummary; /* draw summary */
+ boolean visible; /* invisible rings exist, can be sorted, not displayed */
boolean sort; /* Sort this ring or not */
int sortDir; /* +1 = ASC, -1 = DESC */
double maxVal; /* maximum value, used for sorting */
@@ -64,8 +65,10 @@
double maxR; /* max radius for all rings */
int width; /* pix width */
boolean drawSummary; /* draw summary (pie chart) */
+ boolean subgrouped; /* if successful subgrouping applied */
+
struct hash *data; /* data for center (pie chart) */
};
char *heatMapDbProfile = "localDb";
@@ -83,8 +86,11 @@
void vgRadiusBox(struct vGfx *vg, int x0, int y0, double rStart, double rStop,
double tStart, double tStop, Color col)
{
+if ((rStart == rStop) || (tStart == tStop)) // zero height/thickness
+ return;
+
struct gfxPoly *gp = gfxPolyNew();
int x, y;
double r, t, tStep;
@@ -139,13 +145,44 @@
cm->width = 0;
cm->data = NULL;
cm->drawSummary = FALSE;
+cm->subgrouped = FALSE;
return cm;
}
-struct ring *addRingToCircleMap(struct circleMap *cm, char *name, struct genoHeatmap *gh)
+struct ring *cloneRing(struct ring *rg)
+{
+if (!rg)
+ return NULL;
+
+struct ring *rg2;
+AllocVar(rg2);
+rg2->name = cloneString(rg->name);
+rg2->dataset = cloneString(rg->dataset);
+rg2->type = cloneString(rg->type);
+rg2->maxDev = rg->maxDev;
+rg2->gain = rg->gain;
+rg2->numElements = rg->numElements;
+rg2->minR = rg->minR;
+rg2->maxR = rg->maxR;
+rg2->data = NULL;
+
+rg2->drawSummary = rg->drawSummary;
+rg2->median = 0.0;
+
+rg2->visible = rg->visible;
+
+rg2->sort = rg->sort;
+rg2->sortDir = rg->sortDir;
+rg2->maxVal = rg->maxVal;
+
+return rg2;
+}
+
+struct ring *addRingToCircleMap(struct circleMap *cm, char *name, struct genoHeatmap *gh,
+ boolean isVisible)
{ /* Initialize a ring, add it circleLay, and return reference to it */
struct ring *rg;
AllocVar(rg);
rg->name = cloneString(name);
@@ -160,8 +197,10 @@
rg->drawSummary = FALSE;
rg->median = 0.0;
+rg->visible = isVisible;
+
rg->sort = FALSE;
rg->sortDir = 0;
rg->maxVal = 0.0;
@@ -471,9 +510,16 @@
double i = 0.0;
struct slName *sl;
struct slDouble *sd, *sdList;
-Color lightGray = vgFindColorIx(vg, 225, 225, 225);
+
+Color missingColor;
+if (cm->subgrouped)
+ missingColor = MG_WHITE; // when subgrouped, gray is distracting
+else
+ missingColor = vgFindColorIx(vg, 225, 225, 225); // light gray
+
+
for (sl = cm->samples; sl; sl = sl->next)
{
tStart = 2.0 * PI * i / numSamples;
tStop = 2.0 * PI * (i + 1.0) / numSamples;
@@ -483,9 +529,9 @@
struct hashEl *el = hashLookup(rg->data, sl->name);
if (!el)
{
- vgRadiusBox(vg, x0, y0, rg->minR, rg->maxR, tStart, tStop, lightGray);
+ vgRadiusBox(vg, x0, y0, rg->minR, rg->maxR, tStart, tStop, missingColor);
continue;
}
sdList = el->val; // slDouble list of expScores
@@ -565,22 +611,33 @@
cm->width = width;
cm->maxR = (double) cm->width / 2.0;
cm->minR = 0.75 * cm->maxR;
-int numRings = slCount(cm->rings);
+struct ring *rg;
+int numRings = 0;
+for (rg = cm->rings; rg; rg = rg->next)
+ if (rg->visible)
+ numRings++;
+
double step = (cm->maxR - cm->minR) / (double) numRings;
+double buffer = 0.0;
+if (cm->subgrouped)
+ buffer = step / 5.0; // put buffer between subgrouped rings
+buffer = 0.0;
+
double rStart = cm->minR;
-double rStop = cm->minR + step;
+double rStop = cm->minR + (step - buffer);
-struct ring *rg;
for (rg = cm->rings; rg; rg = rg->next)
{
+ if (!rg->visible) // keep minR/maxR at zero for no display
+ continue;
rg->minR = rStart;
rg->maxR = rStop;
rStart += step;
- rStop += step;
+ rStop = rStart + (step - buffer);
}
}
void setupSummary(struct circleMap *cm)
@@ -669,8 +726,10 @@
}
void sortCircleMap(struct circleMap *cm)
{ /* Sorting goes from inner ring out, averaging all probes within a ring for value */
+if (!cm->samples)
+ return;
/* Setup sorting by gene value */
setupGeneSort(cm);
@@ -688,9 +747,9 @@
sn->name = cloneString(sl->name);
sn->list = NULL;
for (rg = cm->rings; rg; rg = rg->next)
{
- if (!rg->sort)
+ if (!rg->sort || !rg->data)
continue;
struct hashEl *el = hashLookup(rg->data, sn->name);
if (!el)
val = rg->maxVal + 0.1; // if no val, set all to above inner ring's max
@@ -747,22 +805,32 @@
gh->name, NULL, gs);
if (!geneHash) // gene hash could not be allocated, bad.
continue;
- struct ring *rg = addRingToCircleMap(cm, gene, gh);
+ struct ring *rg = addRingToCircleMap(cm, gene, gh, TRUE);
addGeneDataToRing(rg, geneHash, gene, gh->sampleList);
hashFree(&geneHash);
}
slReverse(&cm->rings);
}
-void addFeatureToCircleMap(struct circleMap *cm, char *datasets)
+void addFeaturesToCircleMap(struct circleMap *cm, char *datasets)
{
char *featureList = cartOptionalString(cart, hgh2FeatureList);
-if (!featureList)
+char *featureSort = cartOptionalString(cart, hgh2FeatureSort);
+
+if (!featureList && !featureSort)
return;
+boolean isVisible = TRUE;
+if (!featureList)
+ { /* in order for sorting to work, need features in rings,
+ * but should be invisible unless featureList was set */
+ isVisible = FALSE;
+ featureList = featureSort;
+ }
+
struct genoHeatmap *gh = NULL;
struct slName *sl, *slList = slNameListFromComma(datasets);
for (sl = slList; sl; sl = sl->next)
{
@@ -794,9 +862,9 @@
break;
if (!col)
continue;
- struct ring *rg = addRingToCircleMap(cm, col->name, gh);
+ struct ring *rg = addRingToCircleMap(cm, col->name, gh, isVisible);
addFeatureDataToRing(conn, rg, col, gh);
}
hFreeConn(&conn);
}
@@ -835,8 +903,11 @@
}
boolean needSplit(struct ring *rg, struct slName **ptSubsets, int subsetNum)
{
+if (!rg->data) // no data, no split!
+ return FALSE;
+
int subset;
struct slName *sl;
int needSplit = 0;
@@ -847,26 +918,102 @@
struct hashEl *el = hashLookup(rg->data, sl->name);
if (!el)
continue;
needSplit++;
+ break;
}
}
return (needSplit > 1);
}
+void removeSamplesFromRing(struct circleMap *cm, struct ring *rg)
+{
+if (!rg->data) // nothing to remove
+ return;
+
+struct slName *sl, *slList = NULL;
+for (sl = cm->samples; sl; sl = sl->next)
+ {
+ struct hashEl *el = hashLookup(rg->data, sl->name);
+ if (!el) // not in ring, so keep sample name in circle's list
+ slNameAddHead(&slList, sl->name);
+ }
+slReverse(&slList); // maintain original order
+
+slNameFreeList(&cm->samples); // remove old sample list
+cm->samples = slList; // set to new list.
+}
+
+
+boolean removeRing(struct circleMap *cm, struct ring *toRemove)
+{
+/* Delete any circleMap samples on the to-be-removed ring */
+removeSamplesFromRing(cm, toRemove);
+
+if (cm->rings == toRemove) /* ring to remove is first, set to next */
+ {
+ cm->rings = toRemove->next;
+ return TRUE;
+ }
+
+struct ring *rg, *nextRg;
+for (rg = cm->rings; rg; rg = rg->next)
+ {
+ nextRg = rg->next;
+ if (nextRg == toRemove)
+ {
+ rg->next = nextRg->next;
+ nextRg->next = NULL;
+ return TRUE;
+ }
+ }
+
+return FALSE;
+}
+
void splitRing(struct circleMap *cm, struct ring *rg,
struct slName **ptSubsets, int subsetNum)
{
-return;
+int subset;
+struct ring *rg2, *ptRings[subsetNum];
+for (subset = 0; subset < subsetNum; subset++)
+ ptRings[subset] = cloneRing(rg);
+
+struct slName *sl;
+for (subset = 0; subset < subsetNum; subset++)
+ {
+ rg2 = ptRings[subset];
+ rg2->data = hashNew(0);
+
+ for (sl = ptSubsets[subset]; sl; sl = sl->next)
+ {
+ struct hashEl *el = hashLookup(rg->data, sl->name);
+ if (!el)
+ continue;
+ struct slDouble *sdList = el->val;
+
+ hashAdd(rg2->data, sl->name, sdList);
+ hashRemove(rg->data, sl->name);
+ }
+ }
+
+/* Remove empty ring that was split */
+boolean removed = removeRing(cm, rg);
+if (!removed)
+ errAbort("Problem with removing ring");
+
+/* Add new rings */
+for (subset = 0; subset < subsetNum; subset++)
+ slAddHead(&cm->rings, ptRings[subset]);
}
void splitCircleMap(struct circleMap *cm, struct slName **ptSubsets, int subsetNum)
{
-struct ring *rg;
-
-for (rg = cm->rings; rg; rg = rg->next)
+struct ring *rg, *nextRg;
+for (rg = cm->rings; rg; rg = nextRg)
{
+ nextRg = rg->next;
if (!needSplit(rg, ptSubsets, subsetNum))
continue;
splitRing(cm, rg, ptSubsets, subsetNum);
}
@@ -897,8 +1044,9 @@
if (!ifSubsets)
continue;
splitCircleMap(cm, ptSubsets, subsetNum);
+ cm->subgrouped = TRUE;
}
}
@@ -910,21 +1058,21 @@
/* Add gene data (if gene is set) */
addGeneToCircleMap(cm, datasets, gene);
/* Add feature data (if featureList is set) */
-addFeatureToCircleMap(cm, datasets);
+addFeaturesToCircleMap(cm, datasets);
/* Set up any subgrouping info */
setupSubgroups(cm, datasets);
-/* Layout circle map, setting radial widths */
-layoutCircleMap(cm, width);
-
/* Setup any summary (displaying only median value) */
setupSummary(cm);
/* Sort circle map data */
sortCircleMap(cm);
+
+/* Layout circle map, setting radial widths */
+layoutCircleMap(cm, width);
}
void modeGetCircleMap()
{