Okay so I have a datetime x-axis on an MSChart. I want to plot months below the first of each month and years below the change of a year. Here's what I have so far:
for (int i = 0; i < rdate.Length -1 ; i++)
{
if (rdate[i].Day == 01 && set == 0)
chart1.ChartAreas[0].AxisX.CustomLabels.Add(
rdate[i].AddDays(-20).ToOADate(), rdate[i].AddDays(20).ToOADate(),
Convert.ToString(rdate[i].ToString("MMMM")), 1, LabelMarkStyle.None);
set = 1;
if (rdate[i].Day > 01)
set = 0;
i++;
if (rdate[i].Year > rdate[i-1].Year)
chart1.ChartAreas[0].AxisX.CustomLabels.Add(
rdate[i].AddDays(-20).ToOADate(), rdate[i].AddDays(20).ToOADate(),
Convert.ToString(rdate[i].ToString("yyyy")), 2, LabelMarkStyle.None);
}
However for some reason this skips some months... The years do not show up at all.
rdate is a datetime array used to populate the x axis.
Here is an example of what my code does:
As you can see, the labels are behaving unexpectedly. I would also like to show a larger tick mark for these dates, and reduce the number of day labels based upon the date range, but I'm at a loss. Anyone done this sort of thing before?
I recently had a similar issue with MSChart when adding too many labels to the x-axis. The solution was reduce the number of ticks without losing data.
This approach worked for me but you will have to adapt it to your specific needs.
dataSeries.XValueType = ChartValueType.Auto;
dataSeries.Points.AddXY(record.DateTime, value);
I then determined the min and max dates for the given data to determine the preferred interval, your implementation will vary:
var totalDays = (maxDate.Value - minDate.Value).TotalDays;
if (totalDays < 60)
chartArea.AxisX.IntervalType = DateTimeIntervalType.Days;
else if (totalDays < 120)
chartArea.AxisX.IntervalType = DateTimeIntervalType.Weeks;
else
chartArea.AxisX.IntervalType = DateTimeIntervalType.Months;
Specify the AxisX label format:
In your case you might have to change the Format together with the interval.
chartArea.AxisX.LabelStyle.Format = Thread.CurrentThread.CurrentCulture.DateTimeFormat.ShortDatePattern;
Hopefully there are some key parts that will provide value for you but you still have to modify it for your particular needs.
Related
I try to draw Chart via C# with table as picture.
However, as you can see A4 data in date: 7 and 8/6 should stay with same 7 and 8/6 X-Axis, abnormal here all of them left to 5 & 6/6 X-Axis. Could you help me to fix it.
for (int i = 0; i < 14; i++)
{
string productname = dataGridView1.Rows[i].Cells[0].Value.ToString();
string datetime = dataGridView1.Rows[i].Cells[2].Value.ToString();
int para = Convert.ToInt16(dataGridView1.Rows[i].Cells[1].Value);
if (chart_dashboard.Series.IndexOf(productname) != -1)
{
chart_dashboard.Series[productname].Points.AddXY(datetime, para);
chart_dashboard.ChartAreas[0].AxisX.Interval = 1;
}
else
{
chart_dashboard.Series.Add(productname);
chart_dashboard.Series[productname].Points.AddXY(datetime, para);
chart_dashboard.ChartAreas[0].AxisX.Interval = 1;
}
}
A common mistake.
string datetime = dataGridView1.Rows[i].Cells[2].Value.ToString();
This is wrong! If you add the x-values as strings they all are added as 0 and the Series can't align them to the proper slots on the X-Axis. So they get added from left to right sequentially..
Instead simply add the x-values as the DateTimes they are supposed to be!
So if the Cells contain DateTime values use:
DateTime datetime = (DateTime) dataGridView1.Rows[i].Cells[2].Value;
If they don't, convert them to DateTime
DateTime datetime = Convert.ToDateTime(dataGridView1.Rows[i].Cells[2].Value);
To control the x-values type set the XValueType for each series:
chart_dashboard.Series[yourSeries].XValueType = ChartValueType.DateTime;
To control the way the axis labels are displayed set their formatting:
chart_dashboard[ChartAreas[0].AxisX.LabelStyle.Format = someDateTimeFormatString;
To create a string like "Week 1" you would
set the XValueType to int16
add the x-value as the week numbers
format it like ..axis.LabelStyle.Format = "Week #0";
To extract the number from your data split by space and Convert.ToInt16 !
If one really needs to insert sparse x-values as strings one would have to insert a dummy DataPoint at each gap in a series.
Creating a dummy DataPoint is simple:
DataPoint dp = new DataPoint() { IsEmpty = true};
But knowing where the gaps are in advance is the challenge! The 'best' way is to go over the data and filling in the before adding the points. Or go over it later and instead of adding, inserting the dummys at the gaps. Both is a lot more trouble than getting the data right in the first place!
I'm using the MS Chart control in .Net 4 to display 4 data series, the X axis is set to datetime type.
with the interval set to days the graph includes weekend even though no weekend dates are included in the data.
All the series except one have the same date points, the exception is a projection line that starts on the last date and continues for a number of working days (excludes weekends).
How can remove the display of weekends (or dates that have no value) from the chart for all series?
this is a winforms .Net 4.0 Application.
foreach (var series in chart2.Series)
{
series.ChartType = SeriesChartType.Line;
series.BorderWidth = 5;
series.XValueType = ChartValueType.Date;
// I Tried this to remove weekends but it results in the graph showing a big red X
series.IsXValueIndexed = true;
}
Edit with Code to reproduce my issue below:
DateTime dt = DateTime.Now;
chart1.ChartAreas[0].AxisX.IntervalType = DateTimeIntervalType.Days;
Series test1 = new Series("Test1");
test1.XValueType = ChartValueType.Date;
for (int i = 1; i < 7; i++)
{
//skip the weekend
if (dt.DayOfWeek.ToString() == "Saturday") dt = dt.AddDays(1);
if (dt.DayOfWeek.ToString() == "Sunday") dt = dt.AddDays(1);
test1.Points.AddXY(dt.Date, i);
dt = dt.AddDays(1);
i++;
}
chart1.Series.Add(test1);
Series test2 = new Series("Test2");
test1.XValueType = ChartValueType.Date;
for (int i = 1; i < 7; i++)
{
//skip the weekend
if (dt.DayOfWeek.ToString() == "Saturday") dt = dt.AddDays(1);
if (dt.DayOfWeek.ToString() == "Sunday") dt = dt.AddDays(1);
test2.Points.AddXY(dt.Date, i);
dt = dt.AddDays(1);
i++;
}
chart1.Series.Add(test2);
foreach (var series in chart1.Series)
{
series.ChartType = SeriesChartType.Line;
series.BorderWidth = 5;
series.IsXValueIndexed=true;
}
chart1.ChartAreas[0].AxisX.LabelStyle.Angle = 45;
chart1.ChartAreas[0].AxisX.LabelStyle.Interval = 1;
You are adding the x-values as DateTime, which is what you should do. But by default this means the all x-values are positionend proportionally, as one usually wants them to be.
But your case is an exception, that is even mentioned in the documentation of the Series.IsXValueIndexed property:
All data points in a series use sequential indices, and if this
property is true then data points will be plotted sequentially,
regardless of their associated X-values. This means that there will be
no "missing" data points.
For example, assume there are three (3) data points in a series having
X-values of 1, 2 and 4. If this property was false, there would be a
data point missing at the X-axis location labeled "3". However, if you
set this property to true, the three data points will be plotted at
points 1, 2, and 4, sequentially, and there will be no missing data
point. The X-axis location labeled "3" will not appear on the chart.
This is useful when you do not want to have missing data points for
intervals that you know you will not have data for, such as weekends.
Note however:
If you are displaying multiple series and at least one series uses
indexed X-values, then all series must be aligned — that is, have the
same number of data points—and the corresponding points must have the
same X-values.
So you were correct in using this property, however, most likely, your series were not fully aligned.
To make sure they are one often can make use of one of the Chart.DataManipulator.InsertEmptyPoints overloads. Unfortunately they all work with a fixed Interval, not with a template Series.
So you will need to makes sure to add one Empty DataPoint wherever your data are missing a value in a Series. If the data are databound you will have to do that in the DataSource!
I just wonder if anyone knows how to change the LineStyle of the Major and Minor grid for a ZedGraph?
For example I have:
graphPane.XAxis.MinorGrid.IsVisible = true;
I want something along this line:
graphPane.XAxis.MinorGrid.LineStyle => solid line.
I've done a lot of research today but could not find the answer.
Thank you in advance for your time.
You probably have autoscaling set to true if you switch this off you can then set steps which you wish to use its best to stick with some numbers which are easily divisible otherwise you can get some strange numbers.
myPane.XAxis.Scale.MajorStepAuto = False
myPane.XAxis.Scale.MajorStep = 100
zg1.AxisChange()
zg1.refresh()
The above code is fully x-axis I'm fairly sure it will be similar to change the y-axis. I would start with a major axis and get the right first and you may find that the minor ones work well automatically.
The co code below is probably doing something very similar to what you're looking for and at the end of the case I've just switched on the XAxis.Scale.MajorStepAuto just in case we get some strange number
Select Case CDbl(maxNumber)
Case Is <= 100
myPane.XAxis.Scale.MajorStep = 10
Case Is <= 300
myPane.XAxis.Scale.MajorStep = 25
Case Is <= 1000
myPane.XAxis.Scale.MajorStep = 50
Case Is <= 5000
myPane.XAxis.Scale.MajorStep = 100
Case Is <= 10000
myPane.XAxis.Scale.MajorStep = 250
Case Is <= 50000
myPane.XAxis.Scale.MajorStep = 1000
Case Else
myPane.XAxis.Scale.MajorStepAuto = True
End Select
The following will draw a you solid line in aqua for the major grid line
myPane.XAxis.MajorGrid.DashOff = 0
myPane.XAxis.MajorGrid.Color = Color.Aqua
Hope that helps
I am writing a vehicle tracking application using GMAP.NET
I want to display simultaneous movement of multiple vehicle markers based on date/time.
For this, I would like to use a Trackbar such that when the User slides the trackbar, the corresponding movement of multiple markers is shown.
I did the same application on the browser and it worked very well. I converted the datetime attribute of the marker tag to a UNIX Timestamp and then set the trackbar (NOUI Slider) values to the the UNIX Timestamp range.
But, Now I find that I cannot do this at all with the Windows Desktop C# Trackbar.
The problems are:
The trackbar is unable to take very large timestamp values. Eg. 5 years data.
Even after reducing the very large numbers, the trackbar still cannot take such high values and keeps lagging or crashing.
Eg. I need to show data for 5 years. In this case, my trackbar would have minimum value - 1262304000 (i.e. 01-01-2010) to 1425203100 (i.e. 01-03-2015 | 09:45).
But such large values just don't work with my trackbar.
I have even taken reduction eg. setting 1262304000 as 1 and then 162899100 (i.e. 1425203100 - 1262304000) becomes my maximum value.
But even this is very intensive and the trackbar does not work.
Please suggest if there is a time-trackbar which can show very a large datetimerange or how I can use a regular trackbar with very large values.
The code as follows -
A. The function to convert datetime to a UNIX Timestamp
public Int32 UnixTimeStampUTC(DateTime datetime)
{
Int32 unixTimeStamp;
DateTime zuluTime = datetime.ToUniversalTime();
DateTime unixEpoch = new DateTime(1970, 1, 1).ToUniversalTime();
unixTimeStamp = (Int32)(zuluTime.Subtract(unixEpoch)).TotalSeconds;
return unixTimeStamp;
}
B. Taking the DateTime from a DataTable by Concatenating Date & Time Columns and Adding a third Column to hold the Unix TimeStamp of the DateTime Column
for (int z = 0; z < dt.Rows.Count; z++)
{
if (reviseddt.Rows[z]["date"].ToString() != "")
{
dte = DateTime.Parse(reviseddt.Rows[z]["date"].ToString());
dteticks = UnixTimeStampUTC(dte);
}
else
{
dteticks = 0;
}
if (reviseddt.Rows[z]["time"].ToString() != "")
{
tm = DateTime.Parse(reviseddt.Rows[z]["time"].ToString());
tmticks = UnixTimeStampUTC(tm);
}
else
{
tmticks = 0;
}
Int32 fullDt = dteticks + tmticks;
reviseddt.Rows[z]["datetime"] = fullDt.ToString();
reviseddt.Rows[z]["datetimestring"] = reviseddt.Rows[z]["date"].ToString() + reviseddt.Rows[z]["time"].ToString();
C. Initalising the Trackbar by Getting the min and max values from the datetime column in the datatable and then taking the range as the difference between the min and max values. Hence, Trackbar range = 1 to (Max-Min)
string strminlevel = toplotDataTable.Compute("min(datetime)", String.Empty).ToString();
string strmaxLevel = toplotDataTable.Compute("max(datetime)", String.Empty).ToString();
Int32 minLevel = Convert.ToInt32(strminlevel);
Int32 maxLevel = Convert.ToInt32(strmaxLevel);
Int32 rangeint = maxLevel - minLevel;
trackBarMoveTarget.Maximum = rangeint;
trackBarMoveTarget.Minimum = 1;
trackBarMoveTarget.LargeChange = 100;
trackBarMoveTarget.SmallChange = 1;
There are two problems with using TrackBar at this kind of scale.
First you need to be able to move the track bar left and right, but if the SmallChange and LargeChange properties are too small then you may be making a lot of progress, but it simply doesn't show on the track bar. Try this for a start:
trackBarMoveTarget.Maximum = rangeint;
trackBarMoveTarget.Minimum = 1;
trackBarMoveTarget.LargeChange = rangeint / 50;
trackBarMoveTarget.SmallChange = rangeint / 200;
The other problem is that the TrackBar control tries to render helpful little tick marks along its length. By default the TickFrequency is 1 and the Maximum value is 10. When You set Maximum to 162899100 without changing TickFrequency then the poor TrackBar control has to try and render 162899100 tick marks and that takes a long time. Try this:
trackBarMoveTarget.TickFrequency = rangeint / 100;
Be realistic - the trackbar only has a resolution down to 1 pixel - most displays are, at the most 1920 pixels wide. Therefore the resolution only has to be 1920 - let's round it up to 2000.
Now you have a 5 year period = 5 * 365 + 1 (for the odd leap year) = 1826. This is almost equal to our original 2000 odd. So let's make it 1826.
So set the Minimum value to 0 and the Maximum to 1826.
When you get the track event you take the first date 01-01-2010 and add the value of the trackbar to it:
var firstDate = new DateTime(2010, 1, 1).Date;
var trackDate = firstDate + TimeSpan.FromDays(trackBar.Value);
easy and quick.
I am writing an application in Visual Studio Express [C#], and I need to display 12 ColorGrids [128 x 128] at the same time, in realtime.
This is how I setup my chart:
tChart1.Aspect.View3D = false;
tChart1.Aspect.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed;
tChart1.Legend.Visible = false;
tChart1.Axes.Bottom.Title.Text = "R";
tChart1.Axes.Bottom.SetMinMax(0, 127);
tChart1.Axes.Bottom.Increment = 20;
tChart1.Axes.Left.Title.Text = "D";
tChart1.Axes.Left.SetMinMax(0, 127);
And then I init the ColorGrid like this:
for (int d = 0; d < 128; d++)
{
for (int r = 0; r < 128; r++)
{
ColorGrid.Add(r, 0, d);
}
}
And then, in realtime, all I do is I update the YValues in some for-loop which covers the complete 128 x 128 range:
ColorGrid.YValues[index] = value;
And after the for loop, I call:
ColorGrid.BeginUpdate();
ColorGrid.EndUpdate();
I currently have this for 12 TChart controls, which are displayed together on a Form.
I also tried combining the 12 charts into one big chart, by plotting 12 graphs as a 6 x 2 "sub-plot" graph, and that only made a small performance difference.
Is there a way to get 10+fps with:
either 12 separate [128 x 128] graphs, or one [128*6 x 128*2] graph???
If I have left anything unclear, please let me know :-)
Thank you
JD
To improve the ColorGrid drawing time is a feature request already present in Steema's wish list (TF02016286).
Also note that, in general, as more points and elements of the chart to be drawn (grid lines, gradients, etc) more time is needed to draw the chart. So I'm not sure if it can be improved to the point you require.
A tip I don't see implemented in your example is to hide the ColorGrid Pen. This improves a bit the performance:
ColorGrid.Pen.Visible = false;
Also note ColorGrid.BeginUpdate() and ColorGrid.EndUpdate() are thought to be called before and after Clearing and repopulating the series respectively, not both together and after modifying the series values.