public static Axis Parse(String str) { var split = str.Split(','); var axis = new Axis(); if (split.Length > 0) { axis.Label = split[0].Replace("[mu]", "μ"); } if (split.Length > 1) { var range = split[1].Split('-'); if (range.Length == 1) { axis.Maximum = ParseRange(range[0]); } else if (range.Length == 2) { axis.Minimum = ParseRange(range[0]); axis.Maximum = ParseRange(range[1]); } } if (split.Length > 2) { axis.MajorInterval = int.Parse(split[2]); } if (split.Length > 3) { axis.MinorInterval = int.Parse(split[3]); } return axis; }
static void Main(string[] args) { string outputPath = "graph.png"; int imgWidth = 768; int imgHeight = 384; int margin = 16; var xAxis = new Axis(); var yAxis = new Axis(); var dataSets = new List<DataSet>(); for (int i = 0; i < args.Length; ++i) { switch (args[i]) { case "-o": case "--output": outputPath = args[++i]; break; case "-w": case "--width": imgWidth = int.Parse(args[++i]); break; case "-h": case "--height": imgHeight = int.Parse(args[++i]); break; case "-x": case "--xaxis": xAxis = Axis.Parse(args[++i]); break; case "-y": case "--yaxis": yAxis = Axis.Parse(args[++i]); break; default: dataSets.Add(DataSet.Parse(args[i])); break; } } if (xAxis.Minimum == int.MinValue) { xAxis.Minimum = (int) Math.Floor(dataSets.Min(x => x.GetPoints().Min(y => y.X))); } if (xAxis.Maximum == int.MaxValue) { xAxis.Maximum = (int) Math.Ceiling(dataSets.Max(x => x.GetPoints().Max(y => y.X))); } if (yAxis.Minimum == int.MinValue) { yAxis.Minimum = (int) Math.Floor(dataSets.Min(x => x.GetPoints().Min(y => y.Y))); } if (yAxis.Maximum == int.MaxValue) { yAxis.Maximum = (int) Math.Ceiling(dataSets.Max(x => x.GetPoints().Max(y => y.Y))); } using (var bmp = new Bitmap(imgWidth, imgHeight)) { using (var ctx = Graphics.FromImage(bmp)) { ctx.Clear(Color.White); var labelFont = new Font(FontFamily.GenericSansSerif, 20f); var labelBrush = new SolidBrush(Color.Gray); var intervalFont = new Font(FontFamily.GenericSansSerif, 14f); var intervalBrush = new SolidBrush(Color.Gray); int left = margin + 64; int right = imgWidth - margin; int top = margin; int bottom = imgHeight - margin - 64; int width = right - left; int height = bottom - top; ctx.SmoothingMode = SmoothingMode.AntiAlias; var axisPen = new Pen(Color.DarkGray, 2f); var majorGridPen = new Pen(Color.LightGray, 2f); var minorGridPen = new Pen(Color.LightGray, 1f); ctx.DrawStringCentred(xAxis.Label, labelFont, labelBrush, left + width / 2f, bottom + 56f); ctx.TranslateTransform(left - 56f, top + height / 2f); ctx.RotateTransform(-90f); ctx.DrawStringCentred(yAxis.Label, labelFont, labelBrush, 0f, 0f); ctx.ResetTransform(); for (int i = 0; i * xAxis.MajorInterval <= xAxis.Maximum; ++i) { int x = (i * xAxis.MajorInterval * width) / xAxis.Maximum; ctx.DrawLine(majorGridPen, left + x, top, left + x, bottom + 4); ctx.DrawStringCentred((i * xAxis.MajorInterval).ToString(), intervalFont, intervalBrush, left + x, bottom + 16); } for (int i = 1; i * xAxis.MinorInterval <= xAxis.Maximum; ++i) { int x = (i * xAxis.MinorInterval * width) / xAxis.Maximum; ctx.DrawLine(minorGridPen, left + x, top, left + x, bottom); } for (int i = 0; i * yAxis.MajorInterval <= yAxis.Maximum; ++i) { int y = (i * yAxis.MajorInterval * height) / yAxis.Maximum; ctx.DrawLine(majorGridPen, left - 4, bottom - y, right, bottom - y); ctx.DrawStringRightAligned((i * yAxis.MajorInterval).ToString(), intervalFont, intervalBrush, left - 6, bottom - y); } for (int i = 1; i * yAxis.MinorInterval <= yAxis.Maximum; ++i) { int y = (i * yAxis.MinorInterval * height) / yAxis.Maximum; ctx.DrawLine(minorGridPen, left, bottom - y, right, bottom - y); } foreach (var dataSet in dataSets) { var points = dataSet.GetPoints() .Select(p => new PointF( left + ((p.X - xAxis.Minimum) * width) / xAxis.Maximum, top + ((yAxis.Maximum - p.Y + yAxis.Minimum) * height) / yAxis.Maximum)) .ToArray(); ctx.DrawLines(dataSet.Pen, points); } ctx.DrawLine(axisPen, left, top, left, bottom + 4); ctx.DrawLine(axisPen, left - 4, bottom, right, bottom); int legendTop = top + margin; int legendRight = right - margin; int legendWidth = 56 + (int) Math.Ceiling(dataSets.Max(x => ctx.MeasureString(x.Label, intervalFont).Width)); int legendHeight = dataSets.Count * 32 + 16; int legendLeft = legendRight - legendWidth; int legendBottom = legendTop + legendHeight; ctx.FillRectangle(new SolidBrush(Color.FromArgb(191, Color.White)), legendLeft, legendTop, legendWidth, legendHeight); ctx.DrawRectangle(minorGridPen, legendLeft, legendTop, legendWidth, legendHeight); int yPos = legendTop + 8; foreach (var dataSet in dataSets) { ctx.DrawRectangle(minorGridPen, legendLeft + 12f, yPos + 4f, 24f, 24f); ctx.FillRectangle(new SolidBrush(dataSet.Pen.Color), legendLeft + 14f, yPos + 6f, 20f, 20f); ctx.DrawStringLeftAligned(dataSet.Label, intervalFont, labelBrush, legendLeft + 48f, yPos + 16f); yPos += 32; } } bmp.Save(outputPath); } }