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!
Related
I am still new in wpf development. I have a datagrid with 7 columns, days of the week(sunday to saturday). I want to display the days of any month depending on the user's selection on the grid. May someone please help me with this? thank you. At the moment, I have a switch case for all the months in a year and I can get the days in the month, I just need to know how to add the result to the datagrid and for the days to fall on the right day.
this is what I have;
switch (cTvDaySelected)
{
case "January":
var dates = new List<string>();
for (var date = new DateTime(d1.Year, d1.Month, 1); date.Month == d1.Month; date = date.AddDays(1))
{
dates.Add(date.ToLongDateString().Substring(0,2));
//for (int i = 0; i < dates.Count; i++)
//{
// dm.sun = date.ToLongTimeString().Substring(0,2);
//}
}
dm.sun = dates.FirstOrDefault();
MonthModel.Add(dm);
month_record.ItemsSource = MonthModel;
break;
}
DateTime.DaysInMonth function will help you in your situation. Here is similar logic which can help you to get your desire output.
int Year = 2019;
int Month = 2;
int TotalDaysInMonth = DateTime.DaysInMonth(Year, Month);
for (int i = 1; i <= TotalDaysInMonth; i++)
{
DateTime dt = new DateTime(Year, Month, i);
// Insert it into your Model...
}
I have a function that build chart according to selected time range.
The onClick function determinate stored procedure and data source parameters, make makes DataBind() and calls to showChartSum() function
Stored procidure output in case of week range
Need to set d_date as AxisX and the other values as AxisY
Code:
public void showChartSum()
{
DataTable dt_data;
DataView dv_data;
string error_message;
int range_id;
chart_sum.Visible = true;
chart_avg.Visible = false;
range_id = int.Parse(rbl_display02.SelectedValue);
dv_data = (DataView)sds_report.Select(new DataSourceSelectArguments());
dt_data = dv_data.ToTable("DTData", false, "d_date", "tip", "deposit", "compensation", "salary");
if (dt_data.Rows.Count > 0)
{
dt_data = validateMaxChartInput(dt_data);
chart_sum.DataSource = dt_data;
chart_sum.Series["series_tip"].XValueMember = "d_date";
chart_sum.Series["series_tip"].YValueMembers = "tip";
chart_sum.Series["series_deposit"].XValueMember = "d_date";
chart_sum.Series["series_deposit"].YValueMembers = "deposit";
chart_sum.Series["series_compensation"].XValueMember = "d_date";
chart_sum.Series["series_compensation"].YValueMembers = "compensation";
chart_sum.Series["series_compensation"].Color = Color.Red;
chart_sum.Series["series_salary"].XValueMember = "d_date";
chart_sum.Series["series_salary"].YValueMembers = "salary";
chart_sum.Series["series_salary"].Color = Color.SaddleBrown;
//chart_sum.ChartAreas[0].AxisX.Interval = 1;
switch (range_id)
{
case 1:
//chart_sum.ChartAreas[0].AxisX.LabelStyle.Format = "dd/M/yyyy";
chart_sum.ChartAreas[0].AxisY.Interval = 500;
break;
case 2:
//chart_sum.ChartAreas[0].AxisX.LabelStyle.Format = "M/yyyy";
chart_sum.ChartAreas[0].AxisY.Interval = 2000;
break;
case 3:
//chart_sum.ChartAreas[0].AxisX.LabelStyle.Format = "yyyy";
chart_sum.ChartAreas[0].AxisY.Interval = 4000;
break;
}
chart_sum.ChartAreas[0].AxisX.LabelStyle.Angle = 90;
chart_sum.DataBind();
}
else
{
error_message = "הנתונים עבור הטווח הנבחר לא קיימים במערכת";
this.Page.Form.Controls.Add(fn.createCustomMessage(error_message));
pnl_chart.Visible = false;
}
}
The date values are not based on data source, its auto generated according to specified interval.
Chart image
When i comment the interval as sagested by TaW, I get the following output in case of week (fine except of leading and closing labels)
In case of month the labels somehow generated with two weeks interval
Please advise how to display date on chart AxisX as it appear in DataSource and not auto-generated values.
I am creating a WPF application using MVVM. I am wanting to create a basic list of bookings for a certain date that are pulled back from a database, but also include blank spaces in the list (to be displayed in a listbox) to show when there is free time in between bookings, during working hours.
So far I can get blank spaces adding but only for the empty gaps within 2 bookings, whereas I want the spaces to be displayed for every hour from 9:00 until 21:00.
private void CheckForGaps(List<DisplayBookingDetails> list)
{
DateTime endIndex;
DateTime startIndex;
int minBookingLength = 60;
DisplayBookingDetails[] test;
DisplayBookingDetails nullMarker = null;
DateTime dayStart = new DateTime(0001, 01, 01).AddHours(09).AddMinutes(00).AddSeconds(00);
DateTime dayEnd = new DateTime(0001, 01, 01).AddHours(21).AddMinutes(00).AddSeconds(00);
test = list.ToArray();
List<DisplayBookingDetails> testList = new List<DisplayBookingDetails>();
for (int i = 0; i < test.Length; i++)
{
if (i > 0)
{
endIndex = list[i - 1].EndTime;
startIndex = list[i].StartTime;
int diff = ((int)(startIndex - endIndex).TotalMinutes);
testList.Add(test[i - 1]);
while (diff >= minBookingLength)
{
nullMarker = new DisplayBookingDetails(0) { Start = endIndex.ToShortTimeString(), End = endIndex.AddMinutes(60).ToShortTimeString() };
testList.Add(nullMarker);
diff -= minBookingLength;
}
}
}
if (test.Length > 0)
testList.Add(test[test.Length - 1]);
DisplayBookingDetails = testList;
}
The code above goes through the array and if it isn't empty it checks the differences between bookings and adds the null marker row in the list, but I would like this display empty rows even if the date has no bookings at all.
Does anyone know how I could go about adding this functionality, thanks?
I'm not sure why you create test instead of using list, but I have completely altered your code to do exactly what you want.
private void CheckForGaps(List<DisplayBookingDetails> list)
{
DateTime endPrevious;
DateTime startCurrent;
int minBookingLength = 60;
DisplayBookingDetails nullMarker = null;
DateTime selectedDate = [CalendarObject].Value.Date;
DateTime dayStart = selectedDate.AddHours(09)
DateTime dayEnd = selectedDate.AddHours(21)
List<DisplayBookingDetails> testList = new List<DisplayBookingDetails>();
if (list.Length > 0) // First we check if the list has any items
{
DateTime startTime = dayStart;
DateTime endTime = list[0].StartTime;
// Fill the gap before the first appointment with blank appointments
while ((endTime - startTime).TotalMinutes >= minBookingLength)
{
nullMarker = new DisplayBookingDetails(0) { Start = startTime.ToShortTimeString(), End = startTime.AddMinutes(minBookingLength).ToShortTimeString() };
testList.Add(nullMarker);
startTime = startTime.AddMinutes(minBookingLength);
}
// Go through the appointments adding them
for (int i = 1; i < list.Length; i++)
{
testList.Add(list[i - 1]);
endPrevious = list[i - 1].EndTime;
startCurrent = list[i].StartTime;
startTime = endPrevious;
// Fill gaps between appointments
while ((startCurrent - startTime).TotalMinutes >= minBookingLength)
{
nullMarker = new DisplayBookingDetails(0) { Start = startTime.ToShortTimeString(), End = startTime.AddMinutes(minBookingLength).ToShortTimeString() };
testList.Add(nullMarker);
startTime = startTime.AddMinutes(minBookingLength);
}
}
// Add the last appointment
testList.Add(list[list.Length - 1]);
// Add blank appointments after the last appointment until End of Day
startTime = list[list.Length - 1].EndTime;
while ((dayEnd - startTime).TotalMinutes >= minBookingLength)
{
nullMarker = new DisplayBookingDetails(0) { Start = startTime.ToShortTimeString(), End = startTime.AddMinutes(minBookingLength).ToShortTimeString() };
testList.Add(nullMarker);
startTime = startTime.AddMinutes(minBookingLength);
}
}
else // No items in list, add all blank appointments
{
DateTime startTime = dayStart;
while((dayEnd - startTime).TotalMinutes >= minBookingLength)
{
nullMarker = new DisplayBookingDetails(0) { Start = startTime.ToShortTimeString(), End = startTime.AddMinutes(minBookingLength).ToShortTimeString() };
testList.Add(nullMarker);
startTime = startTime.AddMinutes(minBookingLength);
}
}
// Display the final list
DisplayBookingDetails.ItemsSource = testList;
}
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;
I want to make a survey with asp.net and c#.
It is clear that I can do it. But for the results I want to show them in a pie-chart and histogram.
The questions have only two answers "yes" and "no".
In pie-chart the whole percentage of "yes" and percentage of "no" like %55 "yes", %45 "no".
In histogram I want to show each question which is divided into 2 part ("yes" and "no").
In order to do these (pie-chart and the histogram), should I use component like Telerik?
Or can I do this with drawing library in .NET?
You can use Asp.net Chart controls for representing the data in pie charts......and it also depends on databinding.
if you are using datatable to get data from database then asp.net chart controls much better ...
would you pls take a look at this link for more information....
https://web.archive.org/web/20211020111731/https://www.4guysfromrolla.com/articles/120804-1.aspx
EDIT
This is function getting data from database..
public DataTable GetVisits(System.DateTime startdate , System.DateTime enddate)
{
const string sql = #"SELECT CONCAT(UPPER(SUBSTRING(visit_Status, 1, 1)), SUBSTRING(visit_Status FROM 2)) as Status, COUNT('x') AS Visits
FROM visits
WHERE visit_Date BETWEEN #startdate AND #enddate
GROUP BY visit_Status";
return sqlexecution(startdate, enddate, sql);
}
I am representing this data in stackcolumn chart.
if you want to represent in pie chart , you can change in code
public void DrawMembersvisits(Chart targetchartcontrol, DateTime startdate, DateTime enddate)
{
chart1 = targetchartcontrol;
Series series = null;
Title title;
string area = null;
chart1.ChartAreas.Clear();
chart1.Series.Clear();
chart1.Titles.Clear();
DataTable membervisits = null;
area = "Visits";
chart1.ChartAreas.Add(area);
series = chart1.Series.Add(area);
series.ChartArea = area;
title = chart1.Titles.Add("Member Visits");
title.Alignment = ContentAlignment.MiddleCenter;
title.Font = new Font(FontFamily.GenericSansSerif, 10, FontStyle.Regular);
title.DockedToChartArea = area;
chart1.Titles.Add("").DockedToChartArea = area;
foreach (Title titles in chart1.Titles)
{
titles.IsDockedInsideChartArea = false;
}
foreach (ChartArea areas in chart1.ChartAreas)
{
areas.Area3DStyle.Enable3D = true;
areas.AxisX.LabelStyle.IsEndLabelVisible = false; areas.AxisX.LabelStyle.Angle = -90;
areas.AxisX.LabelStyle.IsEndLabelVisible = true;
areas.AxisX.LabelStyle.Enabled = true;
}
foreach (Legend legends in chart1.Legends)
{
legends.Enabled = false;
}
foreach (Series serie in chart1.Series)
{
serie.ChartType = SeriesChartType.StackedColumn;
// change here to get the pie charts
// charttypes.ChartType = SeriesChartType.Pie;
// charttypes["LabelStyle"] = "Outside";
// charttypes["DoughnutRadius"] = "30";
// charttypes["PieDrawingStyle"] = "SoftEdge";
// charttypes.BackGradientStyle = GradientStyle.DiagonalLeft;
serie["LabelStyle"] = "Outside";
serie["ColumnDrawingStyle"] = "SoftEdge";
serie["LabelStyle"] = "Top";
serie.IsValueShownAsLabel = true;
serie.BackGradientStyle = GradientStyle.DiagonalLeft;
}
membervisits = visistsdataf.GetVisits(startdate, enddate);
chart1.Series[0].Points.DataBindXY(membervisits.Rows, "Status", membervisits.Rows, "Visits");
foreach (Series chartSeries in chart1.Series)
{
foreach (DataPoint point in chartSeries.Points)
{
switch (point.AxisLabel)
{
case "Accepted": point.Color = Color.Green; break;
case "Refused": point.Color = Color.Red; break;
}
point.Label = string.Format("{0:0} - {1}", point.YValues[0], point.AxisLabel);
}
}
}