public void DrawErrorBar(PlotDimensions dims, Graphics gfx, Pen penLine, double[] errorArray, bool xError, bool positiveError) { if (errorArray is null) { return; } for (int i = 0; i < Xs.Length; i++) { float centerPixelX = dims.GetPixelX(Xs[i]); float centerPixelY = dims.GetPixelY(Ys[i]); float errorSize = positiveError ? (float)errorArray[i] : -(float)errorArray[i]; if (xError) { float xWithError = dims.GetPixelX(Xs[i] + errorSize); gfx.DrawLine(penLine, centerPixelX, centerPixelY, xWithError, centerPixelY); gfx.DrawLine(penLine, xWithError, centerPixelY - CapSize, xWithError, centerPixelY + CapSize); } else { float yWithError = dims.GetPixelY(Ys[i] + errorSize); gfx.DrawLine(penLine, centerPixelX, centerPixelY, centerPixelX, yWithError); gfx.DrawLine(penLine, centerPixelX - CapSize, yWithError, centerPixelX + CapSize, yWithError); } } }
private void RenderHeatmap(PlotDimensions dims, Bitmap bmp, bool lowQuality) { using (Graphics gfx = GDI.Graphics(bmp, lowQuality)) { gfx.InterpolationMode = InterpolationMode.NearestNeighbor; double minScale = Math.Min(dims.PxPerUnitX, dims.PxPerUnitY); if (BackgroundImage != null && !DisplayImageAbove) { gfx.DrawImage( BackgroundImage, dims.GetPixelX(0), dims.GetPixelY(0) - (float)(height * minScale), (float)(width * minScale), (float)(height * minScale)); } gfx.DrawImage( BmpHeatmap, dims.GetPixelX(0), dims.GetPixelY(0) - (float)(height * minScale), (float)(width * minScale), (float)(height * minScale)); if (BackgroundImage != null && DisplayImageAbove) { gfx.DrawImage(BackgroundImage, dims.GetPixelX(0), dims.GetPixelY(0) - (float)(height * minScale), (float)(width * minScale), (float)(height * minScale)); } } }
private void RenderBarHorizontal(PlotDimensions dims, Graphics gfx, double position, double value, double valueError, double yOffset) { // bar body float centerPx = dims.GetPixelY(position); double edge2 = position + barWidth / 2; double value1 = Math.Min(valueBase, value) + yOffset; double value2 = Math.Max(valueBase, value) + yOffset; double valueSpan = value2 - value1; var rect = new RectangleF( x: dims.GetPixelX(value1), y: dims.GetPixelY(edge2), height: (float)(barWidth * dims.PxPerUnitY), width: (float)(valueSpan * dims.PxPerUnitX)); // errorbar double error1 = value > 0 ? value2 - Math.Abs(valueError) : value1 - Math.Abs(valueError); double error2 = value > 0 ? value2 + Math.Abs(valueError) : value1 + Math.Abs(valueError); float capPx1 = dims.GetPixelY(position - errorCapSize * barWidth / 2); float capPx2 = dims.GetPixelY(position + errorCapSize * barWidth / 2); float errorPx2 = dims.GetPixelX(error2); float errorPx1 = dims.GetPixelX(error1); if (fill) { using (var fillBrush = GDI.Brush((value < 0) ? negativeColor : fillColor, hatchColor, hatchStyle)) gfx.FillRectangle(fillBrush, rect.X, rect.Y, rect.Width, rect.Height); } if (borderLineWidth > 0) { using (var outlinePen = new Pen(borderColor, borderLineWidth)) gfx.DrawRectangle(outlinePen, rect.X, rect.Y, rect.Width, rect.Height); } if (errorLineWidth > 0 && valueError > 0) { using (var errorPen = new Pen(errorColor, errorLineWidth)) { gfx.DrawLine(errorPen, errorPx1, centerPx, errorPx2, centerPx); gfx.DrawLine(errorPen, errorPx1, capPx2, errorPx1, capPx1); gfx.DrawLine(errorPen, errorPx2, capPx2, errorPx2, capPx1); } } if (showValues) { using (var valueTextFont = GDI.Font(FontName, FontSize, FontBold)) using (var valueTextBrush = GDI.Brush(FontColor)) using (var sf = new StringFormat() { LineAlignment = StringAlignment.Center, Alignment = StringAlignment.Near }) gfx.DrawString(value.ToString(), valueTextFont, valueTextBrush, rect.X + rect.Width, centerPx, sf); } }
public static void MeanAndError(PlotDimensions dims, Bitmap bmp, bool lowQuality, Population pop, Random rand, double popLeft, double popWidth, Color color, Position position, bool useStdErr = false) { // adjust edges to accomodate special positions if (position == Position.Hide) { return; } if (position == Position.Left || position == Position.Right) { popWidth /= 2; } if (position == Position.Right) { popLeft += popWidth; } // determine the center point and calculate bounds double centerX = popLeft + popWidth / 2; double xPx = dims.GetPixelX(centerX); double yPx = dims.GetPixelY(pop.mean); double errorMaxPx, errorMinPx; if (useStdErr) { errorMaxPx = dims.GetPixelY(pop.mean + pop.stdErr); errorMinPx = dims.GetPixelY(pop.mean - pop.stdErr); } else { errorMaxPx = dims.GetPixelY(pop.mean + pop.stDev); errorMinPx = dims.GetPixelY(pop.mean - pop.stDev); } // make cap width a fraction of available space double capWidthFrac = .38; double capWidth = popWidth * capWidthFrac; double capPx1 = dims.GetPixelX(centerX - capWidth / 2); double capPx2 = dims.GetPixelX(centerX + capWidth / 2); float radius = 5; using (Graphics gfx = GDI.Graphics(bmp, lowQuality)) using (Pen pen = GDI.Pen(color, 2)) using (Brush brush = GDI.Brush(color)) { gfx.FillEllipse(brush, (float)(xPx - radius), (float)(yPx - radius), radius * 2, radius * 2); gfx.DrawLine(pen, (float)xPx, (float)errorMinPx, (float)xPx, (float)errorMaxPx); gfx.DrawLine(pen, (float)capPx1, (float)errorMinPx, (float)capPx2, (float)errorMinPx); gfx.DrawLine(pen, (float)capPx1, (float)errorMaxPx, (float)capPx2, (float)errorMaxPx); } }
public void Render(PlotDimensions dims, Bitmap bmp) { if (IsValidData() == false) { throw new InvalidOperationException($"Invalid data: {ValidationErrorMessage}"); } using (Graphics gfx = Graphics.FromImage(bmp)) using (var fontBrush = new SolidBrush(FontColor)) using (var frameBrush = new SolidBrush(frameColor)) using (var font = GDI.Font(FontName, FontSize, FontBold)) { float pixelX = dims.GetPixelX(x); float pixelY = dims.GetPixelY(y); SizeF stringSize = GDI.MeasureString(gfx, text, font); RectangleF stringRect = new RectangleF(0, 0, stringSize.Width, stringSize.Height); if (rotation == 0) { (pixelX, pixelY) = ApplyAlignmentOffset(pixelX, pixelY, stringSize.Width, stringSize.Height); } gfx.TranslateTransform(pixelX, pixelY); gfx.RotateTransform((float)rotation); if (frame) { gfx.FillRectangle(frameBrush, stringRect); } gfx.DrawString(text, font, fontBrush, new PointF(0, 0)); gfx.ResetTransform(); } }
public void RenderOhlc(PlotDimensions dims, Bitmap bmp, bool lowQuality) { double fractionalTickWidth = .7; float boxWidth = 10; if (AutoWidth) { double spacingPx = GetSmallestSpacing() * dims.PxPerUnitX; boxWidth = (float)(spacingPx / 2 * fractionalTickWidth); } using (Graphics gfx = Graphics.FromImage(bmp)) using (Pen pen = new Pen(Color.Magenta)) { gfx.SmoothingMode = lowQuality ? SmoothingMode.HighSpeed : SmoothingMode.AntiAlias; gfx.TextRenderingHint = lowQuality ? TextRenderingHint.SingleBitPerPixelGridFit : TextRenderingHint.AntiAliasGridFit; for (int i = 0; i < ohlcs.Length; i++) { var ohlc = ohlcs[i]; var ohlcTime = (Sqeuential) ? i : ohlc.time; float pixelX = dims.GetPixelX(ohlcTime); if (AutoWidth == false) { boxWidth = (float)(ohlc.timeSpan * dims.PxPerUnitX / 2 * fractionalTickWidth); } pen.Color = ohlc.closedHigher ? ColorUp : ColorDown; pen.Width = (boxWidth >= 2) ? 2 : 1; // the main line PointF wickTop = new PointF(pixelX, dims.GetPixelY(ohlc.low)); PointF wickBot = new PointF(pixelX, dims.GetPixelY(ohlc.high)); gfx.DrawLine(pen, wickBot, wickTop); // open and close lines float xPx = wickTop.X; float yPxOpen = dims.GetPixelY(ohlc.open); float yPxClose = dims.GetPixelY(ohlc.close); gfx.DrawLine(pen, xPx - boxWidth, yPxOpen, xPx, yPxOpen); gfx.DrawLine(pen, xPx + boxWidth, yPxClose, xPx, yPxClose); } } }
public void Render(PlotDimensions dims, Bitmap bmp, bool lowQuality = false) { using (Graphics gfx = GDI.Graphics(bmp, lowQuality)) using (Pen pen = GDI.Pen(Color.Black)) { pen.CustomEndCap = new AdjustableArrowCap(2, 2); for (int i = 0; i < xs.Length; i++) { for (int j = 0; j < ys.Length; j++) { Vector2 v = vectors[i, j]; float tailX = dims.GetPixelX(xs[i] - v.X / 2); float tailY = dims.GetPixelY(ys[j] - v.Y / 2); float endX = dims.GetPixelX(xs[i] + v.X / 2); float endY = dims.GetPixelY(v.Y + ys[j] - v.Y / 2); pen.Color = arrowColors[i * ys.Length + j]; gfx.DrawLine(pen, tailX, tailY, endX, endY); } } } }
public void Render(PlotDimensions dims, Bitmap bmp, bool lowQuality = false) { using (var gfx = GDI.Graphics(bmp, lowQuality)) using (var pen = GDI.Pen(color, lineWidth, lineStyle, true)) { if (IsHorizontal) { float pixelX1 = dims.GetPixelX(dims.XMin); float pixelX2 = dims.GetPixelX(dims.XMax); float pixelY = dims.GetPixelY(position); gfx.DrawLine(pen, pixelX1, pixelY, pixelX2, pixelY); } else { float pixelX = dims.GetPixelX(position); float pixelY1 = dims.GetPixelY(dims.YMin); float pixelY2 = dims.GetPixelY(dims.YMax); gfx.DrawLine(pen, pixelX, pixelY1, pixelX, pixelY2); } } }
public void Render(PlotDimensions dims, Bitmap bmp, bool lowQuality = false) { if (string.IsNullOrWhiteSpace(text)) { return; // no render needed } if (IsValidData() == false) { throw new InvalidOperationException($"Invalid data: {ValidationErrorMessage}"); } using (Graphics gfx = Graphics.FromImage(bmp)) using (var font = GDI.Font(FontName, FontSize, FontBold)) { gfx.SmoothingMode = lowQuality ? SmoothingMode.HighSpeed : SmoothingMode.AntiAlias; gfx.TextRenderingHint = lowQuality ? TextRenderingHint.SingleBitPerPixelGridFit : TextRenderingHint.AntiAliasGridFit; float pixelX = dims.GetPixelX(x); float pixelY = dims.GetPixelY(y); SizeF stringSize = GDI.MeasureString(gfx, text, font); RectangleF stringRect = new RectangleF(0, 0, stringSize.Width, stringSize.Height); if (rotation == 0) { (pixelX, pixelY) = ApplyAlignmentOffset(pixelX, pixelY, stringSize.Width, stringSize.Height); } gfx.TranslateTransform(pixelX, pixelY); gfx.RotateTransform((float)rotation); if (frame) { using (var frameBrush = new SolidBrush(frameColor)) { gfx.FillRectangle(frameBrush, stringRect); } } using (var fontBrush = new SolidBrush(FontColor)) { gfx.DrawString(text, font, fontBrush, new PointF(0, 0)); } gfx.ResetTransform(); } }
public static void Distribution(PlotDimensions dims, Bitmap bmp, bool lowQuality, Population pop, Random rand, double popLeft, double popWidth, Color color, Position position, LineStyle lineStyle) { // adjust edges to accomodate special positions if (position == Position.Hide) { return; } if (position == Position.Left || position == Position.Right) { popWidth /= 2; } if (position == Position.Right) { popLeft += popWidth; } // contract edges slightly to encourage padding between elements double edgePaddingFrac = 0.2; popLeft += popWidth * edgePaddingFrac; popWidth -= (popWidth * edgePaddingFrac) * 2; double[] ys = DataGen.Range(pop.minus3stDev, pop.plus3stDev, dims.UnitsPerPxY); if (ys.Length == 0) { return; } double[] ysFrac = pop.GetDistribution(ys); PointF[] points = new PointF[ys.Length]; for (int i = 0; i < ys.Length; i++) { float x = (float)dims.GetPixelX(popLeft + popWidth * ysFrac[i]); float y = (float)dims.GetPixelY(ys[i]); points[i] = new PointF(x, y); } using (Graphics gfx = GDI.Graphics(bmp, lowQuality)) using (Pen pen = GDI.Pen(color, 1, lineStyle, true)) { gfx.DrawLines(pen, points); } }
public void RenderCandles(PlotDimensions dims, Bitmap bmp, bool lowQuality) { double fractionalTickWidth = .7; float boxWidth = 10; if (AutoWidth) { double spacingPx = GetSmallestSpacing() * dims.PxPerUnitX; boxWidth = (float)(spacingPx / 2 * fractionalTickWidth); } using (Graphics gfx = Graphics.FromImage(bmp)) using (Pen pen = new Pen(Color.Magenta)) using (SolidBrush brush = new SolidBrush(Color.Magenta)) { gfx.SmoothingMode = lowQuality ? SmoothingMode.HighSpeed : SmoothingMode.AntiAlias; gfx.TextRenderingHint = lowQuality ? TextRenderingHint.SingleBitPerPixelGridFit : TextRenderingHint.AntiAliasGridFit; for (int i = 0; i < ohlcs.Length; i++) { var ohlc = ohlcs[i]; var ohlcTime = (Sqeuential) ? i : ohlc.time; float pixelX = dims.GetPixelX(ohlcTime); if (AutoWidth == false) { boxWidth = (float)(ohlc.timeSpan * dims.PxPerUnitX / 2 * fractionalTickWidth); } pen.Color = ohlc.closedHigher ? ColorUp : ColorDown; brush.Color = ohlc.closedHigher ? ColorUp : ColorDown; pen.Width = (boxWidth >= 2) ? 2 : 1; // the wick below the box PointF wickLowBot = new PointF(pixelX, dims.GetPixelY(ohlc.low)); PointF wickLowTop = new PointF(pixelX, dims.GetPixelY(ohlc.lowestOpenClose)); gfx.DrawLine(pen, wickLowBot, wickLowTop); // the wick above the box PointF wickHighBot = new PointF(pixelX, dims.GetPixelY(ohlc.highestOpenClose)); PointF wickHighTop = new PointF(pixelX, dims.GetPixelY(ohlc.high)); gfx.DrawLine(pen, wickHighBot, wickHighTop); // the candle PointF boxLowerLeft = new PointF(pixelX, dims.GetPixelY(ohlc.lowestOpenClose)); PointF boxUpperRight = new PointF(pixelX, dims.GetPixelY(ohlc.highestOpenClose)); gfx.FillRectangle(brush, boxLowerLeft.X - boxWidth, boxUpperRight.Y, boxWidth * 2, boxLowerLeft.Y - boxUpperRight.Y); } } }
public void Render(PlotDimensions dims, Bitmap bmp, bool lowQuality = false) { PointF defaultPoint = new PointF(dims.GetPixelX(x), dims.GetPixelY(y)); PointF textLocationPoint = (rotation == 0) ? TextLocation(defaultPoint) : defaultPoint; using (Graphics gfx = GDI.Graphics(bmp, lowQuality)) using (var framePen = new Pen(frameColor, frameSize * 2)) { gfx.TranslateTransform((int)textLocationPoint.X, (int)textLocationPoint.Y); gfx.RotateTransform((float)rotation); if (frameSize > 0) { gfx.DrawRectangle(framePen, new Rectangle(0, 0, image.Width - 1, image.Height - 1)); } gfx.DrawImage(image, new PointF(0, 0)); gfx.ResetTransform(); } }
public new void Render(PlotDimensions dims, Bitmap bmp, bool lowQuality = false) { base.Render(dims, bmp, lowQuality); if (isHighlighted is null || isHighlighted.Length == 0) { return; } using (var gfx = Graphics.FromImage(bmp)) { gfx.SmoothingMode = lowQuality ? SmoothingMode.HighSpeed : SmoothingMode.AntiAlias; gfx.TextRenderingHint = lowQuality ? TextRenderingHint.SingleBitPerPixelGridFit : TextRenderingHint.AntiAliasGridFit; var highlightedIndexes = Enumerable.Range(0, isHighlighted.Length).Where(x => isHighlighted[x]); foreach (int i in highlightedIndexes) { PointF pt = new PointF(dims.GetPixelX(xs[i]), dims.GetPixelY(ys[i])); MarkerTools.DrawMarker(gfx, pt, highlightedShape, highlightedMarkerSize, highlightedColor); } } }
public static void Scatter(PlotDimensions dims, Bitmap bmp, bool lowQuality, Population pop, Random rand, double popLeft, double popWidth, Color fillColor, Color edgeColor, byte alpha, Position position) { // adjust edges to accomodate special positions if (position == Position.Hide) { return; } if (position == Position.Left || position == Position.Right) { popWidth /= 2; } if (position == Position.Right) { popLeft += popWidth; } // contract edges slightly to encourage padding between elements double edgePaddingFrac = 0.2; popLeft += popWidth * edgePaddingFrac; popWidth -= (popWidth * edgePaddingFrac) * 2; float radius = 5; using (Graphics gfx = GDI.Graphics(bmp, lowQuality)) using (Pen penEdge = GDI.Pen(Color.FromArgb(alpha, edgeColor))) using (Brush brushFill = GDI.Brush(Color.FromArgb(alpha, fillColor))) { foreach (double value in pop.values) { double yPx = dims.GetPixelY(value); double xPx = dims.GetPixelX(popLeft + rand.NextDouble() * popWidth); gfx.FillEllipse(brushFill, (float)(xPx - radius), (float)(yPx - radius), radius * 2, radius * 2); gfx.DrawEllipse(penEdge, (float)(xPx - radius), (float)(yPx - radius), radius * 2, radius * 2); } } }
public void Render(PlotDimensions dims, Bitmap bmp, bool lowQuality = false) { PointF[] points = new PointF[xs.Length]; for (int i = 0; i < xs.Length; i++) { points[i] = new PointF(dims.GetPixelX(xs[i]), dims.GetPixelY(ys[i])); } using (Graphics gfx = GDI.Graphics(bmp, lowQuality)) using (Brush fillBrush = GDI.Brush(Color.FromArgb((byte)(255 * fillAlpha), fillColor))) using (Pen outlinePen = GDI.Pen(lineColor, (float)lineWidth)) { if (fill) { gfx.FillPolygon(fillBrush, points); } if (lineWidth > 0) { gfx.DrawPolygon(outlinePen, points); } } }
public static void Box(PlotDimensions dims, Bitmap bmp, bool lowQuality, Population pop, Random rand, double popLeft, double popWidth, Color color, Position position, BoxFormat boxFormat, HorizontalAlignment errorAlignment = HorizontalAlignment.Right) { // adjust edges to accomodate special positions if (position == Position.Hide) { return; } if (position == Position.Left || position == Position.Right) { popWidth /= 2; } if (position == Position.Right) { popLeft += popWidth; } double errorMaxPx, errorMinPx; double yPxTop, yPxBase; double yPx; if (boxFormat == BoxFormat.StdevStderrMean) { errorMaxPx = dims.GetPixelY(pop.mean + pop.stDev); errorMinPx = dims.GetPixelY(pop.mean - pop.stDev); yPxTop = dims.GetPixelY(pop.mean + pop.stdErr); yPxBase = dims.GetPixelY(pop.mean - pop.stdErr); yPx = dims.GetPixelY(pop.mean); } else if (boxFormat == BoxFormat.OutlierQuartileMedian) { errorMaxPx = dims.GetPixelY(pop.maxNonOutlier); errorMinPx = dims.GetPixelY(pop.minNonOutlier); yPxTop = dims.GetPixelY(pop.Q3); yPxBase = dims.GetPixelY(pop.Q1); yPx = dims.GetPixelY(pop.median); } else { throw new NotImplementedException(); } // make cap width a fraction of available space double capWidthFrac = .38; double capWidth = popWidth * capWidthFrac; // contract edges slightly to encourage padding between elements double edgePaddingFrac = 0.2; popLeft += popWidth * edgePaddingFrac; popWidth -= (popWidth * edgePaddingFrac) * 2; double leftPx = dims.GetPixelX(popLeft); double rightPx = dims.GetPixelX(popLeft + popWidth); RectangleF rect = new RectangleF( x: (float)leftPx, y: (float)yPxTop, width: (float)(rightPx - leftPx), height: (float)(yPxBase - yPxTop)); // determine location of errorbars and caps double capPx1, capPx2, errorPxX; switch (errorAlignment) { case HorizontalAlignment.Center: double centerX = popLeft + popWidth / 2; errorPxX = dims.GetPixelX(centerX); capPx1 = dims.GetPixelX(centerX - capWidth / 2); capPx2 = dims.GetPixelX(centerX + capWidth / 2); break; case HorizontalAlignment.Right: errorPxX = dims.GetPixelX(popLeft + popWidth); capPx1 = dims.GetPixelX(popLeft + popWidth - capWidth / 2); capPx2 = dims.GetPixelX(popLeft + popWidth); break; case HorizontalAlignment.Left: errorPxX = dims.GetPixelX(popLeft); capPx1 = dims.GetPixelX(popLeft); capPx2 = dims.GetPixelX(popLeft + capWidth / 2); break; default: throw new NotImplementedException(); } using (Graphics gfx = GDI.Graphics(bmp, lowQuality)) using (Pen pen = GDI.Pen(Color.Black)) using (Brush brush = GDI.Brush(color)) { // draw the box gfx.FillRectangle(brush, rect.X, rect.Y, rect.Width, rect.Height); gfx.DrawRectangle(pen, rect.X, rect.Y, rect.Width, rect.Height); // draw the line in the center gfx.DrawLine(pen, rect.X, (float)yPx, rect.X + rect.Width, (float)yPx); // draw errorbars and caps gfx.DrawLine(pen, (float)errorPxX, (float)errorMinPx, (float)errorPxX, rect.Y + rect.Height); gfx.DrawLine(pen, (float)errorPxX, (float)errorMaxPx, (float)errorPxX, rect.Y); gfx.DrawLine(pen, (float)capPx1, (float)errorMinPx, (float)capPx2, (float)errorMinPx); gfx.DrawLine(pen, (float)capPx1, (float)errorMaxPx, (float)capPx2, (float)errorMaxPx); } }
public static void Bar(PlotDimensions dims, Bitmap bmp, bool lowQuality, Population pop, Random rand, double popLeft, double popWidth, Color color, Position position, bool useStdErr = false) { // adjust edges to accomodate special positions if (position == Position.Hide) { return; } if (position == Position.Left || position == Position.Right) { popWidth /= 2; } if (position == Position.Right) { popLeft += popWidth; } // determine the center point and calculate bounds double centerX = popLeft + popWidth / 2; double xPx = dims.GetPixelX(centerX); double yPxTop = dims.GetPixelY(pop.mean); double yPxBase = dims.GetPixelY(0); double errorMaxPx, errorMinPx; if (useStdErr) { errorMaxPx = dims.GetPixelY(pop.mean + pop.stdErr); errorMinPx = dims.GetPixelY(pop.mean - pop.stdErr); } else { errorMaxPx = dims.GetPixelY(pop.mean + pop.stDev); errorMinPx = dims.GetPixelY(pop.mean - pop.stDev); } // make cap width a fraction of available space double capWidthFrac = .38; double capWidth = popWidth * capWidthFrac; double capPx1 = dims.GetPixelX(centerX - capWidth / 2); double capPx2 = dims.GetPixelX(centerX + capWidth / 2); // contract edges slightly to encourage padding between elements double edgePaddingFrac = 0.2; popLeft += popWidth * edgePaddingFrac; popWidth -= (popWidth * edgePaddingFrac) * 2; double leftPx = dims.GetPixelX(popLeft); double rightPx = dims.GetPixelX(popLeft + popWidth); RectangleF rect = new RectangleF((float)leftPx, (float)yPxTop, (float)(rightPx - leftPx), (float)(yPxBase - yPxTop)); using (Graphics gfx = GDI.Graphics(bmp, lowQuality)) using (Pen pen = GDI.Pen(Color.Black)) using (Brush brush = GDI.Brush(color)) { gfx.FillRectangle(brush, rect.X, rect.Y, rect.Width, rect.Height); gfx.DrawRectangle(pen, rect.X, rect.Y, rect.Width, rect.Height); gfx.DrawLine(pen, (float)xPx, (float)errorMinPx, (float)xPx, (float)errorMaxPx); gfx.DrawLine(pen, (float)capPx1, (float)errorMinPx, (float)capPx2, (float)errorMinPx); gfx.DrawLine(pen, (float)capPx1, (float)errorMaxPx, (float)capPx2, (float)errorMaxPx); } }
public void Render(PlotDimensions dims, Bitmap bmp, bool lowQuality = false) { int numGroups = normalized.GetUpperBound(0) + 1; int numCategories = normalized.GetUpperBound(1) + 1; double sweepAngle = 2 * Math.PI / numCategories; double minScale = new double[] { dims.PxPerUnitX, dims.PxPerUnitX }.Min(); PointF origin = new PointF(dims.GetPixelX(0), dims.GetPixelY(0)); double[] radii = new double[] { 0.25 * minScale, 0.5 * minScale, 1 * minScale }; using (Graphics gfx = GDI.Graphics(bmp, lowQuality)) using (Pen pen = GDI.Pen(webColor)) using (Brush brush = GDI.Brush(Color.Black)) using (StringFormat sf = new StringFormat() { LineAlignment = StringAlignment.Center }) using (Font font = GDI.Font()) { for (int i = 0; i < radii.Length; i++) { gfx.DrawEllipse(pen, (int)(origin.X - radii[i]), (int)(origin.Y - radii[i]), (int)(radii[i] * 2), (int)(radii[i] * 2)); StringFormat stringFormat = new StringFormat() { Alignment = StringAlignment.Near, LineAlignment = StringAlignment.Far }; gfx.DrawString($"{normalizedMax * radii[i] / minScale:f1}", new Font(FontFamily.GenericSansSerif, 8), brush, origin.X, (float)(-radii[i] + origin.Y), stringFormat); } for (int i = 0; i < numCategories; i++) { PointF destination = new PointF((float)(1.1 * Math.Cos(sweepAngle * i - Math.PI / 2) * minScale + origin.X), (float)(1.1 * Math.Sin(sweepAngle * i - Math.PI / 2) * minScale + origin.Y)); gfx.DrawLine(pen, origin, destination); if (categoryNames != null) { PointF textDestination = new PointF( (float)(1.3 * Math.Cos(sweepAngle * i - Math.PI / 2) * minScale + origin.X), (float)(1.3 * Math.Sin(sweepAngle * i - Math.PI / 2) * minScale + origin.Y)); if (Math.Abs(textDestination.X - origin.X) < 0.1) { sf.Alignment = StringAlignment.Center; } else { sf.Alignment = dims.GetCoordinateX(textDestination.X) < 0 ? StringAlignment.Far : StringAlignment.Near; } gfx.DrawString(categoryNames[i], font, brush, textDestination, sf); } } for (int i = 0; i < numGroups; i++) { PointF[] points = new PointF[numCategories]; for (int j = 0; j < numCategories; j++) { points[j] = new PointF( (float)(normalized[i, j] * Math.Cos(sweepAngle * j - Math.PI / 2) * minScale + origin.X), (float)(normalized[i, j] * Math.Sin(sweepAngle * j - Math.PI / 2) * minScale + origin.Y)); } ((SolidBrush)brush).Color = fillColors[i]; pen.Color = lineColors[i]; gfx.FillPolygon(brush, points); gfx.DrawPolygon(pen, points); } } }
private void RenderAxis(PlotDimensions dims, Bitmap bmp, bool lowQuality) { using (Graphics gfx = GDI.Graphics(bmp, lowQuality)) using (Pen pen = GDI.Pen(Color.Black)) using (Brush brush = GDI.Brush(Color.Black)) using (Font axisFont = GDI.Font(null, 12)) using (StringFormat right_centre = new StringFormat() { Alignment = StringAlignment.Far, LineAlignment = StringAlignment.Center }) using (StringFormat centre_top = new StringFormat() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Near }) { double offset = -2; double minScale = Math.Min(dims.PxPerUnitX, dims.PxPerUnitY); gfx.DrawString($"{AxisOffsets[0]:f3}", axisFont, brush, dims.GetPixelX(0), dims.GetPixelY(offset), centre_top); gfx.DrawString($"{AxisOffsets[0] + AxisMultipliers[0]:f3}", axisFont, brush, new PointF((float)((width * minScale) + dims.GetPixelX(0)), dims.GetPixelY(offset)), centre_top); gfx.DrawString($"{AxisOffsets[1]:f3}", axisFont, brush, dims.GetPixelX(offset), dims.GetPixelY(0), right_centre); gfx.DrawString($"{AxisOffsets[1] + AxisMultipliers[1]:f3}", axisFont, brush, new PointF(dims.GetPixelX(offset), dims.GetPixelY(0) - (float)(height * minScale)), right_centre); } }
public void Render(PlotDimensions dims, Bitmap bmp, bool lowQuality = false) { using (Graphics gfx = GDI.Graphics(bmp, lowQuality)) using (Pen backgroundPen = GDI.Pen(dataBackgroundColor)) using (Pen outlinePen = GDI.Pen(outlineColor, outlineSize)) using (Brush brush = GDI.Brush(Color.Black)) using (Brush fontBrush = GDI.Brush(centerTextColor)) using (Font sliceFont = GDI.Font(null, sliceFontSize)) using (Font centerFont = GDI.Font(null, centerFontSize)) using (StringFormat sfCenter = new StringFormat() { LineAlignment = StringAlignment.Center, Alignment = StringAlignment.Center }) { double[] proportions = values.Select(x => x / values.Sum()).ToArray(); AxisLimits2D limits = GetLimits(); double centreX = limits.xCenter; double centreY = limits.yCenter; float diameterPixels = .9f * Math.Min(dims.DataWidth, dims.DataHeight); // record label details and draw them after slices to prevent cover-ups double[] labelXs = new double[values.Length]; double[] labelYs = new double[values.Length]; string[] labelStrings = new string[values.Length]; RectangleF boundingRectangle = new RectangleF( dims.GetPixelX(centreX) - diameterPixels / 2, dims.GetPixelY(centreY) - diameterPixels / 2, diameterPixels, diameterPixels); if (donutSize > 0) { GraphicsPath graphicsPath = new GraphicsPath(); float donutDiameterPixels = (float)donutSize * diameterPixels; RectangleF donutHoleBoundingRectangle = new RectangleF( dims.GetPixelX(centreX) - donutDiameterPixels / 2, dims.GetPixelY(centreY) - donutDiameterPixels / 2, donutDiameterPixels, donutDiameterPixels); graphicsPath.AddEllipse(donutHoleBoundingRectangle); Region excludedRegion = new Region(graphicsPath); gfx.ExcludeClip(excludedRegion); } double start = -90; for (int i = 0; i < values.Length; i++) { // determine where the slice is to be drawn double sweep = proportions[i] * 360; double sweepOffset = explodedChart ? -1 : 0; double angle = (Math.PI / 180) * ((sweep + 2 * start) / 2); double xOffset = explodedChart ? 3 * Math.Cos(angle) : 0; double yOffset = explodedChart ? 3 * Math.Sin(angle) : 0; // record where and what to label the slice double sliceLabelR = 0.35 * diameterPixels; labelXs[i] = (boundingRectangle.X + diameterPixels / 2 + xOffset + Math.Cos(angle) * sliceLabelR); labelYs[i] = (boundingRectangle.Y + diameterPixels / 2 + yOffset + Math.Sin(angle) * sliceLabelR); string sliceLabelValue = (showValues) ? $"{values[i]}" : ""; string sliceLabelPercentage = showPercentages ? $"{proportions[i] * 100:f1}%" : ""; string sliceLabelName = (showLabels && groupNames != null) ? groupNames[i] : ""; labelStrings[i] = $"{sliceLabelValue}\n{sliceLabelPercentage}\n{sliceLabelName}".Trim(); ((SolidBrush)brush).Color = colors[i]; gfx.FillPie(brush: brush, x: (int)(boundingRectangle.X + xOffset), y: (int)(boundingRectangle.Y + yOffset), width: boundingRectangle.Width, height: boundingRectangle.Height, startAngle: (float)start, sweepAngle: (float)(sweep + sweepOffset)); if (explodedChart) { gfx.DrawPie( pen: backgroundPen, x: (int)(boundingRectangle.X + xOffset), y: (int)(boundingRectangle.Y + yOffset), width: boundingRectangle.Width, height: boundingRectangle.Height, startAngle: (float)start, sweepAngle: (float)(sweep + sweepOffset)); } start += sweep; } ((SolidBrush)brush).Color = Color.White; for (int i = 0; i < values.Length; i++) { if (!string.IsNullOrWhiteSpace(labelStrings[i])) { gfx.DrawString(labelStrings[i], sliceFont, brush, (float)labelXs[i], (float)labelYs[i], sfCenter); } } if (outlineSize > 0) { gfx.DrawEllipse( outlinePen, boundingRectangle.X, boundingRectangle.Y, boundingRectangle.Width, boundingRectangle.Height); } gfx.ResetClip(); if (centerText != null) { gfx.DrawString(centerText, centerFont, fontBrush, dims.GetPixelX(0), dims.GetPixelY(0), sfCenter); } if (explodedChart) { // draw a background-colored circle around the perimeter to make it look like all pieces are the same size backgroundPen.Width = 20; gfx.DrawEllipse( pen: backgroundPen, x: boundingRectangle.X, y: boundingRectangle.Y, width: boundingRectangle.Width, height: boundingRectangle.Height); } } }
public void Render(PlotDimensions dims, Bitmap bmp, bool lowQuality = false) { if (IsValidData() == false) { throw new InvalidOperationException($"Invalid data: {ValidationErrorMessage}"); } using (var gfx = Graphics.FromImage(bmp)) using (var font = GDI.Font(FontName, FontSize, FontBold)) using (var fontBrush = new SolidBrush(FontColor)) using (var linePen = new Pen(LineColor, LineWidth)) using (var sfNorth = new StringFormat() { LineAlignment = StringAlignment.Near, Alignment = StringAlignment.Center }) using (var sfWest = new StringFormat() { LineAlignment = StringAlignment.Center, Alignment = StringAlignment.Near }) { gfx.SmoothingMode = lowQuality ? SmoothingMode.HighSpeed : SmoothingMode.AntiAlias; gfx.TextRenderingHint = lowQuality ? TextRenderingHint.SingleBitPerPixelGridFit : TextRenderingHint.AntiAliasGridFit; // determine where the corner of the scalebar will be float widthPx = (float)(Width * dims.PxPerUnitX); float heightPx = (float)(Height * dims.PxPerUnitY); PointF cornerPoint = new PointF(dims.GetPixelX(dims.XMax) - Padding, dims.GetPixelY(dims.YMin) - Padding); // move the corner point away from the edge to accommodate label size var xLabelSize = GDI.MeasureString(gfx, HorizontalLabel, font); var yLabelSize = GDI.MeasureString(gfx, VerticalLabel, font); cornerPoint.X -= yLabelSize.Width * 1.2f; cornerPoint.Y -= yLabelSize.Height; // determine all other points relative to the corner point PointF horizPoint = new PointF(cornerPoint.X - widthPx, cornerPoint.Y); PointF vertPoint = new PointF(cornerPoint.X, cornerPoint.Y - heightPx); PointF horizMidPoint = new PointF((cornerPoint.X + horizPoint.X) / 2, cornerPoint.Y); PointF vertMidPoint = new PointF(cornerPoint.X, (cornerPoint.Y + vertPoint.Y) / 2); // draw the scalebar gfx.DrawLines(linePen, new PointF[] { horizPoint, cornerPoint, vertPoint }); gfx.DrawString(HorizontalLabel, font, fontBrush, horizMidPoint.X, cornerPoint.Y, sfNorth); gfx.DrawString(VerticalLabel, font, fontBrush, cornerPoint.X, vertMidPoint.Y, sfWest); } }