C# chart zooming precision - c#

I have a chart with dates (strings) as X values and decimals as Y values. I want to zoom in the chart but when setting:
chart1.ChartAreas[0].CursorX.IsUserEnabled = true;
chart1.ChartAreas[0].CursorX.IsUserSelectionEnabled = true;
chart1.ChartAreas[0].AxisX.ScaleView.Zoomable = true;
it zooms up to interval 1 on the X axis.
I want to zoom-in gradually on the axis but when i set\
chart1.ChartAreas[0].CursorX.Interval = 0.1;
(anything except 1) the labes on the X axis disappear. Can somebody help me please, i am new to the chart controls. Please excuse my ignorance. Any advice would be very grateful
Here is a piece of my code so far:
chart1.ChartAreas[0].CursorX.IsUserEnabled = true;
chart1.ChartAreas[0].CursorX.IsUserSelectionEnabled = true;
chart1.ChartAreas[0].AxisX.ScaleView.Zoomable = true;
chart1.Series[0].IsVisibleInLegend = false;
chart1.Series[0].ChartType = SeriesChartType.Area;
DateTime sday = Convert.ToDateTime(earnings1.dataGridView1[0, 0].Value.ToString());
chart1.Series[0].XValueType = ChartValueType.String;
int i = 0;
chart1.Series[0].SmartLabelStyle.Enabled = false;
foreach (DataGridViewRow dgvr in earnings1.dataGridView1.Rows)
{
decimal testing = Convert.ToDecimal(earnings1.dataGridView1[1, i].Value);
testing = decimal.Truncate(testing);
var point = new DataPoint(i + 1, Convert.ToDouble(testing));
point.Label = testing.ToString();
point.Font = new Font("Century Gothic", 8, FontStyle.Bold);
chart1.Series[0].Points.Add(point);
chart1.Series[0].LabelAngle = -90;
chart1.Series[0].Points[i].AxisLabel = sday.ToString("dd/MM/yyyy");
sday = sday.AddDays(1);
i++;
}

I found the way to do it:
chart1.ChartAreas[0].CursorX.IntervalType = DateTimeIntervalType.Auto;
chart1.ChartAreas[0].CursorX.Interval = 1;
and let Visual Studio do the job for you.

Related

Is there any way to make a Timeline chart in windows forms?

I am trying to make a timeline. I found this How can I make a gannt chart with overlapping points in winforms , and I am using it by now like this:
void limitGantt(Chart chart, DateTime start, DateTime end)
{
Axis ax = chart.ChartAreas[0].AxisX;
ax.Minimum = 0.5;
ax.Maximum = 1.5;
Axis ay = chart.ChartAreas[0].AxisY;
ay.Minimum = start.ToOADate();
ay.Maximum = end.ToOADate();
}
void addGanttTask(Series s, DateTime start, DateTime end, Color c, int slot, string label)
{
int pt = s.Points.AddXY(slot, start, end);
s.Points[pt].Color = c;
s.Points[pt].Label = label;
s.Points[pt].LabelAngle = -90;
s.Points[pt].LabelBackColor = Color.White;
}
void setUpGantt(Chart chart, DateTime start, DateTime end)
{
chart.Series.Clear();
Series s = chart.Series.Add("gantt");
s.ChartType = SeriesChartType.RangeBar;
s.YValueType = ChartValueType.DateTime;
s.XValueType = ChartValueType.DateTime;
s.AxisLabel = "";
s.IsVisibleInLegend = false;
Axis ax = chart.ChartAreas[0].AxisX;
Axis ay = chart.ChartAreas[0].AxisY;
ax.MajorGrid.Enabled = false;
ax.MajorTickMark.Enabled = false;
ax.LabelStyle.Format = " ";
ax.Enabled = AxisEnabled.False;
ay.LabelStyle.Format = "HH:mm";
ay.LabelAutoFitStyle = LabelAutoFitStyles.DecreaseFont;
ay.MajorGrid.Enabled = false;
ay.MajorTickMark.Enabled = false;
ay.LabelStyle.Angle = 90;
ay.LineColor = chart.BackColor;
ay.LabelAutoFitMaxFontSize = 6;
limitGantt(chart, start, end);
}
setUpGantt(frm1.chartTimeLine, start, end);
Series s = frm1.chartTimeLine.Series[0];
addGanttTask(s, firstEvent, firstEvent, Color.DarkSlateBlue, 1, "First Event");
addGanttTask(s, secondEvent, secondEvent, Color.DarkSlateBlue, 1, "Second Event");
As you can see, I have set the start & end value as the same.
This is the result:
timeline attempt
Is not so nice... also the labels positions are not accurate (i.e. 1st event time is represented (more or less)after 11:00 when the true value is 10:55, and also if they are so close they overlap.
Does anyone know another way to make a TimeLine, or at least what I am doing wrong with the labels?
Thank you very much in advance!

How Do I Get The Scale of The Secondary Axis to be Based on My Series Values?

I'm using System.Web.UI.DataVisualization. Charting to create charts in MVC.
I have a chart displaying values in a StackedColumn100 SeriesChartType with the corresponding y-axis values on the primary y-axis on the left side.
Since it is a 100% stacked column series, the primary y-axis is scaled from 0 to 100.
I have then added a secondary series in the form of a Line SeriesChartType tied to a secondary axis (on the right side). I would like this axis to adjust its scale based on the values in the series but it doesn't. No matter what the highest value of this series is, the secondary y-axis also has a scale between 0 to 100.
If I manually set the maximum value for the secondary y-axis the following way:
chart.ChartAreas[0].AxisY2.Maximum = 20;. It works but I don't want to do that since the maximum value can differ greatly based on the search criteria used.
I have really tried to find a solution for this but I can't. According to the documentation and samples it seems that the scale should be based on the series values but I don't get it to work that way. Any help would be greatly appreciated!
Below is a stand alone test function that recreates the problem. I call the function from my view with the following line:
<p><img src="#Url.Action("CreateChart_TestSecondaryAxis")" /> </p>
public FileResult CreateChart_TestSecondaryAxis()
{
System.Web.UI.DataVisualization.Charting.Chart chart = new System.Web.UI.DataVisualization.Charting.Chart();
chart.Width = 800;
chart.Height = 400;
chart.BackColor = Color.FromArgb(211, 223, 240);
chart.BorderlineDashStyle = ChartDashStyle.Solid;
chart.BackSecondaryColor = Color.White;
chart.BackGradientStyle = GradientStyle.TopBottom;
chart.BorderlineWidth = 1;
chart.Palette = ChartColorPalette.BrightPastel;
chart.BorderlineColor = Color.FromArgb(26, 59, 105);
chart.RenderType = RenderType.BinaryStreaming;
chart.BorderSkin.SkinStyle = BorderSkinStyle.Emboss;
chart.AntiAliasing = AntiAliasingStyles.All;
chart.TextAntiAliasingQuality = TextAntiAliasingQuality.Normal;
ChartArea chartArea = new ChartArea();
chartArea.Name = "TestSecondaryAxis";
chartArea.BackColor = Color.Transparent;
chartArea.AxisX.IsLabelAutoFit = false;
chartArea.AxisY.IsLabelAutoFit = false;
chartArea.AxisX.LabelStyle.Font =
new Font("Verdana,Arial,Helvetica,sans-serif",
8F, FontStyle.Regular);
chartArea.AxisY.LabelStyle.Font =
new Font("Verdana,Arial,Helvetica,sans-serif",
8F, FontStyle.Regular);
chartArea.AxisY.LineColor = Color.FromArgb(64, 64, 64, 64);
chartArea.AxisX.LineColor = Color.FromArgb(64, 64, 64, 64);
chartArea.AxisY.MajorGrid.LineColor = Color.FromArgb(64, 64, 64, 64);
chartArea.AxisX.MajorGrid.LineColor = Color.FromArgb(64, 64, 64, 64);
chartArea.AxisX.Title = "Airport";
chartArea.AxisY.Title = "LandingConf";
chartArea.AxisY.TextOrientation = TextOrientation.Rotated270;
chartArea.AxisX.LabelStyle.IsEndLabelVisible = true;
chart.ChartAreas.Add(chartArea);
Series seriesPrimaryAxisConf3 = new Series();
seriesPrimaryAxisConf3.Name = "Conf 3";
seriesPrimaryAxisConf3.IsValueShownAsLabel = false;
seriesPrimaryAxisConf3.Color = Color.Blue;
seriesPrimaryAxisConf3.ChartType = SeriesChartType.StackedColumn100;
seriesPrimaryAxisConf3.BorderWidth = 2;
seriesPrimaryAxisConf3.ChartArea = "TestSecondaryAxis";
DataPoint point;
for (int i = 1; i < 11; i++)
{
point = new DataPoint();
point.AxisLabel = "Airport" + i.ToString();
point.YValues = new double[] { i };
seriesPrimaryAxisConf3.Points.Add(point);
}
chart.Series.Add(seriesPrimaryAxisConf3);
Series seriesPrimaryAxisConfFull = new Series();
seriesPrimaryAxisConfFull.Name = "Conf Full";
seriesPrimaryAxisConfFull.IsValueShownAsLabel = false;
seriesPrimaryAxisConfFull.Color = Color.Red;
seriesPrimaryAxisConfFull.ChartType = SeriesChartType.StackedColumn100;
seriesPrimaryAxisConfFull.BorderWidth = 2;
seriesPrimaryAxisConfFull.ChartArea = "TestSecondaryAxis";
for (int i = 1; i < 11; i++)
{
point = new DataPoint();
point.AxisLabel = "Airport" + i.ToString();
point.YValues = new double[] { 11-i };
seriesPrimaryAxisConfFull.Points.Add(point);
}
chart.Series.Add(seriesPrimaryAxisConfFull);
Series seriesSecondaryAxisNoOfFlights = new Series();
seriesSecondaryAxisNoOfFlights.Name = "NoOfFLights";
seriesSecondaryAxisNoOfFlights.IsValueShownAsLabel = false;
seriesSecondaryAxisNoOfFlights.Color = Color.Red;
seriesSecondaryAxisNoOfFlights.ChartType = SeriesChartType.Line;
seriesSecondaryAxisNoOfFlights.BorderWidth = 2;
seriesSecondaryAxisNoOfFlights.ChartArea = "TestSecondaryAxis";
for (int i = 1; i < 11; i++)
{
point = new DataPoint();
point.AxisLabel = "Airport" + i.ToString();
point.YValues = new double[] { i };
seriesSecondaryAxisNoOfFlights.Points.Add(point);
}
chart.Series.Add(seriesSecondaryAxisNoOfFlights);
chart.Series["NoOfFLights"].YAxisType = AxisType.Secondary;
chart.ChartAreas["TestSecondaryAxis"].AxisY2.LineColor = Color.Transparent;
chart.ChartAreas["TestSecondaryAxis"].AxisY2.MajorGrid.Enabled = false;
chart.ChartAreas["TestSecondaryAxis"].AxisY2.MajorTickMark.Enabled = false;
MemoryStream ms = new MemoryStream();
chart.SaveImage(ms);
return File(ms.GetBuffer(), #"image/png");
}
MSChart is a nice control but unfortunately Microsoft has always failed to properly document it.
And with the latest changes at MSDN things have gone from bad to worse, so I can't actually point to the rules that go for the various ChartTypes.
In your case I deduct this (rather wacky) rule:
To attach a non 100%-series to an indepently scaled secondary y-axis
it must be the first series but the stacked series still must be added
first.
So, if you want to get a result like this:
..you need to adapt the code. Here are the changes and additions needed..:
First we have to insert the line series at the front but do that after the stack100 series have beeen added..:
chart.Series.Insert(0, seriesSecondaryAxisNoOfFlights); // instead of adding it
Next we need to owner-draw the line as it would get burried under the columns otherwise.
Code the PostPaint event like this:
private void Chart_PostPaint(object sender, ChartPaintEventArgs e)
{
Chart chart = sender as Chart; //*
Series s = chart.Series[0]; // make sure to pick the right one!
Axis ax = chart.ChartAreas[0].AxisX;
Axis ay = chart.ChartAreas[0].AxisY2; // !!
var pts = s.Points.Select(x =>
new PointF((float)ax.ValueToPixelPosition(x.XValue),
(float)ay.ValueToPixelPosition(x.YValues[0])));
using (Pen pen = new Pen(s.Color, s.BorderWidth))
e.ChartGraphics.Graphics.DrawLines(pen, pts.ToArray());
}
For this to work the series need valid x-values. So add this line:
point.XValue = i; // set both x and y-values!
I also added a few nudges to the axis positioning:
ChartArea ca = chart.ChartAreas["TestSecondaryAxis"];
ca.AxisY.Maximum = 100;
ca.AxisX.Minimum = 0.5;
ca.AxisX.IntervalOffset = 0.5;

C# Scaling Axes of chart

I have a problem with charts in my application. I want to use charts to display histograms of pictures. I want to add a gradient rectangle under chart with colors from black to R/G/B/White, so I draw it as Background Image of each chart. When values on AxisY ar greater then 1k everything is fine, but when those values have less then 4 digits there is a problem screen. Anyone know how to prevent extension of AxisX?
Init charts:
for(int i = 0; i < 3; i++)
{
ca = new ChartArea();
ca.AxisX.Interval = 1D;
ca.AxisX.IntervalOffsetType = System.Windows.Forms.DataVisualization.Charting.DateTimeIntervalType.Number;
ca.AxisX.LabelAutoFitStyle = System.Windows.Forms.DataVisualization.Charting.LabelAutoFitStyles.WordWrap;
ca.AxisX.MajorGrid.Enabled = false;
ca.AxisY.MajorGrid.LineColor = System.Drawing.Color.DarkGray;
ca.BackColor = System.Drawing.Color.Transparent;
ca.BackSecondaryColor = System.Drawing.Color.Transparent;
ca.BorderWidth = 0;
ca.Name = "ChartArea" + i.ToString();
ca.AxisY.LabelAutoFitStyle = LabelAutoFitStyles.DecreaseFont;
ca.AxisX.Minimum = 0;
ca.AxisX.Interval = 256;
ca.AxisY.IntervalAutoMode = IntervalAutoMode.VariableCount;
s = new Series();
s.BorderWidth = 0;
s.ChartArea = "ChartArea" + i.ToString();
s.IsVisibleInLegend = false;
s.Name = "Series" + i.ToString(); ;
s.Color = Colors[i];
s["PointWidth"] = "1";
HistCharts[i] = new Chart();
HistCharts[i].Anchor = AnchorStyles.Top | AnchorStyles.Right;
HistCharts[i].BackColor = Color.Transparent;
HistCharts[i].BackgroundImageLayout = ImageLayout.None;
HistCharts[i].BorderlineWidth = 0;
HistCharts[i].ChartAreas.Add(ca);
HistCharts[i].Location = new System.Drawing.Point(405, (i + 3) * Form.Height / 6 - 28);
HistCharts[i].Name = "Chart" + i.ToString();
HistCharts[i].Series.Add(s);
HistCharts[i].Size = new System.Drawing.Size(297, Form.Height / 6 - 27);
HistCharts[i].TabIndex = 6;
HistCharts[i].Text = "chart" + i.ToString();
HistCharts[i].Visible = false;
HistCharts[i].SendToBack();
}
SetChartImage();
for(int i = 0; i < 3; i++)
HistCharts[i].BackgroundImage = HistImages[i];
Set new series and paint:
if(Hists == null)
{
HistCharts[0].Visible = false;
HistCharts[1].Visible = false;
HistCharts[2].Visible = false;
UpdateStatTimer(Time);
return;
}
HistCharts[0].BackgroundImage = HistImages[Hists.Length > 1 ? 1 : 0];
if(Hists[0].SequenceEqual(Hists[1]) && Hists[0].SequenceEqual(Hists[2]))
{
HistCharts[0].Series[0].Color = Color.Black;
HistCharts[0].BackgroundImage = HistImages[0];
HistCharts[0].Visible = true;
HistCharts[1].Visible = false;
HistCharts[2].Visible = false;
}
else
{
HistCharts[0].Series[0].Color = Color.Red;
HistCharts[0].BackgroundImage = HistImages[1];
HistCharts[0].Visible = true;
HistCharts[1].Visible = true;
HistCharts[2].Visible = true;
}
int Max = 0;
for(int i = 0; i < 3; i++)
{
HistCharts[i].Series[0].Points.Clear();
HistCharts[i].ChartAreas[0].AxisY.Maximum = Double.NaN;
for(int j = 0; j < Hists[i].Length; j++)
HistCharts[i].Series[0].Points.AddXY(j + 0.5, Hists[i][j]);
HistCharts[i].Update();
if(HistCharts[i].ChartAreas[0].AxisY.Maximum > Max)
Max = (int) HistCharts[i].ChartAreas[0].AxisY.Maximum;
}
if(StatisticsItemCheck.Checked == false)
{
for(int i = 0; i < 3; i++)
HistCharts[i].ChartAreas[0].AxisY.Maximum = Max;
}
if all Hists are equal Green and Blue histograms are invisible and Red Histogram becomes GrayScale Histogram
This is not really about scaling..:
The reason your images don't always align with the Y-Axis is that the Y-Axis legend takes more or less room in various cases. This make the inner plot area move to the right and your carefully aligned image doesn't fit anymore.
When the Y-Axis moves to the right the whole plotarea shrinks, at least if the default vlaues of Auto are still valid for the various elements..
The simplest workaround is to set the position from Auto to a fixed value that suits all your data:
chart1.ChartAreas[0].InnerPlotPosition.X = someValue;
Note that all element position values are in percent of the whole chart! So maybe you will want to modify it upon resizing the chart..? As you have noticed, you also have to resize you images..
To find a good value you can use the debugger to see which are the current ones in both of your cases and pick the larger one and then some extra for safety..
In the same veign you may want to get better control over the format, i.e. the number of digits on your y-axis label values, maybe like this..:
chart1.ChartAreas[0].AxisY.LabelStyle.Format = "0.00"; // some formatstring
Update:
To make use of the system's AutoScaling during(after a resize, you can use this workaround:
First set the Auto on and copy the resulting Elementposition. Then use those values to create a new one under control:
int LeftEdge = yourValue;
chart1.ChartAreas[0].InnerPlotPosition.Auto = true;
ElementPosition EP = chart1.ChartAreas[0].InnerPlotPosition;
chart1.ChartAreas[0].InnerPlotPosition =
new ElementPosition(LeftEdge, EP.Y, EP.Height, 100 - LeftEdge);

MS Chart Strip Lines Intraday

I use a line chart with double in Y axis and DateTime in X axis. My plot has only intraday data: I have one point each minutes between 8 am and 10 pm.
I want to underline certain periods of the plot. The first period begins at 8:50 and continues during 20 minutes. For this I use a stripLine with the following code:
var stripLine = new StripLine();
stripLine.BackColor = Color.White;
stripLine.BackGradientStyle = GradientStyle.TopBottom;
stripLine.BackImageTransparentColor = Color.White;
stripLine.BackSecondaryColor = Color.Transparent;
stripLine.Interval = 1;
stripLine.IntervalType = DateTimeIntervalType.Days;
stripLine.IntervalOffset = 50;
stripLine.IntervalOffsetType = DateTimeIntervalType.Minutes;
stripLine.StripWidth = 20;
stripLine.StripWidthType= DateTimeIntervalType.Minutes;
chartArea.AxisX.StripLines.Add(stripLine);
However I do not get the right result. Indeed, all my chart area is underlined by the strip line..
Here is a plot to illustrate what I want to achieve:
Your question is a bit obscure: your code is striplining the area vertically from 8:50 to 9:10 A.M.
Do you want to create Stripline every (x):50 to (x+1):10 ?
for(int i=0;i<24;i++)
{
var stripLine = new StripLine();
stripLine.BackColor = Color.White;
stripLine.BackGradientStyle = GradientStyle.TopBottom;
stripLine.BackImageTransparentColor = Color.White;
stripLine.BackSecondaryColor = Color.Transparent;
stripLine.Interval = (double)i;
stripLine.IntervalType = DateTimeIntervalType.Hours;
stripLine.IntervalOffset = 50;
stripLine.IntervalOffsetType = DateTimeIntervalType.Minutes;
stripLine.StripWidth = 20;
stripLine.StripWidthType = DateTimeIntervalType.Minutes;
Chart1.ChartAreas[0].AxisX.StripLines.Add(stripLine);
}
Should work.
Do you want to show the StripLine exactly at the points you showed?
var stripLine = new StripLine();
stripLine.BackColor = Color.White;
stripLine.BackGradientStyle = GradientStyle.TopBottom;
stripLine.BackImageTransparentColor = Color.White;
stripLine.BackSecondaryColor = Color.Transparent;
stripLine.Interval = 9;
stripLine.IntervalType = DateTimeIntervalType.Hours;
stripLine.IntervalOffset = 28;
stripLine.IntervalOffsetType = DateTimeIntervalType.Minutes;
stripLine.StripWidth = 8;
stripLine.StripWidthType= DateTimeIntervalType.Seconds;
chartArea.AxisX.StripLines.Add(stripLine);
Is the right solution.
A StripLine is a line and it will only allow you the add colored rectangles.
To create an area that follows your spline curve you need to either
draw it in the PostPaint event
or use an extra Series of type SplineArea
Here is the 2nd way:
..
Series s3 = chart.Series.Add("S3 ");
s1.ChartType = SeriesChartType.Spline;
s2.ChartType = SeriesChartType.Line;
s3.ChartType = SeriesChartType.SplineArea;
s2.Color = Color.Red;
s3.Color = Color.FromArgb(55, Color.RosyBrown);
for (int i = 0; i < 50; i++)
{
s1.Points.AddXY(i,20 - rnd.Next(10) );
s2.Points.AddXY(i,17);
if (i > 10 && i < 20) s3.Points.AddXY(i, s1.Points[i].YValues[0]);
}

Rangebar series not centered

I am working with a RangeBar Chart in a c# form app. When I add the series to the chart they do no line up correctly. When I change the "DrawSideBySide=false" it works fine, but I need some of the series to be side by side.
Any help on this would be greatly appreciated.
My code is just a List of Series being populated and then those series being added to a chart.
I loop through this populating series and adding them to a series list.
Populating-
double yplot1 = (double)user.Projects[i].StartDate.ToOADate();
double yplot2 = (double)user.Projects[i].EndDate.ToOADate();
// Use a different series for each datapoint
Series seriesInstance = new Series();
//seriesInstance.Name = user.Name;
seriesInstance.Label = user.Projects[i].Name + " - " + (user.Projects[i].AllocationPercent * 100).ToString() + "%";
seriesInstance.AxisLabel = user.Name;
seriesInstance.ChartType = SeriesChartType.RangeBar;
// Have a start and end date so plotting 2 points on the y-axis
seriesInstance.YValuesPerPoint = 2;
//seriesInstance.CustomProperties = "DrawSideBySide=true";
//seriesInstance["PixelPointWidth"] = "200";
seriesInstance["MinPixelPointWidth"] = "150";
int xordinal = j;
seriesInstance.IsXValueIndexed = false;
seriesInstance.Points.AddXY(xordinal, yplot1, yplot2);
/*seriesInstance.Points[0].ToolTip = someTipText;
seriesInstance.Points[0].Color = resourceColor;
seriesInstance.Points[0].AxisLabel = xlabel;*/
seriesList.Add(seriesInstance);
Then I add all the series in the list to the chart
foreach (Series plotSeries in seriesList)
{
chart1.Series.Add(plotSeries);
}
// Force x-axis to show each task or resource
chart1.ChartAreas[0].AxisX.Interval = 1;
// Set y-axis to show each day of the month
chart1.ChartAreas[0].AxisY.Interval = 1;
ChartArea chartArea1 = chart1.ChartAreas[0];
chartArea1.AxisX.IsReversed = true;
// Set other y-axis properties
chartArea1.AxisX.ScrollBar.Enabled = true;
chartArea1.AxisX.IsLabelAutoFit = true;
chartArea1.AxisX.ScaleView.Size = 5;
chartArea1.AxisY.IsStartedFromZero = false;
chartArea1.AxisY.IsMarginVisible = false;
if ((lastDate - firstDate).TotalDays < 60)
{
chartArea1.AxisY.IntervalType = DateTimeIntervalType.Days;
}
else if (((lastDate - firstDate).TotalDays > 60) && ((lastDate - firstDate).TotalDays < 365))
{
chartArea1.AxisY.IntervalType = DateTimeIntervalType.Weeks;
}
else
{
chartArea1.AxisY.IntervalType = DateTimeIntervalType.Months;
}
// Set the y-axis labels
chart1.ChartAreas[0].AxisY.Minimum = firstDate.AddDays(-1).ToOADate();
chart1.ChartAreas[0].AxisY.Maximum = lastDate.AddDays(+1).ToOADate();
chart1.ChartAreas[0].AxisY.LabelStyle.Format = "ddd M/d";
// Force redraw of chart
chart1.Update();

Categories

Resources