I have created a CPScatterPlot using Core Plot and have several lines on the graph:
for(int i=0; i<nLines; ++i){
CPScatterPlot *xSquaredPlot = [[[CPScatterPlot alloc] initWithFrame:graph.frame] autorelease];
xSquaredPlot.identifier = [NSString stringWithFormat:#"%d",i];
xSquaredPlot.dataLineStyle.lineWidth = 1.0f;
xSquaredPlot.name = #"dd";
if(i==0)
xSquaredPlot.dataLineStyle.lineColor = [CPColor redColor];
else if (i ==1)
xSquaredPlot.dataLineStyle.lineColor = [CPColor blueColor];
else
xSquaredPlot.dataLineStyle.lineColor = [CPColor greenColor];
xSquaredPlot.dataSource = self;
[graph addPlot:xSquaredPlot];
CPPlotSymbol *greenCirclePlotSymbol = [CPPlotSymbol ellipsePlotSymbol];
if(i==0)
greenCirclePlotSymbol.fill = [CPFill fillWithColor:[CPColor blueColor]];
else if (i ==1)
greenCirclePlotSymbol.fill = [CPFill fillWithColor:[CPColor greenColor]];
else
greenCirclePlotSymbol.fill = [CPFill fillWithColor:[CPColor redColor]];
greenCirclePlotSymbol.size = CGSizeMake(2.0, 2.0);
xSquaredPlot.plotSymbol = greenCirclePlotSymbol;
}
The lines show up great, but I can't seem to find a way to label each line with it's title, or provide a legend.
Any ideas on this?
Thanks in advance!
Update: CorePlot 0.4 has the class CPTLegend:
_graph.legend = [CPTLegend legendWithGraph:_graph];
_graph.legend.textStyle = x.titleTextStyle;
_graph.legend.fill = [CPTFill fillWithColor:[CPTColor darkGrayColor]];
_graph.legend.borderLineStyle = x.axisLineStyle;
_graph.legend.cornerRadius = 5.0;
_graph.legend.swatchSize = CGSizeMake(25.0, 25.0);
_graph.legendAnchor = CPTRectAnchorBottom;
_graph.legendDisplacement = CGPointMake(0.0, 12.0);
See CorePlot_0.4/Source/examples/CorePlotGallery/src/plots/SimpleScatterPlot.m.
Legends have not yet been implemented in Core Plot. You're more than welcome to contribute an implementation of them to the framework.
In the meantime, you could construct a custom UIView with UILabels and colored lines to act as the legend for the graph, then add it as a sibling to the graph (not a subview, or it will not be rendered properly) and order it to show above the graph.
Related
i was just browsing the classes for an hour and cant find it! i started with searching the example of the AAPLot project.
i changed the graph a bit and was expecting to find all settings in the CPTTradingRangePlot class but it´s not there.
there are a lot of properties which i can change, but i can´t find the background settings in any of the classes.
could anybody give me a hint?
// OHLC plot
CPTMutableLineStyle *whiteLineStyle = [CPTMutableLineStyle lineStyle];
whiteLineStyle.lineColor = [CPTColor whiteColor];
whiteLineStyle.lineWidth = 1.0f;
CPTTradingRangePlot *ohlcPlot = [[[CPTTradingRangePlot alloc] initWithFrame:graph.bounds] autorelease];
ohlcPlot.identifier = #"OHLC";
ohlcPlot.lineStyle = whiteLineStyle;
ohlcPlot.barWidth = 4.0f;
ohlcPlot.increaseFill = [(CPTFill *)[CPTFill alloc] initWithColor:[CPTColor greenColor]];
ohlcPlot.decreaseFill = [(CPTFill *)[CPTFill alloc] initWithColor:[CPTColor redColor]];
CPTMutableTextStyle *whiteTextStyle = [CPTMutableTextStyle textStyle];
whiteTextStyle.color = [CPTColor whiteColor];
whiteTextStyle.fontSize = 12.0;
ohlcPlot.labelTextStyle = whiteTextStyle;
ohlcPlot.labelOffset = 5.0;
ohlcPlot.stickLength = 2.0f;
ohlcPlot.dataSource = self;
ohlcPlot.plotStyle = CPTTradingRangePlotStyleCandleStick;
[graph addPlot:ohlcPlot];
Here's a very simple example. This:
CPTColor *your_color = [CPTColor colorWithComponentRed:1 green:0 blue:0 alpha:1];
your_graph.fill = [CPTFill fillWithColor:your_color];
will turn your graph's background red. But as Eric Skroch said, you may want to do this...
your_graph.plotAreaFrame.fill = [CPTFill fillWithColor:your_color];
and / or this...
your_graph.plotAreaFrame.plotArea.fill = [CPTFill fillWithColor:your_color];
depending on the result you want to achieve.
Backgrounds in Core Plot are set using CPTFill objects similar to the increaseFill and decreaseFill in your code sample. Depending on the look you want to achieve, you need to set the fill on graph, graph.plotAreaFrame, and/or graph.plotAreaFrame.plotArea. The axis demo in the Mac version of CPTTestApp uses fills in all three areas so you can see the different parts.
You may set it in xAxis or yAxis using CPTColor.
axisSet.yAxis.alternatingBandFills = [NSArray arrayWithObjects:[CPTColor redColor],
[CPTColor whiteColor], [CPTColor purpleColor], nil];
i finally found it by myself. the background of the chart is managed by a theme. there are several theme files in the folder theme of the core-plot library and one of them is CPTStocksTheme. The CPTStocksTheme creates a blue gradient background which can be changed there.
How to change area gradient color for negative values in Gradient Scatter Plot in Core-Plot in iPhone?
I want gradient colors as below:
For positive values to be Green
For negative values to be Red.
How should I do that?
Just implement the following method of the CPBarPlotDataSource is OK:
- (CPFill *)barFillForBarPlot:(CPBarPlot *)barPlot recordIndex:(NSUInteger)index
{
if (barPlot.identifier == #"profit") {
id item = [self.profits objectAtIndex:index];
double profit = [[item objectForKey:#"profit"] doubleValue];
if (profit < 0.0) {
return [CPFill fillWithGradient:[CPGradient gradientWithBeginningColor:[CPColor redColor] endingColor:[CPColor blackColor]]];
}
}
return nil;
}
Hope to help:)
Well, I don't know if it's too pretty, but I suppose you could do two separate plots with the same dataSource, let's say positivePlot and negativePlot.
CPScatterPlot *positivePlot = [[[CPScatterPlot alloc] init] autorelease];
positivePlot.identifier = #"PositivePlot";
positivePlot.dataSource = self;
[graph addPlot:positivePlot];
CPScatterPlot *negativevePlot = [[[CPScatterPlot alloc] init] autorelease];
negativevePlot.identifier = #"NegativePlot";
negativePlot.dataSource = self;
[graph addPlot:negativePlot];
Now, if you configure your plotSpaces properly, you can separate positive and negative values and configure each plot properly, including area gradient:
CPXYPlotSpace *positivePlotSpace = [graph newPlotSpace];
positivePlotSpace.xRange = [CPPlotRange plotRangeWithLocation:CPDecimalFromFloat(0)
length:CPDecimalFromFloat(100)];
positivePlotSpace.yRange = [CPPlotRange plotRangeWithLocation:CPDecimalFromFloat(0)
length:CPDecimalFromFloat(100)];
CPXYPlotSpace *negativevePlotSpace = [graph newPlotSpace];
negativePlotSpace.xRange = [CPPlotRange plotRangeWithLocation:CPDecimalFromFloat(-100)
length:CPDecimalFromFloat(100)];
negativePlotSpace.yRange = [CPPlotRange plotRangeWithLocation:CPDecimalFromFloat(0)
length:CPDecimalFromFloat(100)];
// Plots configuration
//POSITIVE VALUES
positivePlot.plotSpace = positivePlotSpace;
// Green for positive
CPColor *areaColor = [CPColor colorWithComponentRed:0.0
green:1.0
blue:0.0
alpha:1.0];
CPGradient *areaGradient = [CPGradient gradientWithBeginningColor:areaColor
endingColor:[CPColor clearColor]];
areaGradient.angle = -90.0f;
CPFill *areaGradientFill = [CPFill fillWithGradient:areaGradient];
positivePlot.areaFill = areaGradientFill;
//NEGATIVE VALUES
negativePlot.plotSpace = negativePlotSpace;
// Red for negative
areaColor = [CPColor colorWithComponentRed:1.0
green:0.0
blue:0.0
alpha:1.0];
areaGradient = [CPGradient gradientWithBeginningColor:areaColor
endingColor:[CPColor clearColor]];
areaGradient.angle = -90.0f;
areaGradientFill = [CPFill fillWithGradient:areaGradient];
negativePlot.areaFill = areaGradientFill;
NOTE: This is off the top of my head, as I dont have Core-Plot docs here, or a working configuration to test this in, so the syntax or something might be off, but I think the general concept should work.
Cheers
I'm using Core-Plot for a trend chart in an iPhone app and haven't found how to customize the background. I can create a theme using the built-in themes, like kCPPlainWhiteTheme, but how can I change them? or create a new one?
What i basically need to do is make the background transparent.
EDIT / UPDATE
I jus tested this code but it doesn't seem to work:
//CPTheme *theme = [CPTheme themeNamed:kCPPlainWhiteTheme];
CPTheme *theme = [[CPTheme alloc]init];
chartTrend5 = (CPXYGraph *)[theme newGraph];
chartView.hostedGraph = chartTrend5;
chartTrend5.paddingLeft = 0.0;
chartTrend5.paddingTop = 0.0;
chartTrend5.paddingRight = 0.0;
chartTrend5.paddingBottom = 0.0;
chartTrend5.fill = nil;
chartTrend5.borderLineStyle = nil;
chartView.hostedGraph.fill = nil;
chartTrend5PlotSpace = (CPXYPlotSpace *)chartTrend5.defaultPlotSpace;
chartTrend5PlotSpace.xRange = [CPPlotRange plotRangeWithLocation:CPDecimalFromFloat(0)
length:CPDecimalFromFloat(5)];
// range is 0-125, but since the frame heights is 90,
// we need to convert the points to this adjusted scale. The factor is 0.72 => (90/125)
chartTrend5PlotSpace.yRange = [CPPlotRange plotRangeWithLocation:CPDecimalFromFloat(0)
length:CPDecimalFromFloat(90)];
CPXYAxisSet *axisSet = (CPXYAxisSet *)chartTrend5.axisSet;
CPXYAxis *x = axisSet.xAxis;
x.majorIntervalLength = CPDecimalFromFloat(100);
//x.constantCoordinateValue = CPDecimalFromFloat(2);
x.minorTicksPerInterval = 2;
x.borderWidth = 0;
x.labelExclusionRanges = [NSArray arrayWithObjects:
[CPPlotRange plotRangeWithLocation:CPDecimalFromFloat(-1)
length:CPDecimalFromFloat(800)],
nil];;
CPXYAxis *y = axisSet.yAxis;
y.majorIntervalLength = CPDecimalFromFloat(100);
y.minorTicksPerInterval = 1;
//y.constantCoordinateValue = length:CPDecimalFromFloat(2);
y.labelExclusionRanges = [NSArray arrayWithObjects:
[CPPlotRange plotRangeWithLocation:CPDecimalFromFloat(-26)
length:CPDecimalFromFloat(100)],
nil];
CPScatterPlot *dataSourceLinePlot = [[[CPScatterPlot alloc] init] autorelease];
dataSourceLinePlot.identifier = #"TrendChart";
dataSourceLinePlot.dataLineStyle.lineWidth = 2.f;
dataSourceLinePlot.dataLineStyle.lineColor = [CPColor colorWithComponentRed:(16/255.f)
green:(101/255.f)
blue:(122/255.f)
alpha:1];
dataSourceLinePlot.dataSource = self;
[chartTrend5 addPlot:dataSourceLinePlot];
chartTrend5.fill = nil;
// Put an area gradient under the plot above
CPColor *areaColor = [CPColor colorWithComponentRed:(212/255.f)
green:(233/255.f)
blue:(216/255.f)
alpha:1];
CPGradient *areaGradient = [CPGradient gradientWithBeginningColor:areaColor
endingColor:areaColor];
areaGradient.angle = -90.0f;
CPFill *areaGradientFill = [CPFill fillWithGradient:areaGradient];
dataSourceLinePlot.areaFill = areaGradientFill;
dataSourceLinePlot.areaBaseValue = CPDecimalFromString(#"5.25");
here I set the the fill property of CPXYGraph *chartTrend5 and *CPXYPlotSpace *chartTrend5PlotSpace to nil.
In addition to what Eric suggests, you can also try setting the fill to a clear color. For example, I've used this in the past to provide a transparent background to graphs:
CPTTheme *theme = [CPTTheme themeNamed:kCPPlainWhiteTheme];
graph = (CPTXYGraph *)[theme newGraph];
graph.fill = [CPTFill fillWithColor:[CPTColor clearColor]];
graph.plotAreaFrame.fill = [CPTFill fillWithColor:[CPTColor clearColor]];
Themes are just a convenient way to set a lot of the style properties at once. You can set any of them individually to customize the look. Any time you want an area to be transparent, you can set its fill to nil. Same with line styles--set them to nil to prevent a line from being drawn.
There are two "background" areas that you might be concerned with. The graph has a fill as does the plot area. The plot area is the region where the plots are drawn. Set the fill property on both of these to nil to make the background transparent.
I tried this & it works for me:
// Here 'hostingView' is your CPTGraphHostingView to
// which you add your graph
UIImageView *backgroundImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"background.png"]];
[hostingView addSubview:backgorundImage];
[hostingView sendSubviewToBack:backgroundImage];
I used the .fill and .plot.AreaFrame.fill properties :
plot = [[CPTXYGraph alloc] initWithFrame:CGRectZero];
CPTTheme *theme = [CPTTheme themeNamed:kCPTSlateTheme];
[plot applyTheme:theme];
self.graph.collapsesLayers = NO;
self.graph.hostedGraph = plot;
plot.paddingLeft = 1.0;
plot.paddingTop = 1.0;
plot.paddingRight = 1.0;
plot.paddingBottom = 1.0;
plot.fill = [CPTFill fillWithColor:[CPTColor clearColor]];
plot.plotAreaFrame.fill = [CPTFill fillWithColor:[CPTColor clearColor]];
This works for me.
I am trying to remove the border around a core plot graph on the iPhone - but seem to be struggling on what should be simple in my mind.
Pointers please!
You should be able to nil out the borderLineStyle on the graph's plotArea to remove the border:
graph.plotAreaFrame.borderLineStyle = nil; // don't draw a border
You could also create your own theme, using the ones in the framework as examples, and simply not set the borderLineStyle in that.
None of the answers worked for me. This did the job:
graph.paddingLeft = 0;
graph.paddingRight = 0;
graph.paddingTop = 0;
graph.paddingBottom = 0;
graph.plotAreaFrame.borderWidth = 0;
graph.plotAreaFrame.cornerRadius = 0;
OK I found out how to do it - quite simple really!
CPLineStyle *borderLineStyle = [CPLineStyle lineStyle];
borderLineStyle.lineColor = [CPColor whiteColor];
borderLineStyle.lineWidth = 1.0;
graph.plotArea.borderLineStyle = borderLineStyle;
where graph is your graph object - the reason I had a border in the first place was because I used CPPlainWhiteTheme.
Hope this helps others - is there a better way?
You can set any line style to nil. This will cause the line to not be drawn at all.
In CorePlot 1.0, the structure of CPTGraph has changed slightly. The code for removing the border line of a graph, assuming that graph is of type GPTGraph or a subclass of CPTGraph, is
graph.plotAreaFrame.borderLineStyle = nil;
The correct way with borderLineStyle = nil after applyTheme:
CPTGraph *graph = [[CPTXYGraph alloc] initWithFrame:hostView.bounds];
// Set padding for plot area
[graph applyTheme:[CPTTheme themeNamed:kCPTPlainWhiteTheme]];
graph.plotAreaFrame.borderLineStyle = nil;
If, like me, you are looking to not just remove the border line, but to make a plot that takes up the entire hosting view, the answer from Thomas Johannesmeyer got me on the right track.
Here's what I did:
CPTGraphHostingView* hostingView = [[CPTGraphHostingView alloc] initWithFrame: frame];
CGRect bounds = hostingView.bounds;
CPTGraph *graph = [[CPTXYGraph alloc] initWithFrame:bounds];
hostingView.hostedGraph = graph;
graph.paddingTop = CPTFloat(0.0);
graph.paddingRight = CPTFloat(0.0);
graph.paddingBottom = CPTFloat(0.0);
graph.paddingLeft = CPTFloat(0.0);
graph.plotAreaFrame.paddingTop = CPTFloat(0.0);
graph.plotAreaFrame.paddingRight = CPTFloat(0.0);
graph.plotAreaFrame.paddingBottom = CPTFloat(0.0);
graph.plotAreaFrame.paddingLeft = CPTFloat(0.0);
graph.plotAreaFrame.masksToBorder = NO;
CPTXYAxisSet *axisSet = (CPTXYAxisSet *)graph.axisSet;
CPTXYAxis *x = axisSet.xAxis;
x.labelingPolicy = CPTAxisLabelingPolicyNone;
x.title = nil;
CPTXYAxis *y = axisSet.yAxis;
y.labelingPolicy = CPTAxisLabelingPolicyNone;
y.title = nil;
EDIT: I think my question is better phrased as: How can I have a Y-axis that doesn't start at zero? It seems like the x-axis always gets placed at the y=0, but I would like the x-axis to be at some positive number on the y-axis.
Here's a graph with more regular data... I just wish the x-axis was placed at the minimum y-value for the plot (about 77), instead of at 0.
Here is the function I use to create the graph.
It's a whole bunch of code, and I'm not quite sure which piece might be off to not display the x-axis.
Could the x-axis not showing have something to do with my data?
- (void) showGraph:(SavedDetailScreen*)dataSource {
// create the graph and add it to the view
CPXYGraph *graph = [[CPXYGraph alloc] initWithFrame: CGRectZero];
graph.plotArea.masksToBorder = NO;
CPLayerHostingView *graphView = [[CPLayerHostingView alloc] initWithFrame:CGRectMake(0,0, 280, 240)];
[self addSubview:graphView];
graphView.hostedLayer = graph;
graph.paddingLeft = 50.0;
graph.paddingTop = 20.0;
graph.paddingRight = 10.0;
graph.paddingBottom = 40.0;
// set up the ranges for the graph axis
float minElevation = dataSource.track.tbStats.minAlt;
float maxElevation = dataSource.track.tbStats.maxAlt-dataSource.track.tbStats.minAlt;
float minDistance = 0.0f;
float maxDistance = dataSource.track.tbStats.totalDistance;
CPXYPlotSpace *plotSpace = (CPXYPlotSpace *)graph.defaultPlotSpace;
plotSpace.xRange = [CPPlotRange plotRangeWithLocation:CPDecimalFromFloat(minDistance)
length:CPDecimalFromFloat(maxDistance)];
plotSpace.yRange = [CPPlotRange plotRangeWithLocation:CPDecimalFromFloat(minElevation)
length:CPDecimalFromFloat(maxElevation)];
// style the graph with white text and lines
CPTextStyle *whiteText = [CPTextStyle textStyle];
whiteText.color = [CPColor whiteColor];
CPLineStyle *whiteStyle = [CPLineStyle lineStyle];
whiteStyle.lineColor = [CPColor whiteColor];
whiteStyle.lineWidth = 2.0f;
// set up the axis
CPXYAxisSet *axisSet = (CPXYAxisSet *)graph.axisSet;
CPXYAxis *x = axisSet.xAxis;
CPXYAxis *y = axisSet.yAxis;
x.majorIntervalLength = CPDecimalFromFloat(maxDistance/10.0f);
x.minorTicksPerInterval = 0;
x.majorTickLineStyle = whiteStyle;
x.minorTickLineStyle = whiteStyle;
x.axisLineStyle = whiteStyle;
x.minorTickLength = 5.0f;
x.majorTickLength = 10.0f;
x.labelOffset = 3.0f;
x.labelTextStyle = whiteText;
y.majorIntervalLength = CPDecimalFromFloat(maxElevation/5.0f);
y.minorTicksPerInterval = 0;
y.majorTickLineStyle = whiteStyle;
y.minorTickLineStyle = whiteStyle;
y.axisLineStyle = whiteStyle;
y.minorTickLength = 5.0f;
y.majorTickLength = 10.0f;
y.labelOffset = 3.0f;
y.labelTextStyle = whiteText;
CPScatterPlot *plot = [[[CPScatterPlot alloc] initWithFrame:graph.bounds] autorelease];
plot.dataLineStyle.lineWidth = 2.0f;
plot.dataLineStyle.lineColor = [CPColor blueColor];
plot.dataSource = dataSource;
[graph addPlot:plot];
CPPlotSymbol *greenCirclePlotSymbol = [CPPlotSymbol ellipsePlotSymbol];
greenCirclePlotSymbol.fill = [CPFill fillWithColor:[CPColor greenColor]];
greenCirclePlotSymbol.size = CGSizeMake(2.0, 2.0);
plot.plotSymbol = greenCirclePlotSymbol;
}
I've had the same problem yesterday/today and the solution seems to be using the orthogonalCoordinateDecimal property on the axis. For example:
graph.axisSet.xAxis.orthogonalCoordinateDecimal = CPDecimalFromFloat(minHeight);
You set the position of an axis on the orthogonal axis using the constantCoordinateValue property of the axis. Just set that property on the x axis to a positive value of y, and the axis should move up.
https://github.com/djw/core-plot/tree/9282845bddbb8c40ff314bbfa158beff797c91f7/examples
This states that the isFloatingAxis property has been removed from at least version 0.9.
I also found this in the discussion group as well http://code.google.com/p/core-plot/issues/detail?id=125
After some hunting, it looks like the new way to float an axis looks like this:
x.axisConstraints = [CPTConstraints constraintWithUpperOffset:132];
this framework really needs a better way to configure itself. I don't see any problem jumping out. Maybe just try simplifying the method to the point where debugging becomes manageable. Check the data that you are passing in to make sure it is what you expect it to be. Better yet, create some dummy data that you know will produce the plot you expect.