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.
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 having the most crazy issue ever I have one tabcontrol where I add a tabpage then create a datagridview filling it with a query as datasource and make some visual changes on it and then make the same thing for another tabpage.
I run the code and somehow I get the data I want showing in the gridviews everything fine except the visual changes in the second one. I go debugging and end up finding out that the visual changes aren't happening because technically the query return the second datagridview gets as datasource is = {} so it has no rows to make visual changes on. but the data is showing on the datagridview anyway.
I tried changing the order of the datagridviews and it was the very same issue, so I think it's something about the order the code is but I don't understand what nor where exactly.
I'm working on Visual Studio 2012 in C#, accessing the data of a Access 2010 file. And here is the code in question:
///Tabela por calibrar
DataTable tabelaEqui = null;
tabelaEqui = calibracaoBL.planoCalibracaoAtualCalibradosServico(DateTime.Now.Year, servico);
DataGridView gridPorCalibrar = new DataGridView();
gridPorCalibrar.DataSource = tabelaEqui;
tabControl1.TabPages.Add(cbServico.Text + " - Por Calibrar");
tabControl1.TabPages[0].Controls.Add(gridPorCalibrar);
gridPorCalibrar.Dock = DockStyle.Fill;
gridPorCalibrar.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.DisplayedCells;
gridPorCalibrar.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.DisplayedCells;
for (int i = 0; i < gridPorCalibrar.Rows.Count - 1; i++)
{
for (int j = 5; j < gridPorCalibrar.Rows[i].Cells.Count; j++)
{
string s = gridPorCalibrar.Rows[i].Cells[j].Value.ToString();
Boolean b = !s.Equals("");
if (b)
{
gridPorCalibrar.Rows[i].Cells[j].Style.BackColor = Color.Green;
}
}
}
mudarCabeçalho(gridPorCalibrar);
///Tabela Calibrados
DataTable dt = null;
dt = calibracaoBL.planoCalibracaoAnosAnterioresServico(DateTime.Now.Year, servico);
DataGridView gridCalibrados = new DataGridView(); // here I got check and dt = {}
gridCalibrados.DataSource = dt;
tabControl1.TabPages.Add(cbServico.Text + " - Calibrados");
tabControl1.TabPages[1].Controls.Add(gridCalibrados);
gridCalibrados.Dock = DockStyle.Fill;
gridCalibrados.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.DisplayedCells;
gridCalibrados.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.DisplayedCells;
for (int i = 0; i < gridCalibrados.Rows.Count - 1; i++)
{
for (int j = 5; j < gridCalibrados.Rows[i].Cells.Count; j++)
{
string s = gridCalibrados.Rows[i].Cells[j].Value.ToString();
Boolean b = !s.Equals("");
if (b)
{
gridCalibrados.Rows[i].Cells[j].Style.BackColor = Color.Green;
}
}
}
mudarCabeçalho(gridCalibrados);
Here is the first one:
Here is the second one:
UPDATE in response to #varocarbas :
I'm checking the datasource is blank in two points.
Point one:
dt = calibracaoBL.planoCalibracaoAnosAnterioresServico(DateTime.Now.Year, servico); // that method that runs a query returns {}. But the query itself is not the issue since it works just fine, it's working perfectly when I try it elsewhere.
Point two:
DataTable dt = null;
dt = calibracaoBL.planoCalibracaoAnosAnterioresServico(DateTime.Now.Year, servico);
DataGridView gridCalibrados = new DataGridView(); // here I go check the dt variable and shows dt={}
The code goes into the for (int i = 0; i < gridCalibrados.Rows.Count - 1; i++) but since gridCalibrados.Rows.Count = 0 it skips the loop.
Here is the method mudarCabeçalho
public void mudarCabeçalho(DataGridView grid)
{
for (int i = 5; i < grid.ColumnCount; i++)
{
string[] s = grid.Columns[i].HeaderText.Split('-');
switch (s[1])
{
case "01":
grid.Columns[i].HeaderText = "Jan";
break;
case "02":
grid.Columns[i].HeaderText = "Fev";
break;
case "03":
grid.Columns[i].HeaderText = "Mar";
break;
case "04":
grid.Columns[i].HeaderText = "Abr";
break;
case "05":
grid.Columns[i].HeaderText = "Mai";
break;
case "06":
grid.Columns[i].HeaderText = "Jum";
break;
case "07":
grid.Columns[i].HeaderText = "Jul";
break;
case "08":
grid.Columns[i].HeaderText = "Ago";
break;
case "09":
grid.Columns[i].HeaderText = "Set";
break;
case "10":
grid.Columns[i].HeaderText = "Out";
break;
case "11":
grid.Columns[i].HeaderText = "Nov";
break;
case "12":
grid.Columns[i].HeaderText = "Dez";
break;
}
}
}
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!
I am working on creating a couple of charts and I cannot figure out why there is so much empty space on the left and right side of the chart. I have a Winforms Chart, ChartArea, and Series and there is always a good inch to the left and right side of the chart that seems like wasted space. What setting do I need to change to reduce the size of this empty space? I have included a screenshot of the chart with empty space with this post as well as the code that I use to create it. Thanks in advance.
if (listBoxCharts.SelectedItems.Count == 1)
{
switch (listBoxCharts.SelectedItem.ToString().Trim())
{
case "Incomplete Work Orders By Status":
ChartArea chartArea = new ChartArea();
Series series = new Series();
Title title = new Title();
chartArea.Area3DStyle.Enable3D = true;
chartArea.Area3DStyle.LightStyle = LightStyle.Realistic;
chartArea.Area3DStyle.Rotation = 10;
chartArea.Area3DStyle.WallWidth = 3;
chartArea.BorderColor = Color.Transparent;
chartArea.Name = "IncompleteWorkOrdersByStatus_ChartArea";
// Fix this hack
ChartContainer.ChartAreas.Clear();
this.ChartContainer.ChartAreas.Add(chartArea);
this.ChartContainer.Dock = DockStyle.Fill;
this.ChartContainer.Location = new Point(2, 21);
this.ChartContainer.Name = "Charts";
this.ChartContainer.PaletteCustomColors = new Color[] { Color.LemonChiffon };
series.ChartArea = "IncompleteWorkOrdersByStatus_ChartArea";
series.ChartType = SeriesChartType.StackedColumn;
series.CustomProperties = "DrawingStyle=Cylinder";
series.EmptyPointStyle.BorderDashStyle = ChartDashStyle.NotSet;
series.IsXValueIndexed = true;
series.Name = "IncompleteWorkOrdersByStatus_Series";
List<WorkOrder> incompleteWorkOrders = woDao.getIncompleteWorkOrders();
var uniqueStatuses = (
from statuses in incompleteWorkOrders
select statuses.fkOrderStatus).Distinct().ToList();
int xVal = 1;
foreach (var status in uniqueStatuses)
{
var count = (
from wo in incompleteWorkOrders
where wo.fkOrderStatus == status
select wo).Count();
DataPoint dPoint = new DataPoint(xVal, count);
if (status == null)
{
dPoint.AxisLabel = "No Status";
}
else
{
dPoint.AxisLabel = status.codedesc;
}
dPoint.ToolTip = count + " " + dPoint.AxisLabel;
series.Points.Add(dPoint);
xVal++;
}
this.ChartContainer.Series.Clear();
this.ChartContainer.Series.Add(series);
title.DockedToChartArea = "IncompleteWorkOrdersByStatus_ChartArea";
title.IsDockedInsideChartArea = false;
title.Name = "IncompleteWorkOrdersByStatus_Title";
title.Text = "Incomplete Work Orders By Status";
this.ChartContainer.Titles.Clear();
this.ChartContainer.Titles.Add(title);
break;
default:
break;
}
}
Try playing with the InnerPlotPosition settings:
chart1.ChartAreas[0].InnerPlotPosition.X = 0;
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);
}
}
}