I'm using the Winform DataVisualization.Charting.Chart control. I have added 3 data series into the default chartarea. Each series has an integer y value and a Datetime x value.
If I show any one data series, it works as expected; however, if I combine the data series the dates overlap and are not in chronological order thus making the chart useless. I've hard-coded the values just for a sanity check but still see the same issue.
If anyone knows for a way for this chart to have a single x axis timeline that all data series will just plot the y value onto, it would be greatly appreciated. I've run out of things to try. (Image include below...)
chrtSessions.ChartAreas.Clear();
chrtSessions.ChartAreas.Add(new ChartArea("Default"));
chrtSessions.Series.Clear();
chrtSessions.Titles.Clear();
chrtSessions.Titles.Add("Hours Left For Licensure");
chrtSessions.ChartAreas["Default"].AxisY.Title = "Hours";
chrtSessions.ChartAreas["Default"].AxisX.Title = "Dates";
chrtSessions.ChartAreas["Default"].AxisX.IntervalType = DateTimeIntervalType.Days;
chrtSessions.ChartAreas["Default"].AxisX.LabelStyle.Format = "DD/MM/YYYY";
chrtSessions.Series.Add("Individual");
chrtSessions.Series["Individual"].AxisLabel = "Individual Sessions";
chrtSessions.Series["Individual"].ChartType = SeriesChartType.Line;
chrtSessions.Series["Individual"].BorderWidth = 4;
chrtSessions.Series["Individual"].XValueType = ChartValueType.Date;
for (int index = 0; index < individualData.hours.Count; index++)
{
chrtSessions.Series["Individual"].Points.AddXY(individualData.dates[index].ToShortDateString(), individualData.hours[index]);
}
chrtSessions.Series.Add("Relational");
chrtSessions.Series["Relational"].AxisLabel = "Relational Sessions";
chrtSessions.Series["Relational"].ChartType = SeriesChartType.Line;
chrtSessions.Series["Relational"].BorderWidth = 4;
chrtSessions.Series["Relational"].XValueType = ChartValueType.Date;
for (int index = 0; index < relationalData.hours.Count; index++)
{
chrtSessions.Series["Relational"].Points.AddXY(relationalData.dates[index].ToShortDateString(), relationalData.hours[index]);
}
chrtSessions.Series.Add("Supervision");
chrtSessions.Series["Supervision"].AxisLabel = "Supervision Sessions";
chrtSessions.Series["Supervision"].ChartType= SeriesChartType.Line;
chrtSessions.Series["Supervision"].BorderWidth = 4;
chrtSessions.Series["Supervision"].XValueType = ChartValueType.Date;
for (int index = 0; index < supervisionData.hours.Count; index++)
{
chrtSessions.Series["Supervision"].Points.AddXY(supervisionData.dates[index].ToShortDateString(), supervisionData.hours[index]);
}
Notice on this image that the Date 11/19/2021 occurs twice, but with 11/20/2021 occurring in-between and only yellow dataset actually has data that goes to the 23rd (data should show from 10/29-11/23). The blue line should span 10/31-11/20 and the red line should span from 10/26-11/19.
Related
I have a c# Windows forms application that generates a stacked line graph using the standard MS Chart control, as in the below example.
Is there a way of "smoothing" the lines by formatting the series or some other property?
Looking at MSDN and Google I can't seem to find a way to do this, in Excel there a series.Smooth property...
I have I missed it or is it not possible?
If you liked the smooth look of the SplineAreas you can calculate the necessary values to get just that look:
A few notes:
I have reversed the order of the series; many ways to get the colors right.. (Instead one probably should accumulate in reverse)
The stacked DataPoints need to be aligned, as usual and any empty DataPoints should have their Y-Values to be 0.
Of course in the new series you can't access the actual data values any longer as you now have the accumulated values instead; at least not without reversing the calulation. So if need them keep them around somewhere. The new DataPoints' Tag property is one option..
You can control the ' smoothness' of each Series by setting its LineTension custom attribute:
chart2.Series[0].SetCustomProperty("LineTension", "0.15");
Here is the full example code that creates the above screenshots calculating a 'stacked' SplineArea chart2 from the data in a StackedArea chart1:
// preparation
for (int i = 0; i < 4; i++)
{
Series s = chart1.Series.Add("S" + i);
s.ChartType = SeriesChartType.StackedArea;
Series s2 = chart2.Series.Add("S" + i);
s2.ChartType = SeriesChartType.SplineArea;
}
for (int i = 0; i < 30; i++) // some test data
{
chart1.Series[0].Points.AddXY(i, Math.Abs(Math.Sin(i / 8f)));
chart1.Series[1].Points.AddXY(i, Math.Abs(Math.Sin(i / 4f)));
chart1.Series[2].Points.AddXY(i, Math.Abs(Math.Sin(i / 1f)));
chart1.Series[3].Points.AddXY(i, Math.Abs(Math.Sin(i / 0.5f)));
}
// the actual calculations:
int sCount = chart1.Series.Count;
for (int i = 0; i < chart1.Series[0].Points.Count ; i++)
{
double v = chart1.Series[0].Points[i].YValues[0];
chart2.Series[sCount - 1].Points.AddXY(i, v);
for (int j = 1; j < sCount; j++)
{
v += chart1.Series[j].Points[i].YValues[0];
chart2.Series[sCount - j - 1].Points.AddXY(i, v);
}
}
// optionally control the tension:
chart2.Series[0].SetCustomProperty("LineTension", "0.15");
I have a bar chart and I got a little problem in it.. it's grouping all bars to one single x value column .. i need to split each bar to its x value.. take a look at the snap shoot of the problem..
and my code:
RadChart1.PlotArea.XAxis.AutoScale = false;
RadChart1.PlotArea.XAxis.Items.Clear();
RadChart1.Series.Clear();
for (int i = 0; i < dt.Rows.Count; i++)
{
ChartSeries series = new ChartSeries(dt.Rows[i]["day_name"].ToString(), ChartSeriesType.Bar);
series.Items.Add(new ChartSeriesItem(Convert.ToDouble(dt.Rows[i]["total_timesheet"])));
ChartAxisItem axisItem = new ChartAxisItem(dt.Rows[i]["doc_date"].ToString());
RadChart1.PlotArea.XAxis.Items.Add(axisItem);
RadChart1.Series.Add(series);
}
I'm trying to create a stacked bar chart ,
But I'm getting an error in the lines that has ".Series " (How to define the Series ? )
SeriesChartType chart1 = new SeriesChartType();
// Populate series data
Random random = new Random();
for (int pointIndex = 0; pointIndex < 10; pointIndex++)
{
chart1.Series["LightBlue"].Points.AddY(random.Next(45, 95));
}
// Set chart type
chart1.Series["LightBlue"].ChartType = SeriesChartType.StackedArea100;
// Show point labels
chart1.Series["LightBlue"].IsValueShownAsLabel = true;
// Disable X axis margin
chart1.ChartAreas["Default"].AxisX.IsMarginVisible = false;
// Set the first two series to be grouped into Group1
chart1.Series["LightBlue"]["StackedGroupName"] = "Group1";
chart1.Series["Gold"]["StackedGroupName"] = "Group1";
// Set the last two series to be grouped into Group2
chart1.Series["Red"]["StackedGroupName"] = "Group2";
chart1.Series["DarkBlue"]["StackedGroupName"] = "Group2";
The source code above seems to be from the MS Chart Samples application. Looking at the MS example stacked bar chart on screen, and the source code above, its obvious that the sample code is inadequate and does not show us how to do stacked bar charts.
You can either programmatically create and attach a series:
Series s1 = new Series("LightBlue");
s1.ChartType = SeriesChartType.StackedBar100;
chart1.Series.Add(s1);
or alternatively, you can define the series in your ASPX file and simple add Y values to each series in the code behind:
Random random = new Random();
for(int pointIndex = 0; pointIndex < 10; pointIndex++)
{
Chart1.Series["Series1"].Points.AddY(Math.Round((double)random.Next(45, 95),0));
Chart1.Series["Series2"].Points.AddY(Math.Round((double)random.Next(5, 75),0));
Chart1.Series["Series3"].Points.AddY(Math.Round((double)random.Next(5, 95),0));
Chart1.Series["Series4"].Points.AddY(Math.Round((double)random.Next(35, 95),0));
}
In the MS Chart Samples web solution, have a look at
/ChartTypes/BarColumnCharts/Stacked/stackedchart.aspx
it should have all you need.
I have a Microsoft Chart Controls within my winforms app.
I currently play the X and y values within a loop. I also had the X-axis format set as
ChartAreas[0].AxisX.LabelStyle.Format={"00:00:00"}
This worked fine as a time format, however I noticed once my time values went above 60 seconds, (i.e. 00:00:60), rather than the scale moving up to 1 minute (i.e. 00:01:00) it goes to 61 (i.e. 00:00:61) right up to 99 before it goes to one minute (00:00:99) then (00:01:00)
Is there a way to fix this please?
I suspect that LabelStyle.Format property is used in a similar way as in string.Format(mySringFormat,objToFormat).
Hence, given that your underlying X objects type is double, it will just print a colon-separated double (e.g. 4321 will be 00:43:21).
AFAIK, there isn't an easy way to print a double value like a time value using just a string format.
If you can change the code filling the chart, I suggest you to pass DateTime's for the X values, and then you will be able to use custom DateTime formatting, e.g.
"HH:mm:ss", or others
EDIT:
As per your comment:
// create a base date at the beginning of the method that fills the chart.
// Today is just an example, you can use whatever you want
// as the date part is hidden using the format = "HH:mm:ss"
DateTime baseDate = DateTime.Today;
var x = baseDate.AddSeconds((double)value1);
var y = (double)value2;
series.Points.addXY(x, y);
EDIT 2:
Here's a complete example, it should be easy to apply this logic to your code:
private void PopulateChart()
{
int elements = 100;
// creates 100 random X points
Random r = new Random();
List<double> xValues = new List<double>();
double currentX = 0;
for (int i = 0; i < elements; i++)
{
xValues.Add(currentX);
currentX = currentX + r.Next(1, 100);
}
// creates 100 random Y values
List<double> yValues = new List<double>();
for (int i = 0; i < elements; i++)
{
yValues.Add(r.Next(0, 20));
}
// remove all previous series
chart1.Series.Clear();
var series = chart1.Series.Add("MySeries");
series.ChartType = SeriesChartType.Line;
series.XValueType = ChartValueType.Auto;
DateTime baseDate = DateTime.Today;
for (int i = 0; i < xValues.Count; i++)
{
var xDate = baseDate.AddSeconds(xValues[i]);
var yValue = yValues[i];
series.Points.AddXY(xDate, yValue);
}
// show an X label every 3 Minute
chart1.ChartAreas[0].AxisX.Interval = 3.0;
chart1.ChartAreas[0].AxisX.IntervalType = DateTimeIntervalType.Minutes;
chart1.ChartAreas[0].AxisX.LabelStyle.Format = "HH:mm:ss";
}
I am new to C#.I have been thinking of adding a ButtonControlArray where i can store each button control.Here is part of my code.I am creating a 6*6 array of button Control.
ButtonControl buttonControl;
ButtonControl[,] arrayButtons = new ButtonControl[6,6];
public void createGrid()
{
l = 0;
for (int i = 0; i < numberOfButtons; i++)
{
for (int k = 0; k < numberOfButtons; k++)
{
buttonControl = new ButtonControl();
buttonControl.Location = new Point(l,j);
j += 55;
arrayButtons[i, k] = buttonControl;
//After the above statement if i print Console.WriteLine(""+arrayButtons[i,k]); i am getting only my projectname.buttoncontrol
myGridControl.Controls.Add(buttonControl);
}
l += 55; j = 10;
}
}
I want to access each variable in arrayButtons[][]..like in a 3*3 matrix..if i want 2nd row 1 column element..then i get something like arrayname[2][1]..same way if i want 2nd button in 2nd row how can i get..i tried doing one way but i couldnt figure it out...Can you help me out with this..
What are you having difficulty with?
If you're running into bounds checking problems, you should know that C# arrays start at zero, not one. So the button in the second row, first column is a[1,0] not a[2,1]
If you Google Control Arrays in C# you will get several good matches, including this one.