static char *abbreviatedBandName(struct cytoBand *band, MgFont *font, int width, boolean isDmel) /* Return a string abbreviated enough to fit into space. */ { int textWidth; static char string[32]; /* If have enough space, return original chromosome/band. */ sprintf(string, "%s%s", (isDmel ? "" : skipChr(band->chrom)), band->name); textWidth = mgFontStringWidth(font, string); if (textWidth <= width) return string; /* Try leaving off chromosome */ sprintf(string, "%s", band->name); textWidth = mgFontStringWidth(font, string); if (textWidth <= width) return string; /* Try leaving off initial letter */ sprintf(string, "%s", band->name+1); textWidth = mgFontStringWidth(font, string); if (textWidth <= width) return string; return NULL; }
static char *abbreviateContig(char *string, MgFont *font, int width) /* Return a string abbreviated enough to fit into space. */ { int textWidth; /* If have enough space, return original unabbreviated string. */ textWidth = mgFontStringWidth(font, string); if (textWidth <= width) return string; /* Try skipping over 'ctg' */ string += 3; textWidth = mgFontStringWidth(font, string); if (textWidth <= width) return string; return NULL; }
void vgDrawRulerBumpText(struct vGfx *vg, int xOff, int yOff, int height, int width, Color color, MgFont *font, int startNum, int range, int bumpX, int bumpY) /* Draw a ruler inside the indicated part of mg with numbers that start at * startNum and span range. Bump text positions slightly. */ { int tickSpan; int tickPos; double scale; int firstTick; int remainder; int end = startNum + range; int x; char tbuf[14]; int numWid; int goodNumTicks; int niceNumTicks = width/35; numLabelString(startNum+range, tbuf); numWid = mgFontStringWidth(font, tbuf)+4+bumpX; goodNumTicks = width/numWid; if (goodNumTicks < 1) goodNumTicks = 1; if (goodNumTicks > niceNumTicks) goodNumTicks = niceNumTicks; tickSpan = figureTickSpan(range, goodNumTicks); scale = (double)width / range; firstTick = startNum + tickSpan; remainder = firstTick % tickSpan; firstTick -= remainder; for (tickPos=firstTick; tickPos<end; tickPos += tickSpan) { numLabelString(tickPos, tbuf); numWid = mgFontStringWidth(font, tbuf)+4; x = (int)((tickPos-startNum) * scale) + xOff; vgBox(vg, x, yOff, 1, height, color); if (x - numWid >= xOff) { vgTextCentered(vg, x-numWid + bumpX, yOff + bumpY, numWid, height, color, font, tbuf); } } }
static void midLabel(struct hvGfx *hvg, struct genoLay *gl, struct genoLayChrom *chrom, int yOffset, int fontHeight, int color) /* Draw a chromosome with label on left. */ { MgFont *font = gl->font; int textWidth = mgFontStringWidth(font, chrom->shortName); hvGfxTextRight(hvg, chrom->x - textWidth - gl->spaceWidth, chrom->y + yOffset, textWidth, fontHeight, color, font, chrom->shortName); }
int ggLabelWidth(struct genoGraph *gg, MgFont *font) /* Return width used by graph labels. */ { struct chromGraphSettings *cgs = gg->settings; int i; int minLabelWidth = 0, labelWidth; char buf[24]; fakeEmptyLabels(cgs); for (i=0; i<cgs->linesAtCount; ++i) { safef(buf, sizeof(buf), "%g ", cgs->linesAt[i]); labelWidth = mgFontStringWidth(font, buf); if (labelWidth > minLabelWidth) minLabelWidth = labelWidth; } return minLabelWidth; }
int gifLabelMaxWidth(char **labels, int labelCount) /* Return maximum pixel width of labels. It's ok to have * NULLs in labels array. */ { int width = 0, w, i; MgFont *font = mgMediumFont(); for (i=0; i<labelCount; ++i) { char *label = labels[i]; if (label != NULL) { w = mgFontStringWidth(font, labels[i]); if (w > width) width = w; } } width += 2; return width; }
struct genoLay *genoLayNew(struct genoLayChrom *chromList, MgFont *font, int picWidth, int betweenChromHeight, int minLeftLabelWidth, int minRightLabelWidth, char *how) /* Figure out layout. For human and most mammals this will be * two columns with sex chromosomes on bottom. This is complicated * by the platypus having a bunch of sex chromosomes. */ { int margin = 3; struct slRef *refList = NULL, *ref, *left, *right; struct genoLayChrom *chrom; struct genoLay *gl; int autoCount, halfCount, bases, chromInLine; int leftLabelWidth=0, rightLabelWidth=0, labelWidth; int spaceWidth = mgFontCharWidth(font, ' '); int extraLabelPadding = 0; int autosomeOtherPixels=0, sexOtherPixels=0; int autosomeBasesInLine=0; /* Maximum bases in a line for autosome. */ int sexBasesInLine=0; /* Bases in line for sex chromsome. */ double sexBasesPerPixel, autosomeBasesPerPixel, basesPerPixel; int pos = margin; int y = 0; int fontHeight = mgFontLineHeight(font); int chromHeight = fontHeight; int lineHeight = chromHeight + betweenChromHeight; boolean allOneLine = FALSE; refList = refListFromSlList(chromList); /* Allocate genoLay object and fill in simple fields. */ AllocVar(gl); gl->chromList = chromList; gl->chromHash = hashNew(0); gl->font = font; gl->picWidth = picWidth; gl->margin = margin; gl->spaceWidth = spaceWidth; gl->lineHeight = lineHeight; gl->betweenChromHeight = betweenChromHeight; gl->betweenChromOffsetY = 0; gl->chromHeight = chromHeight; gl->chromOffsetY = lineHeight - chromHeight; /* Save chromosomes in hash too, for easy access */ for (chrom = chromList; chrom != NULL; chrom = chrom->next) hashAdd(gl->chromHash, chrom->fullName, chrom); if (sameString(how, genoLayOnePerLine)) { gl->leftList = refList; } else if (sameString(how, genoLayAllOneLine)) { gl->bottomList = refList; allOneLine = TRUE; } else { /* Put sex chromosomes on bottom, and rest on left. */ separateSexChroms(refList, &refList, &gl->bottomList); autoCount = slCount(refList); gl->leftList = refList; /* If there are a lot of chromosomes, then move later * (and smaller) chromosomes to a new right column */ if (autoCount > 12) { halfCount = (autoCount+1)/2; ref = slElementFromIx(refList, halfCount-1); gl->rightList = ref->next; ref->next = NULL; slReverse(&gl->rightList); } } if (allOneLine) { unsigned long totalBases = 0, bStart=0, bEnd; int chromCount = 0, chromIx=0; for (ref = gl->bottomList; ref != NULL; ref = ref->next) { chrom = ref->val; totalBases += chrom->size; chromCount += 1; } int availablePixels = picWidth - minLeftLabelWidth - minRightLabelWidth - 2*margin - (chromCount-1); double basesPerPixel = (double)totalBases/availablePixels; gl->picHeight = 2*margin + lineHeight + fontHeight; for (ref = gl->bottomList; ref != NULL; ref = ref->next) { chrom = ref->val; bEnd = bStart + chrom->size; int pixStart = round(bStart / basesPerPixel); int pixEnd = round(bEnd / basesPerPixel); chrom->width = pixEnd - pixStart; chrom->height = lineHeight; chrom->x = pixStart + margin + chromIx + minLeftLabelWidth; chrom->y = 0; chromIx += 1; bStart = bEnd; } gl->lineCount = 1; gl->picHeight = 2*margin + lineHeight + fontHeight + 1; gl->allOneLine = TRUE; gl->leftLabelWidth = minLeftLabelWidth; gl->rightLabelWidth = minRightLabelWidth; gl->basesPerPixel = basesPerPixel; gl->pixelsPerBase = 1.0/basesPerPixel; } else { /* Figure out space needed for autosomes. */ left = gl->leftList; right = gl->rightList; while (left || right) { bases = 0; chromInLine = 0; if (left) { chrom = left->val; labelWidth = mgFontStringWidth(font, chrom->shortName) + spaceWidth; if (leftLabelWidth < labelWidth) leftLabelWidth = labelWidth; bases = chrom->size; left = left->next; } if (right) { chrom = right->val; labelWidth = mgFontStringWidth(font, chrom->shortName) + spaceWidth; if (rightLabelWidth < labelWidth) rightLabelWidth = labelWidth; bases += chrom->size; right = right->next; } if (autosomeBasesInLine < bases) autosomeBasesInLine = bases; gl->lineCount += 1; } /* Figure out space needed for bottom chromosomes. */ if (gl->bottomList) { gl->lineCount += 1; sexOtherPixels = spaceWidth + 2*margin; for (ref = gl->bottomList; ref != NULL; ref = ref->next) { chrom = ref->val; sexBasesInLine += chrom->size; labelWidth = mgFontStringWidth(font, chrom->shortName) + spaceWidth; if (ref == gl->bottomList ) { if (leftLabelWidth < labelWidth) leftLabelWidth = labelWidth; sexOtherPixels = leftLabelWidth; } else if (ref->next == NULL) { if (rightLabelWidth < labelWidth) rightLabelWidth = labelWidth; sexOtherPixels += rightLabelWidth + spaceWidth; } else { sexOtherPixels += labelWidth + spaceWidth; } } } /* Do some adjustments if side labels are bigger than needed for * chromosome names. */ if (leftLabelWidth < minLeftLabelWidth) { extraLabelPadding += (minLeftLabelWidth - leftLabelWidth); leftLabelWidth = minLeftLabelWidth; } if (rightLabelWidth < minRightLabelWidth) { extraLabelPadding += (minRightLabelWidth - rightLabelWidth); rightLabelWidth = minRightLabelWidth; } sexOtherPixels += extraLabelPadding; /* Figure out the number of bases needed per pixel. */ autosomeOtherPixels = 2*margin + spaceWidth + leftLabelWidth + rightLabelWidth; basesPerPixel = autosomeBasesPerPixel = autosomeBasesInLine/(picWidth-autosomeOtherPixels); if (gl->bottomList) { sexBasesPerPixel = sexBasesInLine/(picWidth-sexOtherPixels); if (sexBasesPerPixel > basesPerPixel) basesPerPixel = sexBasesPerPixel; } /* Save positions and sizes of some things in layout structure. */ gl->leftLabelWidth = leftLabelWidth; gl->rightLabelWidth = rightLabelWidth; gl->basesPerPixel = basesPerPixel; gl->pixelsPerBase = 1.0/basesPerPixel; /* Set pixel positions for left autosomes */ for (ref = gl->leftList; ref != NULL; ref = ref->next) { chrom = ref->val; chrom->x = leftLabelWidth + margin; chrom->y = y; chrom->width = round(chrom->size/basesPerPixel); chrom->height = lineHeight; y += lineHeight; } /* Set pixel positions for right autosomes */ y = 0; for (ref = gl->rightList; ref != NULL; ref = ref->next) { chrom = ref->val; chrom->width = round(chrom->size/basesPerPixel); chrom->height = lineHeight; chrom->x = picWidth - margin - rightLabelWidth - chrom->width; chrom->y = y; y += lineHeight; } gl->picHeight = 2*margin + lineHeight * gl->lineCount; y = gl->picHeight - margin - lineHeight; /* Set pixel positions for sex chromosomes */ for (ref = gl->bottomList; ref != NULL; ref = ref->next) { chrom = ref->val; chrom->y = y; chrom->width = round(chrom->size/basesPerPixel); chrom->height = lineHeight; if (ref == gl->bottomList) chrom->x = leftLabelWidth + margin; else if (ref->next == NULL) chrom->x = picWidth - margin - rightLabelWidth - chrom->width; else chrom->x = 2*spaceWidth+mgFontStringWidth(font,chrom->shortName) + pos; pos = chrom->x + chrom->width; } } return gl; }
static void altGraphXDrawAt(struct track *tg, void *item, struct hvGfx *hvg, int xOff, int yOff, double scale, MgFont *font, Color color, enum trackVisibility vis) /* Draw an altGraphX at the specified location. */ { int i = 0; int s =0, e=0; int heightPer = tg->heightPer; int start = 0, end = 0; struct altGraphX *ag = item; int width = 0; int x1, x2; /* Create a link to hgc. */ if(tg->mapsSelf && tg->mapItem) { char name[256]; int nameWidth = 0; int textX = 0; start = max(winStart, ag->tStart); end = min(winEnd, ag->tEnd); width = (end - start) * scale; x1 = round((double)((int) start - winStart)*scale) + xOff; textX = x1; if(width == 0) width = 1; /* If there isn't enough room on before the left edge snap the label to the left edge. */ if(withLeftLabels && tg->limitedVis == tvPack) { safef(name, sizeof(name), "%s", tg->itemName(tg, ag)); nameWidth = mgFontStringWidth(font, name); textX = textX - (nameWidth + tl.nWidth/2); if(textX < insideX) textX = insideX - nameWidth; width = width + (x1 - textX); } tg->mapItem(tg, hvg, ag, "notUsed", "notUsed", ag->tStart, ag->tEnd, textX, yOff, width, heightPer); } /* Draw the edges (exons and introns). */ for(i= 0; i < ag->edgeCount; i++) { Color color2; s = ag->vPositions[ag->edgeStarts[i]]; e = ag->vPositions[ag->edgeEnds[i]]; color2 = MG_BLACK; /* If you want to shade by number of transcripts uncomment next line. */ /* color2 = altGraphXColorForEdge(hvg, ag, i); */ if(isExon(ag, i)) { if(vis == tvPack) drawScaledBox(hvg, s, e, scale, xOff, yOff+heightPer/2, heightPer/2, color2); else drawScaledBox(hvg, s, e, scale, xOff, yOff, heightPer, color2); } else { int midX; s = ag->vPositions[ag->edgeStarts[i]]; e = ag->vPositions[ag->edgeEnds[i]]; x1 = round((double)((int) s - winStart)*scale) + xOff; x2 = round((double)((int) e - winStart)*scale) + xOff; if(vis == tvPack) { midX = (x1+x2)/2; hvGfxLine(hvg, x1, yOff+heightPer/2, midX, yOff, color2); hvGfxLine(hvg, midX, yOff, x2, yOff+heightPer/2, color2); } else hvGfxLine(hvg, x1, yOff+heightPer/2, x2, yOff+heightPer/2, color2); } } }