OxyPlot how to add Points to DataPoint? - oxyplot

i have a plotmodel with 2 different lineSeries.
In the first lineSeries can be values between 1000 and 10000.
In the second lineSeries are values between 1 and 10.
So when i plot this I can see the first lineSeries very well, but the second one is just at the bottom.
So I defined two different LinearAxis, one for the right and one for the left side.
m.Axes.Add(new LinearAxis { Position = AxisPosition.Left,Minimum = 0, Maximum = maxPointValue1 });
m.Axes.Add(new LinearAxis { Position = AxisPosition.Right, Minimum = 0, Maximum = maxPointValue2 });
Is it possible to bind the first series to the left LinearAxis and the second to the right Axis?
So that the second series is not at the bottom?
Thanks in advance
Michael

Indeed there is my friend.
On your second axis, this case your right, you need to define a key.
var rightAxis = new OxyPlot.Axes.LinearAxis()
{
Key = "secondary",
Position = AxisPosition.Right,
// And then the rest
}
Now when you include a series, you give that the same key
yourLineSeries.XAxisKey = "secondary";
Now when your series is added, it should use your right axis.
Hope this helps!

Related

OxyPlot.Wpf integer axis - no MinimumMajorStep property

I am using OxyPlot.Wpf and have a need for an axis that will only show integer major steps.
OxyPlot.Wpf.Axis does not have a MinimumMajorStep (which OxyPlot.Axis has). Is there a simple way to achieve the required objective?
I found the answer:
OxyPlot.Wpf.Axis has a public member InternalAxis, which is a OxyPlot.Axis so all I had to do is add the following code somewhere appropriate:
axis.InternalAxis.MinimumMajorStep = 1;
I believe I understood your question correctly. You could make use of the MajorStep property of the axis for the purpose.
For example, from Xaml
<oxy:Plot.Axes>
<oxy:LinearAxis Position="Bottom" MajorStep="5" Minimum="0" Maximum="100"/>
</oxy:Plot.Axes>
Or from ViewModel
var yAxis = new LinearAxis
{
Position = AxisPosition.Bottom,
Maximum = 100,
Minimum = 0,
MajorStep = 5
};
You could additionally set MinorStep="5" (same value as MajorStep) if you would like to the Minor Ticks as well.

Make line chart with values and dates

In my app i use ios-charts library (swift alternative of MPAndroidChart).
All i need is to display line chart with dates and values.
Right now i use this function to display chart
func setChart(dataPoints: [String], values: [Double]) {
var dataEntries: [ChartDataEntry] = []
for i in 0..<dataPoints.count {
let dataEntry = ChartDataEntry(value: values[i], xIndex: i)
dataEntries.append(dataEntry)
}
let lineChartDataSet = LineChartDataSet(yVals: dataEntries, label: "Items count")
let lineChartData = LineChartData(xVals: dataPoints, dataSet: lineChartDataSet)
dateChartView.data = lineChartData
}
And this is my data:
xItems = ["27.05", "03.06", "17.07", "19.09", "20.09"] //String
let unitsSold = [25.0, 30.0, 45.0, 60.0, 20.0] //Double
But as you can see - xItems are dates in "dd.mm" format. As they are strings they have same paddings between each other. I want them to be more accurate with real dates. For example 19.09 and 20.09 should be very close. I know that i should match each day with some number in order to accomplish it. But i don't know what to do next - how i can adjust x labels margins?
UPDATE
After small research where i found out that many developers had asked about this feature but nothing happened - for my case i found very interesting alternative to this library in Swift - PNChart. It is easy to use, it solves my problem.
The easiest solution will be to loop through your data and add a ChartDataEntry with a value of 0 and a corresponding label for each missing date.
In response to the question in the comments here is a screenshot from one of my applications where I am filling in date gaps with 0 values:
In my case I wanted the 0 values rather than an averaged line from data point to data point as it clearly indicates there is no data on the days skipped (8/11 for instance).
From #Philipp Jahoda's comments it sounds like you could skip the 0 value entries and just index the data you have to the correct labels.
I modified the MPAndroidChart example program to skip a few data points and this is the result:
As #Philipp Jahoda mentioned in the comments the chart handles missing Entry by just connecting to the next data point. From the code below you can see that I am generating x values (labels) for the entire data set but skipping y values (data points) for index 11 - 29 which is what you want. The only thing remaining would be to handle the x labels as it sounds like you don't want 15, 20, and 25 in my example to show up.
ArrayList<String> xVals = new ArrayList<String>();
for (int i = 0; i < count; i++) {
xVals.add((i) + "");
}
ArrayList<Entry> yVals = new ArrayList<Entry>();
for (int i = 0; i < count; i++) {
if (i > 10 && i < 30) {
continue;
}
float mult = (range + 1);
float val = (float) (Math.random() * mult) + 3;// + (float)
// ((mult *
// 0.1) / 10);
yVals.add(new Entry(val, i));
}
What I did is fully feed the dates for x data even no y data for it, and just not add the data entry for the specific xIndex, then it will not draw the y value for the xIndex to achieve what you want, this is the easiest way since you just write a for loop and continue if you detect no y value there.
I don't suggest use 0 or nan, since if it is a line chart, it will connect the 0 data or bad things will happen for nan. You might want to break the lines, but again ios-charts does not support it yet (I also asked a feature for this), you need to write your own code to break the line, or you can live with connecting the 0 data or just connect to the next valid data.
The down side is it may has performance drop since many xIndex there, but I tried ~1000 and it is acceptable. I already asked for such feature a long time ago, but it took lot of time to think about it.
Here's a function I wrote based on Wingzero's answer (I pass NaNs for the entries in the values array that are empty) :
func populateLineChartView(lineChartView: LineChartView, labels: [String], values: [Float]) {
var dataEntries: [ChartDataEntry] = []
for i in 0..<labels.count {
if !values[i].isNaN {
let dataEntry = ChartDataEntry(value: Double(values[i]), xIndex: i)
dataEntries.append(dataEntry)
}
}
let lineChartDataSet = LineChartDataSet(yVals: dataEntries, label: "Label")
let lineChartData = LineChartData(xVals: labels, dataSet: lineChartDataSet)
lineChartView.data = lineChartData
}
The solution which worked for me is splitting Linedataset into 2 Linedatasets. First would hold yvals till empty space and second after emptyspace.
//create 2 LineDataSets. set1- till empty space set2 after empty space
set1 = new LineDataSet(yVals1, "DataSet 1");
set2= new LineDataSet(yVals2,"DataSet 1");
//load datasets into datasets array
ArrayList<ILineDataSet> dataSets = new ArrayList<ILineDataSet>();
dataSets.add(set1);
dataSets.add(set2);
//create a data object with the datasets
LineData data = new LineData(xVals, dataSets);
// set data
mChart.setData(data);

How can I make OxyPlot adjust zoom when calling PlotView.Invalidate?

I have a problem with OxyPlot which is as follows:
I create a new PlotView and attach a PlotModel with some axes when my program starts.
In my program, the user can open a file, which is interpreted and plotted in the PlotView control.
To display the new Series, I do
myPlotView.Invalidate(true);
This will display the data on in the plot, however OxyPlot does not perform any zooming. How can I pan and zoom automatically, such that the plot covers the whole PlotView?
I tried to set
myPlotView.Model.Axes[0].DataMinimum = someValue1
myPlotView.Model.Axes[1].DataMinimum = someValue2
myPlotView.Model.Axes[0].DataMaximum = someValue3
myPlotView.Model.Axes[1].DataMaximum = someValue4
but nothing happens.
Axes calculates the ViewMinimum and ViewMaxium (the real thing you are watching) only if Minimum and Maximum are not specified, you can set them to Double.NaN before resetting, so the ViewMinimum and ViewMaximum will be calculated based on DataMinimum and DataMaximum
foreach (var ax in _plotModel.Axes)
ax.Maximum = ax.Minimum = Double.NaN;
PlotView.ResetAllAxes();
Also if you changed the data points, you must call to Plot.InvalidatePlot() so the DataMinimum and DataMaximum gets updated too.
Do a Axis reset and update the Minimum/Maximum of each Axis.
e.g.
PlotView.ActualModel.Axes[0].Reset();
PlotView.ActualModel.Axes[1].Reset();
PlotView.ActualModel.Axes[0].Minimum = 50;
PlotView.ActualModel.Axes[0].Maximum = 250;
PlotView.ActualModel.Axes[1].Minimum = 50;
PlotView.ActualModel.Axes[1].Maximum = 250;
PlotView.InvalidatePlot(true);
you should of course use the min/max value from your data.

How to add a text on top of a column with ZedGraph?

How can I add some text on top of a bar in a chart.
This is the code I have to add the bar:
var color = ColorTranslator.FromHtml(row.Colour);
var barItem = graphPane.AddBar(row.Propensity.ToString(), null, Ys.ToArray(), color);
Thank you
Here is a quick example using TextObj to simply add labels to each bar.
GraphPane myPane = zedGraphControl1.GraphPane;
double[] y = { 100, 50, 75, 125 };
BarItem myBar = myPane.AddBar("Data", null, y, Color.Red);
for (int i = 0; i < myBar.Points.Count; i++)
{
TextObj barLabel = new TextObj(myBar.Points[i].Y.ToString(), myBar.Points[i].X, myBar.Points[i].Y + 5);
barLabel.FontSpec.Border.IsVisible = false;
myPane.GraphObjList.Add(barLabel);
}
myBar.Label.IsVisible = true;
zedGraphControl1.AxisChange();
zedGraphControl1.Invalidate();
Of course this just uses the value of the data as the label. If you wanted to use custom labels, you could create a string array or list and use that inside the loop.
Here are some ZedGraph references:
Introduction and examples: http://www.codeproject.com/KB/graphics/zedgraph.aspx
Source code documentation: http://zedgraph.sourceforge.net/documentation/default.html
You need to define AlignH and AlignV in your text object:
TextObj textLabel = new TextObj(value.ToString(), positionX, value, CoordType.AxisXYScale, AlignH.Center, AlignV.Top);
AlignV define the position of your value on the bar.
Providing you want the label text to match the value of each bar, then you can do it with a single line of code:
BarItem.CreateBarLabels(graphPane, false, "F0");
Note that the 3rd parameter is a double.ToString format. e.g. "F0" = 12, "F2" = 12.34
However, if you want any flexibity with it then this solution is not ideal. It also doesn't work very well if you have a stacked bar chart, because having any 0 value data will cause labels to overlap and look horrific

How can I do a padding between my highest x-value and the plot's right gap in Highcharts?

I need to delete the margins between my lines and plot gap.
I decided to use the startOnTick and endOnTick property but in this case line's points in the gap are not seen or seen only part of them.
Please, help if you know how, of course)))
You can set maxPadding and minPadding within chart options provided to the constructor.
Or you can use setExtremes(min, max) after instantiate the chart for dynamic values.
var myChart = new Highchart.chart(options),
extremes = myChart.xAxis[0].getExtremes(),
minPadding = 20,
maxPadding = 20;
myChart.xAxis[0].setExtremes(extremes.dataMin - minPadding, extremes.dataMax + maxPadding);