Zoom in/out chart using downsampling function - c#

I use a .NET Winform version teechart 4.1.2014.8126 evalution version.
When I zoom in / out chart using downsampling function, Something is wrong.
Look at the below picture.
This is a chart using downsampling function. We can see about 50 ~60 visible mark point.
This is a zoom in chart 1 time. We can see about 16 ~ 20 visible mark point.
Why visible count is decrease when I zoom in? I want more detail view, when I zoom in chart.
private void InitializeChart()
{
this.cursorTool1 = new Steema.TeeChart.Tools.CursorTool();//
this.tChart1.Tools.Add(this.cursorTool1);//
this.cursorTool1.FollowMouse = true;//
this.cursorTool1.Style = Steema.TeeChart.Tools.CursorToolStyles.Vertical;//
this.cursorTool1.Change += new Steema.TeeChart.Tools.CursorChangeEventHandler(this.cursorTool1_Change);//
CreateArrays();
tChart1.Aspect.View3D = false;
tChart1.Zoom.Direction = ZoomDirections.Both;//.Horizontal;//
tChart1.Series.Add(points = new Steema.TeeChart.Styles.Points());
tChart1.Series.Add(fastLine = new Steema.TeeChart.Styles.FastLine());
downSampling = new Steema.TeeChart.Functions.DownSampling(tChart1.Chart);
points.Add(xValues, yValues);
points.Active = false;
int pixelCount = 60;
downSampling.DisplayedPointCount = pixelCount;
downSampling.Method = Steema.TeeChart.Functions.DownSamplingMethod.MinMaxFirstLast;// Null;
fastLine.TreatNulls = Steema.TeeChart.Styles.TreatNullsStyle.DoNotPaint;
fastLine.DataSource = points;
fastLine.Function = downSampling;
this.tChart1.Axes.Custom.Add(new Steema.TeeChart.Axis(this.tChart1.Chart));//
this.tChart1[1].CustomVertAxis = this.tChart1.Axes.Custom[0];//
this.tChart1[0].CustomVertAxis = this.tChart1.Axes.Custom[0];//
this.fastLine.Marks.Visible = true;//
}
private void CreateArrays()
{
int length = 100000;
xValues = new Nullable<double>[length];
yValues = new Nullable<double>[length];
Random rnd = new Random();
for (int i = 0; i < length; i++)
{
xValues[i] = i;
yValues[i] = i;
}
}
private void tChart1_Zoomed(object sender, EventArgs e)
{
tChart1[1].CheckDataSource(); //series 1 is the function series
}

This is not a defect, but expected behaviour. If we add the following code to your example (with the relevant event declaration):
void tChart1_AfterDraw(object sender, Graphics3D g)
{
string s = "Count: " + tChart1[1].Count.ToString() + Utils.NewLine
+ "Displayed Count: " + (tChart1[1].LastVisibleIndex - tChart1[1].FirstVisibleIndex).ToString();
tChart1.Header.Text = s;
}
We can see that "Count" is what you have defined in your variable "pixelCount" and "Displayed Count" decreases as the bottom axis maximum and minimum move closer together.
I think you are expecting the "Displayed Count" to increase as the bottom axis maximum and minimum move closer together, but this is not going to happen as long as the series "Count" remains the same. To increase the series "Count" on zooming you will have to increase the value of "pixelCount" and recalculate.

Related

Multiple chart areas in one column

I have a chart with multiple chart areas. When I press a button a new chart area is being created etc.
My problem is that after adding some chart areas I get the following result :
I want to have each chart area in only one column, one after the other like this :
is this possible ?
EDIT: Adding chart areas dynamically
on the left it is the chart with 3 chart areas added and the right is the chart with 4 areas.
Use property ChartArea.AlignWithChartArea
Through the use of the AlignWithChartArea, AlignmentOrientation and AlignmentStyle properties, it is possible to align or synchronize two or more chart areas horizontally, vertically or both.
First, set the AlignWithChartArea property to the name of a ChartArea object. This chart area will then be aligned, based on the AlignmentStyle setting, which defines the alignment to use, and the AlignmentOrientation setting, which defines the elements of the chart area that should be used to set the alignment.
So to put ChartArea2 below ChartArea1:
ChartArea2.AlignWithChartArea1;
ChartArea2.AlignmentStyle = AreaAlignmentStyles.Position;
ChartArea2.AlignmentOrientation = AreaAlignmentOrientation.Vertical;
Here is how you can achive what you need, also referring for your question here: https://stackoverflow.com/questions/67124754/dynamically-add-chart-areas-in-vertical-alignment
Use the Position property and please read comments inside the code:
private void button1_Click(object sender, EventArgs e)
{
List<ChartArea> Areas = new List<ChartArea>();
int numberOfAreas = 5;
chart1.Legends[0].Enabled = false;
for (int k = 1; k <= numberOfAreas; k++) // YOU WANT 5 and not 4 AREAS - changed k< to k<=
{
var S1 = new Series();
chart1.Series.Add(S1);
S1.Name = k.ToString();
for (int j = 0; j < 100; j += 10) S1.Points.AddXY(j, j / 10);
S1.Color = Color.Transparent;
Areas.Add(new ChartArea(k.ToString()));
chart1.ChartAreas.Add(Areas[k - 1]); // IT IS k-1 and not k - we start counting from 0
S1.ChartArea = k.ToString();
chart1.ChartAreas[k - 1].AlignWithChartArea = chart1.ChartAreas[k - 1].Name;
chart1.ChartAreas[k - 1].AlignmentStyle = AreaAlignmentStyles.Position;
chart1.ChartAreas[k - 1].AlignmentOrientation = AreaAlignmentOrientations.Vertical;
}
// NOW THE IMPORTANT PART
float currentHeight = 0;
foreach (var itm in Areas)
{
itm.Position.Height = 100 / numberOfAreas; // Note: the valus are in percenteges and not absolute pixels
itm.Position.Y = currentHeight;
itm.Position.X = 5;
itm.Position.Width = 95;
currentHeight += 100 / numberOfAreas;
}
}
OUTPUT:

Visual bug when inputting numbers too high into a Windows Form app line graph

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);

Scrolling/Moving MS chart area to highlighted datapoint when in zoom state

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;

MS Charts showing wrong X Axis values

I have one chart control with two buttons.First call candlestick chart.Second call bar chart.If I call only one of them everything is fine.But if I click the button for bar chart it gets the X Axis values from the candlestick chart.Bar chart X Axis should be from 0-15.
How they look:
https://imgur.com/a/IICYh
On formload candlestick chart is loaded first.Everything is still fine.
When Close/Open button for the bar chart is clicked.Its left with the X Axis values from candlestick chart.
When I click Chart button for the candlestick chart after hitting Close/Open.
Y Axis values are missing now.
Methods for calling the charts:
public void CandleStickChartMain()
{
// clear the chart
if (ChartCandle.Series.Count > 0) this.ChartCandle.Series[0].Points.Clear();
this.ChartCandle.Series.Clear();
this.ChartCandle.Titles.Clear();
//Clear Grid
ChartCandle.ChartAreas["ChartArea1"].AxisX.MajorGrid.LineWidth = 0;
ChartCandle.ChartAreas["ChartArea1"].AxisY.MajorGrid.LineWidth = 0;
//Series
ChartCandle.Series.Add("Date");
ChartCandle.Series["Date"].YValuesPerPoint = 4;
ChartCandle.Series["Date"].XValueMember = "Day";
ChartCandle.Series["Date"].YValueMembers = "High,Low,Open,Close";
ChartCandle.Series["Date"].XValueType = ChartValueType.DateTime;
ChartCandle.Series["Date"].CustomProperties = "PriceDownColor=Red,PriceUpColor=Green";
ChartCandle.Series["Date"]["OpenCloseStyle"] = "Triangle";
ChartCandle.Series["Date"]["ShowOpenClose"] = "Both";
ChartCandle.DataManipulator.IsStartFromFirst = true;
ChartCandle.Series["Date"].ChartType = SeriesChartType.Candlestick;
//Axis Y Minimum
ChartCandle.ChartAreas["ChartArea1"].AxisY.Minimum = Open.Min() - (Open.Min() / 50);
//Data Binding
ChartCandle.DataSource = ChartDataTable;
ChartCandle.DataBind();
}
public void BarChart()
{
// clear the chart
if (ChartCandle.Series.Count > 0) this.ChartCandle.Series[0].Points.Clear();
this.ChartCandle.Series.Clear();
this.ChartCandle.Titles.Clear();
// Set palette
this.ChartCandle.Palette = ChartColorPalette.Excel;
// Set title
this.ChartCandle.Titles.Add("Price Data Open/Close");
//Add series
//Series Open
var seriesOpen = ChartCandle.Series.Add("Open");
for (int i = 0; i < Open.Length; i++)
{
seriesOpen.Points.Add(Open[i]);
}
//Series Close
var SeriesClose = ChartCandle.Series.Add("Close");
for (int i = 0; i < Close.Length; i++)
{
SeriesClose.Points.Add(Close[i]);
}
var chartAreaOpenClose = ChartCandle.ChartAreas[seriesOpen.ChartArea];
// Zoom and scroll options
// set view range to [0,max]
chartAreaOpenClose.AxisX.Minimum = 0;
chartAreaOpenClose.AxisX.Maximum = Open.Length + 1;
// enable autoscroll
chartAreaOpenClose.CursorX.AutoScroll = true;
// let's zoom to [0,blockSize] (e.g. [0,100])
chartAreaOpenClose.AxisX.ScaleView.Zoomable = true;
chartAreaOpenClose.AxisX.ScaleView.SizeType = DateTimeIntervalType.Number;
int position = 0;
int size = 15;
chartAreaOpenClose.AxisX.ScaleView.Zoom(position, size);
// disable zoom-reset button (only scrollbar's arrows are available)
chartAreaOpenClose.AxisX.ScrollBar.ButtonStyle = ScrollBarButtonStyles.SmallScroll;
// set scrollbar small change to blockSize (e.g. 100)
chartAreaOpenClose.AxisX.ScaleView.SmallScrollSize = 15;
// additional
ChartCandle.ChartAreas[0].AxisY.IsStartedFromZero = false;
}

How can I see 2 Series over my chart on the same graph when values are different (very high and very low)

I define 2 Series (I am using Telerik) that represent my Network Traffic rate (MBit/sec and Packet/sec):
AreaSeries series;
AreaSeries series2;
series = new AreaSeries();
radChartView1.Series.Add(series);
series.BorderColor = Color.SteelBlue;
series.BackColor = Color.FromArgb(20, Color.SkyBlue);
series.BorderWidth = 1;
series.HorizontalAxis.ShowLabels = false;
series.VerticalAxis.ShowLabels = false;
series2 = new AreaSeries();
radChartView1.Series.Add(series2);
series2.BorderColor = Color.Gray;
series2.BackColor = Color.FromArgb(20, Color.Gray);
series2.BorderWidth = 1;
series2.HorizontalAxis.ShowLabels = false;
series2.VerticalAxis.ShowLabels = false;
My chart received the real time data via Timer:
private void timerStatistics_Tick(object sender, EventArgs e)
{
try
{
if (series.DataPoints.Count > 40)
series.DataPoints.RemoveAt(0);
series.DataPoints.Add(new Telerik.Charting.CategoricalDataPoint(AdapterStatistics.BitsPerSecond * 0.000001));
if (series2.DataPoints.Count > 40)
series2.DataPoints.RemoveAt(0);
series2.DataPoints.Add(new Telerik.Charting.CategoricalDataPoint(AdapterStatistics.PacketsPerSecond));
}
catch (Exception)
{ }
}
And my problem is that because my 2 values are very different i only can see one of my Series (usually Packet/sec) because for example MBit/sec get the value 1.4 and Packet/sec get the value 200 so from my chart i can see the biggest value, the lowest value is so small that it cannot be seen (see my screenshot inside the red rectangle a very small blue line... ):
How to fix it?
Not sure how it applies to Telerik controls, but in the regular chart control, you can have 2 x-axes and 2 y-axes, and assign different series to use different axes. Thus, you could do something like:
series.YAxisType = AxisType.Primary;
series2.YAxisType = AxisType.Secondary;
Axis yaxis1 = chart.ChartAreas[0].AxisY;
Axis yaxis2 = chart.ChartAreas[0].AxisY2;
yaxis1.Maximum = 1e6;
yaxis2.Maximum = 1e3;
Looks like it's very similar using Telerik controls, taken straight from the Telerik website (http://www.telerik.com/help/winforms/chartview-axes-multiple-axes.html):
LinearAxis verticalAxis1 = new LinearAxis();
verticalAxis1.AxisType = AxisType.Second;
LinearAxis verticalAxis2 = new LinearAxis();
verticalAxis2.AxisType = AxisType.Second;
verticalAxis2.HorizontalLocation = AxisHorizontalLocation.Right;
series.HorizontalAxis = horizontalAxis;
series.VerticalAxis = verticalAxis1;
series2.HorizontalAxis = horizontalAxis;
series2.VerticalAxis = verticalAxis2;

Categories