Problem
i've run into an issue where deserializing any value with json.net (even dummy values) seems to mess up the dates along the x-axis of my mschart control. this is a chart that's supposed to have date values along the x-axis:
===bad===
the chart is produced by the following minimal code:
using System.Windows.Forms.DataVisualization.Charting;
using System.Threading;
using Newtonsoft.Json;
public partial class Form1 : Form
{
Thread thread;
public Form1()
{
InitializeComponent();
chart1.Dock = DockStyle.Fill;
thread = new Thread(Plot);
thread.Start();
}
void Plot()
{
// prepare chart
chart1.Invoke((MethodInvoker)delegate
{
chart1.ChartAreas.Clear();
chart1.Series.Clear();
ChartArea area = new ChartArea();
chart1.ChartAreas.Add(area);
Series series = new Series("water level");
series.ChartArea = area.Name;
series.ChartType = SeriesChartType.Line;
chart1.Series.Add(series);
});
// plot line by adding 2 points: ((time)0, 0) and ((time)1, 1)
for (int i = 0; i < 2; i++)
{
object dummy = JsonConvert.DeserializeObject<object>("null");
chart1.Invoke((MethodInvoker)delegate
{
DateTime time = new DateTime(1970, 1, 1, 0, 0, i, DateTimeKind.Utc);
chart1.Series["water level"].Points.AddXY(time, i);
});
}
}
}
commenting out the only json.net line following line results in the expected result:
object dummy = JsonConvert.DeserializeObject<object>("null");
===good===
Question
is there something wrong with my code?
Update
i just replaced the concerned line with
Thread.Sleep(5000);
and the problem still occurs. i thought that maybe i'm modifying the chart too early. but now, i'm not sure what to make of it.
i had a look through the properties of the Series object, and saw that XValueType was set to "Double". so i tried explicitly setting it to "DateTime" when creating it, and that solved the problem:
Series series = new Series("water level");
series.ChartArea = area.Name;
series.XValueType = ChartValueType.DateTime; /* <---- added this line */
series.ChartType = SeriesChartType.Line;
chart1.Series.Add(series);
it is set to "Auto" by default, which appareantly does not always get set to "DateTime". i guess i should have looked at the properties much earlier.
it's still a strange issue to me, and i have no idea what causes it, so this is more of a workaround.
Related
I am currently using WinForms. I have two Lists of Values (doubles) which I visualize with the NuGet package "LiveCharts". Now to my problem: The list of the values constantly changes as new values are added to both lists with a frequency of up 200 values / second. Right now I am doing this with Random Values. In a loop I add a new random value to each list and remove the value with the index 0. Now I want the chart to update everytime a new value is added to the list, but although I call the method which should do that everytime I change the values, the chart only updates after the loop ended.
This method is called by a button and should add 10 new values. This works, but the chart only updates after the for-loop is finished, although the UpdateChart() method is called everytime.
private void ReloadButton_Click(object sender, EventArgs e)
{
for (int i = 0; i < 10; i++)
{
valueList1.RemoveAt(0);
AddRandomValueToList1();
valueList2.RemoveAt(0);
AddRandomValueToList2();
UpdateChart();
}
}
This is the UpdateChart() method I use to update the chart Revenue is a class object and contains a value and a DateTime
private void UpdateChart()
{
series1 = new SeriesCollection();
// series.Clear();
double[] values1 = new double[valueList1.Count];
double[] values2 = new double[valueList2.Count];
int index = 0;
foreach(Revenue current in valueList1)
{
values1[index] = current.value;
index++;
}
index = 0;
foreach (Revenue current in valueList2)
{
values2[index] = current.value;
index++;
}
series1.Add(new LineSeries()
{
Title = "Values1",
Values = new ChartValues<double>(values1)
});
series1.Add(new LineSeries()
{
Title = "Values2",
Values = new ChartValues<double>(values2)
});
cartesianChart1.Series = series1;
}
I have already tried to add breaks (Thread.Sleep) hoping the chart would refresh, but that did not work. As well as the cartesianChart1.Refresh() method which I called in the for-loop. Also did I disable the animations, but still got not the result I was hoping achieve.
Now I do not know what I can do to force the chart to refresh everytime I change the values of the lists in order to create a realtime chart.
I am grateful for every help
Thanks in advance
I have a Xamarin forms application which has an event that runs every second and fetches data from a Characteristic. In this event I create the whole layout, set the data and update the view like this:
public void UpdateDisplay (ICharacteristic c) {
//Lots of irrelevant code above this.
foreach (Accelerometer item in acceloReadings)
{
counter += 1;
//Y-graph data
DataPoint itemPointY = new DataPoint();
itemPointY.X = counter;
itemPointY.Y = item.yAxes;
PointsY.Add(itemPointY);
}
yAs = new PlotModel("Variations Y-Axis");
yAs.PlotType = PlotType.XY;
yAs.Axes.Add(new LinearAxis(AxisPosition.Left, -270, 270));
y = new LineSeries();
//Custom color
y.Color = OxyColor.FromArgb(255, 154, 200, 253);
y.ItemsSource = PointsY;
yAs.Series.Add(y);
opvY = new OxyPlotView
{
WidthRequest = 100,
HeightRequest = 100,
BackgroundColor = Color.Aqua
};
opvY.Model = yAs;
Content = new StackLayout
{
opvY,
}
};
}
That code fills up all the models etc and I then want to update my graphs in the same method. I've tried a few ways:
//After all the data is re-loaded and added I want to refresh my graphs.
xAs.InvalidatePlot(true);
opvX.Model.InvalidatePlot(true);
opvX.InvalidateDisplay();
However none of these have any succes. When you look at the official docs you can see clearly it states:
"To update the plot, you must do one of the following alternatives:
Change the Model property of the PlotView control
Call Invalidate on the PlotView control
Call Invalidate on the PlotModel"
While I've tried all these ways none of them update my graphs/view. When I manually click and resize the graph I can see the data is refreshed. Eventually I want to create the graphs just once in the main method and then update the graphs with the InvalidateDisplay.
So, what am I doing wrong?!
I'm attempting to open a chart in another window form, however the classes used for the data in the chart is in the first form. My goal here is to have a chart be able to open many times in a modeless window.
in form1.cs I build my chart:
Chart chart = new Chart();
Series price = new Series("Price"); //create new series
chart.Series.Add(price);
chart.Series["Price"].ChartType = SeriesChartType.Candlestick;
chart.Series["Price"]["OpenCloseStyle"] = "Candlestick";
chart.Series["Price"]["ShowOpenClose"] = "Both";
chart.Series["Price"]["PriceUpColor"] = "Green"; //Price increase = green
chart.Series["Price"]["PriceDownColor"] = "red"; //price decrease = red
for (int i = 0; i < data.Count; i++)
{
chart.Series["Price"].Points.AddXY(data[i].getDate(), data[i].getHigh()); //Adds date and high value
chart.Series["Price"].Points[i].YValues[1] = System.Convert.ToDouble(data[i].getLow()); //Low value added to chart
chart.Series["Price"].Points[i].YValues[2] = System.Convert.ToDouble(data[i].getOpen()); //open value added to chart
chart.Series["Price"].Points[i].YValues[3] = System.Convert.ToDouble(data[i].getClose()); //close value added to chart
}
Form2.cs:
public void DisplayChart(Chart newChart)
{
chart1 = newChart;
chart1.Show();
}
It is best to make the Chart is a separate class and call or create it from whichever form you need.
This follows object-oriented principles so you can reuse code and also use it for multiple purposes/views.
I am a new gay on WPF and D3.
The value of X axis in my chart is not meaningful(just 1,2,3,....), so I want to hide the value, just keep the ticks.
How can I do this?
Tnx for anyone whose can help.
Know this has been up for a year but I stumbled across the question as I had the same problem. I was looking to remove the x axis as am just plotting Voltage vs time in real time and the time unit isn't important.
Anyway the solution turned out to be simple.
plotter.HorizontalAxis.Remove();
So my setup C# code behind the WPF now looks like this.
public graph()
{
InitializeComponent();
this.DataContext = this;
_voltagePointCollection = new VoltagePointCollection();
var ds = new EnumerableDataSource<VoltagePoint>(_voltagePointCollection);
//ds.SetXMapping(x => dateAxis.ConvertToDouble(x.Date));
ds.SetXMapping(x => x.tick);
ds.SetYMapping(y => y.Voltage);
plotter.AddLineGraph(ds, Colors.Green, 2, "Volts");
MaxVoltage = 1;
MinVoltage = 0;
BackgroundColor = Brushes.White;
YRangeMin = 0;
YRangeMax = 30;
plotter.HorizontalAxis.Remove();
plotter.LegendVisible = false;
}
Hope this helps someone.
Updated the code to give you a better idea of what's happening and to allow the data to load faster.
I have still not seen anything posted online that answers this question.
I have a MS Chart control on a C# application (Visual Studio 2010 Express, if that makes a difference). Data loads at a slow realtime rate (once per second). My intent is to display 6 minutes of data at a time, with the ability to scroll to another page of data if necessary. I want the data to fill the chart from the left hand side. As the data is added to the chart, the scroll bar and X axis legends also move over so that I can only see the latest data point. I have to scroll to the left to see earlier data -- and the the scroll bar jumps back when the new data point is added. I want the scroll bar to stay in one place (left edge) unless I move it. I have a 1 second timer on my form and new data is added with every time cycle.
I hope this is sufficient. Any help?
Code to Initialize the Chart control:
DateTime startTime = DateTime.Now;
DateTime endTime = startTime.AddMinutes(6);
DateTime maxTime = startTime.AddMinutes(24);
// Bind the chart to the list.
chartAssociateProductivity.DataSource = Globals.listKohlsPerformanceDataSource;
chartAssociateProductivity.ChartAreas["ChartArea1"].CursorX.AutoScroll = true; // enable autoscroll
chartAssociateProductivity.ChartAreas["ChartArea1"].CursorX.IsUserEnabled = false;
chartAssociateProductivity.ChartAreas["ChartArea1"].CursorX.IsUserSelectionEnabled = false;
chartAssociateProductivity.ChartAreas["ChartArea1"].AxisX.Minimum = startTime.ToOADate();
chartAssociateProductivity.ChartAreas["ChartArea1"].AxisX.Maximum = endTime.ToOADate();
chartAssociateProductivity.ChartAreas["ChartArea1"].AxisX.ScaleView.Zoomable = true;
chartAssociateProductivity.ChartAreas["ChartArea1"].AxisX.ScrollBar.IsPositionedInside = true;
chartAssociateProductivity.ChartAreas["ChartArea1"].AxisX.ScaleView.Zoom(startTime.ToOADate(), 6, DateTimeIntervalType.Minutes);
chartAssociateProductivity.ChartAreas["ChartArea1"].AxisX.ScaleView.Position = 0;// startTime.ToOADate();
chartAssociateProductivity.ChartAreas["ChartArea1"].AxisX.MinorTickMark.Enabled = true;
// disable zoom-reset button (only scrollbar's arrows are available)
chartAssociateProductivity.ChartAreas["ChartArea1"].AxisX.ScrollBar.ButtonStyle = ScrollBarButtonStyles.SmallScroll;
// set scrollbar small change to blockSize (e.g. 100)
chartAssociateProductivity.ChartAreas["ChartArea1"].AxisX.ScaleView.SmallScrollSize = 100;
Code to Add the Data (for the example, I will add constant data):
private void timer1_Tick(object sender, EventArgs e)
{
listPerformanceDataSource.Add(new PerformanceRecord(0, 248));
}
The data structure:
public class PerformanceRecord
{
int bagCount, goal;
public PerformanceRecord(int bagCount, int goal)
{
this.bagCount = bagCount;
this.goal = goal;
}
public int BagCount
{
get { return bagCount; }
set { bagCount = value; }
}
public int Goal
{
get { return goal; }
set { goal = value; }
}
}
// Create a list.
public static List<PerformanceRecord> listPerformanceDataSource = new List<PerformanceRecord>();
ChartArea chartArea=new ChartArea();
chartArea = chart1.ChartAreas[series.ChartArea];
int scrollBarVal=chartArea.AxisX.ScaleView.Position;
you have to make a chartArea instance and use its axis position