Measurement Studio for .NET Languages

cancel
Showing results for 
Search instead for 
Did you mean: 

How do I place text on a ScatterGraph and have an arrow point to a data point on a plot?

For example, show the minimum point with the string "MIN" and draw an arrow from the text to the minimum point.

I am using Measurement Studio 7.0 with C#. This could be accomplished in MS 6.0 with annotations.
0 Kudos
Message 1 of 3
(4,964 Views)
The Measurement Studio 7.0 graphs (WaveformGraph and ScatterGraph) expose events that allow you to custom draw areas of the control. Most of these events appear as pairs of BeforeDraw____ and AfterDraw___. The BeforeDraw events are raised before the drawing begins and AfterDraw events are raised after the drawing has completed.

In your case, you can attach an event handler to the AfterDrawPlotArea event of the ScatterGraph since you want to draw on top of everything that is drawn in the plot area. In the event handler:

// Assuming e is the name of the AfterDrawEventArgs parameter.

// Find the minimum y-value on the first plot in the Plots
// collection of the graph.
double[] xData = scatterGraph1.Plots[0].GetXData();
double[] yData = scatterGraph1.Plots[0].GetYData();

if (yData.Length > 0)
{
double x = xData[0];
double yMin = yData[0];

for (int i = 1; i < yData.Length; ++i)
{
if (yData[i] < yMin)
{
x = xData[i];
yMin = yData[i];
}
}

// Map the data point to a point in device coordinates.
PointF minPoint = scatterGraph1.Plots[0].MapPoint(e.Bounds, x, yMin);

// Calculate the starting point for the line of the
// arrow.
PointF startingPoint = new PointF(minPoint.X + 1, minPoint.Y - 1);
PointF endingPoint = new PointF(minPoint.X + 10, startingPoint.Y - 9);

// Draw a vertical line representing the stick of the
// arrow from the point.
e.Graphics.DrawLine(Pens.White, startingPoint, endingPoint);

PointF leftArrowEnd = new PointF(startingPoint.X, startingPoint.Y - 3);
PointF rightArrowEnd = new PointF(startingPoint.X + 3, startingPoint.Y);

// Draw the arrows.
e.Graphics.DrawLine(Pens.White, startingPoint, leftArrowEnd);
e.Graphics.DrawLine(Pens.White, startingPoint, rightArrowEnd);

// Calculate the location of the text by centering it
// about the arrow.
SizeF textSize = e.Graphics.MeasureString("MIN", scatterGraph1.Font);
PointF textLocation = new PointF(endingPoint.X + 1, endingPoint.Y - (textSize.Height / 2));

// Draw the "MIN" string
e.Graphics.DrawString("MIN", scatterGraph1.Font, Brushes.White, textLocation);
}

Hope this helps.

Abhishek Ghuwalewala
Measurement Studio
National Instruments
Abhishek Ghuwalewala | Measurement Studio | National Instruments
Message 2 of 3
(4,964 Views)
You can achieve this via the custom drawing services of the plot. In this case, you want to augment the drawing of the plot, so you can write an event handler for the plot's AfterDraw event, use the plot's mapping methods to easily translate data points to screen coordinates, and then draw the text and arrow with the System.Drawing APIs. For example, look in the dropdown box at the top of the Properties window in the Windows Forms designer, find the plot that you want to add the text and arrow to, click the Events tab, and add an event handler for the AfterDraw event called OnPlotAfterDraw:

private void OnPlotAfterDraw(object sender, AfterDrawXYPlotEventArgs e)
{
DrawMinAnnotation(e.Plot, e.Graphics, e.Bounds, Color.White);
}

Here's one way you can implement the drawing for the annotation:

void DrawMinAnnotation(XYPlot plot, Graphics g, Rectangle bounds, Color c)
{
if (plot == null)
throw new ArgumentNullException("plot");

if (g == null)
throw new ArgumentNullException("g");

// Define values to use in drawing. Customize these if desired.
const string minimumText = "MIN";
Font textFont = ((plot.Owner != null) ? plot.Owner.Font : Control.DefaultFont);

if (plot.HistoryCount > 0)
{
// Find the minimum Y value.
double[] xData = plot.GetXData(), yData = plot.GetYData();
double minimumX = xData[0], minimumY = yData[0];

for (int i = 0; i < yData.Length; ++i)
{
if (yData[i] < minimumY)
{
minimumX = xData[i];
minimumY = yData[i];
}
}

// Map the minimum point to screen coordinates.
PointF minimumPoint = plot.MapPoint(bounds, minimumX, minimumY);

// Calculate where the text should be drawn. This calculation puts
// the text in the middle of the plot area.
SizeF textSize = g.MeasureString(minimumText, textFont);
PointF textOrigin = new PointF(
bounds.X + ((bounds.Width - textSize.Width) / 2),
bounds.Y + ((bounds.Height - textSize.Height) / 2)
);

// Calculate where the starting point of the line should be drawn.
float startX = 0, startY = 0;
if (minimumPoint.X < textOrigin.X)
startX = textOrigin.X;
else
startX = textOrigin.X + textSize.Width;

if (minimumPoint.Y < textOrigin.Y)
startY = textOrigin.Y;
else
startY = textOrigin.Y + textSize.Height;

PointF startPoint = new PointF(startX, startY);

// Draw the arrow and the text.
using (Pen textPen = new Pen(c))
using (Brush textBrush = new SolidBrush(c))
{
textPen.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;
g.DrawLine(textPen, startPoint, minimumPoint);
g.DrawString(minimumText, textFont, textBrush, textOrigin);
}
}
}

- Elton
Message 3 of 3
(4,964 Views)