Drawing a grid for plotting a graph
-
Hi, I am plotting a graph between frequency on x-axis and gain on y-axis. X-axis(frequency) needs to vary logarithmically and y-axis(gain) needs to vary linearly. The first step was to create the axis and put numbers on the lines. As the default origin is at the Left Top corner of the client area, I moved the origin to the center of the client area and inverted the y-axis, so that whatever drawing takes place it should be as per the new origin and looks more realistic. I tried to create few lines along with string to number them. Lines are drawn properly, however the string also got inverted. Here is the code, I tried to use. It can be used in any winform application.
private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.TranslateTransform(this.ClientSize.Width / 2, this.ClientSize.Height / 2);
g.ScaleTransform(1, -1);Point A = new Point(0, 0); Point B = new Point(120, 80); Point C = new Point(120, -80); g.DrawLine(Pens.Red, A, B); g.DrawLine(Pens.Green, A, C); g.DrawLine(Pens.Purple, 0, 0, -50, 70); //g.ResetTransform(); g.DrawString("3", new Font("Arial", 16), new SolidBrush(Color.Purple), B); }
Question 1: How can we draw string after inverting the y-axis? Question 2: How can we make vertical lines that should vary logarithmically? Any idea/solution is welcome.
Praveen Raghuvanshi Software Developer
-
Hi, I am plotting a graph between frequency on x-axis and gain on y-axis. X-axis(frequency) needs to vary logarithmically and y-axis(gain) needs to vary linearly. The first step was to create the axis and put numbers on the lines. As the default origin is at the Left Top corner of the client area, I moved the origin to the center of the client area and inverted the y-axis, so that whatever drawing takes place it should be as per the new origin and looks more realistic. I tried to create few lines along with string to number them. Lines are drawn properly, however the string also got inverted. Here is the code, I tried to use. It can be used in any winform application.
private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.TranslateTransform(this.ClientSize.Width / 2, this.ClientSize.Height / 2);
g.ScaleTransform(1, -1);Point A = new Point(0, 0); Point B = new Point(120, 80); Point C = new Point(120, -80); g.DrawLine(Pens.Red, A, B); g.DrawLine(Pens.Green, A, C); g.DrawLine(Pens.Purple, 0, 0, -50, 70); //g.ResetTransform(); g.DrawString("3", new Font("Arial", 16), new SolidBrush(Color.Purple), B); }
Question 1: How can we draw string after inverting the y-axis? Question 2: How can we make vertical lines that should vary logarithmically? Any idea/solution is welcome.
Praveen Raghuvanshi Software Developer
Leave the graphics object untranslated and untransformed. Do the y-axis inversion and scaling in separate code instead. That way, you have full control over what is drawn where. A good idea would be to encapsulate all of that conversion processing so that you can call it using just "normal" values.
Ciao, luker
-
Leave the graphics object untranslated and untransformed. Do the y-axis inversion and scaling in separate code instead. That way, you have full control over what is drawn where. A good idea would be to encapsulate all of that conversion processing so that you can call it using just "normal" values.
Ciao, luker
Thanks Lukeer!!! I tried your suggestion, missed somewhere. Appreciate if you can help me draw three lines with numbering on them according to the order of drawing them. I wish to have origin in the center of the window and all points should be given according to that. Y-axis should be positive in the upward direction and negative in the downward direction. Thanks,
Praveen Raghuvanshi Software Developer
-
Hi, I am plotting a graph between frequency on x-axis and gain on y-axis. X-axis(frequency) needs to vary logarithmically and y-axis(gain) needs to vary linearly. The first step was to create the axis and put numbers on the lines. As the default origin is at the Left Top corner of the client area, I moved the origin to the center of the client area and inverted the y-axis, so that whatever drawing takes place it should be as per the new origin and looks more realistic. I tried to create few lines along with string to number them. Lines are drawn properly, however the string also got inverted. Here is the code, I tried to use. It can be used in any winform application.
private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.TranslateTransform(this.ClientSize.Width / 2, this.ClientSize.Height / 2);
g.ScaleTransform(1, -1);Point A = new Point(0, 0); Point B = new Point(120, 80); Point C = new Point(120, -80); g.DrawLine(Pens.Red, A, B); g.DrawLine(Pens.Green, A, C); g.DrawLine(Pens.Purple, 0, 0, -50, 70); //g.ResetTransform(); g.DrawString("3", new Font("Arial", 16), new SolidBrush(Color.Purple), B); }
Question 1: How can we draw string after inverting the y-axis? Question 2: How can we make vertical lines that should vary logarithmically? Any idea/solution is welcome.
Praveen Raghuvanshi Software Developer
As Lukeer says, you should calculate the canvas position from chart coordinates yourself. Using translate and scale seems clever but as you've discovered it causes text to be drawn upside down as well. When I draw a log chart I still place gridlines linearly but label them logarithmically (e.g. 0.5, 1, 2, 4, or 1, 10, 100, 1000). I find the 'log graphpaper' approach to be fussy and generally not helpful. But if you want to do that then it is easy enough to calculate the appropriate chart coordinate Y values (log y at sensible Y values such as 1, 2, 5 each power of 10), and then you can transform those like all the other things for drawing.
-
Thanks Lukeer!!! I tried your suggestion, missed somewhere. Appreciate if you can help me draw three lines with numbering on them according to the order of drawing them. I wish to have origin in the center of the window and all points should be given according to that. Y-axis should be positive in the upward direction and negative in the downward direction. Thanks,
Praveen Raghuvanshi Software Developer
Here is a quick proposal with horrible readablility:
private PointF Transform(PointF logicalPoint) { float logicalXMin = -100; float logicalXMax = 100; float logicalYMin = -100; float logicalYMax = 100; float canvasXMin = this.ClientRectangle.Left; float canvasXMax = this.ClientRectangle.Right; float canvasYMin = this.ClientRectangle.Top; float canvasYMax = this.ClientRectangle.Bottom; float canvasX = ((((float)(Math.Log(logicalPoint.X, 10))) - logicalXMin) / (logicalXMax - logicalXMin) \* (canvasXMax - canvasXMin)) + canvasXMin; float canvasY = ((-logicalPoint.Y - logicalYMin ) / (logicalYMax - logicalYMin) \* (canvasYMax - canvasYMin)) + canvasYMin; return (new PointF(canvasX, canvasY)); }
You use a control as canvas. You have to transform logical co-ordinates into canvas co-ordinates. Therefore you look at your logical value in relation to logical maximum and minimum. Then apply the same relation to canvas minimum and maximum. Since canvas Y-axis is inverted, you have to use negative logical Y value to compensate. As mathematics dictates, you can't use negative X values here. Draw grid lines using logical co-ordinates. They should get processed just as any data point.
for( int power = 0, power < 4, power++)
{
g.DrawLine( gridPen, Math.Pow(1, power), logicalYMin, Math.Pow(1, power), logicalYMax);
g.DrawLine( gridPen, Math.Pow(2, power), logicalYMin, Math.Pow(2, power), logicalYMax);
g.DrawLine( gridPen, Math.Pow(5, power), logicalYMin, Math.Pow(5, power), logicalYMax);
}Horizontal grid lines should be even easier.
for( int i = logicalYMin; i <= logicalYMax; i += 10)
{
g.DrawLine( gridPen, logicalXMin, i, logicalXMax, i);
}Ciao, luker
modified on Wednesday, July 13, 2011 7:17 AM
-
Here is a quick proposal with horrible readablility:
private PointF Transform(PointF logicalPoint) { float logicalXMin = -100; float logicalXMax = 100; float logicalYMin = -100; float logicalYMax = 100; float canvasXMin = this.ClientRectangle.Left; float canvasXMax = this.ClientRectangle.Right; float canvasYMin = this.ClientRectangle.Top; float canvasYMax = this.ClientRectangle.Bottom; float canvasX = ((((float)(Math.Log(logicalPoint.X, 10))) - logicalXMin) / (logicalXMax - logicalXMin) \* (canvasXMax - canvasXMin)) + canvasXMin; float canvasY = ((-logicalPoint.Y - logicalYMin ) / (logicalYMax - logicalYMin) \* (canvasYMax - canvasYMin)) + canvasYMin; return (new PointF(canvasX, canvasY)); }
You use a control as canvas. You have to transform logical co-ordinates into canvas co-ordinates. Therefore you look at your logical value in relation to logical maximum and minimum. Then apply the same relation to canvas minimum and maximum. Since canvas Y-axis is inverted, you have to use negative logical Y value to compensate. As mathematics dictates, you can't use negative X values here. Draw grid lines using logical co-ordinates. They should get processed just as any data point.
for( int power = 0, power < 4, power++)
{
g.DrawLine( gridPen, Math.Pow(1, power), logicalYMin, Math.Pow(1, power), logicalYMax);
g.DrawLine( gridPen, Math.Pow(2, power), logicalYMin, Math.Pow(2, power), logicalYMax);
g.DrawLine( gridPen, Math.Pow(5, power), logicalYMin, Math.Pow(5, power), logicalYMax);
}Horizontal grid lines should be even easier.
for( int i = logicalYMin; i <= logicalYMax; i += 10)
{
g.DrawLine( gridPen, logicalXMin, i, logicalXMax, i);
}Ciao, luker
modified on Wednesday, July 13, 2011 7:17 AM
Thanks, I will give a shot.
Praveen Raghuvanshi Software Developer