Mark the regions over the zed graph - c#

Currently I am using ZedGraph to display my curve. I want to mark the particular regions of the curve over the ZedGraph control and label it like follows.
Note: I need different type of markings in the X and Y axis based on the text size.
Thanks for your help in advance.

You have two options,
1) Use BoxObject to draw at a specific region as follows
and you can use the source code as follows:
private void Form1_Load(object sender, EventArgs e)
{
// Create an instance of Graph Pane
GraphPane myPane = zedGraphControl1.GraphPane;
// Build a PointPairList with points based on Sine wave
PointPairList list = new PointPairList();
for (double i = 0; i < 36; i++)
{
double x = i * 10.0 + 50.0;
double y = Math.Sin(i * Math.PI / 15.0) * 16.0;
list.Add(x, y);
}
// Hide the legend
myPane.Legend.IsVisible = false;
// Add a curve
LineItem curve = myPane.AddCurve("label", list, Color.Red, SymbolType.Circle);
curve.Line.Width = 1.5F;
curve.Symbol.Fill = new Fill(Color.White);
curve.Symbol.Size = 5;
// Make the XAxis start with the first label at 50
myPane.XAxis.Scale.BaseTic = 50;
// Fill the axis background with a gradient
myPane.Chart.Fill = new Fill(Color.White, Color.SteelBlue, 45.0F);
// Draw Region 1
drawRegion(list[0].X, list[10].X,"Positive Cycle");
// Calculate the Axis Scale Ranges
zedGraphControl1.AxisChange();
// Refresh to paint the graph components
Refresh();
}
private void drawRegion(double xMin, double xMax, string regName)
{
GraphPane pane = zedGraphControl1.GraphPane;
BoxObj box = new BoxObj(xMin,20, xMax, 40.0, Color.Empty, Color.LightSteelBlue);// Color.FromArgb(225, 245, 225));
box.Location.CoordinateFrame = CoordType.AxisXYScale;
box.Location.AlignH = AlignH.Left;
box.Location.AlignV = AlignV.Top;
// place the box behind the axis items, so the grid is drawn on top of it
box.ZOrder = ZOrder.E_BehindCurves;//.D_BehindAxis;//.E_BehindAxis;
pane.GraphObjList.Add(box);
// Add Region text inside the box
TextObj myText = new TextObj(regName, 160, -15);
myText.Location.CoordinateFrame = CoordType.AxisXYScale;
myText.Location.AlignH = AlignH.Right;
myText.Location.AlignV = AlignV.Center;
myText.FontSpec.IsItalic = true;
myText.FontSpec.IsBold = false;
myText.FontSpec.FontColor = Color.Red;
myText.FontSpec.Fill.IsVisible = false;
myText.FontSpec.Border.IsVisible = false;
pane.GraphObjList.Add(myText);
zedGraphControl1.Refresh();
}
2) This is a bit difficult but do-able, Draw individual vertical lines discussed here: 1, 2 and add the required text etc.
I suggest you to use the option 1, which is lot easier than 2 !

Related

How to use windows forms report with radial gauge

I tried to find information on how to use a radial gauge in a windows form report.
I really can't find anything on this. Not sure if there is not much info on this.
Is there anyone who can get me some info on this? How would I be able to use a value from a text box in a report viewer to show this on a radial gauge and even using a track bar to get some idea how to use it.
Even if getting a small example to build on this would be really great :-)
You have several options even without any external stuff.
You can draw a gauge needle onto a gauge image. Here is an example.
You can draw the needle onto an image by either calulating the outer point and drawing a line to the center or by rotating the canvas as in the link.
Or you can use the built-in MSChart control and its Doughnut charttype.
Here is an example for this:
The code is simple:
first we set up the chart by adding three DataPoints; then we code a function to update the value.
The points are for
the open, transparent part
the value of the gauge in green
the rest of the scale in red
For testing I use these variables:
double valMin = 0; // user data minimum
double valMax = 100; // ~ maximum
float angle = 60; // open pie angle at the bottom
string valFmt = "{0}°"; // a format string
My current value is pulled from a trackbar.
Setup code:
void setupChartGauge(double val, double vMin, double vMax, float a)
{
valMin = vMin;
valMax = vMax;
angle = a;
Series s = gaugeChart.Series[0];
s.ChartType = SeriesChartType.Doughnut;
s.SetCustomProperty("PieStartAngle", (90 - angle/2) + "");
s.SetCustomProperty("DoughnutRadius", "10");
s.Points.Clear();
s.Points.AddY(angle);
s.Points.AddY(0);
s.Points.AddY(0);
setChartGauge(0);
s.Points[0].Color = Color.Transparent;
s.Points[1].Color = Color.Chartreuse;
s.Points[2].Color = Color.Tomato;
}
and setting a value:
void setChartGauge(double val)
{
Series s = gaugeChart.Series[0];
double range = valMax - valMin;
double aRange = 360 - angle;
double f = aRange / range;
double v1 = val * f;
double v2 = (range - val) * f;
s.Points[1].YValues[0] = v1;
s.Points[2].YValues[0] = v2;
gaugeChart.Titles[0].Text = String.Format(valFmt, val);
gaugeChart.Refresh();
}
I have added minimal styling:
The Chart has a Title docked centered bottom which I also update
I have set a back color
I paint an inner circle in the Paint event like so:
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
Rectangle r = chart1.ClientRectangle;
r.Inflate(-10, -10);
using (SolidBrush brush = new SolidBrush(Color.FromArgb(55, Color.Beige)))
e.Graphics.FillEllipse(brush, r);
Note that Pie and Doughnut charts can have only one series. To show a 2nd one you would need an overlapping 2nd chartarea with the exact same Position.
There are infinite ways to draw stuff, both from scratch or updating the MsChart control. Various gradient brushes come to mind. Adding ticks and a needle will involve rotation code, which basically consists of 3 lines of code..
Update:
Here is an example of drawing a gauge needle.
The code should be called from a Paint event and should pass out a valid Graphics object (read: e.Graphics), a float for the data value, a Rectangle to place the gauge in, a Color and a float for the percentage of the rectangle size to use.
private void drawNeedle(Graphics g, float val, Rectangle r, Color c, float length)
{
Point pc = new Point(r.X + r.Width / 2, r.Y + r.Height / 2);
Point p2 = new Point((int)( pc.X + r.Width / 2 * length / 100f), pc.Y);
using (Pen pen = new Pen(c, 3f)
{ StartCap = LineCap.RoundAnchor, EndCap = LineCap.ArrowAnchor })
{
g.SmoothingMode = SmoothingMode.AntiAlias;
g.TranslateTransform(pc.X, pc.Y);
g.RotateTransform(val - (270 - angle / 2));
g.TranslateTransform(-pc.X, -pc.Y);
g.DrawLine(pen, pc, p2);
g.ResetTransform();
}
}
You can use it in any control that support owner-drawing including the chart..:
drawNeedle(e.Graphics, (float)gaugeChart.Series[0].Points[1].YValues[0], r, Color.White, 70f);
Here is a simple example with a TrackBar:
private Syncfusion.Windows.Forms.Gauge.RadialGauge radialGauge1;
private System.Windows.Forms.TrackBar trackBar1;
private Syncfusion.Windows.Forms.Gauge.Needle needle1;
private void InitializeComponent()
{
this.needle1 = new Syncfusion.Windows.Forms.Gauge.Needle();
this.needle1.Value = 0F;
this.trackBar1 = new System.Windows.Forms.TrackBar();
this.radialGauge1 = new Syncfusion.Windows.Forms.Gauge.RadialGauge();
this.trackBar1.Value = (int) needle1.Value;
this.radialGauge1.EnableCustomNeedles = true;
this.radialGauge1.NeedleCollection.Add(needle1);
this.radialGauge1.Size = new System.Drawing.Size(230, 230);
this.radialGauge1.TabIndex = 0;
this.trackBar1.Scroll += new System.EventHandler(this.trackBar1_Scroll);
}
And a scroll event which sync between gauge and trackBar:
private void trackBar1_Scroll(object sender, EventArgs e)
{
needle1.Value = trackBar1.Value;
}

Stripline label

Currently, I have been doing a project on graphs on windows form. Now I have something to ask.
Is there by any chance a way to move the Stripeline label out of my chart and not have it in the chart to something like this What I expect it to be and also make my stripeline tinner because it is too thick
till date what i do
What I expect it to be
This is my stripline code in case you need it
StripLine stripLine1 = new StripLine();
stripLine1.StripWidth = 0.01;
stripLine1.BorderColor = System.Drawing.Color.Blue;
stripLine1.BorderWidth = 0;
stripLine1.BorderDashStyle = ChartDashStyle.Solid;
stripLine1.IntervalOffset = Convert.ToDouble(textBox7.Text);
stripLine1.BackColor = System.Drawing.Color.Blue;
stripLine1.Text = "x̅";
chart1.ChartAreas[0].AxisY.StripLines.Add(stripLine1);
No, StripLines are drawn inside their ChartArea only.
There are at least two options:
You can display their Text outside of it by coding a PaintXXX event, maybe like this:
private void chart1_PostPaint(object sender, ChartPaintEventArgs e)
{
ChartArea ca = chart1.ChartAreas[0];
Axis ax = ca.AxisX;
Axis ay = ca.AxisY;
Graphics g = e.ChartGraphics.Graphics;
foreach (StripLine sl in ay.StripLines)
{
double v = (sl.Interval != double.NaN ? sl.Interval : 0) + sl.IntervalOffset;
TextRenderer.DrawText(g, sl.Text, sl.Font, new Point(
(int)ax.ValueToPixelPosition(ax.Maximum),
(int)ay.ValueToPixelPosition(v)),Color.Black);
}
}
Fine-tuning the position, maybe by honoring the TextAlignment properties is up to you..
Note that this will now display the text twice; a simple solution it to make the original label transparent:
YourStripLine.ForeColor = Color.Transparent;
Also note that drawn graphics will not get exported if you serialize the chart.
An alternative would be to set the secondary y-axis and add the labels as CustomLabels. On second thought, I think this is preferrable, at least if you don't need the secondary y-axis.
Here I do it for one stripline:
Axis ay2 = chart1.ChartAreas[0].AxisY2;
ay2.Enabled = AxisEnabled.True;
ay2.LineColor = Color.Transparent;
CustomLabel cl = new CustomLabel();
cl.Text = stripLine.Text;
double v = (stripLine.Interval != double.NaN ? stripLine.Interval : 0)
+ stripLine.IntervalOffset;
cl.FromPosition = v - 0.001;
cl.ToPosition = v + 0.001;
ay2.CustomLabels.Add(cl);
You here also will want to make the original text transparent.

Zedgraph Horizontal Bar graph with different bar colors C#

I am working on zedgraph and generating a horizontal bar graph. I only want to know if there is any way by which each single bar can be made of different color. The output of the code is acceptable, I only intend on changing the color of the bars being generated. Any help would be much appreciated. Thanks!
myPane.YAxis.Title.Text = "Nominees";
myPane.XAxis.Title.Text = "Votes";
// Make up some random data points
string[] labels= new string[count];
for (int i = count-1; i >= 0; i--)
{
labels[counter] = voternames[i];
counter++;
}
for (int i = count1-1; i >= 0; i--)
{
y0[counter1] = Convert.ToDouble(votes[i]);
counter1++;
}
// Generate a red bar with "Curve 1" in the legend
BarItem myBar = myPane.AddBar("", y0, null, Color.Green);
// Draw the X tics between the labels instead of
// at the labels
myPane.YAxis.MajorTic.IsBetweenLabels = false;
// Set the XAxis labels
myPane.YAxis.Scale.TextLabels = labels;
// Set the XAxis to Text type
myPane.YAxis.Type = AxisType.Text;
myPane.BarSettings.Base = BarBase.Y;
// Fill the Axis and Pane backgrounds
myPane.Fill = new Fill(Color.FromArgb(250, 250, 255));
// Tell ZedGraph to refigure the
// axes since the data have changed
zgc.AxisChange();
zgc.Refresh();
Found what I was looking for, the original link to source is:
http://www.ironpython.info/index.php?title=Multi-colored_Bar_Chart_with_ZedGraph. The main modification was making a Point pair list instead of sending the double array for creating bars, giving reference to color array and setting min and max range for fills. The modified code is as follows:
myPane.YAxis.Title.Text = "Nominees";
myPane.XAxis.Title.Text = "Votes";
// Make up some random data points
string[] labels= new string[count];
//string[] labelx = new string[count];
for (int i = count-1; i >= 0; i--)
{
labels[counter] = voternames[i];
counter++;
}
for (int i = count1-1; i >= 0; i--)
{
y0[counter1] = Convert.ToDouble(votes[i]);
counter1++;
}
for (int i = 0; i < y0.Length; i++)
{
//Adding the x axis data and using y axis as a source to color a single bar
list.Add(y0[i], i / 2.0);
}
Color[] colors = new Color[] {Color.Red, Color.Yellow, Color.Green, Color.Blue, Color.Purple};
// Generate a bar with point pair list in the legend
BarItem myBar = myPane.AddBar("", list, Color.Green);
// Giving ref of color array
myBar.Bar.Fill = new Fill(colors);
//Setting to fill with using point values of y axis
myBar.Bar.Fill.Type = FillType.GradientByY;
//Setting min and max range is important
myBar.Bar.Fill.RangeMin = 0;
myBar.Bar.Fill.RangeMax = Convert.ToInt32(y0[0]);
// Draw the X tics between the labels instead of
// at the labels
myPane.YAxis.MajorTic.IsBetweenLabels = false;
// Set the XAxis labels
myPane.YAxis.Scale.TextLabels = labels;
// Set the XAxis to Text type
myPane.YAxis.Type = AxisType.Text;
myPane.BarSettings.Base = BarBase.Y;
// Fill the Axis and Pane backgrounds
//myPane.Chart.Fill = new Fill(Color.White,Color.FromArgb(255, 255, 166), 90F);
myPane.Fill = new Fill(Color.FromArgb(250, 250, 255));
// Tell ZedGraph to refigure the
// axes since the data have changed
zgc.AxisChange();
zgc.Refresh();

Line Chart Rectangle Annotation resize acording to the point counts

I have a line chart. I read a value and its recording time from a database and add those to line chart every second. So my points increases every second.
The problem is that. I added a line and rectangle annonation to my line chart. Line annonation stay at same width as it had at the beginning but rectangle annonation's width changes acording to the points' count i have added.
Like this;
I just want that rectangle annonation have a fixed width How can i do that?
Code;
VerticalLineAnnotation VA;
RectangleAnnotation RA;
double xFactor = 0.03;
double yFactor = 0.02;
VA = new VerticalLineAnnotation();
VA.AxisX = chartMonitor.ChartAreas[0].AxisX;
VA.AllowMoving = true;
VA.IsInfinitive = true;
VA.ClipToChartArea = chartMonitor.ChartAreas[0].Name;
VA.Name = "myLine";
VA.LineColor = Color.Red;
VA.LineWidth = 2;
VA.X = 1;
RA = new RectangleAnnotation();
RA.AxisX = chartMonitor.ChartAreas[0].AxisX;
RA.IsSizeAlwaysRelative = false;
RA.Width = 10 * xFactor;
RA.Height = 30 * yFactor;
VA.Name = "myRect";
RA.LineColor = Color.Red;
RA.BackColor = Color.Red;
RA.AxisY = chartMonitor.ChartAreas[0].AxisY;
RA.Y = -RA.Height;
RA.X = VA.X - RA.Width / 2;
RA.Text = "M1";
RA.ForeColor = Color.White;
RA.Font = new System.Drawing.Font("Arial", 8f);
chartMonitor.Annotations.Add(VA);
chartMonitor.Annotations.Add(RA);
chartMonitor.AnnotationPositionChanged += new EventHandler(chartMonitor_AnnotationPositionChanged);
chartMonitor.AnnotationPositionChanging += new EventHandler<AnnotationPositionChangingEventArgs>(chartMonitor_AnnotationPositionChanging);
void chartMonitor_AnnotationPositionChanging(object sender, AnnotationPositionChangingEventArgs e)
{
if (sender == VA) RA.X = VA.X - RA.Width / 2;
}
void chartMonitor_AnnotationPositionChanged(object sender, EventArgs e)
{
VA.X = (int)(VA.X + 0.5);
RA.X = VA.X - RA.Width / 2;
}
I think I remember that piece of code..
The Annotation is bound to the X-Axis, which means most of its Properties are measured in X-Axis values. (Not the LineWidth, though, which is in Pixels or the FontSize, which works as usual..)
I had included a factor to let you scale things as needed.
Assuming a value f1 = 0.03 works well for N1 data points you will need to re-calculate for N2 data points like this:
xFactor = f1 * N1 / N2;
So you should introduce a const f1 and re-calculate the factor when you add or remove plot points..
Here is a function that will do that:
void scaleAnnotation(Annotation A)
{
ChartArea CA = chart1.ChartAreas[0];// pick your chartarea..
A.AxisX = CA.AxisX; // .. and axis!
int N = S1.Points.Count; // S1 being your Series !
// to keep the label width constant the chart's width must be considered
// 60 is my 'magic' number; you must adapt for your chart's x-axis scale!
double xFactor = 60 * N / chart1.Width;
A.Width = 1 * xFactor ;
A.X = VA.X - A.Width / 2;
}
I found that even when resizing the chart, adding 10.000 points and removing them one by one the label's width is pretty much constant.
Note: You will have to adapt the xFactor to your Chart's x-Values scale; do a few tests..!
I find that calling this every time I add a point keeps the label at a pretty constant size even when the chart itself has hundereds of points.

How can I avoid that ZedGraph relabels my YAxis, dividing by 1000?

I am creating a C# visual studio forms application that uses zedgraph to chart the data that the program collects but I am running into the following issue when plotting the data:
My y-axis values are usually in the 100,000+ range so when zed graph plots the value it labels the y-axis labels with stuff like 0, 10, 15, 20, 25 and then on the y-axis label it will append "(10^3)" to the title and will plot the values accordingly. What I want to do is have it label the y-axis either with values like 0, 10,000, 15,000, 20,000 etc or 0, 10k, 15k, 20k and so on and not have it adjust the y-axis title.
I tried setting YAxis.Scale.MajorStep = double.Parse("10000"); but the only effect that has is to add a ton of more tick lines on the y-axis but no other effect. Here is my code that graphs the data:
private void createGraph()
{
GraphPane myPane = zdc_graph.GraphPane;
myPane.CurveList.Clear();
myPane.GraphObjList.Clear();
myPane.Title.Text = this.monitoredHost.hostName + "\nWorkState[" +
this.monitoredHost.currentWorkState + "]";
myPane.XAxis.Title.Text = "";
myPane.YAxis.Title.Text = "OPS Per Second";
myPane.YAxis.Scale.FontSpec.FontColor = Color.Blue;
myPane.YAxis.Title.FontSpec.FontColor = Color.Blue;
myPane.YAxis.Scale.MaxAuto = true;
myPane.Y2Axis.Title.Text = "Reading";
myPane.Y2Axis.IsVisible = true;
myPane.Y2Axis.Scale.FontSpec.FontColor = Color.Red;
myPane.Y2Axis.Title.FontSpec.FontColor = Color.Red;
myPane.XAxis.Type = AxisType.Date;
myPane.XAxis.Scale.Format = "T";
myPane.XAxis.Scale.MajorUnit = DateUnit.Second;
myPane.YAxis.Scale.Min = 0;
myPane.YAxis.Scale.MajorStep = double.Parse("10000");
myPane.Y2Axis.Scale.Min = 0;
LineItem kpiCurve = myPane.AddCurve("OPS Per Second",
this.monitoredHost.graphKpiList,
Color.Blue,SymbolType.Circle);
LineItem pwrCurve = myPane.AddCurve("Reading",
this.monitoredHost.graphPwrList, Color.Red,
SymbolType.Circle);
kpiCurve.Line.Width = 2.0F;
kpiCurve.Symbol.Size = 4.0F;
kpiCurve.Symbol.Fill = new Fill(Color.White);
pwrCurve.Line.Width = 2.0F;
pwrCurve.Symbol.Size = 4.0F;
pwrCurve.Symbol.Fill = new Fill(Color.White);
pwrCurve.IsY2Axis = true;
myPane.Chart.Fill = new Fill(Color.White, Color.FromArgb(255, 255, 210), -45F);
zdc_graph.AxisChange();
zdc_graph.Refresh();
}
I hope this makes sense. Thanks for the help.
ZedGraph is attempting to detect magnitude and simplify the graph. You can turn this off with the following:
myPane.YAxis.Scale.MagAuto = false;
This will result in y-axis labels like 100000.
If you want to format the label with a separator comma like 100,000:
myPane.YAxis.Scale.Format = "#,#";
Finally, if you prefer to show 100k, you'll need to subscribe to the ScaleFormatEvent and return your own format, like this:
myPane.YAxis.ScaleFormatEvent += new Axis.ScaleFormatHandler(YAxis_ScaleFormatEvent);
string YAxis_ScaleFormatEvent(GraphPane pane, Axis axis, double val, int index)
{
return String.Format("{0}k", val / 1000);
}
I am having similar problem. So applying your method it works on the application but i also want to print out the graph in a PDF file (using MigraDoc) but it does work.
public Bitmap printGraphPane()
{
ZedGraphControl graph = new ZedGraphControl();
GraphPane newGP = myPane.GraphPane;
//newGP.YAxis.Scale.Mag = 0;
//newGP.YAxis.Scale.Format = "#";
//newGP.YAxis.ScaleFormatEvent += new Axis.ScaleFormatHandler(YAxis_ScaleFormatEvent);
Bitmap bit = new Bitmap(newGraph.Width, newGraph.Height);
newGraph.ClientSize = bit.Size;
newGraph.DrawToBitmap(bit, new Rectangle(0, 0, newGraph.Width, newGraph.Height));
return bit;
}

Categories

Resources