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!
Related
I'm trying to set a rangbar chart in devexpress to show the task's range time.
rangeBarChart.Series.Clear();
Series series = new Series("S1", ViewType.RangeBar);
series.ValueScaleType = ScaleType.DateTime;
DateTime stime = Convert.ToDateTime("2019-08-29 8:00");
DateTime etime = Convert.ToDateTime("2019-08-29 12:00");
SeriesPoint point = new SeriesPoint("task1", stime, etime);
series.Points.Add(point);
rangeBarChart.Series.Add(series);
((XYDiagram)rangeBarChart.Diagram).Rotated = true;
DateTime rangestime = Convert.ToDateTime("2019-08-29 8:00");
DateTime rangeetime = Convert.ToDateTime("2019-08-29 18:00");
((XYDiagram)rangeBarChart.Diagram).AxisY.VisualRange.Auto = false;
((XYDiagram)rangeBarChart.Diagram).AxisY.VisualRange.SetMinMaxValues(rangestime, rangeetime);
I want the AxisY ranges from 8:00 - 18:00 although the point range from 8:00 to 12:00.
However, the code runs like this
How can I make an axis range bigger than value's range
To specify the overall range of Series associated with the axis you should use the WholeRange property instead of the VisualRange:
((XYDiagram)rangeBarChart.Diagram).AxisY.WholeRange.Auto = false;
((XYDiagram)rangeBarChart.Diagram).AxisY.WholeRange.AutoSideMargins = false;
((XYDiagram)rangeBarChart.Diagram).AxisY.WholeRange.SetMinMaxValues(rangestime, rangeetime);
Take a look at the Visual Ranges and Whole Ranges article for details.
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 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 use Microsoft.DataVisualization.Charting and want to get the value of the point when i click on it.
My problem: i want exactly that value i clicked, even if its only a value calculated by the Chart and between 2 points.
Example: 3 points: P(0;3), P(1;6), P(3;12)
When i click at x-Value 2 i want to get 9 as result if the line is linear.
Currently i do that:
HitTestResult[] hits = chart.HitTest(e.X, e.Y, false, ChartElementType.PlottingArea);
//DataInformation save the DateTime and Value for later use
DataInformation[] dinfo = new DataInformation[hits.Length];
foreach (ChartArea area in chart.ChartAreas)
{
area.CursorX.LineWidth = 0; //clear old lines
}
for (int i = 0; i < hits.Length; i++) //for all hits
{
if (hits[i].ChartElementType == ChartElementType.PlottingArea)
{
//val saves the x-value clicked in the ChartArea
double val = hits[i].ChartArea.AxisX.PixelPositionToValue(e.X);
DataPoint pt = chart.Series[hits[i].ChartArea.Name].Points.Last(elem => elem.XValue < val);
dinfo[i].caption = hits[i].ChartArea.Name;
dinfo[i].value = pt.YValues[0].ToString();
//hits[i].ChartArea.CursorX.Position = pt.XValue;
}
}
This show the right values for every existing data point but not that clicked point.
How can i get the exact value?
It seems, there is no way to get the exact value. I changed to OxyPlot. OxyPlot can show the data much faster and you can get the exact value for any point.
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.