Coreplot editing plotspace - objective-c

I came up with a small problem. Now, I've got a program which plots
graphs. For that I've set up few functions.
First when loaded the graph gets initialized with the plotspace
etc. Then when the user clicks a button, a new plot gets added to the
graph. But with that I have the necessity to change the
plotSpace.xRange and plotsPace.yRange. How can I do so after having
initialized the graph already?
Thanks for your thoughts!

You can change the plot space ranges at any point, not just on creation of the graph. Once you do so, the graph should adjust the displayed axis ranges onscreen. I don't believe you even need to reload the data for a given graph after this.
As an example, the following code should adjust the X range of a plot to be from 0 to 100:
CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)graph.defaultPlotSpace;
[plotSpace setXRange:[CPTPlotRange plotRangeWithLocation:CPTDecimalFromInteger(0) length:CPTDecimalFromInteger(100)]];
where graph is a CPTXYGraph instance, in this case.

Related

How would one draw an arbitrary curve in createJS

I am attempting to write a function using createJS to draw an arbitrary function and I'm having some trouble. I come from a d3 background so I'm having trouble breaking out of the data-binding mentality.
Suppose I have 2 arrays xData = [-10, -9, ... 10] and yData = Gaussian(xData) which is psuedocode for mapping each element of xData to its value on the bell curve. How can I now draw yData as a function of xData?
Thanks
To graph an arbitrary function in CreateJS, you draw lines connecting all the data points you have. Because, well, that's what graphing is!
The easiest way to do this is a for loop going through each of your data points, and calling a lineTo() for each. Because the canvas drawing API starts a line where you last 'left off', you actually don't even need to specify the line start for each line, but you DO have to move the canvas 'pen' to the first point before you start drawing. Something like:
// first make our shape to draw into.
let graph = new createjs.Shape();
let g = graph.graphics
g.beginStroke("#000");
xStart = xData[0];
yStart = yourFunction(xData[0]);
g.moveTo(xStart, yStart);
for( let i = 1; i < xData.length; i++){
nextX = xData[i], but normalized to fit on your graph area;
nextY = yourFunction(xData[i]), but similarly normalized;
g.lineTo(nextX, nextY);
}
This should get a basic version of the function drawing! Note that the line will be pretty jagged if you don't have a lot of data points, and you'll have to treat (normalize) your data to make it fit onto your screen. For instance, if you start at -10 for X, that's off the screen to the left by 10 pixels - and if it only runs from -10 to +10, your entire graph will be squashed into only 20 pixels of width.
I have a codepen showing this approach to graphing here. It's mapped to hit every pixel on the viewport and calculate a Y value for it, though, rather than your case where you have input X values. And FYI, the code for graphing is all inside the 'run' function at the top - everything in the PerlinNoiseMachine class is all about data generation, so you can ignore it for the purposes of this question.
Hope that helps! If you have any specific follow-up questions or code samples, please amend your question.

Core Plot Gallery real time plot design criteria

I few curiosities from the RealTimePlot.m of the CorePlotGallery sample real time plot setup:
// Plot space
CPTXYPlotSpace * plotSpace = (CPTXYPlotSpace *)graph.defaultPlotSpace;
plotSpace.xRange = [CPTPlotRange plotRangeWithLocation:#0.0 length:#(kMaxDataPoints - 2)];
plotSpace.yRange = [CPTPlotRange plotRangeWithLocation:#0.0 length:#1.0];
plotSpace.allowsUserInteraction = YES;
It notes a range of points - kMaxDataPoints, initially 52, which appears to be the visible range of plot points from the initial window/view size.
The delegate newData method trims the earliest point to be added, to maintain this queue but my question is how was this value (52) derived?
Is it possible to calc at run-time this visible range even when the user pinches / zooms?
Wouldn't it better to trim the point(s) afterwards - after adding, when the quantity is known of points added, from the range beginning?
It's a "magic number" derived by saying "that's looks good" rather than any empirical method. Of course you can calculate it based on the size of the plot area. Using a constant is just a shortcut. Because of the design of the app, we know that the graph won't change size on iOS, so it's a reasonable shortcut to make there.
I don't understand the last part of the question.

How can I get and set the position of a draggable legend in matplotlib

I'm trying to get and set the position of a draggable legend in matplotlib. My application consists of an interactive GUI, which has a redraw/plot function that should perform the follow steps:
save the position of the current legend.
clear the current axes and perform various plotting operations, which may or may add labels to their plots.
build a new draggable legend (ax.legend().draggable()) and restore the old position of the legend.
In between these steps the user is free to drag the legend around, and the goal is to persist the legend position when the plots are redrawn.
My first approach was to use oldpos = legend.get_bbox_to_anchor() and legend.set_bbox_to_anchor(oldpos) in steps 1 and 3. However this causes to move the legend completely off the visible area.
Note that I have to use ax.legend() and cannot use fig.legend(lines, labels), since step 2 is completely decoupled, i.e., I don't know anything about lines and labels in step 3. According to answers to the question How to position and align a matplotlib figure legend? there seems to be a difference between these two possibilities regarding axes or figure coordinates. Obviously my problem calls for figure coordinates, but I haven't fully understood how to convert the bbox to a "bbox in figure coordinates".
The even more severe problem I just realized is that apparently legend.get_bbox_to_anchor() always seems to return the same values irrespective of the drag position. So maybe the anchor can only be (ab-)used to manipulate the position of static legends? Is there another/proper way to save and restore the position of a draggable legend?
By looking at the implementation of Legend I found out that there is an undocumented property _loc, which exactly does what I want. My solution now looks astonishingly simple:
oldLegPos = ax.get_legend()._loc
# perform all plotting operations...
legend = ax.legend().draggable()
legend._loc = oldLegPos
It looks like _loc automatically stores figure coordinates, since I do not have to convert the coordinates in any way (eg. when the plotting operations completely change the axes ranges/coordinates).

core plot datasource - issue

I have a question for optimize a core plot graph, if I want to plot the function y=8*sin(x) I use a parse and I get the value of a range (for example -5,+5), after calculate it I plot the graph.
If I drag up or down the plot some value are covered, so they are unnecessary and I can remove it, after this add some point on visible range for have a better line.
Now I have a datasource of more interval, 3 array with the y value of this interval: -5,-2 one of 0,3 and one 4,5 (this number are for example). How can I plot this line on my plot View, I need to add some code like this:
CPTScatterPlot *xSquaredPlot = [[CPTScatterPlot alloc] initWithFrame:graph.defaultPlotSpace.accessibilityFrame];
xSquaredPlot.identifier = #"Grafico";
xSquaredPlot.interpolation = CPTScatterPlotInterpolationLinear;
xSquaredPlot.delegate = self;
CPTMutableLineStyle *lineStyleFunc = [CPTMutableLineStyle lineStyle];
lineStyleFunc.lineWidth = 1.0f;
lineStyleFunc.lineColor = [CPTColor redColor];
xSquaredPlot.dataLineStyle = lineStyleFunc;
xSquaredPlot.dataSource = self;
[graph addPlot:xSquaredPlot];
but the problem i that I don't know how line I have, I need to create it dynamically, how can I do it? adding this code when I create the arrays of new interval? but when I need to update datasource?
Core Plot will skip drawing points that fall outside the visible plot area when it can, so you don't have to worry too much about doing that in your datasource. You don't want to be adding and removing a lot of data points as the user scrolls around—that will just cause more work for the plotting code and slow it down.
Since you are plotting a function, one thing you can do is only generate data points in a fairly small range, say just slightly outside the visible x-range. Use a plot space delegate to monitor changes and add points as needed when the user scrolls or zooms the graph.
Use the -insertDataAtIndex:numberOfRecords: method to add data points to the plot. This will have better performance than -reloadData which forces the plot to load all of its data, not just the new values.

Using CPTAnnotation in CorePlot DatePlot (iOS)

I am Using CorePlot in my app, and I want to display a annotation over the plotSymbol. I haven't found any code in the sample projects of the latest 0.9 version of CorePlot. After some research i have come to this point:
- (void)scatterPlot:(CPTScatterPlot *)plot plotSymbolWasSelectedAtRecordIndex:(NSUInteger)index
{
CPTLayerAnnotation *annot = [[CPTLayerAnnotation alloc]initWithAnchorLayer:graph];
CPTBorderedLayer * logoLayer = [[(CPTBorderedLayer *) [CPTBorderedLayer alloc] initWithFrame:CGRectMake(10,10,100,50)] autorelease];
CPTFill *fillImage = [CPTFill fillWithImage:[CPTImage imageForPNGFile:#"whatEver!"]];
logoLayer.fill = fillImage;
annot.contentLayer = logoLayer;
annot.rectAnchor=CPTRectAnchorTop;
[graph addAnnotation:annot];
}
But its obviously not working.... Can anybody help me?
My goal is to get an annotation over the selected plot symbol, similar to annotations in MKMapView.
Update
It is a DatePlot, just to clarify things and it is working with time intervals since 2001 on the x-axis.
There are several examples of this in the Core Plot example apps. The gradient scatter plot in the Plot Gallery app (and several other apps as well) use this method to attach a text label to the selected point. The point selection demo in the Mac version of CPTTestApp uses a second scatter plot to draw a crosshairs over the selected point.
Remember to set the plotSymbolMarginForHitDetection property on the scatter plot, too. The default is 0, which means you have to hit the center of the point exactly to register a touch.
There are two types of annotation in Core Plot. A CPTLayerAnnotation is anchored to a given Core Animation layer (the graph in your case). A CPTPlotSpaceAnnotation is anchored to a plot space coordinate (== data coordinate). Your comment below makes it sound like you want to use a plot space annotation instead of a layer annotation.