I am trying to create a line chart that shows test results over a period of time (interval of weeks). It's the first time I've used the chart control and I seem to keep displaying a grey square if I add points in from a loop:
Like this http://imageshack.us/a/img69/4718/69sq.png
I just can't see where I'm going wrong in my code - if i add some generic points in by hand then it will display properly.
Here is the code I'm using:
chtBreakdown.ChartAreas[0].AxisY.Minimum = 0;
chtBreakdown.ChartAreas[0].AxisY.Maximum = 100;
chtBreakdown.ChartAreas[0].AxisY.Interval = 10;
chtBreakdown.ChartAreas[0].AxisX.IntervalType = DateTimeIntervalType.Weeks;
chtBreakdown.ChartAreas[0].AxisX.Interval = 1;
dtiStart.Value = DateTime.Now.AddMonths(-3);
dtiEnd.Value = DateTime.Now;
chtBreakdown.Series.Clear();
DateTimeOffset minimum = dtiStart.Value;
DateTimeOffset maximum = dtiEnd.Value;
chtBreakdown.ChartAreas[0].AxisX.Minimum = minimum.DateTime.ToOADate();
chtBreakdown.ChartAreas[0].AxisX.Maximum = maximum.DateTime.ToOADate();
foreach (User u in allUsers)
{
List<Training> userTraining = u.TrainingList.Where(t => t.StartTime >= minimum && t.StartTime <= maximum).OrderBy(t => t.EndTime).ToList();
if (userTraining.Count != 0)
{
Series series = new Series(u.DisplayName);
series.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
series.BorderWidth = 2;
series.XValueType = ChartValueType.DateTime;
foreach (Training t in userTraining) series.Points.AddXY(t.StartTime.DateTime, t.PassPercentage);
chtBreakdown.Series.Add(series);
}
}
Can anybody show me where I'm going wrong?
Your Series instances are probably not associated to any ChartArea by default. Try to add this:
series.ChartArea = chtBreakdown.ChartAreas[0].Name;
Related
I have a C# Windows Forms application in which there is a screen designed to show a Graph using the DataVisualization.Charting.Chart class where the X axis are composed of DateTime and the Y Axis are composed of integers (the goal is to represent the memory usage in MB over time of some other processes). So, I want to display this in a format of a Continuous function. But when I set the DataVisualization.Charting.Series object type to SeriesChartType.Line the Form plots the graph in a very strange way, see image below:
and when I set the object series type to SeriesChartType.Point the displayed graph is:
Notice that there are a lot of points that are in blank and that's ok because there aren't any registry of memory usage between those time intervals. The only problem I'm complaining here is that in the Line mode the graph is being plotted in this strange way. The code for the generation of these graphs is:
private void CarregaSerieMemoria()
{
// this InvokeRequired is because it is called in a separeted Thread, the graph creation happens in the Else block
if (this.InvokeRequired)
{
VoidVoidDelegate d = new VoidVoidDelegate(CarregaSerieMemoria);
this.Invoke(d);
}
else
{
try {
// Data table containing the Memory Usage history
foreach (DataRow row in Dados.dsComponentes.Tables["MemoryHistory"].Rows)
{
string proc = row["NomeProcesso"].ToString();
if (!string.IsNullOrEmpty(proc))
{
string dataStr = row["TimeStamp"].ToString();
string memoriaStr = row["Memoria"].ToString();
DateTime data;
int memoria;
try
{
data = DateTime.ParseExact(dataStr, "yyyyMMdd-HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture);
memoria = int.Parse(memoriaStr) / 1000;
}
catch (FormatException)
{
continue;
}
if (TemSerieProc(proc))
{ // if there is already a Series object with proc name
Series s = this.chartMemory.Series.Where(x => x.Name.Equals(proc)).FirstOrDefault();
s.Points.AddXY(data, memoria);
}
else
{ // else creates a new Series object and add this current point (data,memoria)
Series s = DefineNovaSerie(proc);
s.XValueType = ChartValueType.DateTime;
s.Points.AddXY(data, memoria);
this.chartMemory.Series.Add(s);
}
}
}
chartMemory.ChartAreas[0].AxisX.LabelStyle.Format = "dd/MM/yyyy HH:mm:ss";
chartMemory.ChartAreas[0].AxisX.Interval = 30;
chartMemory.ChartAreas[0].AxisX.IntervalType = DateTimeIntervalType.Minutes;
chartMemory.ChartAreas[0].AxisX.IntervalOffset = 1;
chartMemory.ChartAreas[0].AxisX.Minimum = graphDateBegin.ToOADate();
chartMemory.ChartAreas[0].AxisX.Maximum = graphDateEnd.AddHours(24).ToOADate();
chartMemory.ChartAreas[0].AxisX.MajorGrid.LineWidth = 0;
chartMemory.ChartAreas[0].AxisY.MajorGrid.LineWidth = 0;
chartMemory.ChartAreas[0].AxisX.ScaleView.Zoomable = true;
chartMemory.ChartAreas[0].AxisY.ScaleView.Zoomable = true;
chartMemory.ChartAreas[0].AxisX.Title = "Horário";
chartMemory.ChartAreas[0].AxisY.Title = "Memória (MegaBytes)";
chartMemory.MouseWheel += chartMemory_MouseWheel;
chartMemory.MouseClick += chartMemory_MouseClick;
chartMemory.Visible = true;
labelLoad.Visible = false;
btnReload.Visible = true;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
private Series DefineNovaSerie(string proc)
{
Series temp = new Series(proc);
temp.ChartType = SeriesChartType.Line;
//temp.MarkerSize = 10;
temp.Color = GetNextColor(nextColorInt++);
return temp;
}
You populating chart from not ordered data. Your x axis is date so your data should be ordered by date when adding point to chart.
Here is an example (not tested) how you might fix the issue by sorting your data from datatable on TimeStamp field.
var dataTable = Dados.dsComponentes.Tables["MemoryHistory"];
var orderedDataView = new DataView(dataTable);
orderedDataView.Sort = "TimeStamp";
foreach (DataRow row in orderedDataView.ToTable().Rows)
{
//rest of code
}
I'm trying to create this chart using EPPlus:
Area Imports Exports
North America 9.00010837 14.54751448
South America 7.878137347 4.878011063
Europe 32.41924303 39.37317481
Middle East 6.859031587 12.94288951
Africa 7.611513341 2.938054884
Asia 36.23196633 25.32035526
The result should look like:
Here's my code:
dataSheet.Cells["A1"].Value = "Area";
dataSheet.Cells["B1"].Value = "Imports";
dataSheet.Cells["C1"].Value = "Exports";
var row = 2;
foreach (var item in items)
{
dataSheet.Cells["A" + row].Value = item.GeographicalAreaPersianName;
dataSheet.Cells["B" + row].Value = item.ImportsShare;
dataSheet.Cells["C" + row].Value = item.ExportsShare;
row++;
}
var diagram = diagramSheet.Drawings.AddChart("chart", eChartType.ColumnClustered);
for (int i = 2; i <= row; i++)
{
var series = diagram.Series.Add($"'Data'!B{i}:C{i}", $"'Data'!A{i}:A{i}");
}
diagram.Border.Fill.Color = System.Drawing.Color.Green;
Yet what I get is this result:
As you can see series title is not shown correctly and I can't find proper help in EPPlus. How can I correct this?
Let us say that data are stored as demonstrated by the following screenshot:
The following should do the trick:
var diagram = worksheet.Drawings.AddChart("chart", eChartType.ColumnClustered);
for (int i = 2; i <= row; i++)
{
var series = diagram.Series.Add($"B{i}:C{i}", "B1:C1");
series.Header = worksheet.Cells[$"A{i}"].Value.ToString();
}
diagram.Border.Fill.Color = System.Drawing.Color.Green;
The second parameter of Add method stands for title of series {"Imports", "Exports"}
For the Areas, you have to set the header.
Resulting chart looks like: (Actual result of code above):
I'm doing currently some first Windows Phone 8 / XAML experiments and use the WinRTXamlToolkit chart control. While I managed to get my data drawn, I have problems to redraw the control to display changed data.
CHART_Overview.Series.Add(_lsChartOvw);
((AreaSeries)CHART_Overview.Series[0]).ItemsSource = _lstLogOvw;
LinearAxis dta = new LinearAxis();
dta.Title = "X";
dta.Orientation = AxisOrientation.X;
dta.ShowGridLines = true;
CHART_Overview.Axes.Add(dta);
CHART_Overview.Axes.Add(new LinearAxis()
{
Minimum = 0,
Maximum = 100,
Orientation = AxisOrientation.Y,
Interval = 20,
ShowGridLines = true,
Title = "Y"
});
Random rd = new Random((int)DateTime.Now.ToFileTimeUtc());
for(int i = 0; i < 20; i++)
{
_lstLogOvw.Add(new GenericValueItem() { X = i, Y = rd.Next(1, 100) });
}
I tried the following update scheme
_lstLogOvw.Clear();
for (int i = 0; i < 20; i++)
{
_lstLogOvw.Add(new GenericValueItem() { X = i, Y = rd.Next(1, 100) });
}
((AreaSeries)CHART_Overview.Series[0]).ItemsSource = _lstLogOvw;
The list is of type ObservableCollection. It's probably a binding problem but I've not much XAML experience at the moment to fully understand the refresh mechanism.
Don't know the proper way of doing it, but you can get around it by force the ItemSource to be null before assigning back to the actual list.
((AreaSeries)CHART_Overview.Series[0]).ItemsSource = null;
((AreaSeries)CHART_Overview.Series[0]).ItemsSource = _lstLogOvw;
As you can clearly see the XAMDataChart is skipping putting the label on every other column.
I have no clue why this is happening. The code is the same for all of them and I have verified that the data is there.
Here is how they are generated
CategoryXAxis catX = new CategoryXAxis();
NumericYAxis numY = new NumericYAxis();
foreach (var series in control.masterCollection)
{
catX.Name = "catX";
catX.ItemsSource = series;
catX.Label = "{Label}";
catX.Gap = 20;
numY.Name = "numY";
ColumnSeries cs = new ColumnSeries()
{
ItemsSource = series,
ValueMemberPath = "YPoint",
XAxis = catX,
YAxis = numY
};
}
The answer to this question is setting the Category X Axis objects interval to 1.
catX.Interval = 1;
I'm making a chart in C# that is linked to donation data. Each week, the total donations are recorded in the table. The chart pulls those numbers and graphs them in a line graph.
The problem that I'm having is that each week is being recorded as a day of the week, and so controls that should work based on weeks are not working correctly. I attached my code and a picture of the result below.
I want to know why each data point here is being displayed as a day of the week. Is it how I'm loading the data?
Thanks for any help that you can give.
Here's my code:
#region Chart4
string DonationSelect = this.DonationSelect.SelectedValue;
Time = Convert.ToInt32(DonationSelect);
if (Time > 3)
Chart4.Series[0].IsValueShownAsLabel = false;
else
Chart4.Series[0].IsValueShownAsLabel = true;
Chart4.Series[0].ChartType = SeriesChartType.Line;
Chart4.ChartAreas["ChartArea1"].AxisX.IsMarginVisible = true;
StartDate = GetNextDay(DateTime.Today, DayOfWeek.Sunday);
TargetDate = GetNextDay(StartDate.AddMonths(-1 * Time), DayOfWeek.Sunday);
for (DateTime i = TargetDate; i <= DateTime.Now; i = i.AddDays(7))
{
int Donations = 0;
var oDonation = oDatabase.ExecuteScalar(#"SELECT Offering FROM
tblStats WHERE Date=#Date",
"Date", i);
if (oDonation != null && oDonation != DBNull.Value)
{
Donations = Convert.ToInt32(oDonation);
}
//int Attendance = Convert.ToInt32();
string Date = i.ToShortDateString();
Chart4.Series[0].Points.AddXY(Date, Donations);
}
StripLine StripLine = new StripLine();
StripLine.BackColor = Color.LightGray;
StripLine.Interval = 1;
StripLine.IntervalType = DateTimeIntervalType.Weeks;
StripLine.StripWidth = .5;
StripLine.StripWidthType = DateTimeIntervalType.Weeks;
StripLine.IntervalOffset = 0;
StripLine.IntervalOffsetType = DateTimeIntervalType.Days;
Chart4.Legends.Add(new Legend("Legend3"));
Chart4.Series[0].Legend = "Legend3";
Chart4.Series[0].IsVisibleInLegend = true;
Chart4.Series[0].LegendText = "Donations";
Chart4.BorderSkin.SkinStyle = BorderSkinStyle.Emboss;
Chart4.BackColor = Color.PowderBlue;
Chart4.Series[0].BorderWidth = 3;
Chart4.Series[0].BorderColor = Color.Orange;
Chart4.ChartAreas["ChartArea1"].AxisX.Title = "Date";
Chart4.ChartAreas["ChartArea1"].BackColor = Color.LightGray;
Chart4.ChartAreas["ChartArea1"].BackSecondaryColor = Color.White;
Chart4.ChartAreas["ChartArea1"].BackGradientStyle = GradientStyle.TopBottom;
Chart4.ChartAreas["ChartArea1"].AxisX.StripLines.Add(StripLine);
#endregion
According to http://msdn.microsoft.com/en-us/library/system.globalization.calendar.getweekofyear.aspx, you may try to replace these lines :
string Date = i.ToShortDateString();
Chart4.Series[0].Points.AddXY(Date, Donations);
with those :
DateTimeFormatInfo dfi = DateTimeFormatInfo.CurrentInfo;
Calendar cal = dfi.Calendar;
Chart4.Series[0].Points.AddXY(cal.GetWeekOfYear(i, dfi.CalendarWeekRule,
dfi.FirstDayOfWeek), Donations);
Okay, so I fiddled around with it a lot more yesterday, and here was the problem:
string Date = i.ToShortDateString();
Chart4.Series[0].Points.AddXY(Date, Donations);
The issue was that in order for dates to work right, they need to be added to the axis as DateTime variables instead of strings. As such, anything working with weeks simply counted in units of 7 strings.
The correct code is here:
Chart4.Series[0].Points.AddXY(i, Donations);
Thanks for pointing me in the right direction!