Interactive data point selection?

TeeChart for Microsoft Visual Studio .NET, Xamarin Studio (Android, iOS & Forms) & Monodevelop.
Post Reply
Michal Blazejczyk
Newbie
Newbie
Posts: 64
Joined: Fri Jun 16, 2006 12:00 am

Interactive data point selection?

Post by Michal Blazejczyk » Fri Jan 05, 2007 10:28 pm

Hi,

I'm trying to figure out how to provide the following feature to my users. Let's say I have a scatter plot displayed (a Points series). The user wants to select a number of points by clicking and dragging the mouse. Selected points will then be retrieved and some additional information about them will be provided in a separate window.

How can I achieve this?

Best,
Michal Blazejczyk
Best,
Michal Blazejczyk
Lead Programmer
Genome Quebec

Narcís
Site Admin
Site Admin
Posts: 14730
Joined: Mon Jun 09, 2003 4:00 am
Location: Banyoles, Catalonia
Contact:

Post by Narcís » Mon Jan 08, 2007 10:28 am

Hi Michal,

Yes, you need to do this manually using chart events, for example:

Code: Select all

		private void Form1_Load(object sender, EventArgs e)
		{
			tChart1.Aspect.View3D = false;
			points1.FillSampleValues();

			tChart1.Panning.MouseButton = MouseButtons.Middle;

			ResetCoords();
		}

		private void ResetCoords()
		{
			X0 = -1;
			Y0 = -1;
		}

		private int X0, Y0;
		
		private void tChart1_MouseDown(object sender, MouseEventArgs e)
		{
			if (e.Button == MouseButtons.Right)
			{
				X0 = e.X;
				Y0 = e.Y;
			}
		}		

		private void tChart1_MouseUp(object sender, MouseEventArgs e)
		{
			listBox1.Items.Clear();

			if ((X0 != -1) && (Y0 != -1))
			{
				for (int i = 0; i < points1.Count; i++)
				{
					if ((points1.CalcXPos(i) >= X0) && (points1.CalcXPos(i) <= e.X) &&
							(points1.CalcYPos(i) >= Y0) && (points1.CalcYPos(i) <= e.Y))
					{
						listBox1.Items.Add("Point " + i.ToString() + ": " + points1.XValues[i].ToString() +
																", " + points1.YValues[i].ToString());
					}
				}

				ResetCoords();
			}
		}

		private void tChart1_MouseMove(object sender, MouseEventArgs e)
		{
			if ((X0 != -1) && (Y0 != -1))
			{
				tChart1.Graphics3D.Brush.Visible = false;
				tChart1.Graphics3D.Pen.Color = Color.Black;
				tChart1.Graphics3D.Rectangle(X0, Y0, e.X, e.Y);
			}			
		}
Best Regards,
Narcís Calvet / Development & Support
Steema Software
Avinguda Montilivi 33, 17003 Girona, Catalonia
Tel: 34 972 218 797
http://www.steema.com
Image Image Image Image Image Image
Instructions - How to post in this forum

Michal Blazejczyk
Newbie
Newbie
Posts: 64
Joined: Fri Jun 16, 2006 12:00 am

Post by Michal Blazejczyk » Mon Jan 08, 2007 9:01 pm

Hi,

I found a way that is easier to program:

Code: Select all

private void OnZoomed( object sender, System.EventArgs e )
{
  // Here, _chart.Axes.Bottom.Minimum, _chart.Axes.Bottom.Maximum
  // _chart.Axes.Left.Minimum, and _chart.Axes.Left.Maximum
  // delimit the selected area.
  
  // Do whatever needs to be done...

  _chart.Zoom.Undo();
}
It works very well because, as the Help says:
This event gets called BEFORE the Chart class is repainted to show the new Axis scales.
:D

Best,
Michal
Best,
Michal Blazejczyk
Lead Programmer
Genome Quebec

Wicket
Newbie
Newbie
Posts: 20
Joined: Mon Jan 15, 2007 12:00 am

Post by Wicket » Wed Mar 21, 2007 1:25 pm

I'm looking for the same kind of behaviour, but I have found some problems with both the above methods. The "simple one" implementing OnZoomed will unzoom any previously zooming. I want my users to be able to zoom AND select lines. So let's say they have zoomed on an area, and then tries to select some lines, Zoom.Undo() will reset the zoom.

The other example (overriding mouseUp/down/move seems to work, but the drawn box disappers as soon as the mousepointer remains on the same spot for a short while. I would like the box to always be shown (like the zoom box).

Has anyone implemented such a solution?

Regards Andreas

Narcís
Site Admin
Site Admin
Posts: 14730
Joined: Mon Jun 09, 2003 4:00 am
Location: Banyoles, Catalonia
Contact:

Post by Narcís » Wed Mar 21, 2007 3:26 pm

Hi Andreas,

Yes, this can be achieved using TeeChart's AfterDraw event and something like this:

Code: Select all

		private void Form1_Load(object sender, EventArgs e)
		{
			tChart1.Aspect.View3D = false;
			points1.FillSampleValues();

			tChart1.Panning.MouseButton = MouseButtons.Middle;

			ResetCoords();
		}

		private void ResetCoords()
		{
			X0 = -1;
			Y0 = -1;
		}

		private int X0, Y0, X1, Y1;
		
		private void tChart1_MouseDown(object sender, MouseEventArgs e)
		{
			if (e.Button == MouseButtons.Right)
			{
				X0 = e.X;
				Y0 = e.Y;
			}
		}		

		private void tChart1_MouseUp(object sender, MouseEventArgs e)
		{
			listBox1.Items.Clear();

			if ((X0 != -1) && (Y0 != -1))
			{
				for (int i = 0; i < points1.Count; i++)
				{
					if ((points1.CalcXPos(i) >= X0) && (points1.CalcXPos(i) <= e.X) &&
							(points1.CalcYPos(i) >= Y0) && (points1.CalcYPos(i) <= e.Y))
					{
						listBox1.Items.Add("Point " + i.ToString() + ": " + points1.XValues[i].ToString() +
																", " + points1.YValues[i].ToString());
					}
				}

				ResetCoords();
			}
		}

		private void tChart1_MouseMove(object sender, MouseEventArgs e)
		{			
			if (e.Button == MouseButtons.Right)
			{
				X1 = e.X;
				Y1 = e.Y;
			}

			tChart1.Invalidate();
		}

		private void tChart1_AfterDraw(object sender, Steema.TeeChart.Drawing.Graphics3D g)
		{
			if ((X0 != -1) && (Y0 != -1))
			{
				g.Brush.Visible = false;
				g.Pen.Color = Color.Black;
				g.Rectangle(X0, Y0, X1, Y1);
			}
		}
Best Regards,
Narcís Calvet / Development & Support
Steema Software
Avinguda Montilivi 33, 17003 Girona, Catalonia
Tel: 34 972 218 797
http://www.steema.com
Image Image Image Image Image Image
Instructions - How to post in this forum

Wicket
Newbie
Newbie
Posts: 20
Joined: Mon Jan 15, 2007 12:00 am

Post by Wicket » Wed Mar 21, 2007 3:50 pm

Oh, great, I came up with something similiar (using the OnPaint) method, but I changed to use After draw. However, tChart1.Invalidate(); should be done inside if(e.Button == MouseButtons.Right), otherwise the zoombox (leftclicking and dragging) will flipp out... (don't ask me why) =)

Well, my problem is solved.

My code for checking if any point/line is selected is this:
foreach (Line line in Series)
{
for (int i = 0; i < line.Count; i++)
{
if ((line.CalcXPos(i) >= X0) && (line.CalcXPos(i) <= e.X) &&
(line.CalcYPos(i) >= Y0) && (line.CalcYPos(i) <= e.Y))
{
// Found a selected point, add it to some collection
break;
}
}
}

I haven't played with a large scale of lines yet, but I guess this method could become timeconsuming... or? Is there a better way? I need to know witch lines my "selection box" includes.

Narcís
Site Admin
Site Admin
Posts: 14730
Joined: Mon Jun 09, 2003 4:00 am
Location: Banyoles, Catalonia
Contact:

Post by Narcís » Wed Mar 21, 2007 4:32 pm

Hi Wicket,
I haven't played with a large scale of lines yet, but I guess this method could become timeconsuming... or? Is there a better way?
Yes, you are right. I can't think of a better way to achieve that at the moment.
I need to know witch lines my "selection box" includes.
Sorry but I don't understand what do you exactly mean. Could you please give us some more information?

Thanks in advance.
Best Regards,
Narcís Calvet / Development & Support
Steema Software
Avinguda Montilivi 33, 17003 Girona, Catalonia
Tel: 34 972 218 797
http://www.steema.com
Image Image Image Image Image Image
Instructions - How to post in this forum

Wicket
Newbie
Newbie
Posts: 20
Joined: Mon Jan 15, 2007 12:00 am

Post by Wicket » Wed Mar 21, 2007 9:22 pm

Lets say I have 10 lines drawn on the chart. Then I make a 'selectionbox'. After releasing the mousebutton I want to find out witch of my 10 lies that passes through the box. As my implementation is made right now, I'm only checking the points of the lines, so if a line is passing through the box, but doesn't have a point inside the box, the line will not be selected.

In fact, individual points are not interested for me at all, it's either the complete line or nothing at all. So if there exist a mote efficient way to tell if some part of a line (serie) passes through a rectangualr box, I'd be glad to hear about it.

Regards Andreas

Narcís
Site Admin
Site Admin
Posts: 14730
Joined: Mon Jun 09, 2003 4:00 am
Location: Banyoles, Catalonia
Contact:

Post by Narcís » Thu Mar 22, 2007 8:44 am

Hi Andreas,

To achieve what you request you should implement MouseUp event as shown below. To optimize the implementation you could add an array and mark which series have been already selected and check this before doing redundant processing.

Code: Select all

		private void tChart1_MouseUp(object sender, MouseEventArgs e)
		{
			listBox1.Items.Clear();

			if ((X0 != -1) && (Y0 != -1))
			{
				for (int x = X0; x <= X1; x++)
					for (int y = Y0; y <= Y1; y++)
						for (int i = 0; i < tChart1.Series.Count; i++)
							if (tChart1[i].Clicked(x, y) != -1)
								listBox1.Items.Add(tChart1[i].Title);

				ResetCoords();
			}
		}
Best Regards,
Narcís Calvet / Development & Support
Steema Software
Avinguda Montilivi 33, 17003 Girona, Catalonia
Tel: 34 972 218 797
http://www.steema.com
Image Image Image Image Image Image
Instructions - How to post in this forum

Post Reply