Look at this picture from my web application ASP.NET 4.0.
As you can se the lines have a different length. Also there is duplicate x axis entry.
The blue serie has a missing datapoint, the yellow does not.
Question 1:
How do I align them so the x- axis stays the same. Currently im doing this. And make the lines equally long?
Question 2: Is there a way to make the chart interactive so that you can some and hold the cursor on the line to see data from that point, using ASP.NET?
int amountofrows = Convert.ToInt32(dt.Rows[0]["antal"].ToString());
for (int i = 0; i < amountofrows; i++)
{
List<string> xvals = new List<string>();
List<decimal> yvals = new List<decimal>();
string serieName = dt.Rows[i]["doman_namn"].ToString();
Chart1.Series.Add(serieName);
Chart1.Series[i].ChartType = SeriesChartType.Line;
foreach (DataRow dr in dt.Rows)
{
try
{
if (String.Equals(serieName, dr["doman_namn"].ToString(), StringComparison.Ordinal))
{
xvals.Add(dr["ranking_date"].ToString());
yvals.Add(Convert.ToDecimal(dr["ranking_position"].ToString()));
}
}
catch (Exception)
{
throw new InvalidOperationException("Diagrammet kunde inte ritas upp");
}
}
try
{
Chart1.Series[serieName].XValueType = ChartValueType.String;
Chart1.Series[serieName].YValueType = ChartValueType.Auto;
Chart1.Series[serieName].Points.DataBindXY(xvals.ToArray(), yvals.ToArray());
Chart1.DataManipulator.InsertEmptyPoints(1, IntervalType.Days, serieName);
}
catch (Exception ex)
{
throw new InvalidOperationException(ex.Message);
}
}
Chart1.DataBind();
Chart1.Visible = true;
This was the answer!
Thanks for pointing that out JBL!
foreach (System.Web.UI.DataVisualization.Charting.Series serien in Chart1.Series)
{
foreach(System.Web.UI.DataVisualization.Charting.DataPoint dataPoint in serien.Points)
{
if (dataPoint.YValues[0] == 0)
{
dataPoint.IsEmpty = true;
}
}
serien.Sort(PointSortOrder.Ascending,sortBy:("X"));
}
Related
What i am trying to do here is loop a bunch of .csv files split the data, and then put the data in a listview, this is all working fine:
private void BtnRun_Click(object sender, EventArgs e)
{
try {
RunExtraction();
listViewMain.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
} catch (Exception ex) {
Helpers.DebugLogging("[" + DateTime.Now + "]-[" + ex.ToString() + "]");
}
}
private void ProcessCsvFile(string CsvLocation, string CsvFile) {
try {
string[] lines = File.ReadAllLines(#"backlinks\data.txt");
string[] hosts_list = new string[lines.Length];
for (int i = 0; i < lines.Length; i++)
{
hosts_list[i] = (lines[i].Split('|')[0]);
}
using (var reader = new StreamReader(CsvLocation))
{
while(reader.Peek() != -1) {
string line = reader.ReadLine();
List<string> lineValues = line.Split(',').ToList();
if (!lineValues[0].StartsWith("Time")) {
ListViewItem lv = new ListViewItem(lineValues[0].Replace(#"""", " "));
lv.SubItems.Add(lineValues[1].Replace(#"""", " "));
lv.SubItems.Add(lineValues[2]);
listViewMain.Items.Add(lv);
}
}
countToolStrip.Text = listViewMain.Items.Count.ToString() + " extracted ...";
}
} catch (Exception ex) {
Helpers.DebugLogging("[" + DateTime.Now + "]-[" + ex.ToString() + "]");
}
}
What i don't know how to do is alternate the colour between say green and pink for example, like this in the listview:
csv data = green
csv data = pink
csv data = green
csv data = pink
etc
In the listview, i don't need every row alternate, but every csv file block of information imported, they are different sizes in length, I cannot think of a way to do it, any help would be appreciated.
Since you haven't shared some parts of your code, I assume RunExtraction is calling ProcessCsvFile in a loop over csv files. Just add a new argument color to ProcessCsvFile. In RunExtraction, alternate it before calling ProcessCsvFile. Pseudocode below:
RunExtraction()
{
var colors = new List<Color>() { Colors.Green, Colors.Pink }; // add more if you want
var colorIndex = 0;
var csvLocation = "<some-path>";
foreach (var csvFile in csvFiles) {
var color = colors[colorIndex % colors.Count]; // allows you use more than two colors to alternate
ProcessCsvFile(csvLocation, color); // CsvFile is not used, so it is removed
colorIndex++;
}
}
You may just use a simple counter inside the loop and check if it's even/odd
var counter = 1;
while (/* ... */)
{
// ...
if (counter%2 == 0) lv.ForeColor = Color.Green;
// ...
counter++;
}
You can loop through GridView using DataGridViewRow and check if the row is even then Green else Pink for odd rows. Just like this:
foreach (DataGridViewRow row in GridView1.Rows)
if (row.Index % 2==0 )
{
row.DefaultCellStyle.BackColor = Color.Green;
}
else{
row.DefaultCellStyle.BackColor = Color.Pink;
}
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 have data in the form shown below. I want to display the data in such a way that time (the "No column name" column in the figure) should be along the Y-axis and testiD and queryId in the X-axis. I need it in such a way that items with same testId should be grouped (in the X-axis) and the corresponding time should be displayed (Y-axis)
here is the code I use, it does not work as I expected.
protected internal Chart GenerateChart(DataTable dtChartDataSource,Chart chart,int intType )
{
ChartArea chartArea = new ChartArea() { Name = "ChartArea" };
chart.ChartAreas.Add(chartArea);
chart.Palette = ChartColorPalette.BrightPastel;
string series = string.Empty;
if (dtChartDataSource != null)
{
foreach (DataColumn dc in dtChartDataSource.Columns)
{
if (chart.Series.FindByName(dc.ColumnName) == null)
{
series = dc.ColumnName[1].ToString();
chart.Series.Add(series);
chart.Series[series].ChartType = (SeriesChartType)intType;
}
foreach (DataRow dr in dtChartDataSource.Rows)
{
double dataPoint = 0;
double.TryParse(dr[dc.ColumnName].ToString(), out dataPoint);
DataPoint objDataPoint = new DataPoint() { AxisLabel = "series", YValues = new double[] { dataPoint } };
chart.Series[series].Points.Add(dataPoint);
}
}
}
return chart;
}
I could get my requirement done by below code.
public Chart fnTestChart(Chart chart, DataTable dt)
{
DataTable dtUniqueCols = dt.DefaultView.ToTable(true, "Test ID");
chart.ChartAreas.Add("area");
chart.ChartAreas["area"].AxisX.Minimum = 0;
//chart.ChartAreas["area"].AxisX.Interval = 1;
chart.ChartAreas["area"].AxisY.Minimum = 0;
//chart.ChartAreas["area"].AxisY.Interval = 1;
foreach (DataRow dr in dtUniqueCols.Rows)
{
chart.Series.Add(dr[0].ToString());
}
foreach (DataRow dr in dt.Rows)
{
chart.Series[dr[0].ToString()].Points.AddXY(dr[1].ToString(), dr[2].ToString());
}
return chart;
}
You can use many different libraries, to achieve this goal.
Ex: (Visblox)
http://csharp-source.net/open-source/charting-and-reporting
I have the following data in sql that needs to be represented in Stacked Column chart.
Name Type Amount
Paul T1 100
John T2 200
John T3 300
The name represents the X-axis and the Type as Series. The issue I am facing is duplicate X-axis value with the same name. This is the code example I was following before getting the duplicate Name but now doesn't make sense.
SectionData data = GetSectionData(sectionId);
List<double[]> yValues= new List<double[]>();
if (data != null && data.LineItems.Count() > 0)
{
List<string> xValues = new List<string>();
List<string> typeNames = new List<string>();
int index=0;
foreach (var yval in data.LineItems)
{
xValues.Add(yval.Name);
typeNames.Add(yval.TypeName);
double[] temp = new double[data.LineItems.Count()];
temp.SetValue(yval.Amont, index);
yValues.Add(temp);
index++;
}
foreach (string name in typeNames)
{
StackedColumnChart.Series.Add(
new Series
{
Name = name,
ChartType = SeriesChartType.StackedColumn,
Font= new Font("Segoe UI", 8),
CustomProperties="DrawingStyle=Cylinder",
Legend = "Default"
}
);
}
for (int counter = 0; counter < typeNames.Count; counter++)
{
try
{
StackedColumnChart.Series[counter].Points.DataBindXY(xValues, yValues.Select(i => i[counter]).ToList());
}
catch (Exception ex)
{
//throw ex
}
}
}
Any help.
I have 2 problems:
I want the names from the datatable but it is showing me in numeric form.
I would like a gap between the two bars but I can't find a way.
Here is the code:
private void InitializeGraph (DataTable poDt)
{
Telerik.Charting.ChartSeries chartseries = new Telerik.Charting.ChartSeries();
try
{
chartseries.Type = Telerik.Charting.ChartSeriesType.Bar;
Telerik.Charting.ChartSeriesItem csItem;
RadChart1.PlotArea.XAxis.AutoScale = true;
RadChart1.PlotArea.XAxis.DataLabelsColumn = "Name";
for (int iRow = 0; iRow < poDt.Rows.Count; iRow++)
{
chartseries = new Telerik.Charting.ChartSeries();
chartseries.Type = Telerik.Charting.ChartSeriesType.Bar;
chartseries.Name = poDt.Rows[iRow]["Name"].ToString().Trim();
csItem = new Telerik.Charting.ChartSeriesItem();
csItem.Name = poDt.Rows[iRow]["Name"].ToString();
csItem.Label.TextBlock.Text = poDt.Rows[iRow]["Value"].ToString();
RadChart1.PlotArea.XAxis.Appearance.TextAppearance.AutoTextWrap = Telerik.Charting.Styles.AutoTextWrap.True;
csItem.YValue = Int32.Parse(poDt.Rows[iRow]["Value"].ToString());
chartseries.AddItem(csItem);
RadChart1.Series.Add(chartseries);
}
RadChart1.PlotArea.XAxis.AddRange(1, poDt.Rows.Count, 1);
RadChart1.PlotArea.XAxis[poDt.Rows.Count].TextBlock.Text = chartseries.Name;
poDt.Rows.Count.ToString();
RadChart1.PlotArea.XAxis.AutoShrink = false;
RadChart1.PlotArea.XAxis.AutoShrink = true;
RadChart1.Series.Add(chartseries);
RadChart1.PlotArea.Appearance.Border.Visible = false;
RadChart1.Appearance.Border.Visible = true;
RadChart1.PlotArea.YAxis.IsLogarithmic = true;
RadChart1.PlotArea.YAxis.AutoScale = true;
RadChart1.PlotArea.YAxis.Appearance.ValueFormat=Telerik.Charting.Styles.ChartValueFormat.Number;
RadChart1.Appearance.BarWidthPercent = 50;
RadChart1.Chart.Appearance.FillStyle.MainColor = System.Drawing.Color.Red;
RadChart1.Chart.Appearance.FillStyle.MainColor = System.Drawing.Color.Transparent;
RadChart1.Legend.Appearance.FillStyle.MainColor = System.Drawing.Color.Transparent;
}
catch (Exception Ex)
{
//throw;
}
finally
{
poDt.Clear();
poDt = null;
chartseries = null;
}
}
Sorry, I do not believe there is a way to display two X-axis at the same time.
My suggestion is you use a CategoricalAxis for your X axis and create a custom bar chart that has a legend which differentiates the two values. I don't have any working samples, however you can use this Telerik Silverlight demo for starters.
Also, switch to RadChartView if you can. Because I would then suggest an easier approach, which is using a Categorical X-Axis and create multiple Y axes. If you go that route, you can do something like this for a DateTimeContinuous (or Categorical) X-axis with multiple Y-axes :
int count = 0;
LineSeries lineSeries = new LineSeries();
lineSeries.CategoryBinding = new PropertyNameDataPointBinding() { PropertyName = "TimeStamp" };
lineSeries.ValueBinding = new PropertyNameDataPointBinding() { PropertyName = "Value" };
lineSeries.VerticalAxis = new LinearAxis()
{
Title = "Title Here"
};
lineSeries.ItemsSource = yourCollection.Values;
//First Y-axis to be placed on the left of X-axis,
//additional Y-axes to be placed on right
if (count > 0 )
{
lineSeries.VerticalAxis.HorizontalLocation = Telerik.Charting.AxisHorizontalLocation.Right;
}
count++;
chartName.Series.Add(lineSeries);
Hope this helps.