mschart horizontal scroll causing unwanted chart area width change - c#

When I scroll horizontally a zoomed mschart I see an ugly chart area flicker (right border), caused by unwanted change of its width (this is due to variable scaling of the chart during horizontal scrolling).
Any ideas how to improve that?
Code example:
DateTime zeroTime = new DateTime(1, 1, 1, 0, 0, 0);
int k = 0;
chart1.Series[0].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
chart1.Dock = DockStyle.Fill;
chart1.BackColor = Color.Salmon;
this.chart1.ChartAreas["ChartArea1"].CursorX.IsUserEnabled = true;
this.chart1.ChartAreas["ChartArea1"].CursorY.IsUserEnabled = true;
this.chart1.ChartAreas["ChartArea1"].CursorX.IsUserSelectionEnabled = true;
this.chart1.ChartAreas["ChartArea1"].CursorY.IsUserSelectionEnabled = true;
this.chart1.ChartAreas["ChartArea1"].AxisX.ScaleView.Zoomable = true;
this.chart1.ChartAreas["ChartArea1"].AxisY.ScaleView.Zoomable = true;
this.chart1.ChartAreas["ChartArea1"].AxisX.ScrollBar.IsPositionedInside = true;
this.chart1.ChartAreas["ChartArea1"].AxisY.ScrollBar.IsPositionedInside = true;
this.chart1.ChartAreas["ChartArea1"].AxisX.ScaleView.SmallScrollMinSizeType =DateTimeIntervalType.Seconds;
this.chart1.ChartAreas["ChartArea1"].AxisX.ScaleView.SmallScrollSizeType = DateTimeIntervalType.Seconds;
chart1.ChartAreas["ChartArea1"].CursorY.Interval = 0.1;
chart1.ChartAreas["ChartArea1"].CursorX.Interval = 5.0;
chart1.ChartAreas["ChartArea1"].AxisX.LabelStyle.Format = "HH:mm:ss";
chart1.ChartAreas["ChartArea1"].CursorX.IntervalType = System.Windows.Forms.DataVisualization.Charting.DateTimeIntervalType.Seconds;
for (int i = 0; i < 600; i++)
{if (i < 200 ){k=i/10;} else if(i<400){k=20;}else{k=(600-i)/10;}; chart1.Series[0].Points.AddXY(zeroTime.AddSeconds(i * 5), 0 - k);}

The resizing of the chart can be influenced by the InnerPlotPosition property of the chart area. The default here is InnerPlotPosition.Auto set to true and this leads to the width change.
The chart width change can be stopped by switching to manual mode:
this.chart1.ChartAreas["ChartArea1"].InnerPlotPosition.Auto = false;
// optional:
this.chart1.ChartAreas["ChartArea1"].InnerPlotPosition.X = 0; // all values are percentage
this.chart1.ChartAreas["ChartArea1"].InnerPlotPosition.Y = 0;
this.chart1.ChartAreas["ChartArea1"].InnerPlotPosition.Height = 100;
this.chart1.ChartAreas["ChartArea1"].InnerPlotPosition.Width = 100;

Related

Windows forms C# how to make the grid lines of a chart square?

I have a chart in windows forms and I want the gridlines to be squared. The gridline is anchored to bottom, top, left and right so it resizes with the screen. How do I make the grid lines always square and make the whole chart resize with the screen?
I have tried setting the width and height to be the same, but it doesn't work since the series names of the chart are on the right.
EDIT 1:
Here is the full uncensored code:
chart1.ChartAreas[0].AxisY.Minimum = 0;
chart1.ChartAreas[0].AxisY.Maximum = max;
chart1.ChartAreas[0].AxisX.Minimum = 0;
chart1.ChartAreas[0].AxisX.Maximum = max;
chart1.ChartAreas[0].AxisX.LabelStyle.Format = "0";
chart1.ChartAreas[0].AxisY.LabelStyle.Format = "0";
chart1.ChartAreas[0].AxisX.Interval = 1;
chart1.ChartAreas[0].AxisY.Interval = 1;
chart1.ChartAreas[0].AxisX.IntervalAutoMode = IntervalAutoMode.FixedCount;
chart1.ChartAreas[0].RecalculateAxesScale();
for (int i = 0; i < points.ToArray().Length; i++)
dt.Rows.Add(pointsArr[i, 0], pointsArr[i, 1]);
chart1.DataSource = dt;
chart1.Series["תחום הפתרונות האפשריים"].BorderWidth = 0;
float[] OptimalPoint = CalculateOptimalPt(convertEq(z), ListArToAr(points));
if (OptimalPoint[0] == 0)
{
for (int i = 0; i < 2; i++)
{
DataPoint dp = new DataPoint();
dp.SetValueXY(i, OptimalPoint[1]);
if (i > 0) dp.Color = Color.Transparent;
chart1.Series["פיתרון אופטימלי"].Points.Add(dp);
}
}
else
chart1.Series["פיתרון אופטימלי"].Points.AddXY(OptimalPoint[0], OptimalPoint[1]);
chart1.Series["פיתרון אופטימלי"].Points[0].MarkerSize = 10;
chart1.Series["תחום הפתרונות האפשריים"].XValueMember = "X_Value";
chart1.Series["תחום הפתרונות האפשריים"].YValueMembers = "Y_Value";
chart1.Series["תחום הפתרונות האפשריים"].ChartType = SeriesChartType.Area;
panel1.Visible = false;
panel2.Visible = true;
You can do it by anchoring the chart only to the Top and Left and calculating and setting the Width and Height yourself when Form size changes.
To do so we get fundamental data of the chart in the form constructor.
private readonly Size _innerMargin = new Size(183, 55); // Estimated
private readonly Size _outerMargin;
private readonly float _aspectRatio;
public Form1()
{
InitializeComponent();
_outerMargin = Size - chart1.Size;
Size innerSize = chart1.Size - _innerMargin;
_aspectRatio = (float)innerSize.Width / innerSize.Height;
}
_innerMargin is the estimated total difference between the chart size and the plot area with the gridlines. I actually got it from a screenshot and measured it in a graphics application.
_outerMargin is the difference of the form size and the chart control size.
This calculation of the initial _aspectRatio assumes the grid lines build perfect squares when the form opens. Instead, you could set this aspect ratio from the known number of squares in X and Y:
_aspectRatio = 16f / 16f; // From your example image.
In the Form_Resize event handler, we then set the new size of the chart. Depending on whether the current aspect ratio (calculated from the theoretical new maximum plot area size) is less than or greater than the original aspect ratio, the height or the width of the chart determines the maximum chart size. The other dimension must be calculated so that the aspect ratio of plot area remains the same.
private void Form1_Resize(object sender, EventArgs e)
{
Size maxChartSize = Size - _outerMargin;
Size innerSize = maxChartSize - _innerMargin;
double currentAspectRatio = (float)innerSize.Width / innerSize.Height;
if (currentAspectRatio < _aspectRatio) {
int chartWidth = Width - _outerMargin.Width;
chart1.Width = chartWidth;
chart1.Height = (int)((chartWidth - _innerMargin.Width) / _aspectRatio + _innerMargin.Height);
} else {
int chartHeight = Height - _outerMargin.Height;
chart1.Height = chartHeight;
chart1.Width = (int)((chartHeight - _innerMargin.Height) * _aspectRatio + _innerMargin.Width);
}
}

WinForms: highlighting X and Y axes

I'm making a program to graph parabolas, and I want to make the X and Y axes (the ones from (0,0)) a different color. I haven't found any options to do so, and the only solution I've found is to make a large grid and set its increment to half the graph's size. Is there an alternative?
I used the default chart control. I'd expect something like:
You can set Crossing for axis to move the axis to center of chart. Also you can set LineWidth for axis to make it thicker. Also you can set ArrowStyle to have an arrow at the end of axis.
For example, to have a chart like this:
Use such code:
private void Form1_Load(object sender, EventArgs e)
{
//Set Chart Margins
this.chart1.ChartAreas[0].Position.Auto = false;
this.chart1.ChartAreas[0].Position.X = 10;
this.chart1.ChartAreas[0].Position.Y = 10;
this.chart1.ChartAreas[0].Position.Width = 80;
this.chart1.ChartAreas[0].Position.Height = 80;
//Configure X Axis
this.chart1.ChartAreas[0].AxisX.Crossing = 0;
this.chart1.ChartAreas[0].AxisX.Interval = 1;
this.chart1.ChartAreas[0].AxisX.LabelStyle.Enabled = false;
this.chart1.ChartAreas[0].AxisX.LineWidth = 2;
this.chart1.ChartAreas[0].AxisX.ArrowStyle =
System.Windows.Forms.DataVisualization.Charting.AxisArrowStyle.Lines;
//Configure Y Axis
this.chart1.ChartAreas[0].AxisY.Crossing = 0;
this.chart1.ChartAreas[0].AxisY.Interval = 5;
this.chart1.ChartAreas[0].AxisY.LineWidth = 2;
this.chart1.ChartAreas[0].AxisY.LabelStyle.Enabled = false;
this.chart1.ChartAreas[0].AxisY.ArrowStyle =
System.Windows.Forms.DataVisualization.Charting.AxisArrowStyle.Lines;
//Set Chart Type
this.chart1.Series[0].ChartType =
System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Spline;
//Set Data
var p = new List<PointF>();
for (int i = -5; i <= 5; i++)
{
p.Add(new PointF(i, i * Math.Abs(i)));
}
this.chart1.DataSource = p;
this.chart1.Series[0].XValueMember = "X";
this.chart1.Series[0].YValueMembers = "Y";
this.chart1.Series[0].IsVisibleInLegend = false;
}

how to update values on axes of point chart in c#

In my project im having a point chart .For each and every 1 second time interval im updating the values in the points chart that's works fine.But while updating the values it is automatically splitting 4 values on x axis like 1,2,3,4 (1,2,3,4 are x axis values).But i want 10 fixed values to be plot on x axis.How to do it?
Please refer my code below ,
series.Name = "Series";
series.Color = System.Drawing.Color.Green;
series.IsVisibleInLegend = false;
series.IsXValueIndexed = true;
series.YAxisType=AxisType.Primary;
series.ChartType = SeriesChartType.Point;
this.chart.Series.Add(series);
chart.ChartAreas[0].AxisX.MajorGrid.LineWidth = 0;
chart.ChartAreas[0].AxisY.MajorGrid.LineWidth = 0;
chart.ChartAreas[0].AxisY2.MajorGrid.LineWidth = 0;
chart.ChartAreas[0].AxisX.Title = "X Axis value";
chart.ChartAreas[0].AxisY.Title = "Y Axis value1";
chart.ChartAreas[0].AxisY2.Title = "Y Axis value2";
chart.ChartAreas[0].AxisX.ScrollBar.Size = 15;
chart.ChartAreas[0].AxisX.ScrollBar.ButtonStyle = ScrollBarButtonStyles.All;
chart.ChartAreas[0].AxisX.ScrollBar.IsPositionedInside = false;
chart.ChartAreas[0].AxisX.ScrollBar.Enabled = true;
chart.ChartAreas[0].AxisX.ScaleView.Zoom(2,3);
chart.ChartAreas[0].CursorX.IsUserEnabled = true;
chart.ChartAreas[0].CursorY.IsUserEnabled = true;
chart.ChartAreas[0].AxisX.ScaleView.Zoomable = true;
chart.ChartAreas[0].AxisY.ScaleView.Zoomable = true;
chart.ChartAreas[0].AxisY2.ScaleView.Zoomable = true;
chart.ChartAreas[0].CursorX.IsUserSelectionEnabled = true;
chart.ChartAreas[0].CursorY.IsUserSelectionEnabled = true;
I am assuming you want your x axis shows 0-10 range:
Try add follow code:
chart.ChartAreas[0].AxisX.Maximum = 10;
chart.ChartAreas[0].AxisX.Minimum = 0;
If you use horizontal scroll bar for your chart,use the following code to display 10 intervals on x-axis.
chart.ChartAreas[0].AxisX.ScaleView.Zoom(2, 9);

C# Chart use CustomLabels with scrollbar

I don't understand something. If i don't use the customlabels, the chart will use the default label. And then if I move the scrollbar , the chart size won't adjust. The Chart view maintain the original size.
But if I use this code to change the label at row 0. (other rows don't have this problem)
chart1.ChartAreas[0].AxisY2.CustomLabels.Add((i) ,
(i+1), (ntemp * 10).ToString(), 0, LabelMarkStyle.SideMark);
And Move the scrollbar, the chart View will be a little different for size. The chart will flicker, and I don't want it.
Thanks in advance.
Here is example
Random rand = new Random();
chart1.Series.Clear();
var series = chart1.Series.Add("My Series");
series.ChartType = SeriesChartType.RangeBar;
series.Color = Color.Black;
series.YAxisType = AxisType.Secondary;
for (int i = 10; i > 2; i--)
series.Points.AddXY(i, (rand.Next(3600, 7200)), (rand.Next(30000, 80000)));
var chartArea = chart1.ChartAreas[series.ChartArea];
chartArea.BorderDashStyle = ChartDashStyle.Solid; //最外圍的框框
chartArea.BorderWidth = 10;
chartArea.AxisY.Enabled = AxisEnabled.False;
chartArea.AxisY2.Enabled = AxisEnabled.True;
chartArea.AxisY2.LabelStyle.IntervalType = DateTimeIntervalType.Number;
chartArea.AxisY2.Interval = 3600;
chartArea.AxisY2.Minimum = 0;
chartArea.AxisY2.Maximum = 86400;
chartArea.AxisY2.ScaleView.Zoom(0, 3600 * 4);
for (int i = 0; i <= 24 * 6; i++)
{
int ntemp = i % 6;
if (ntemp != 0)
{
/*Problem Here !!*/
//chart1.ChartAreas[0].AxisY2.CustomLabels.Add((i) * 600, (i + 1) * 600, (ntemp * 10).ToString(), 0, LabelMarkStyle.Box);
}
}
chartArea.CursorY.AutoScroll = true;
chartArea.AxisY2.ScaleView.Zoomable = true;
chartArea.AxisY2.ScrollBar.ButtonStyle = ScrollBarButtonStyles.SmallScroll;
chartArea.AxisY2.ScrollBar.IsPositionedInside = false;
}
Well, I was intrigued about how and if this can be achieved with OxyPlot, and I think it can ...
Here's the code I've used, and here's a screenshot:
var model = new PlotModel("IntervalBarSeries") { LegendPlacement = LegendPlacement.Outside };
var temp_serie = new IntervalBarSeries
{
Title = "IntervalBarSeries 1",
FillColor = OxyColors.Black
};
var categoryAxis = new CategoryAxis
{
Position = AxisPosition.Left,
IsZoomEnabled = false, // No zoom on this axis
IsPanEnabled = false, // Right mouse move won't affect this axis
MajorGridlineStyle = LineStyle.Solid
,StartPosition = 1, EndPosition = 0 // This will reverse the order
};
var valueAxis = new LinearAxis(AxisPosition.Top)
{
MinimumPadding = 0.1, MaximumPadding = 0.1,
IsZoomEnabled = true,
MajorGridlineStyle = LineStyle.Solid,
MajorStep = 3600,
AbsoluteMinimum = 0
};
for (int i = 10; i > 2; i--)
{
temp_serie.Items.Add(new IntervalBarItem {
Start = rand.Next(3600, 7200),
End = rand.Next(30000, 80000)
});
categoryAxis.Labels.Add("Activity "+i);
}
model.Series.Add(temp_serie);
model.Axes.Add(categoryAxis);
model.Axes.Add(valueAxis);
MyPlotModel = model;
Now, I'm using MVVM and just binding to the plot model from my View with:
<oxy:Plot Model="{Binding MyPlotModel}"/>
But you can figure out how to do the same with WinForms once (if?) you decide to use OxyPlot and import it.
I'm assuming you're doing some work that is related to times, but your code obviously doesn't say so ... you could play around with the top header, and maybe set how to show the numbers (ATM, with no zoom, they overlap each other a bit. zooming with scroller solves that, but that's just because i've set the tick size to 3600 ... )

Why does the x scrollbar get stuck on mschart?

int blockSize = 100;
// generates random data (i.e. 30 * blockSize random numbers)
Random rand = new Random();
var valuesArray = Enumerable.Range(0, blockSize * 30).Select(x => rand.Next(1, 10)).ToArray();
// clear the chart
chart1.Series.Clear();
//chart1.ChartAreas[0].AxisX.Interval = 3.0;
//chart1.ChartAreas[0].AxisX.IntervalType = DateTimeIntervalType.Auto;
DateTime now = DateTime.Now;
chart1.ChartAreas[0].AxisX.LabelStyle.Format = "HH:mm:ss";
chart1.ChartAreas[0].AxisX.Minimum = now.ToOADate();
// fill the chart
var series = chart1.Series.Add("My Series");
series.XValueType = ChartValueType.DateTime;
series.ChartType = SeriesChartType.Line;
//series.XValueType = ChartValueType.Int32;
//DateTime.Now.AddSeconds(i).ToOADate()
for (int i = 0; i < valuesArray.Length; i++)
series.Points.AddXY(now.AddSeconds(i).ToOADate(), valuesArray[i]);
var chartArea = chart1.ChartAreas[series.ChartArea];
// set view range to [0,max]
//chartArea.AxisX.Minimum = 0;
//chartArea.AxisX.IntervalType = DateTimeIntervalType.Seconds;
//chartArea.AxisX.Interval = 10d;
// chartArea.AxisX.Maximum = 100;
// enable autoscroll
chartArea.CursorX.AutoScroll = true;
// let's zoom to [0,blockSize] (e.g. [0,100])
chartArea.AxisX.ScaleView.Zoomable = true;
chartArea.AxisX.ScaleView.SizeType = DateTimeIntervalType.Auto;
int position = 0;
int size = blockSize;
chartArea.AxisX.ScaleView.Zoom(now.AddSeconds(-5).ToOADate(), now.AddSeconds(20).ToOADate());
//chart1.ChartAreas[0].AxisX.ScaleView.ZoomReset();
// disable zoom-reset button (only scrollbar's arrows are available)
chartArea.AxisX.ScrollBar.ButtonStyle = ScrollBarButtonStyles.SmallScroll;
// set scrollbar small change to blockSize (e.g. 100)
chartArea.AxisX.ScaleView.SmallScrollSize = (new TimeSpan(0,0,10)).TotalSeconds;
With the above code I am unable to drag the scroll bar. I just gets stuck when I click on the scroll bar.I can scroll using the arrows.
chartArea.AxisX.ScaleView.SmallScrollMinSize = .01;
chartArea.AxisX.ScaleView.SmallScrollMinSizeType = DateTimeIntervalType.Seconds;
chartArea.AxisX.ScaleView.SmallScrollSizeType = DateTimeIntervalType.Seconds;
You need to specify the minimum scroll size to get it to work.

Categories