How to show asp.net chart grouped by 2 parameters - asp.net

I want to present some condensed data to the user using the Chart component.
SQL (C# / Oracle):
SELECT c.date, c.approved, count(distinct c.f1) amt_c, count(b.f1) amt_b, sum(b.value) sum_values
FROM contracts c
JOIN bens b ON c.ben_id = b.id
WHERE :YearMonth = to_char(c.date,'YYYYMM') AND NOT c.approved = 'REJECTED'
GROUP BY c.date, c.approved
ORDER BY c.date
I have this SQL in a method that passes a DataSet to the ObjectDataSource in the .aspx page (The approved field can have 3 values: REJECTED, APPROVED and PENDING).
Chart in .aspx page:
<asp:Chart ID="Chart1" runat="server" DataSourceID="RelatorioDataSource"
Width="700px" Compression="10" Palette="Chocolate">
<Series>
<asp:Series Name="Contracts" XValueMember="date"
YValueMembers="amt_c" IsXValueIndexed="False"
XValueType="DateTime" IsValueShownAsLabel="True" BorderDashStyle="DashDot"
CustomProperties="DrawingStyle=Emboss, EmptyPointValue=Zero, DrawSideBySide=True"
YValuesPerPoint="4">
</asp:Series>
<asp:Series BorderDashStyle="DashDot" ChartArea="ChartArea1"
CustomProperties="DrawingStyle=Emboss, EmptyPointValue=Zero, DrawSideBySide=True"
IsValueShownAsLabel="True" Name="Bens"
XValueMember="date" XValueType="DateTime"
YValueMembers="amt_b" YValuesPerPoint="4">
</asp:Series>
</Series>
<ChartAreas>
<asp:ChartArea Name="ChartArea1">
</asp:ChartArea>
</ChartAreas>
</asp:Chart>
I want to show the numbers of approved/pending contracts/bens for each day (4 bars), but the chart shows only two columns.

Solved by creating an object relatorio to hold the returned data (instead of the DataSet), filtering the results using LINQ to Objects, and adding the series programmatically in codeBehind.
var approved = relatorio
.Where(r => r.APPROVED == "APPROVED")
.ToList()
;
var pending = relatorio
.Where(r => r.APPROVED == "PENDING")
.ToList()
;
Creating Legends
Legend legenda = new Legend("Legenda");
legenda.Docking = Docking.Bottom;
legenda.LegendStyle = LegendStyle.Row;
legenda.Alignment = System.Drawing.StringAlignment.Center;
Creating series in a loop
for (int i = 0; i < 4; i++) {
Series temp = new Series {
XAxisType = AxisType.Primary,
XValueType = ChartValueType.DateTime,
YAxisType = AxisType.Primary,
//mostra só a quantidade de contratos
IsValueShownAsLabel = i % 2 == 0 ? true : false,
ChartType = SeriesChartType.Column,
CustomProperties = "EmptyPointValue=Zero",
Legend = "Legenda"
};
grafico.Series.Add(temp);
}
approvedValues.Points.DataBindXY(approved, "DATE", approved, "SUM_VALUES");
DataBinding series
// approved CONTRACTS
grafico.Series[0].Points.DataBindXY(approved, "DATE", approved, "AMT_C");
grafico.Series[0].LegendText = "Contratos approved";
// approved BENS
grafico.Series[1].Points.DataBindXY(approved, "DATE", approved, "AMT_B");
grafico.Series[1].LegendText = "Ben approved";
grafico.Series[1].ChartType = SeriesChartType.Line;
// pending CONTRACTS
grafico.Series[2].Points.DataBindXY(pending, "DATE", pending, "AMT_C");
grafico.Series[2].LegendText = "Contratos pending";
// pending BENS
grafico.Series[3].Points.DataBindXY(pending, "DATE", pending, "AMT_B");
grafico.Series[3].LegendText = "Ben pending";
grafico.Series[3].ChartType = SeriesChartType.Line;

Create a group for each series..
example:
chart1.series[0]["StackedGroupName"] = "group1";

Related

Legend Items appearing n times more than the number of items in Series in ASP.Net Pie Chart using MS Chart Control

I am using MS Chart Control in ASP.Net using VB.Net. The chart type is Pie. I am facing a weird problem where the number of items displayed in the legend is square of the number of Series present. This means if I have 2 series added to the pie chart, 4 items are displayed in legend and if I have 7 series added to the pie chart, 49 items appear in the legend. The 1st set of 7 items displaying the correct data and the others just displaying 0.
Here is the markup of my chart control in ASPX -
<asp:Chart runat="server" ID="chartX" CssClass="chart" Width="420px" Height="500px" ImageType="Jpeg">
<Series></Series>
<ChartAreas>
<asp:ChartArea Name="ChartArea1"></asp:ChartArea>
</ChartAreas>
<Legends>
<asp:Legend Docking="Bottom" Alignment="Center" Font="Calibri"></asp:Legend>
</Legends>
</asp:Chart>
Here is the code to populate chart control in ASPX.vb -
Dim table As DataTable = PopulateData()
Dim dv As DataView = New DataView(table, "Count > 0", "", DataViewRowState.OriginalRows)
For Each r As DataRow In dv.ToTable().Rows
Dim series As String = r("Name").ToString()
chartX.Series.Add(series)
chartX.Series(series).ChartType = DataVisualization.Charting.SeriesChartType.Pie
chartX.Series(series).XValueMember = "Name"
chartX.Series(series).YValueMembers = "Count"
chartX.ChartAreas(0).Area3DStyle.Enable3D = True
chartX.Series(series).Label = "#VALX" & Environment.NewLine & "(#PERCENT)"
chartX.Series(series)("PieLabelStyle") = "Disabled"
Next
chartX.DataSource = dv
chartX.DataBind()
Hoping for any answers.
If I'm not mistaken, you are adding a new series for each row in you table. Instead you should be adding the series once for the table and then binding your data.
You do not need to iterate through all rows when setting up your graph. Do it only once binding to the table. I never touch VB, but it should looks something like this
Dim table As DataTable = PopulateData()
Dim dv As DataView = New DataView(table, "Count > 0", "", DataViewRowState.OriginalRows)
' setup just once
Dim series As String = "Series Name"
chartX.Series.Add(series)
chartX.Series(series).ChartType = DataVisualization.Charting.SeriesChartType.Pie
chartX.Series(series).XValueMember = "Name"
chartX.Series(series).YValueMembers = "Count"
chartX.ChartAreas(0).Area3DStyle.Enable3D = True
chartX.Series(series).Label = "#VALX" & Environment.NewLine & "(#PERCENT)"
chartX.Series(series)("PieLabelStyle") = "Disabled"
' bind to the entire set
chartX.DataSource = dv
chartX.DataBind()

How to create a stacked column chart?

I have following SQL Server Result.
How to create a stacked column chart with asp.net 4 chart control?
Hospital September October April
OMD 10 20 15
IRH 15 16 18
Something like this:
Here is an example:
ASPX:
<asp:Chart ID="chart1" runat="server">
<Series>
<asp:Series Name="Series1" Label="September"></asp:Series>
<asp:Series Name="Series2" Label="October"></asp:Series>
<asp:Series Name="Series3" Label="April"></asp:Series>
</Series>
<ChartAreas>
<asp:ChartArea Name="ChartArea1"></asp:ChartArea>
</ChartAreas>
</asp:Chart>
<asp:Button ID="Button1" runat="server" Text="Graph" onclick="Button1_Click" />
C# Code-Behind:
protected void Button1_Click(object sender, EventArgs e)
{
// September Data
Chart1.Series[0].Points.Add(new DataPoint(0, 10));
Chart1.Series[0].Points.Add(new DataPoint(1, 15));
// October Data
Chart1.Series[1].Points.Add(new DataPoint(0, 20));
Chart1.Series[1].Points.Add(new DataPoint(1, 16));
// April Data
Chart1.Series[2].Points.Add(new DataPoint(0, 15));
Chart1.Series[2].Points.Add(new DataPoint(1, 18));
foreach (Series cs in chart1.Series)
cs.ChartType = SeriesChartType.StackedColumn;
}
Or with SQL Data source ds you can do the following directly:
DataTable dt = new DataTable();
dt = ds.Tables[0];
DataView dv = new DataView(dt);
chart1.DataSource = dv;
chart1.DataBind();
foreach (Series cs in chart1.Series)
cs.ChartType = SeriesChartType.StackedColumn;

Asp.net Chart control multiple series binding

I have got following dataset which is returned by SQL Server:
Group Name Month Total ORDER
Group-India Apr 80
Group-US Apr 70
Group-Europe Apr 60
Group-India May 82
Group-US May 85
Group-Europe May 89
ASP.Net Charts - I need to display this CHART by MONTH (means Apr will be one series and MAY will be separate series) and Y-axis should be GROUPNAME (and show count for it).
Please help
Regards
use DataBindCrossTable
Sample class
public class Sample
{
public string groupName { get; set; }
public string month { get; set; }
public int totalOrder { get; set; }
}
.aspx
<asp:Chart ID="Chart1" runat="server" Width="600px">
<Legends>
<asp:Legend TitleFont="Microsoft Sans Serif, 8pt, style=Bold" BackColor="Transparent" Font="Trebuchet MS, 8.25pt, style=Bold" IsTextAutoFit="False" Enabled="True" Name="Default"></asp:Legend>
</Legends>
<Series>
</Series>
<ChartAreas>
<asp:ChartArea Name="ChartArea1">
</asp:ChartArea>
</ChartAreas>
</asp:Chart>
code behind (.aspx.cs)
var sampleData =
new List<Sample> {
new Sample { month = "apr", groupName = "Group-India", totalOrder = 50 },
new Sample { month = "apr", groupName = "Group-US", totalOrder = 500 },
new Sample { month = "apr", groupName = "Group-Europe", totalOrder = 151 },
new Sample { month = "May", groupName = "Group-India", totalOrder = 15 },
new Sample { month = "May", groupName = "Group-US", totalOrder = 150 },
new Sample { month = "May", groupName = "Group-Europe", totalOrder = 1500}
};
// data bind
Chart1.DataBindCrossTable(sampleData, "groupName", "month", "totalOrder", "Label=totalOrder");
and here's the output
If you don't want to write a class for mapping, then you can directly convert a data table to Enumerable() as follow.
List<DataRow> list = dt.AsEnumerable().ToList();
Something like this
using (con = new SqlConnection(cs))
{
com = new SqlCommand("ERPM_Learnar_Info_By_Gender", con);
com.CommandType = CommandType.StoredProcedure;
adapt = new SqlDataAdapter(com);
dt = new DataTable();
adapt.Fill(dt);
List<DataRow> list = dt.AsEnumerable().ToList();
Chart1.DataBindCrossTable(list, "Gender_Name", "District_Name", "Total", "Label=Total");
and the result is
stored procedure result was this

Place StripeLine On Top of Series (Adjust Z-Index/Z-Order)

I'm building a Column chart with System.Web.UI.DataVisualization.Charting and would like to show a dotted line to represent an average. StripeLine seems to be exactly what I'm looking for except it sits under/behind the columns (see example).
Is there a way to adjust the "Z-Index" of a StripeLine so that it is shown in front of/on top of the Series?
I don't see a property for this and changing the order I add the Series and StripeLine doesn't make a difference.
You can use Annotations
double avg = Chart1.Series[0].Points.Average(p => p.XValue);
double lineHeight = avg;
HorizontalLineAnnotation ann = new HorizontalLineAnnotation();
ann.AxisX = Chart1.ChartAreas[0].AxisX;
ann.AxisY = Chart1.ChartAreas[0].AxisY;
ann.IsSizeAlwaysRelative = false;
ann.AnchorY = lineHeight;
ann.IsInfinitive = true;
ann.ClipToChartArea = Chart1.ChartAreas[0].Name; ann.LineColor = Color.Red; ann.LineWidth = 3;
Chart1.Annotations.Add(ann);
HTML Code
<asp:Chart runat="server" ID="Chart1" ImageStorageMode="UseImageLocation" Width="800px" Height="400px" OnClick="Chart1_Click">
<ChartAreas >
<asp:ChartArea></asp:ChartArea>
</ChartAreas>
<series>
<asp:Series Name="Students" BorderColor="180, 26, 59, 105">
<Points>
<asp:DataPoint AxisLabel="jon" XValue="5" YValues="4" />
<asp:DataPoint AxisLabel="kon" XValue="15" YValues="44" />
<asp:DataPoint AxisLabel="pol" XValue="85" YValues="90" />
</Points>
</asp:Series>
</series>
</asp:Chart>
Code for Text Annotation
TextAnnotation txtAnn = new TextAnnotation();
txtAnn.AxisX = Chart1.ChartAreas[0].AxisX;
txtAnn.AxisY = Chart1.ChartAreas[0].AxisY;
txtAnn.IsSizeAlwaysRelative = false;
txtAnn.AnchorY = lineHeight;
txtAnn.AnchorX = Chart1.Series[0].Points.Last().XValue;
txtAnn.AnchorAlignment = ContentAlignment.BottomLeft;
txtAnn.Text = "DivisionOne(35.5)";
txtAnn.ClipToChartArea = Chart1.ChartAreas[0].Name; txtAnn.ForeColor = Color.Red;
Chart1.Annotations.Add(txtAnn);
You can get more information here
More Information About Annotations
Chart Image
You can just use the text property of the stripeline
Chart1.ChartAreas("ChartArea1").AxisY.StripLines(0).Text = "Line
Title"

ASP Chart Labels to display at the data points on multiple series ASP.NET 4

I have an ASP Chart (v4) which displays the data I need perfectly. I want it to show labels at the top of the data points and I am having some difficulty with it.
Here is my code that works for both series but does not display the labels:
If MySQLReader.HasRows Then
Chart1.DataSource = MySQLReader
Chart1.Series("New Customers Created").XValueMember = "Salesperson"
Chart1.Series("New Customers Created").YValueMembers = "NCC"
Chart1.Series("Target").XValueMember = "Salesperson"
Chart1.Series("Target").YValueMembers = "Target"
Chart1.DataBind()
Chart1.Height = 500
Chart1.Width = 750
Chart1.ChartAreas("ChartArea1").AxisX.MajorGrid.Enabled = False
Chart1.ChartAreas("ChartArea1").AxisY.MajorGrid.Enabled = True
LBLError.Text = ""
Else
Chart1.Visible = False
LBLError.Text = "<div class='error'>Your search did not match any records in the database. Please try again</div>"
End If
MySQLReader.Close()
MyConn.Close()
Now here is my updated code that displays the Labels but only for one series.
If MySQLReader.HasRows Then
Chart1.Series("New Customers Created").Points.DataBind(MySQLReader, "Salesperson", "NCC", "Label=NCC")
Chart1.Series("Target").Points.DataBind(MySQLReader, "Salesperson", "Target", "Label=Target")
Chart1.Height = 500
Chart1.Width = 750
Chart1.ChartAreas("ChartArea1").AxisX.MajorGrid.Enabled = False
Chart1.ChartAreas("ChartArea1").AxisY.MajorGrid.Enabled = True
Chart1.Series("New Customers Created")("LabelStyle") = "Bottom"
Chart1.Series("New Customers Created").Font = New Drawing.Font("Arial", 8)
LBLError.Text = ""
Else
Chart1.Visible = False
LBLError.Text = "<div class='error'>Your search did not match any records in the database. Please try again</div>"
End If
MySQLReader.Close()
MyConn.Close()
So my question is, please can you help me display both series in the updated code with labels for each series? Thanks!
OK, I figured it out.
using the first batch of code is fine. Adding the following IsValueShownAsLabel="True" shows the labels:
<asp:Series Name="New Customers Created" Legend="New Cust" IsValueShownAsLabel="True">
</asp:Series>
<asp:Series Name="Target" Legend="New Cust" IsValueShownAsLabel="True">
</asp:Series>

Resources