I have a chart control on a winform that should log some counting p hour.
On 12H clock repeat in local PC time.
So the chart starts from 0 to 11
The problem is that when its 12:20 or 12:50 or 12:10
I cannot get the numbering to start at 0 on the X axis
My main inits the chart like :
int[] numbers = new int[11] {12,11,10,91,82,7,66,5,44,3,2,1};
chart1.ChartAreas[0].AxisX.Maximum = 11;
chart1.ChartAreas[0].AxisX.Minimum = 0;
chart1.ChartAreas[0].AxisX.Interval = 1;
Then a loop updates and redraws the chart like below
DateTime currentTime = DateTime.UtcNow.ToLocalTime();
int hour12 = (currentTime.Hour % 12);
numbers[hour12]++;
chart1.Series["total"].Points.DataBindY(numbers);
I also tried but it didnt help here.
chart1.ChartAreas[0].AxisX.IsMarginVisible = false;
Replace
chart1.Series["total"].Points.DataBindY(numbers);
with
chart1.Series["total"].Points.DataBindXY(Enumerable.Range(0,12).ToArray(), numbers);
Update:
Set AxisX so that all chart series shows up correctly:
chart1.ChartAreas[0].AxisX.Maximum = 12;
chart1.ChartAreas[0].AxisX.Minimum =-1;
chart1.ChartAreas[0].AxisX.Interval = 1;
In addition to Sakis to remove -1 and 12 to get the 0..11 scale.
chart1.ChartAreas[0].AxisX.Maximum = 12;
chart1.ChartAreas[0].AxisX.Minimum =-1;
chart1.ChartAreas[0].AxisX.Interval = 1;
chart1.ChartAreas[0].AxisX.CustomLabels.Add(-1.5, -0.5, "Hour");
chart1.ChartAreas[0].AxisX.CustomLabels.Add(11.5, 12.5, " ");
for(int i=0;i<12;i++) chart1.ChartAreas[0].AxisX.CustomLabels.Add(i-0.9, i+0.9, i.ToString());
Related
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.
The problem is that I want to set some fixed values for 3 types of charts:
First is a week chart so it need to have Sunday to Saturday values on X axis.
Second is month so it have to set the days of the current month
The last one its a year chart that need to show months from 1 to 12 or jan to dec.
I did watch a lot of tutorials but any of those set points like I want and most of them teach how to set X and Y points, but I want a fixed X point and get the Y point from the DB.
To get these fixed ranges :
I have set up the chart like so:
private void rb_range_CheckedChanged(object sender, EventArgs e)
{
Chart chart = chart8;
Series s = chart.Series[0];
s.ChartType = SeriesChartType.Line;
s.XValueType = ChartValueType.DateTime;
s.YValueType = ChartValueType.Double;
Axis ax = chart.ChartAreas[0].AxisX;
Axis ay = chart.ChartAreas[0].AxisY;
//ax.IsMarginVisible = true; // max or may be necessary
ax.Interval = 1;
if (rb_week.Checked)
{
setValues('w', 123);
ax.IntervalType = DateTimeIntervalType.Days;
ax.LabelStyle.Format = "dddd";
}
else if (rb_month.Checked)
{
setValues('m', 123);
ax.IntervalType = DateTimeIntervalType.Days;
ax.LabelStyle.Format = "dd";
}
else if (rb_year.Checked)
{
setValues('y', 123);
ax.IntervalType = DateTimeIntervalType.Months;
ax.LabelStyle.Format = "MMMM";
}
s.Points.Clear();
foreach (var dp in points) s.Points.Add(dp);
// after the points are added or bound to you may want to..
// set the minimum&maximum, but if the data fit you don't have to!
ax.Minimum = points.Min(x => x.XValue);
ax.Maximum = points.Max(x => x.XValue);
}
A few Notes :
It is important to select or bind only those dates that should go into the chart! If you make mistakes here the limits will be off!
If your data are dense enough, that is, if they inclused the 1st and last day of the interval they refer to, you can omit setting the Minimum and Maximum on the x-axis; in that case also include ax.IsMarginVisible = false; to avoid points from the neighboring ranges showing up.
If you data are sparse you may need to determine the Minimum and Maximum values differently than simply picking the first and last x-values. Instead you should pick the correct DateTime values. Note that you need to pick real DateTimes and convert them to double with the ToOADate() function, as the axis properties expect value units.
You can study the code I used to create my data for hints on how to get the Date of the 1st and last day of a given week, month or year..
Note how I use DateTime.DaysInMonth to get the correct number of days in a given month
If you chose Column as ChartType the 1st and last columns may get cut. For this case you can expand the range by adding half a unit to the Maximum and subtracting the same from the Minimum. You may also need to add one such amount to the IntervalOffset.
Here is how I set up the points:
List<DataPoint> points = new List<DataPoint>();
void setValues(char time, int rand)
{
Random rnd = new Random(rand); // random data values
points = new List<DataPoint>();
DateTime dn = DateTime.Now;
DateTime dw = new DateTime(dn.Year, dn.Month, dn.Day % 7 + 1); //my weeks start on monday
DateTime dm = new DateTime(dn.Year, dn.Month, 1);
DateTime dy = new DateTime(dn.Year, 1, 1);
if (time == 'w') for (int i = 0; i < 7; i++)
points.Add(new DataPoint(dw.AddDays(i).ToOADate(), rnd.Next(100) + 50));
if (time == 'm') for (int i = 0; i < DateTime.DaysInMonth(dn.Year, dn.Month); i++)
points.Add(new DataPoint(dm.AddDays(i).ToOADate(), rnd.Next(100) + 50));
if (time == 'y') for (int i = 0; i < 12; i++)
points.Add(new DataPoint(dy.AddMonths(i).ToOADate(), rnd.Next(100) + 50));
}
I'm trying to add five columns of labels to my form, with 37 labels in the first three columns and 35 in the fourth. I'm trying to be a good programmer and avoid retyping code over and over again, so I'd like to handle all four columns in one loop if possible. Here's what I've got so far.
Label[] countLabel = new Label[200];
int PointY = 20;
int PointX = 20;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 37; j++ )
{
countLabel[j] = new Label();
countLabel[j].Location = new Point(PointX, PointY);
countLabel[j].Text = Convert.ToString(j + 1);
panel1.Controls.Add(countLabel[j]);
PointY += countLabel[j].Height;
}
PointX+=100;
}
I'm trying to do this:
for 0 through 3,
for 0 through 36
create a label
set its text to the count + 1
add it to the screen
make the next label be just below this one
Then, after the first group of 37 is output, make the next column be to the right 100px.
Whenever this runs, the first 37 form perfectly, and then the 38th is shifted to the right but below number 37. How can I reset the Y position so that the next column starts at the same Y position as the first column and goes all the way down?
Won't a simple
PointY = 20;
just after the line
`PointX+=100;`
do it? It would reset Y and the next one would start from top.
I am trying to visualise data with a chart. I have done for hours, need to do for days and weeks to compare. Here is a sample code for the how I visualise hourly, having problems doing the same thing for day like monday, tuesday down to sunday in the intervals. How can I do this for day intervals?
chart1.ChartAreas.Add("area");
chart1.ChartAreas["area"].AxisX.Minimum = 0;
chart1.ChartAreas["area"].AxisX.Maximum = 24;
chart1.ChartAreas["area"].AxisX.Interval = 1;
chart1.ChartAreas["area"].AxisY.Minimum = 0;
chart1.ChartAreas["area"].AxisY.Maximum = intYAxisMax;
chart1.ChartAreas["area"].AxisY.Interval= 10;
chart1.Series.Add("Electric");
chart1.Series.Add("Gas");
chart1.Series["Electric"].Color = Color.Red;
chart1.Series["Gas"].Color = Color.Green;
chart1.ChartAreas["area"].AxisX.Title = "Hours";
chart1.ChartAreas["area"].AxisY.Title = "KW/H";
Title objTest = new Title("Daily Data Usage");
chart1.Titles.Add(objTest);
Legend objLegend = new Legend("Testing");
chart1.Legends.Add(objLegend);
//chart1.Series["Electric"].Points.AddXY(20 , 203);
//chart1.Series["Gas"].Points.AddXY(11, 70);
Try this:
chart1.Series["Electric"].IsXValueIndexed = true;
//Add data
chart1.Series["Electric"].Points.AddXY(1, 203);
chart1.Series["Electric"].Points.AddXY(2, 70);
//X-axis labels
chart1.Series["Electric"].Points[0].AxisLabel = "Sunday";
chart1.Series["Electric"].Points[1].AxisLabel = "Monday";
etc...
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";
}