I'm creating an application which plots data from a serial port. My problem is that sometimes chart size increases when values go below the X axis and, as a result, some values on X axis disappear.
I've set min and max Y axis value, so I wonder how it is possible for the horizontal axis to moves gently downward for a while and then disappear - possibly due to a lack of space?.
It occurs only for first and last label, and sometimes the last grid line disappears too.
Here is piece of code which generate chart values:
int minStress = -200, maxStress=200;
double maxTime=20.0, minTime=0.0;
private void timer1_Tick(object sender, EventArgs e)
{
Stress = serialPort1.ReadLine();
label6.Text = Stress;
StressChart.ChartAreas[0].AxisX.Minimum = minTime;
StressChart.ChartAreas[0].AxisX.Maximum = maxTime;
StressChart.ChartAreas[0].AxisX.ScaleView.Zoomable = true;
StressChart.ChartAreas[0].AxisY.ScaleView.Zoomable = true;
this.StressChart.Series[0].Points.AddXY((minTime + maxTime) / 2, Stress);
minTime=minTime + TimerInt_2/1000;
maxTime=maxTime + TimerInt_2/1000;
serialPort1.DiscardInBuffer();
}
private void cmbTimerInt_SelectedIndexChanged(object sender, EventArgs e)
{
TimerInt = int.Parse(cmbTimerInt.Text);
TimerInt_2=double.Parse(cmbTimerInt.Text);
timer1.Interval = TimerInt;
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
try
{
minStress = int.Parse(textBox1.Text);
}
catch { }
if (minStress < maxStress)
{
StressChart.ChartAreas[0].AxisY.Minimum = minStress;
}
}
private void textBox2_TextChanged(object sender, EventArgs e)
{
try
{
maxStress = int.Parse(textBox2.Text);
}
catch { }
if (maxStress > minStress)
{
StressChart.ChartAreas[0].AxisY.Maximum = maxStress;
}
}
Here is code which sets chart properties:
chartArea1.AxisX.LabelStyle.Format = "0.0";
chartArea1.Name = "ChartArea1";
this.StressChart.ChartAreas.Add(chartArea1);
legend1.Name = "Legend1";
this.StressChart.Legends.Add(legend1);
this.StressChart.Location = new System.Drawing.Point(225, 12);
this.StressChart.Name = "StressChart";
series1.ChartArea = "ChartArea1";
series1.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Spline;
series1.Legend = "Legend1";
series1.Name = "Series1";
this.StressChart.Series.Add(series1);
this.StressChart.Size = new System.Drawing.Size(1175, 426);
this.StressChart.TabIndex = 5;
this.StressChart.Text = "chart1";
chartArea1.AxisX.LabelAutoFitStyle = 0;
chartArea1.AxisY.LabelAutoFitStyle = 0;
chartArea1.AxisX.MajorTickMark.Size = 0;
chartArea1.AxisX.IsMarginVisible = true;
chartArea1.AxisY.IsMarginVisible = true;
The reason of such behaviour was decimal places number of X axis labels. Solution is to round these values down to one decimal place.
minTime = Math.Round(minTime,1) + Math.Round(TimerInt_2/1000,1);
maxTime = Math.Round(maxTime,1) + Math.Round(TimerInt_2/1000,1);
Related
I'm trying to draw an axis table (x-y) in WPF from code-behind; and I want to give it drag and drop option which can see more of the axis table.
I had created static axis but I don't know how to create a dynamic one?
Can anybody help me with this stuff ?
Thanks.
for (int i = 10; i < 400; i+=10)
{
Line a = new Line();
a.X1 = 0;
a.Y1 = i;
a.X2 = canGraph.Width;
a.Y2 = a.Y1;
a.Stroke = System.Windows.Media.Brushes.Black;
a.StrokeThickness = 0.5;
canGraph.Children.Add(a);
Line b = new Line();
b.X1 = i;
b.Y1 = 0;
b.X2 = i;
b.Y2 = canGraph.Height;
b.Stroke = System.Windows.Media.Brushes.Black;
b.StrokeThickness = 0.5;
canGraph.Children.Add(b);
if (i % 50 == 0)
{
a.StrokeThickness = 1;
b.StrokeThickness = 1;
}
if (i == 200)
{
a.StrokeThickness = 2;
b.StrokeThickness = 2;
}
}
This should get you started. Add event handler(s) to your main axis and canGraph -
...
if (i == 200)
{
a.StrokeThickness = 2;
b.StrokeThickness = 2;
a.MouseLeftButtonDown += A_MouseLeftButtonDown;
}
}
canGraph.MouseLeftButtonUp += CanGraph_MouseLeftButtonUp;
canGraph.MouseMove += CanGraph_MouseMove;
Add following methods -
Line _selectedAxis = null;
private void CanGraph_MouseMove(object sender, MouseEventArgs e)
{
if (_selectedAxis != null)
{
var line = _selectedAxis;
var pos = e.GetPosition(line);
textBlock.Text = $"({pos.X}, {pos.Y})";
line.Y1 = pos.Y;
line.Y2 = pos.Y;
}
}
private void CanGraph_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
_selectedAxis = null;
}
private void A_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var line = sender as Line;
_selectedAxis = line;
}
Now hold you main horizontal axis and drag it.
You can do the same for vertical axis as well.
For Zooming
Initialize canGraph.RenderTransform with ScaleTransform and subscribe to MouseWheel event. Note RenderTransformOrigin is set to (0.5, 0.5) to zoom from center instead of top left (default) -
canGraph.RenderTransformOrigin = new Point(0.5, 0.5);
canGraph.RenderTransform = new ScaleTransform();
canGraph.MouseWheel += CanGraph_MouseWheel;
And the function -
private void CanGraph_MouseWheel(object sender, MouseWheelEventArgs e)
{
var transform = canGraph.RenderTransform as ScaleTransform;
var factor = transform.ScaleX;
factor += (e.Delta > 0 ? 1 : (factor == 1 ? 0 : -1));
transform.ScaleX = factor;
transform.ScaleY = factor;
}
I'm guessing you have added Line type object to draw axes, then gave it to window content.
Then just add events, like MouseLeftButtonDown event, or MouseMove event.Add appropriate methods.
Change your object positions on MouseMove event, like:
(For a certain line)
private void MouseMoveMethod(object sender, MouseEventArgs e)
{
var obj = sender as Line;
obj.X1 = e.GetPosition(this).X; //Line start x coordinate
obj.Y1 = e.GetPosition(this).Y; //Line start y coordinate
...
}
My requirement is in my line graph( which is developed with c# MS Chart), I
always need to display 10 points(samples) at a time. The xaxis has interval value 1.
Initially the Xaxis tick values are (1,2,3,4,5,6,7,8,9,10), After 1 second of time interval, I
have to plot 10 points(samples) starts from 2nd point(i.e. I have to skip 1st
point).Now I need to update the xaxis tick values also , it should be starts from
2,now the xaxis tick values should be like 2,3,4,5,6,7,8,9,10,11). Likewise
After every second the starting value of x axis
tick needs to be increased by 1.
How to update Xaxis tick value in the chart dynamically ?
I am using below code
private void Form1_Load(object sender, EventArgs e)
{
loadCsvFile("C:\\mydata.csv");
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
this.timer1 = new System.Windows.Forms.Timer(this.components);
chart = new System.Windows.Forms.DataVisualization.Charting.Chart();
chart.Location = new System.Drawing.Point(1, 1);
chart.Size = new System.Drawing.Size(700, 700);
// Add a chartarea called "draw", add axes to it and color the area black
chart.ChartAreas.Add("draw");
numofSamples = 10;
chart.ChartAreas["draw"].AxisX.Minimum = 1;
chart.ChartAreas["draw"].AxisX.Maximum = 10;
chart.ChartAreas["draw"].AxisX.Interval = 1;
chart.ChartAreas["draw"].AxisX.Title = "X Axis";
chart.ChartAreas["draw"].AxisX.MajorGrid.LineColor = System.Drawing.Color.Black;
chart.ChartAreas["draw"].AxisX.MajorGrid.LineDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Dash;
chart.ChartAreas["draw"].AxisY.Minimum = 0;
chart.ChartAreas["draw"].AxisY.Maximum = 1000;
chart.ChartAreas["draw"].AxisY.Interval = 250;
chart.ChartAreas["draw"].AxisY.Title = "Y Axis";
chart.ChartAreas["draw"].AxisY.MajorGrid.LineColor = Color.Black;
chart.ChartAreas["draw"].AxisY.MajorGrid.LineDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Dash;
chart.ChartAreas["draw"].BackColor = Color.White;
// Create a new function series
chart.Series.Add("Tags");
// Set the type to line
chart.Series["Tags"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
// Color the line of the graph light green and give it a thickness of 3
chart.Series["Tags"].Color = Color.LightGreen;
chart.Series["Tags"].BorderWidth = 3;
chart.Series["Tags"].MarkerStyle = MarkerStyle.Circle;
chart.Series["Tags"].MarkerSize = 10;
chart.Legends.Add("MyLegend");
chart.Legends["MyLegend"].BorderColor = Color.Tomato; // I like tomato juice!
Controls.Add(this.chart);
// hook up timer event
this.timer1.Interval = 1000;
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
timer1.Start();
}
public void loadCsvFile(string filePath)
{
var reader = new StreamReader(File.OpenRead(filePath));
while (!reader.EndOfStream)
{
List<string> listA = new List<string>();
string line = reader.ReadLine();
mList.Add(line );
}
}
int i = 0;
int n = 0;
private void timer1_Tick(object sender, EventArgs e)
{
if (n > 20)
n = 0;
int j=0;
chart.Series["Tags"].Points.Clear();
for (i=n; i < mList.Count; i++)
{
string l =mList[i];
chart.Series["Tags"].Points.AddY(l);
j++;
if (j == 10)
break;
}
n++;
chart.Update();
}
List<List<string>> mList = new List<List<string>>();
I am using chart control in my c# application.Using timer updating values in chart at every 1 seconds.Also i enabled scroll bar for the chart , so the scroll bar is keep on adjusting while the values are adding. Actually my requirement is if i drag the scroll bar and hold at any point it has to freeze at that particular point only.It should not adjust when ever i drag and hold the scroll bar at the particular point.How to do that ? Please refer the code below,
int x1=10, x2=10, y1=10, y2=10; //globally declared
private void button1_Click(object sender, EventArgs e) //chart preparation in button click
{
chart1.Series.Clear();
series1.MarkerStyle = MarkerStyle.Circle;
series1.MarkerColor = Color.BlueViolet;
series1.MarkerSize = 7;
series1.Color = System.Drawing.Color.Green;
series1.IsXValueIndexed = true;
series1.YAxisType = AxisType.Primary;
series1.ChartType = SeriesChartType.Line;
this.chart1.Series.Add(series1);
series2.MarkerStyle = MarkerStyle.Circle;
series2.MarkerColor = Color.Orange;
series2.MarkerSize = 7;
series2.Color = System.Drawing.Color.Purple;
series2.IsXValueIndexed = true;
series2.YAxisType = AxisType.Secondary;
series2.ChartType = SeriesChartType.Line;
this.chart1.Series.Add(series2);
chart1.ChartAreas[0].CursorX.AutoScroll = true;
chart1.ChartAreas[0].CursorY.AutoScroll = true;
chart1.ChartAreas[0].AxisX.ScrollBar.Size = 15;
chart1.ChartAreas[0].AxisX.ScrollBar.ButtonStyle = ScrollBarButtonStyles.All;
chart1.ChartAreas[0].AxisX.ScrollBar.IsPositionedInside = false;
chart1.ChartAreas[0].AxisX.ScrollBar.Enabled = true;
chart1.ChartAreas[0].AxisX.ScaleView.Zoomable = true;
chart1.Series[0].Points.AddXY(x1, y1);
chart1.Series[1].Points.AddXY(x2, y2);
chart1.ChartAreas[0].AxisX.ScaleView.Position = chart1.ChartAreas[0].AxisX.Minimum;// scrollPosition;
chart1.ChartAreas[0].AxisX.ScaleView.Zoom(chart1.ChartAreas[0].AxisX.Maximum - nCheck, chart1.ChartAreas[0].AxisX.Maximum);
x1 += 1;
x2 += 1;
nlength++;
if (nlength == 25)
{
nCheck = 30;
chart1.Update();
}
else if (nlength == 50)
nCheck = 50;
timer1.Start();
}
public void createGraph() //called in timer
{
chart1.Series[0].Points.AddXY(x1, y1);
chart1.Series[1].Points.AddXY(x2, y2);
chart1.ChartAreas[0].AxisX.ScaleView.Position = chart1.ChartAreas[0].AxisX.Minimum;// scrollPosition;
chart1.ChartAreas[0].AxisX.ScaleView.Zoom(chart1.ChartAreas[0].AxisX.Maximum - nCheck, chart1.ChartAreas[0].AxisX.Maximum);
x1 += 1;
x2 += 1;
nlength++;
if (nlength == 25)
{
nCheck = 30;
chart1.Update();
}
else if(nlength == 50)
nCheck = 50;
}
private void chart1_AxisScrollBarClicked(object sender, ScrollBarEventArgs e)
{
chart1.ChartAreas[0].CursorX.AutoScroll = false;
chart1.ChartAreas[0].CursorY.AutoScroll = false; //here i need to update some code i think so ...
}
As long as the minimum and maximum of an axis is not set, it will auto-adjust to data. Here is an example where a start of user selection fixes the range of x-axis to current view and applies the selection as zoom and frees the axis range again when selection is completed.
double SelectionStartX=0, SelectionEndX=0;
Chart.SelectionRangeChanging += (object sender, CursorEventArgs e) =>
{
//Record selection to be applied as zoom in SelectionRangeChanged event
SelectionStartX = e.ChartArea.CursorX.SelectionStart;
SelectionEndX = e.ChartArea.CursorX.SelectionEnd;
//Stop motion - Fix x-axis range to width of view
e.Axis.Maximum = e.Axis.ScaleView.ViewMaximum;
e.Axis.Minimum = e.Axis.ScaleView.ViewMinimum;
};
Chart.SelectionRangeChanged += (object sender, CursorEventArgs e) =>
{
//Reset previous zooming and apply only last user selected range
if (e.Axis.ScaleView.IsZoomed)
{
e.Axis.ScaleView.ZoomReset();
e.Axis.ScaleView.Zoom(SelectionStartX, SelectionEndX);
}
//Continue motion - Make chart adaptive to data range
e.Axis.Minimum = double.NaN;
e.Axis.Maximum = double.NaN;
};
I want to make a graph of instant charge against time but the chart is not displaying anything.
What I am doing wrong?
Here is my code and snapshot of my output:
namespace WindowsFormsApplication21
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
double max = 24000000, min = 23999999.85;
chart1.ChartAreas.Add("0");
chart1.ChartAreas[0].AxisY.Minimum = min;
chart1.ChartAreas[0].AxisY.Maximum = max;
chart1.Series[0].Color = Color.Red;
}
private void button1_Click(object sender, EventArgs e)
{
double[] q = new double[10];
for (int i = 0; i < q.Length; i++)
{
int t = i + 1;
q[i] = (24 * Math.Pow(10, 6)) * Math.Exp(t / (2000 * Math.Pow(10,6)));
chart1.Series[0].Points.AddXY(t, q[i]);
}
}
}
}
This is my output
As you can see, your data simply don't fit the values; all are above 24M, which is the maximum you even show.
You should not try to hard-code these values imo. They may work today and stop working with the next set of data..
Here is how you can set them in code, after adding the DataPoints:
ChartArea CA = chart1.ChartAreas[0];
Series S1 = chart1.Series[0];
CA.AxisY.Maximum = S1.Points.Max(x => x.YValues[0]);
CA.AxisY.Minimum = S1.Points.Min(x => x.YValues[0]);
CA.AxisY.LabelStyle.Format = "###,###,###,##0.000";
(My system shows the decimal points in German localization.)
I have text file with one line in it. The line looks like this:
100 300 200 400 658 487 2636 254 245 527
These numbers represent X and Y coordinates of points (first and second are X and Y of point N1, third and fourth are X and Y of point N2,...., ).
I read the file and put it in an array.
My next step is to draw the picture boxes in a container (panel).
The problem is that the panel is only showing the control with last coordinates.
private void CreateBlastHole(string[] pointCoordinate)
{
PictureBox blastHole = new PictureBox();
blastHole.Height = 15;
blastHole.Width = 15;
blastHole.BackColor = Color.Blue;
for (int i = 0; i < pointCoordinate.Length; i++)
{
blastHole.Left = int.Parse(pointCoordinate[i]);
i = i + 1;
blastHole.Top = int.Parse(pointCoordinate[i]);
drawingPanel.Controls.Add(blastHole);
}
blastHole.Click += new EventHandler(BlastHole_Click);
ToolTip tooltip1 = new ToolTip();
// Set up delays for the tooltip
tooltip1.AutoPopDelay = 5000;
tooltip1.InitialDelay = 1000;
tooltip1.ReshowDelay = 500;
// Force the tooltip text to be displayed whether or not the form is active.
tooltip1.ShowAlways = true;
// Set up the tooltip text for the controls
int axisX = blastHole.Location.X;
int axisY = blastHole.Location.Y;
string coordinates = "Точка N " + blastHole.Name + "X = " + axisX.ToString() + " Y = " + axisY.ToString();
tooltip1.SetToolTip(blastHole, coordinates);
}
private void BlastHole_Click(object sender, EventArgs e)
{
MessageBox.Show(MousePosition.X.ToString(), MousePosition.Y.ToString());
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void openButton_Click(object sender, EventArgs e)
{
openFileDialogPoints.ShowDialog();
string name = openFileDialogPoints.FileName;
File.ReadAllLines(name);
string[] points = File.ReadAllText(name).Split( );
CreateBlastHole(points);
}
private void drawingPanel_Paint(object sender, PaintEventArgs e)
{
}
private void buttonDrawHole_Click(object sender, EventArgs e)
{
}
You need to move your code inside the for-loop, to create more than one PictureBox. Currently, you are only creating one instance, reusing it for each blastHole.
Try something like this instead:
private void CreateBlastHole(string[] pointCoordinate)
{
for (int i = 0; i < pointCoordinate.Length; i++)
{
PictureBox blastHole = new PictureBox();
blastHole.Height = 15;
blastHole.Width = 15;
blastHole.BackColor = Color.Blue;
blastHole.Left = int.Parse(pointCoordinate[i]);
i = i + 1;
blastHole.Top = int.Parse(pointCoordinate[i]);
drawingPanel.Controls.Add(blastHole);
blastHole.Click += new EventHandler(BlastHole_Click);
ToolTip tooltip1 = new ToolTip();
// Set up delays for the tooltip
tooltip1.AutoPopDelay = 5000;
tooltip1.InitialDelay = 1000;
tooltip1.ReshowDelay = 500;
// Force the tooltip text to be displayed whether or not the form is active.
tooltip1.ShowAlways = true;
// Set up the tooltip text for the controls
int axisX = blastHole.Location.X;
int axisY = blastHole.Location.Y;
string coordinates = "Точка N " + blastHole.Name + "X = " + axisX.ToString() + " Y = " + axisY.ToString();
tooltip1.SetToolTip(blastHole, coordinates);
}
}