I have an issue with the BalloonMarker I used for my graph as it won't display the marker for all the chart elements, but only for one of them.
I used the BalloonMarker from the ChartsDemo project for a bar chart. The marker gets displayed, but only for one of the bars from the charts. I don't know if it is a coincidence or not, but it gets displayed for the bar from the middle.
I can't see what I am missing here. Is there any mistake or any other setting I can add in order to make the marker display properly?
This is the code I used to create the BallonMarker for the chart:
BalloonMarker *balloonMarker = [[BalloonMarker alloc]
initWithColor: [UIColor colorWithWhite:180/255. alpha:0.9]
font: [UIFont systemFontOfSize:10.0]
textColor: UIColor.whiteColor
insets: UIEdgeInsetsMake(8.0, 8.0, 20.0, 8.0)];
balloonMarker.chartView = barChartOrdersView;
balloonMarker.minimumSize = CGSizeMake(40.f, 20.f);
I added the marker to the chart using this code:
barChartOrdersView.drawMarkers = YES;
barChartOrdersView.marker = balloonMarker;
The properties for the bar chart are:
barChartOrdersView.gridBackgroundColor = [UIColor whiteColor];
barChartOrdersView.backgroundColor = [UIColor whiteColor];
barChartOrdersView.drawBarShadowEnabled = NO;
barChartOrdersView.drawValueAboveBarEnabled = YES;
barChartOrdersView.chartDescription.enabled = NO;
barChartOrdersView.dragEnabled = NO;
[barChartOrdersView setScaleEnabled:NO];
barChartOrdersView.pinchZoomEnabled = NO;
barChartOrdersView.rightAxis.enabled = NO;
barChartOrdersView.leftAxis.drawGridLinesEnabled = YES;
barChartOrdersView.leftAxis.drawLabelsEnabled = YES;
barChartOrdersView.leftAxis.labelFont = [UIFont systemFontOfSize:10.f];
barChartOrdersView.leftAxis.labelPosition = YAxisLabelPositionOutsideChart;
barChartOrdersView.leftAxis.spaceTop = 0.15;
barChartOrdersView.leftAxis.axisMinimum = 0.0;
barChartOrdersView.xAxis.labelPosition = XAxisLabelPositionBottom;
barChartOrdersView.xAxis.drawGridLinesEnabled = NO;
barChartOrdersView.xAxis.axisMinimum = 0.0;
barChartOrdersView.xAxis.granularity = 1.0;
barChartOrdersView.xAxis.labelFont = [UIFont systemFontOfSize:10.f];
barChartOrdersView.xAxis.drawGridLinesEnabled = NO;
barChartOrdersView.xAxis.granularity = 1.0;
barChartOrdersView.xAxis.labelCount = 7;
barChartOrdersView.xAxis.valueFormatter = [DayAxisValueFormatter new];
barChartOrdersView.legend.enabled = YES;
barChartOrdersView.legend.horizontalAlignment = ChartLegendHorizontalAlignmentLeft;
barChartOrdersView.legend.verticalAlignment = ChartLegendVerticalAlignmentBottom;
barChartOrdersView.legend.orientation = ChartLegendOrientationHorizontal;
barChartOrdersView.legend.drawInside = NO;
barChartOrdersView.legend.form = ChartLegendFormSquare;
barChartOrdersView.legend.formSize = 9.0;
barChartOrdersView.legend.font = [UIFont fontWithName:#"HelveticaNeue-Light" size:11.f];
barChartOrdersView.legend.xEntrySpace = 4.0;
Make sure the entries you passed in is sorted by ascending order of x value.
Unordered entries could result in unexpected behavior such as dataset flashing or marker not tappable as you mentioned.
Related
I have a chart which is styled like so, but the chart does not fill the view, it seem to maintain a spacing between the edges, as if to allow for the axis labels to be drawn. How can I force the chart portion to take the full size of the Charts view?
When inspecting the view the LineChartViews size is expected, its just that there is a noticeable spacing between the graph and the view, its inset and I cant seem to figure out to to prevent that.
self.chartView = [[LineChartView alloc] init];
self.chartView.delegate = self;
self.chartView.chartDescription.enabled = NO;
self.chartView.chartDescription.enabled = NO;
self.chartView.dragEnabled = NO;
self.chartView.pinchZoomEnabled = NO;
self.chartView.drawGridBackgroundEnabled = NO;
[self.chartView setScaleEnabled:NO];
[self.chartView setUserInteractionEnabled:NO];
ChartYAxis *leftAxis = self.chartView.leftAxis;
leftAxis.axisMaximum = minVal.doubleValue;
leftAxis.axisMinimum = maxVal.doubleValue;
leftAxis.drawGridLinesEnabled = NO;
leftAxis.drawZeroLineEnabled = NO;
leftAxis.drawLimitLinesBehindDataEnabled = NO;
leftAxis.drawAxisLineEnabled = NO;
leftAxis.drawLabelsEnabled = NO;
self.chartView.xAxis.drawAxisLineEnabled = NO;
self.chartView.xAxis.drawGridLinesEnabled = NO;
self.chartView.xAxis.drawLabelsEnabled = NO;
self.chartView.rightAxis.enabled = NO;
self.chartView.legend.form = ChartLegendFormLine;
self.chartView.legend.enabled = NO;
I've figured it out with some trial and error.
self.chartView.minOffset = 0;
I am using charts library (Charts)
I am developing the application allows me to show number of guests in restaurant realtime and compare data between different days.
For example look at this picture
The dashed line means data for the compared to date. I would like to create BarChart like this but library only allows me to show 4 grouped bars. I want to show dashed bars above colored with small offset. Help me out please
My code is:
for (int i = 0; i < days.count; i++) {
BarChartDataEntry *guysEntry = [[BarChartDataEntry alloc] initWithX:i y:[guys[i] integerValue]];
[guysChartDataArray addObject:guysEntry];
BarChartDataEntry *girlsEntry = [[BarChartDataEntry alloc] initWithX:i y:[girls[i] integerValue]];
[girlsChartDataArray addObject:girlsEntry];
BarChartDataEntry *guysCompareToEntry = [[BarChartDataEntry alloc] initWithX:i y:[guysCompareTo[i] integerValue]];
[guysCompareToChartDataArray addObject:guysCompareToEntry];
BarChartDataEntry *girlsCompareToEntry = [[BarChartDataEntry alloc] initWithX:i y:[girlsCompareTo[i] integerValue]];
[girlsCompareToChartDataArray addObject:girlsCompareToEntry];
}
BarChartDataSet *guysChartDataSet = [[BarChartDataSet alloc] initWithValues:guysChartDataArray label:#"Guys"];
guysChartDataSet.colors = #[[UIColor maleColor]];
guysChartDataSet.valueTextColor = [UIColor clearColor];
BarChartDataSet *girlsChartDataSet = [[BarChartDataSet alloc] initWithValues:girlsChartDataArray label:#"Girls"];
girlsChartDataSet.colors = #[[UIColor femaleColor]];
girlsChartDataSet.valueTextColor = [UIColor clearColor];
LineChartXAxisFormatter *barGraphXFormatter = [[LineChartXAxisFormatter alloc] init];
barGraphXFormatter.xLabels = [days mutableCopy];
self.barChartView.xAxis.valueFormatter = barGraphXFormatter;
self.barChartView.xAxis.centerAxisLabelsEnabled = YES;
self.combinedChartView.xAxis.valueFormatter = barGraphXFormatter;
self.combinedChartView.xAxis.centerAxisLabelsEnabled = YES;
float groupSpace = 0.06f;
float barSpace = 0.02f;
float barWidth = 0.45f;
BarChartDataSet *guysCompareToChartDataSet = [[BarChartDataSet alloc] initWithValues:guysCompareToChartDataArray label:#"Guys (Compare)"];
guysCompareToChartDataSet.colors = #[[UIColor clearColor]];
guysCompareToChartDataSet.barBorderWidth = 1.f;
guysCompareToChartDataSet.barBorderColor = [UIColor grayColor];
guysCompareToChartDataSet.isDashedBorder = YES;
guysCompareToChartDataSet.axisDependency = AxisDependencyLeft;
guysCompareToChartDataSet.valueTextColor = [UIColor clearColor];
BarChartDataSet *girlsCompareToChartDataSet = [[BarChartDataSet alloc] initWithValues:girlsCompareToChartDataArray label:#"Girls (Compare)"];
girlsCompareToChartDataSet.colors = #[[UIColor clearColor]];
girlsCompareToChartDataSet.barBorderWidth = 1.f;
girlsCompareToChartDataSet.barBorderColor = [UIColor grayColor];
girlsCompareToChartDataSet.isDashedBorder = YES;
girlsCompareToChartDataSet.axisDependency = AxisDependencyLeft;
girlsCompareToChartDataSet.valueTextColor = [UIColor clearColor];
NSArray *dataSets = #[guysChartDataSet, girlsChartDataSet, guysCompareToChartDataSet, girlsCompareToChartDataSet];
BarChartData *barChartData = [[BarChartData alloc] initWithDataSets:dataSets];
barChartData.barWidth = barWidth;
CGFloat initialValue = 0;
CGFloat groupCount = days.count;
self.barChartView.xAxis.axisMinimum = initialValue;
self.barChartView.xAxis.axisMaximum = initialValue + [barChartData groupWidthWithGroupSpace:groupSpace barSpace: barSpace] * groupCount;
[barChartData groupBarsFromX:0 groupSpace:groupSpace barSpace:barSpace];
self.barChartView.data = barChartData;
I want to make something like:
Now that you've changed your question, this requires a different solution.
As I mentioned in the comments before, you need to manually calculate each bar's position. Then, don't use the grouping feature, because you've already grouped them how you want.
// Determine bar sizing and spacing parameters.
int barsPerGroup = 2;
double targetGroupWidth = 1;
double barSpacing = 0.2;
double groupSpacing = 0.3;
double barWidth = (targetGroupWidth - groupSpacing - barSpacing * barsPerGroup) / barsPerGroup;
double compareBarOffset = barWidth / 3;
for (int i = 0; i < entryCount; i++) {
// Determine X position for each bar
// NOTE: This is the most important step!
double groupStartPosition = targetGroupWidth * i;
double group1X = groupStartPosition + barWidth / 2;
double group1CompareX = group1X + compareBarOffset;
double group2X = group1X + barWidth + barSpacing;
double group2CompareX = group2X + compareBarOffset;
// Create data entries positioned at values calculated by previous step
NSNumber *group1Value = group1[i];
NSNumber *group1CompareValue = group1Compare[i];
NSNumber *group2Value = group2[i];
NSNumber *group2CompareValue = group2Compare[i];
BarChartDataEntry *group1DataEntry = [[BarChartDataEntry alloc] initWithX:group1X
y:[group1Value doubleValue]];
BarChartDataEntry *group1CompareDataEntry = [[BarChartDataEntry alloc] initWithX:group1CompareX
y:[group1CompareValue doubleValue]];
BarChartDataEntry *group2DataEntry = [[BarChartDataEntry alloc] initWithX:group2X
y:[group2Value doubleValue]];
BarChartDataEntry *group2CompareEntry = [[BarChartDataEntry alloc] initWithX:group2CompareX
y:[group2CompareValue doubleValue]];
// ...
}
// Create Data Sets, set styles, etc.
// ...
// Do NOT use this method because bars are already grouped.
//[barChartView groupBarsFromX:0 groupSpace:groupSpacing barSpace:barSpacing];
RESULT:
Note: I can't find the property isDashedBorder, so I don't know what version of the library you're using. Instead, I just set clear bars with a solid gray border.
With Charts, it looks you can:
Stack data into the same bar.
Group bars so that they overlap.
It also looks like you can't:
Give each data entry in the stacked bar a separate border color. (If you supply a border color, it will apply to the entire bar.)
Note about documentation
Do remember that Charts is modeled after MPAndroidChart and follows its API very closely.
Therefore, if you need help, refer to their documentation. The Java syntax is a bit foreign to me, but with the help of Xcode's autocomplete, I was able to find everything I needed.
Code:
Please take note of three specific parts:
How to create stacked data entries.
Inability to set separate borders per item in stacked bar.
How to overlap bars by providing a negative bar spacing.
I'm by no means an expert in this library, but simply reading the documentation, I was able to put this together.
// MARK: Data Entries
for (int i = 0; i < days.count; i++) {
NSNumber *guyValue = guys[i];
NSNumber *girlValue = girls[i];
// NOTE 1: To get "stacked" bars, use the initializer `initWithX:yValues:`
BarChartDataEntry *guyGirlDataEntry = [[BarChartDataEntry alloc] initWithX:i
yValues:#[guyValue, girlValue]];
NSNumber *guyCompareToValue = guysCompareTo[i];
NSNumber *girlCompareToValue = girlsCompareTo[i];
BarChartDataEntry *guyGirlCompareToEntry = [[BarChartDataEntry alloc] initWithX:i
yValues:#[guyCompareToValue, girlCompareToValue]];
[guyGirlChartDataArray addObject:guyGirlDataEntry];
[guyGirlCompareToChartDataArray addObject:guyGirlCompareToEntry];
}
// MARK: Data Sets
BarChartDataSet *guysGirlsChartDataSet = [[BarChartDataSet alloc] initWithValues:guyGirlChartDataArray label:nil];
BarChartDataSet *guysGirlsCompareToChartDataSet = [[BarChartDataSet alloc] initWithValues:guyGirlCompareToChartDataArray label:nil];
BarChartData *data = [[BarChartData alloc] initWithDataSets:#[guysGirlsCompareToChartDataSet, guysGirlsChartDataSet]];
// MARK: Styling
guysGirlsChartDataSet.stackLabels = #[#"Guys", #"Girls"];
guysGirlsChartDataSet.colors = #[[UIColor maleColor],
[UIColor femaleColor]];
// NOTE 2: Unfortunately, you can only set one border color to the bar.
// It seems, you won't be able to use separate dashed borders in the same bar, like you want.
// For demonstration purposes, I've simply made the comparison colors 50% transparent.
guysGirlsCompareToChartDataSet.stackLabels = #[#"Guys (Compare)", #"Girls (Compare)"];
guysGirlsCompareToChartDataSet.colors = #[[[UIColor maleColor] colorWithAlphaComponent:0.5],
[[UIColor femaleColor] colorWithAlphaComponent:0.5]];
// Sets the x axis label interval, so it doesn't show labels like "0.9"
barChartView.xAxis.granularity = 1;
// Centers the x axis label over the bar group, rather than on the grid line.
barChartView.xAxis.centerAxisLabelsEnabled = YES;
// MARK: Displaying Chart Data
barChartView.data = data;
// Grouping
// I still can't seem to set this properly.
// Even though I tell it to fit the bars exactly and don't show below 0 on the x axis,
// the chart still shows below zero and the right-most bar gets cut off.
// If this isn't a bug, then perhaps you can find the answer to this elsewhere.
barChartView.fitBars = YES;
[barChartView setVisibleXRangeMinimum:0];
// Calculate bar grouping parameters.
NSInteger barCountPerGroup = data.dataSetCount;
double barWidth = 0.4;
// NOTE 3: Negative bar spacing will make the bars overlap.
double barSpace = -0.3;
// According to documentation, total group width (bars and spacing) must add up to 1
double groupSpace = 1 - (barWidth + barSpace) * barCountPerGroup;
// Set the grouping parameters.
data.barWidth = barWidth;
[barChartView groupBarsFromX:0 groupSpace:groupSpace barSpace:barSpace];
// Refresh the chart (if necessary)
[barChartView notifyDataSetChanged];
Output:
The styling isn't very good, but the bars are grouped and overlap like you want.
I trust you can find help with the styling elsewhere.
I want to generate bar chart with dual y axis. I tried like this
-(void)loadGraph
{
_barColors = #[[UIColor cyanColor]];
_currentBarColor = 0;
// CGRect chartFrame = CGRectMake(0.0,
// 0.0,
// 300,
// 300.0);
CGRect chartFrame = CGRectMake(60,128-20,self.view.frame.size.width-40-40,180);//728//1024
_chart = [[SimpleBarChart alloc] initWithFrame:chartFrame];
//_chart.center = CGPointMake(self.view.frame.size.width / 2.0, self.view.frame.size.height / 2.0);
_chart.delegate = self;
_chart.dataSource = self;
_chart.barShadowOffset = CGSizeMake(2.0, 1.0);
_chart.animationDuration = 1.0;
_chart.barShadowColor = [UIColor clearColor];
_chart.barShadowAlpha = 0.5;
_chart.barShadowRadius = 1.0;
_chart.barWidth = 30.0;
_chart.xLabelType = SimpleBarChartXLabelTypeHorizontal;//SimpleBarChartXLabelTypeVerticle;
_chart.incrementValue = 10;
_chart.barTextType = SimpleBarChartBarTextTypeTop;
_chart.barTextColor = [UIColor blackColor];
//
_chart.gridColor = [UIColor clearColor];
//
[scroll addSubview:_chart];
[_chart reloadData];
I'm getting only one single axis without y axis values. Can any one help? I want to draw bar graph with dual y axis with values.
Thanks in advance.
Try this graph if your value is negative it will show you dual y axis.
https://github.com/chasseurmic/TWRCharts
I am trying to work out how I would change the visual advice (arrows) colors for the navigation aspect of Skobbler SDK for iOS. I would like to customize aspects of the visual advice color-wise...
I have the following:
let configAdvice = SKVisualAdviceConfiguration.visualAdviceColor()
configAdvice.countryCode = "US"
configAdvice.streetType = SKStreetType.Secondary
configAdvice.routeStreetColor = UIColor.blackColor()
configAdvice.allowedStreetColor = UIColor.blackColor()
configAdvice.forbiddenStreetColor = UIColor.blackColor()
// config.routeStreetColor = [UIColor colorWithHex:color alpha:1.0];
// config.allowedStreetColor = [UIColor colorWithHex:color alpha:0.0f];
// config.forbiddenStreetColor = [UIColor colorWithHex:color alpha:0.0f];
SKRoutingService.sharedInstance().visualAdviceConfigurations = [configAdvice]
let settings: SKAdvisorSettings = SKAdvisorSettings()
let currentLanguage: String = "en_us"
settings.advisorVoice = currentLanguage
settings.advisorType = .AudioFiles
SKRoutingService.sharedInstance().advisorConfigurationSettings = settings
The result is:
As you can see the arrow is white which is hard to see. So I'm not sure why the code isn't reflected in the visuals...
Visual instructions: listen to didChangeFirstVisualAdvice.
Inside the SKRouteState parameter you will find information about the:
Path to the current (first) visual advice: currentVisualAdvicePath (if you want a coloured image use firstVisualAdviceImageWithColor)
Path to the next (second) visual advice: secondaryVisualAdvicePath (if you want a coloured image use secondVisualAdviceImageWithColor)
To set the colour scheme for the "coloured advices" use the following visualAdviceConfigurations setting:
SKVisualAdviceConfiguration *visualAdviceColor1 = [SKVisualAdviceConfigurationvisualAdviceColor];
visualAdviceColor1.countryCode = #“DE";
visualAdviceColor1.streetType = SKStreetTypeSecondary;
visualAdviceColor1.routeStreetColor = [UIColor whiteColor];
visualAdviceColor1.allowedStreetColor = [UIColor grayColor];
visualAdviceColor1.forbiddenStreetColor = [UIColor blackColor];
[SKRoutingServicesharedInstance].visualAdviceConfigurations = #[visualAdviceColor1];
Here is the code used in demo app (the SDKTools project):
- (void)updateVisualAdviceSign {
SKTNavigationVisualAdviceView *adviceView = self.mainView.navigationView.visualAdviceView;
if (self.navigationInfo.firstAdvice) {
if (self.navigationInfo.firstAdviceIsLast) {
NSString *imageName = self.colorScheme[[SKTNavigationUtils destinationImageNameForStreetType:self.navigationInfo.nextStreetType]];
imageName = [#"Icons/DestinationImages" stringByAppendingPathComponent:imageName];
adviceView.signImageView.image = [UIImage navigationImageNamed:imageName];
} else {
SKVisualAdviceConfiguration *config = [self configurationForStreetType:self.navigationInfo.nextStreetType];
adviceView.signImageView.image = [[SKRoutingService sharedInstance] visualAdviceImageForRouteAdvice:self.navigationInfo.firstAdvice color:config];
}
} else {
adviceView.signImageView.image = nil;
}
}
and:
- (SKVisualAdviceConfiguration *)configurationForStreetType:(SKStreetType)streetType {
NSString *name = [SKTNavigationUtils adviceSignColorNameForStreetType:streetType];
uint32_t color = [self.colorScheme[name] unsignedIntValue];
SKVisualAdviceConfiguration *config = [SKVisualAdviceConfiguration visualAdviceColor];
config.streetType = streetType;
config.countryCode = self.navigationInfo.currentCountryCode;
config.routeStreetColor = [UIColor colorWithHex:color alpha:1.0];
config.allowedStreetColor = [UIColor colorWithHex:color alpha:0.0f];
config.forbiddenStreetColor = [UIColor colorWithHex:color alpha:0.0f];
return config;
}
I am using this to show legend titles:
-(NSString *)legendTitleForPieChart:(CPTPieChart *)pieChart recordIndex:(NSUInteger)index {
NSLog(#"titles: %#", list[index]);
return list[index];
}
I can see console output:
titles: Entertaiment
titles: Entertaiment
titles: Entertaiment
titles: Entertaiment
.
.
.
But on the iPhone I'm seeing this:
Why is this happening and how can I fix it?
(CorePlot_1.5.1 Xcode 5.1 iOS 7.1)
Edit:
My configureLegend method look like this. I add legend to scrollView
-(void)configureLegend {
// 1 - Get graph instance
graph = self.hostView.hostedGraph;
// 2 - Create legend
CPTLegend *theLegend = [CPTLegend legendWithGraph:graph];
// 2 - Set up text style
CPTMutableTextStyle *textStyle = [CPTMutableTextStyle textStyle];
textStyle.color = [CPTColor blackColor];
textStyle.fontName = #"Helvetica-Thin";
textStyle.fontSize = 15.0f;
[[graph legend] setTextStyle:(CPTTextStyle *)textStyle];
theLegend.numberOfColumns = 2;
theLegend.fill = [CPTFill fillWithColor:[CPTColor whiteColor]];
theLegend.borderLineStyle = nil;
theLegend.cornerRadius = 5.0;
theLegend.hidden = NO;
// 4 - Add legend to graph
graph.legend = theLegend;
graph.legendAnchor = CPTRectAnchorBottom;
CGFloat legendPadding = 1.0;
graph.legendDisplacement = CGPointMake(legendPadding, 0.0);
scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(-5, 0, _secondView.frame.size.width, _secondView.frame.size.height + 20)];
scrollView.clipsToBounds = YES;
scrollView.userInteractionEnabled = YES;
scrollView.contentSize = CGSizeMake(_secondView.frame.size.width + 100, _secondView.frame.size.height + 400); //(scrollView.contentSize.width, 1000)
for (UIView *subView in self.secondView.subviews)
{
[subView removeFromSuperview];
}
[scrollView.layer addSublayer:self.hostView.hostedGraph.legend];
[self.secondView addSubview:scrollView];
scrollView.showsVerticalScrollIndicator = YES;
scrollView.showsHorizontalScrollIndicator = NO;
}
Since you add manually the legend view, you have this "reversed view issue".
Indeed, they draw the plots on a "reversed view", and they do the reverse. If I remember well, they do this because of the coordinates (x,y) to make it more understandable, since (x=0,y=0) should be at the left corner up, which is not how you usually do your graph.
So the solution, is to reverse it:
[[yourTitleView layer] setTransform:CATransform3DMakeRotation(M_PI, 1, 0, 0)];