The idea is to simply to plot arrD[i] in a chart called chart5 SeriesA. The issue is that nothing is plotted in the windows form. Maybe someone could help. Many thanks.
chart5 = new Chart();
Series SeriesA = new Series();
Dictionary<int, double> value5 = new Dictionary<int, double>();
for (int i = 0; i < monthCount; i++)
{
value5.Add(i, arrD[i]);
}
SeriesA.XValueMember = "Location";
SeriesA.YValueMembers = "Value";
chart5.DataSource = value5;
chart5.Series.Add("SeriesA");
You do not add the series you created to your chart.
Try this code :
Series SeriesA = new Series();
SeriesA.Points.DataBind(arrD, "Location", "Value", "");
chart5.Series.Add(SeriesA);
Note that we add SeriesA and not "SeriesA"
Ok, I simplified the binding (which works well now) as well as the loop for hiding the zero values. But how to print now the modified chart without zero values .. many thanks.
chart7.Series["Series3"].ChartType = SeriesChartType.Line;
chart7.Series["Series3"].Points.DataBindXY(xVal, arrDouble3);
foreach (Series series in chart7.Series)
{
foreach (DataPoint arrP in series.Points)
{
if (arrP.YValues.Length > 0 && (double)arrP.YValues.GetValue(0) == 0)
{
arrP.IsValueShownAsLabel = false;
}
}
}
chart7.Series["Series3"].Points.DataBindXY(xVal, arrP); ????
Related
I've been trying to to bind a data table adaptor to a Cartesian livecharts line series in c# winform with no luck
I've tried multiple method and none of them worked
Also there is no video on YouTube on how to bind the line series to data table adaptors only to simple data grid view so that data be inserted manually
I have done it with pie chart and I am in desperate need to do the same with line series
Could you help me to solve this problem
Best regards
cartesianChart2.Series.Clear();
SeriesCollection series = new SeriesCollection();
var types= (from o in brake1BindingSource.DataSource as List<Brake1TableAdapter>
select new { Braketype = o.Braketype }).Distinct();
foreach (var type in types)
{
List<double> values = new List<double>();
for (int vin= 1; vin<= 10000; vin++)
{
double value = 0;
var data = from o in brake1BindingSource.DataSource as List<Brake1TableAdapter>
where o.Braketype .Equals(type.Braketype ) && o.Braketype .Equals(vin)
orderby o.VIN ascending
select new { o.filling_amount, o.VIN };
if (data.SingleOrDefault() != null)
value = (double)data.SingleOrDefault().filling_amount;
values.Add(value);
}
series.Add(new LineSeries() { Title = type.Braketype .ToString(), Values = new ChartValues<double>(values) });
}
cartesianChart1.Series = series;
I'm trying to compare a lot of charts using Live Charts according with the numbers of classes inside my List.
I'm trying some like this:
class MyClass
{
IList<double> a;
IList<double> b;
}
And to make a chart:
List<MyClass> aLotOfCharts = new List<MyClass>
for(int i=0; i < aLotOfCharts.Count; i++)
{
SeriesCollection = new SeriesCollection
{
new LineSeries
{
Values = new ChartValues<double> (aLotOfCharts[i].a)
},
};
}
I expect three charts with the "a" Data, but the actual output is only the last position of "aLotOfCharts.a".
I know I need to create more "new LineSeries" to input more charts, but I don't know how I can do this.
I do not know the Live Chart, but I think the answer is something like this:
List<MyClass> aLotOfCharts = new List<MyClass>()
SeriesCollection = new SeriesCollection()
for(int i=0; i < aLotOfCharts.Count; i++)
{
SeriesCollection.Add(new LineSeries
{
Values = new ChartValues<double> (aLotOfCharts[i].a)
});
}
So i'm displaying multiple curves in my chart. However, when i generate a random color, all the other curves will get this color too.
int fileIndex=0;
Random r = new Random();
foreach (var i in graphContainer)
{
fileIndex++;
var series = new Series
{
Name = legendNames[fileIndex],
Color = Color.FromArgb(r.Next(0, 256), r.Next(0, 256), r.Next(0, 256)),
IsVisibleInLegend = true,
IsXValueIndexed = false,
ChartType = SeriesChartType.Line
};
foreach (var j in i)
{
series.Points.AddXY (j.Item2, j.Item1);
}
chart.Invalidate ();
chart.Series.Add (series);
}
Note: all the curves except one has the same values, but you get the idea.
Why is my curves getting the same colors?
Entire function:
private void generateWaveformsFromFileBtn_Click(object sender, EventArgs e)
{
int fileIndex = -1;
string folder = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName) + #"\WaveForms\";
string filter = "*.csv";
string[] filePath = Directory.GetFiles(folder, filter);
List<string> legendNames = new List<string>();
List<Tuple<double, double>> graph = new List<Tuple<double, double>>();
List<List<Tuple<double, double>>> graphContainer = new List<List<Tuple<double, double>>>();
chart.Series.Clear();
foreach(var fileName in filePath) {
legendNames.Add(Path.GetFileName(fileName));
using (TextFieldParser csvParser = new TextFieldParser(fileName))
{
csvParser.SetDelimiters (new string[] { ";" });
csvParser.ReadLine ();
while (!csvParser.EndOfData)
{
string[] fields = csvParser.ReadFields();
double current = Double.Parse(fields[0]);
double inductance = Double.Parse(fields[1]);
graph.Add (new Tuple<double,double>(current, inductance));
}
graphContainer.Add(graph);
}
}
Random r = new Random();
foreach (var i in graphContainer)
{
fileIndex++;
var series = new Series
{
Name = legendNames[fileIndex],
Color = Color.FromArgb(r.Next(0, 256), r.Next(0, 256), r.Next(0, 256)),
IsVisibleInLegend = true,
IsXValueIndexed = false,
ChartType = SeriesChartType.Line
};
foreach (var j in i)
{
series.Points.AddXY (j.Item2, j.Item1);
}
chart.Invalidate ();
chart.Series.Add (series);
}
}
Suggestion: (?)
You have already posted one solution:
Before adding new data in a loop, make sure the old data are deleted. You do it by creating a new instance:
graph = new List<Tuple<double, double>>();
This is a valid approach.
But for completeness' sake let's look at the more direct aproach as well:
graph.Clear();
This clears the data from the list object. But you are adding the graph to the graphContainer list like this:
graphContainer.Add(graph);
which means that the very object gets put into the list which, before the next loop, will be cleared. This is a common mistake. The solution is simple: Don't add the graph object itself into the graphContainer list but a copy of it :
graphContainer.Add(graph.ToList());
The ToList() call is a simple way to create a copy of a List<T>.
As for the post you linked to: The old post is strictly about runtime performance. And not about creating copies of the lists.
But even there, the recommended way to do it is depending on whether you can predict the number of elements you will put in each list.
If you can predict it and if it is somewhat largish, let's say more than a few hundred of large or a many thousands of smallish elements you should tell the list which capacity it should reserve.
This avoids multiple growing pains. After a Clear() the Capacity is retained, avoiding new allocations.
Your elements (Tuples) are small, so you probably don't need to worry about the list growing performance..
As suggested by user #Taw, i forgot to create a new instance of the graph or empty it, between runs.
graph = new List<Tuple<double, double>>(); // <-- solved it
while (!csvParser.EndOfData)
{
string[] fields = csvParser.ReadFields();
...
}
EDIT:
Do not use yourList.Clear() see here why: https://stackoverflow.com/a/35848659/2902996
I have an array of ChartArea area[] and an array of Series series[]
What I need to do is use a different ChartArea for each Series.
This is what is usually done :
Chart Chart0 = new Chart();
ChartArea ChartArea0 = new ChartArea("name");
Chart0.ChartAreas.Add(ChartArea0);
Series Series0 = new Series();
Chart0.Series.Add(Series0);
// link series to area here
Series0.ChartArea = "name";
But in my case, I cannot have a string name for each. It needs to be an array. How can I work around this?
I asked a few clarifying questions in my comment, but if I go off my assumptions of the situation you expressed, here's what I would do:
var sourceStringArray = new string[] { "ChartArea1Name" };
Chart Chart0 = new Chart();
ChartArea ChartArea0 = new ChartArea(sourceStringArray[0]);
Chart0.ChartAreas.Add(ChartArea0);
Series Series0 = new Series();
Chart0.Series.Add(Series0);
// link series to area here
Series0.ChartArea = sourceStringArray[0];
I will edit my answer based on the responses to my comment.
Edit:
Based on your comment:
I need it to be an array as the number of ChartAreas I need is dependant on a variable number of parameters
You would probably want to make a method that does the creation of your ChartArea objects. Something like:
private List<ChartArea> CreateChartAreas(string[] chartAreaNames)
{
var chartAreaInstances = new List<ChartArea>();
foreach (var chartAreaName in chartAreaNames)
{
var tempChart = new Chart();
var tempChartArea = new ChartArea(chartAreaName);
tempChart.ChartAreas.Add(tempChartArea);
var tempSeries = new Series();
tempChart.Series.Add(tempSeries);
tempSeries.ChartArea = chartAreaName;
}
return chartAreaInstances;
}
Then in the main code, do something like:
var sourceStringArray = new string[] { "ChartArea1Name", "ChartArea2Name" };
var chartAreas = CreateChartAreas(sourceStringArray);
foreach (var chartArea in chartAreas)
{
// Do something with your chart area instances.
}
Disclaimer: I haven't tested this code as I don't know what your specific use case is for this.
I have an IEnumerable (List<>) of a particular Type. The Type has a set of properties which I would like to chart as individual series (MVC3/Razor).
Is there a way I can transpose the data in the list of objects into a list of the properties?
e.g.
Given the code below, the end result I am trying to acheive is a set of Series so I have
Bucket1: IEnumerable<Date, Value>
Bucket2: IEnumerable<Date, Value>
etc
So that I can then chart each series to get a line chart with Date on x and value on y, for (in this example) 3 series/lines. This code works perfectly, but just feels wrong somehow?
var buckets = new List<Bucket>(){
new Bucket{
Date=DateTime.Today.AddDays(-3),
Bucket1=1000,
Bucket2=2000,
Bucket3=3000},
new Bucket{
Date=DateTime.Today.AddDays(-2),
Bucket1=1000,
Bucket2=2020,
Bucket3=3300},
new Bucket{
Date=DateTime.Today.AddDays(-1),
Bucket1=1000,
Bucket2=2040,
Bucket3=3600}
};
var chart = new Chart(){ Height = 400, Width = 600 };
var area = new ChartArea();
chart.ChartAreas.Add(area);
var series1 = chart.Series.Add("Bucket 1");
var series2 = chart.Series.Add("Bucket 2");
var series3 = chart.Series.Add("Bucket 3");
foreach (var series in chart.Series)
{
series.ChartType = SeriesChartType.Line;
}
foreach (var item in buckets)
{
series1.Points.AddXY(item.Date, item.Bucket1);
series2.Points.AddXY(item.Date, item.Bucket2);
series3.Points.AddXY(item.Date, item.Bucket3);
}
What about just using a Lambda expression for each serie (code below was not tested - it's just a prototype):
var series1 = buckets.Select(b => new { b.Date, b.Bucket1 });
var series2 = buckets.Select(b => new { b.Date, b.Bucket2 });
Thanks to the comments posted I kept my original code and don't think there's an easier way to do this.