I have still have a problem with C# Chart (in System.Windows.Forms.DataVisualization.Charting namespace).
When i zoom on Y axis, sometimes, interval line aren't redrawn.
Look at the picture below, interval lines are missing under 0.Missing interval line
Usually, there is no problem and 11 interval lines are drawn.
private void chart1_AxisViewChanged(object sender, ViewEventArgs e)
{
if ((e != null) && (sender != null))
{
// on ne récupère que les évènement concernant l'axe Y. L'axe X se gère tout seul car il est unique
if (e.Axis.AxisName.ToString() == "Y")
{
// AxisY.ScaleView.ViewMinimum is the minimum Y axis value displayed. It contains the offset to apply to label, grid and interval on Y axis
e.ChartArea.AxisY.IntervalOffset = (e.ChartArea.AxisY.Interval - e.ChartArea.AxisY.ScaleView.ViewMinimum) % e.ChartArea.AxisY.Interval;
// To update Y axis label, major grid and interval.
e.ChartArea.AxisY.Interval = (e.ChartArea.AxisY.ScaleView.ViewMaximum - e.ChartArea.AxisY.ScaleView.ViewMinimum) / 11;
}
}
}
Above is my axisViewChanged event.
The Y axis is declared as below
chartArea1.AxisY.Interval = (sens.dMaximumValue - sens.dMinimumValue)/11.0;
chartArea1.AxisY.IntervalOffsetType = DateTimeIntervalType.Number;
chartArea1.AxisY.IntervalType = DateTimeIntervalType.Number;
chartArea1.AxisY.LabelStyle.Format = ".000";
chartArea1.AxisY.MajorGrid.LineColor = Color.White; // Color.DarkViolet;
chartArea1.AxisY.MajorGrid.LineDashStyle = ChartDashStyle.Dash;
chartArea1.AxisY.MajorTickMark.Enabled = false;
chartArea1.AxisY.Maximum = sens.dMaximumValue*1.1;
chartArea1.AxisY.Minimum = sens.dMinimumValue*1.1;
chartArea1.AxisY.ScaleView.MinSize = 0.01D;
chartArea1.AxisY.ScaleView.SmallScrollMinSize = 0.001D;
chartArea1.AxisY.ScrollBar.BackColor = Color.White;
chartArea1.AxisY.ScrollBar.ButtonColor = Color.LightGray;
As you can see, it is declared as Number, which is correct i think.
When this problem oocurs, if i click on the scrollbar, the 11 interval are correctly redrawn.
Has something solved this problem ?
Related
I am using C# to try to input numbers into a line graph from a text file. The numbers in the text file are big, as in -30000. Every time I input a large number into the graph, I get a visual glitch that turns the graph black. Am I doing something wrong or is it a bug?
void ChartLoad()
{
var chart = LineGraph.ChartAreas[0];
chart.AxisX.IntervalType =
System.Windows.Forms.DataVisualization.Charting.DateTimeIntervalType.Number;
chart.AxisX.LabelStyle.Format = "";
chart.AxisY.LabelStyle.Format = "";
chart.AxisX.LabelStyle.IsEndLabelVisible = true;
chart.AxisX.Interval = 0.5;
chart.AxisY.Interval = 10;
LineGraph.Series[0].IsVisibleInLegend = false;
LineGraph.Series.Add("Line1");
LineGraph.Series["Line1"].ChartType =
System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
LineGraph.Series["Line1"].Color = Color.Green;
LineGraph.Series.Add("Line2");
LineGraph.Series["Line2"].ChartType =
System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
LineGraph.Series["Line2"].Color = Color.Blue;
LineGraph.Series["Line1"].Points.AddXY(30000, 30000);
LineGraph.Series["Line1"].Points.AddXY(-30000, -30000);
}
The problem is the grid. You have an amazingly small intervall compared to the range of your values. The grid is so tight that it webbes a narrow carpet of gridlines onto your chart.
You could solve it by
switching of the grid:
chart.AxisX.MinorGrid.Enabled = false;
chart.AxisX.MajorGrid.Enabled = false;
chart.AxisY.MajorGrid.Enabled = false;
chart.AxisY.MinorGrid.Enabled = false;
Or by adjusting the axes intervalls to a reasonable number depending on the range of your values. You will see immidiately a difference when you set the interval to:
chart.AxisX.Interval = 10000;
chart.AxisY.Interval = 10000;
Here is a method that could do this for you:
private void AddValuesAndAdjustInterval(string series, double xValue, double yValue)
{
LineGraph.Series[series].Points.AddXY(xValue, yValue);
var chart = LineGraph.ChartAreas[0];
double maxValueX = LineGraph.Series[series].Points.Select(x=> x.XValue).Max();
double minValueX = LineGraph.Series[series].Points.Select(x=> x.XValue).Min();
double maxValueY = LineGraph.Series[series].Points.SelectMany(x=> x.YValues).Max();
double minValueY = LineGraph.Series[series].Points.SelectMany(x => x.YValues).Min();
int stepSize = 20; // the smaller this value the larger the grid separation
chart.AxisX.Interval = (maxValueX - minValueX) / stepSize;
chart.AxisY.Interval = (maxValueY - minValueY) / stepSize;
}
Now you can use it to add values:
AddValuesAndAdjustInterval("Line1", 30000, 30000);
AddValuesAndAdjustInterval("Line1", -30000, -30000);
Windows Forms ZedGraph control in WPF application. The data points are auto-generated and attached to the chart every N seconds. When new data point is added to the chart I shift (pan) chart one point to the left, so there is always no more than last 50 points visible in the viewport. Overall, it works pretty good, except for two things.
Issues
If user tries to zoom in or out, the viewport stops following the last data point and chart goes outside of the screen, so panning stops working
I would like to pan or shift chart using mouse event, without scrolling, but when I press right mouse button and try to move it to the left, it tries to zoom chart instead of panning
protected void CreateChart(ZedGraphControl control)
{
_rand = new Random();
var curve = control.GraphPane.AddJapaneseCandleStick("Demo", new StockPointList());
curve.Stick.IsAutoSize = true;
curve.Stick.Color = Color.Blue;
control.AutoScroll = true; // Always shift to the last data point when new data comes in
control.IsEnableHPan = true; // I assume this should allow me to move chart to the left using mouse
control.IsEnableVPan = true;
control.IsEnableHZoom = true;
control.IsEnableVZoom = true;
control.IsShowPointValues = true;
control.IsShowHScrollBar = false;
control.IsShowVScrollBar = false;
control.IsAutoScrollRange = true; // Always shift to the last data point when new data comes in
control.IsZoomOnMouseCenter = false;
control.GraphPane.XAxis.Type = AxisType.DateAsOrdinal;
control.AxisChange();
control.Invalidate();
var aTimer = new Timer();
aTimer.Elapsed += new ElapsedEventHandler(OnTime);
aTimer.Interval = 100;
aTimer.Enabled = true;
}
protected XDate _xDate = new XDate(2006, 2, 1);
protected double _open = 50.0;
protected Random _rand = new Random();
// Auto generate data points
protected void OnTime(object source, ElapsedEventArgs e)
{
var control = FormCharts;
var x = _xDate.XLDate;
var close = _open + _rand.NextDouble() * 10.0 - 5.0;
var hi = Math.Max(_open, close) + _rand.NextDouble() * 5.0;
var low = Math.Min(_open, close) - _rand.NextDouble() * 5.0;
var pt = new StockPt(x, hi, low, _open, close, 100000);
_open = close;
_xDate.AddDays(1.0);
if (XDate.XLDateToDayOfWeek(_xDate.XLDate) == 6)
{
_xDate.AddDays(2.0);
}
(control.GraphPane.CurveList[0].Points as StockPointList).Add(pt);
control.GraphPane.XAxis.Scale.Min = control.GraphPane.XAxis.Scale.Max - 50; // Hide all points except last 50, after mouse zooming this line stops working
//control.GraphPane.XAxis.Scale.Max = control.GraphPane.XAxis.Scale.Max + 1;
control.AxisChange();
control.Invalidate();
}
Kind of solved it.
First issue with broken auto-scroll after zooming
It happens because zooming sets these parameters to FALSE.
area.XAxis.Scale.MinAuto = false;
area.XAxis.Scale.MaxAuto = false;
To fix it, either set it back to TRUE every time new data point comes. Another way to fix it, is to keep them always as FALSE and move chart manually
protected void MoveChart(GraphPane pane, int pointsToMove, int pointsToShow)
{
pane.XAxis.Scale.Max = pane.XAxis.Scale.Max - pointsToMove;
pane.XAxis.Scale.Min = pane.XAxis.Scale.Max - Math.Abs(pointsToShow);
}
...
// Example : shift one point to the left and show only 50 last points
MoveChart(control.MasterPane.PaneList["Quotes"], -1, 50);
Second issue, implementing custom panning without scrollbar using mouse events.
protected int _mouseX = -1;
protected int _mouseY = -1;
...
control.MouseUpEvent += OnMouseUp;
control.MouseDownEvent += OnMouseDown;
control.MouseMoveEvent += OnMouseMove;
...
// Example : remember X and Y on mouse down and move chart until mouse up event
protected bool OnMouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
{
_mouseX = -1; // unset X on mouse up
_mouseY = -1;
return true;
}
protected bool OnMouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
_mouseX = e.X; // remember last X on mouse down
_mouseY = e.Y;
return true;
}
protected bool OnMouseMove(ZedGraphControl sender, System.Windows.Forms.MouseEventArgs e)
{
if (_mouseX >= 0) // if X was saved after mouse down
{
foreach (var pane in sender.MasterPane.PaneList) // move synced chart panels
{
MoveChart(pane, _mouseX > e.X ? -1 : 1, 50); // if mouse move is increasing X, move chart to the right, and vice versa
}
_mouseX = e.X; // update X to new position
_mouseY = e.Y;
}
return true;
}
In windows form, I am displaying data in MS Chart from Datagridview.
When selecting an row in the datagridview, I am highlighting the corresponding datapoint in the chart with different color.
When chart is in zoom state , if a datapoint is highlighted newly and if it is not in the visible state, I have to scroll/move the chart to highlighted datapoint.
chart.ChartAreas.Add("LineGraphHistory");
chart.ChartAreas["LineGraphHistory"].AxisX.Title = "X Axis";
chart.ChartAreas["LineGraphHistory"].AxisX.MajorGrid.LineColor = System.Drawing.Color.Black;
chart.ChartAreas["LineGraphHistory"].AxisX.MajorGrid.LineDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Dash;
chart.ChartAreas["LineGraphHistory"].AxisY.Title = "Y Axis";
chart.ChartAreas["LineGraphHistory"].AxisY.MajorGrid.LineColor = Color.Black;
chart.ChartAreas["LineGraphHistory"].AxisY.MajorGrid.LineDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Dash;
chart.ChartAreas["LineGraphHistory"].BackColor = Color.White;
chart.ChartAreas["LineGraphHistory"].CursorX.IsUserEnabled = true;
chart.ChartAreas["LineGraphHistory"].CursorX.IsUserSelectionEnabled = true;
chart.ChartAreas["LineGraphHistory"].CursorX.Interval = 0;
chart.ChartAreas["LineGraphHistory"].AxisX.ScaleView.Zoomable = true;
chart.ChartAreas["LineGraphHistory"].AxisX.ScrollBar.Enabled = true;
chart.Legends.Add("Legend");
chart.Legends["Legend"].BorderColor = Color.Tomato;
chart.DataSource = CSVDataTable;
chart.ChartAreas["LineGraphHistory"].AxisX.IntervalType = DateTimeIntervalType.Seconds;
chart.ChartAreas["LineGraphHistory"].AxisX.LabelStyle.Format ="dd-MM-yyyy\n hh:mm:ss"; ;
chart.Series[s].XValueType =ChartValueType.DateTime ;
chart.DataBind();
chart.Update();
private void cDataGrid_SelectionChanged(object sender, EventArgs e)
{
int nCount = csvDataGrid.SelectedRows.Count;
if (nCount > 0)
{
for (int i = 0; i < nCount; i++)
{
int index = csvDataGrid.SelectedRows[i].Index;
if (index >= csvDataGrid.Rows.Count-1)
return;
for (int k = 0; k < chart.Series.Count; k++)
{
DataPointCollection pr = chart.Series[k].Points;
pr[index].MarkerColor = Color.DarkGoldenrod;
pr[index].MarkerStyle = MarkerStyle.Star10;
pr[index].MarkerSize = 20;
// chart.
}
chart.Update();
}
}
}
How to achieve this?
As Taw suggested I tried to set scaleview position.
I have 10 datapoints. The range of x value of datapoints are 20 to 200. Each x value has equal difference of 20. The view size is 100. In zoom mode, when I scrolling to maximum the x range is 101 to 200 in the view , the last point is displayed as 5th point in the view. Whereas if I use your code to set scaleview position to highlight last datapoint , the x range becomes 180 to 240 and highlighted last datpoint is visible as first range.
Why paintviewmin and paintviewmax values are changing?
The images are
You need to calculate the offset from the DataPoint dp.XValue, maybe like this:
Axis ax = chart.ChartAreas[0].AxisX;
var size = ax.ScaleView.ViewMaximum - ax.ScaleView.ViewMinimum;
ax.ScaleView.Position = dp.XValue - size / 2.0;
Example:
Update: When smaller data sets are displayed the automatically added margins mess up the simple calculation above. To avoid this you can add:
chart.ChartAreas[0].AxisX.IsMarginVisible = false;
I need to access the DataPoint via X coordinate, but I can't seem to find any solutions for it. HitTest() is out, since it also needs Y coordinate (cannot hit anything if Y is 0). I know I could select the DataPoints via Linq and the X coordinate, but I was wondering if there are better solutions for this?
More specifically I'm trying to show Candlestick data (Open, Low, High, Close and DateTime) with a TextAnnotation, which follows the CursorX (it's anchored above my X-axis, which is located at the bottom of my chart), and my CursorX is intervalled so it is always in the center of a candle.
What I have so far, is a MouseMove function, which updates my CursorX, but lacks the data access and label update:
PointF _mouse = new PointF();
TextAnnotation _mouseLabel;
void UpdateMouseCursor(object sender, MouseEventArgs e)
{
if( _mouseLabel == null )
return;
_mouse.X = e.Location.X;
_mouse.Y = e.Location.Y;
var cursorX = chart1.ChartAreas[0].CursorX;
cursorX.SetCursorPixelPosition( _mouse, true );
_mouseLabel.X = cursorX.Position;
}
CursorX and _mouseLabel setup:
public void SetupMouse(double interval, DateTimeIntervalType intervalType)
{
chart1.ChartAreas[0].CursorX.IntervalType = intervalType;
chart1.ChartAreas[0].CursorX.Interval = interval;
chart1.ChartAreas[0].CursorX.LineColor = Color.FromArgb(128, 128,128,128);
if( _mouseLabel == null )
{
_mouseLabel = new TextAnnotation();
_mouseLabel.Text = "WOOHOO!";
_mouseLabel.AnchorY = 85;
_mouseLabel.AxisX = chart1.ChartAreas[0].AxisX;
chart1.Annotations.Add( _mouseLabel );
}
}
The visuals:
I have a numericUpDown control which should ,based on the input, draw a straight line on my chart. The input should be only for the Y axis of my chart.
I can see the Tpoint added to Legend but the line is not drawn. What am I missing? I've already looked at the samples for Microsoft Chart Controls and still didn't figure out what's wrong.
private void numericSeries_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == 13)
{
int s = (int)numericSeries.Value;
Series series = chart2.Series.Add("Tpoint" + (chart2.Series.Count).ToString());
series.ChartArea = "ChartArea1";
series.ChartType = SeriesChartType.FastLine;
series.BorderWidth = 1;
series.Color = Color.Blue;
series.Points.AddY(s);
}
}
EDIT Unfortunately i cant upload pictures.
http://i58.tinypic.com/25aqe4m.jpg
2.EDIT - the chart in the picture is a real time chart which represents PWM values from a DC motor (Y value) vs Datetime (X value). The line i want to draw should represent the Setpoint (reference) value i'm trying to achive.
My X axis
chart2.ChartAreas[0].AxisX.Minimum = chart2.Series[0].Points[0].XValue;
chart2.ChartAreas[0].AxisX.Maximum = DateTime.FromOADate(chart2.Series[0].Points[0].XValue).AddSeconds(15).ToOADate();