bars independent on shinobi chart

126 views Asked by At

Using shinobi charts, is there any of the existing series that can be combine or tweak like the graph image below?

Its basically bars that are independent on chart, they do NOT start a 0.

(optional) that each bar has a bottom and top label.

Thank you in advance!

enter image description here

2

There are 2 answers

0
LuAndre On

Resolved the problem by combing Scatter Series and Line Series

Still need some tweaking but its worked enter image description here

View Controller .h file

@interface ScatterHRModifiedLineViewController : UIViewController<SChartDelegate>

@property (weak, nonatomic) IBOutlet UIView *chartView;

@end

View Controller .m file

#import "ScatterHRModifiedLineViewController.h"
#import "ScatterHRModifiedLineGraphDataSource.h"

@interface ScatterHRModifiedLineViewController ()

@property (strong, nonatomic) ScatterHRModifiedLineGraphDataSource *datasource;
@property (strong, nonatomic) ShinobiChart *chart;
@property (assign, nonatomic) CGRect chartFrame;

@end


@implementation ScatterHRModifiedLineViewController

@synthesize chartView;

//MARK: - Lifecycle
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    //chart init
    CGFloat margin = UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone ? 10.0 : 30.0;
    self.chart = [[ShinobiChart alloc] initWithFrame:CGRectInset(self.chartView.bounds, margin, margin)];

    [self.chartView addSubview:self.chart];
    self.chart.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

    //data source setup
    self.datasource = [[ScatterHRModifiedLineGraphDataSource alloc]init];
    self.chart .datasource = self.datasource;

    [self setupChart];
    [self setupTheme];
    [self setupHorizontalLegend];
}//eom

-(void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];

    self.chart= nil;
    self.datasource = nil;
}//eom

#pragma mark - Setup
-(void)setupChart
{
    self.chart.title = @"Heart Rates chart";

    self.chart.delegate = self;

    self.chart.crosshair = [[SChartSeriesCrosshair alloc]init];

    //Legend
    self.chart.legend.hidden = YES;

    //License Key
    self.chart.licenseKey = [[Constants shared] getLicenseKey];

    /* X Axis */
    self.chart.xAxis = [SChartDateTimeAxis new];
    self.chart.xAxis.title = @"Date";
    self.chart.xAxis.labelFormatString = @"MM dd yy";
    self.chart.xAxis.defaultRange = [self.datasource getInitialDateRange];
    self.chart.xAxis.style.majorGridLineStyle.showMajorGridLines = YES;
    self.chart.xAxis.style.majorTickStyle.showLabels = NO;
    self.chart.xAxis.style.majorTickStyle.showTicks = YES;
    self.chart.xAxis.style.minorTickStyle.showTicks = YES;
    self.chart.xAxis.majorTickFrequency = [[SChartDateFrequency alloc]initWithDay:2];

    //axis movement
    self.chart.xAxis.enableGesturePanning = YES;
    self.chart.xAxis.enableGestureZooming = YES;
    self.chart.xAxis.enableMomentumPanning = YES;
    self.chart.xAxis.enableMomentumZooming = YES;


    /* Y Axis */
    self.chart.yAxis = [SChartNumberAxis new];
    self.chart.yAxis.defaultRange = [[SChartRange alloc]initWithMinimum:@60 andMaximum:@120];;
    self.chart.yAxis.title = @"Heart Rates";
    self.chart.yAxis.majorTickFrequency = @1;
    self.chart.yAxis.style.majorGridLineStyle.showMajorGridLines = YES;
    self.chart.yAxis.style.majorTickStyle.showLabels = NO;
    self.chart.yAxis.style.majorTickStyle.showTicks = YES;
    self.chart.yAxis.style.minorTickStyle.showTicks = YES;

    //axis movement
    self.chart.yAxis.enableGesturePanning = NO;
    self.chart.yAxis.enableGestureZooming = NO;
    self.chart.yAxis.enableMomentumPanning = NO;
    self.chart.yAxis.enableMomentumZooming = NO;


}//eom

-(void)setupTheme
{
    SChartTheme * theme = [SChartiOS7Theme new];

    UIColor *darkGrayColor = [UIColor colorWithRed:83.0/255 green:96.0/255 blue:107.0/255 alpha:1];
    theme.chartTitleStyle.font = [UIFont systemFontOfSize:18];
    theme.chartTitleStyle.textColor = darkGrayColor;
    theme.chartTitleStyle.titleCentresOn = SChartTitleCentresOnChart;
    theme.chartStyle.backgroundColor = [UIColor whiteColor];
    theme.legendStyle.borderWidth = 0;
    theme.legendStyle.font = [UIFont systemFontOfSize:16];
    theme.legendStyle.titleFontColor = darkGrayColor;
    theme.legendStyle.fontColor = darkGrayColor;
    theme.crosshairStyle.defaultFont = [UIFont systemFontOfSize:14];
    theme.crosshairStyle.defaultTextColor = darkGrayColor;

    [self styleAxisStyle:theme.xAxisStyle useLightLabelFont:YES];
    [self styleAxisStyle:theme.yAxisStyle useLightLabelFont:YES];
    [self styleAxisStyle:theme.xAxisRadialStyle useLightLabelFont:NO];
    [self styleAxisStyle:theme.yAxisRadialStyle useLightLabelFont:NO];


    [self.chart applyTheme:theme];
}//eom

#pragma mark - Setup Helpers
- (void)styleAxisStyle:(SChartAxisStyle *)style useLightLabelFont:(BOOL)useLightLabelFont
{
    UIColor *darkGrayColor = [UIColor colorWithRed:83.0/255 green:96.0/255 blue:107.0/255 alpha:1];

    style.titleStyle.font = [UIFont systemFontOfSize:16];
    style.titleStyle.textColor = darkGrayColor;
    if (useLightLabelFont) {
        style.majorTickStyle.labelFont = [UIFont systemFontOfSize:14];
    } else {
        style.majorTickStyle.labelFont = [UIFont systemFontOfSize:14];
    }
    style.majorTickStyle.labelColor = style.titleStyle.textColor;
    style.majorTickStyle.lineColor = style.titleStyle.textColor;
    style.lineColor = style.titleStyle.textColor;
}//eom

- (void)setupHorizontalLegend
{
    self.chart.legend.hidden = NO;

    self.chart.legend.style.orientation = SChartLegendOrientationHorizontal;
    self.chart.legend.style.horizontalPadding = @10;
    self.chart.legend.position = SChartLegendPositionBottomMiddle;
    self.chart.legend.style.symbolAlignment = SChartSeriesLegendAlignSymbolsLeft;
    self.chart.legend.style.textAlignment = NSTextAlignmentLeft;
}//eom

Data Source .h file

#import <Foundation/Foundation.h>
#import <ShinobiCharts/ShinobiCharts.h>

@interface ScatterHRModifiedLineGraphDataSource : NSObject<SChartDatasource>


-(SChartDateRange *)getInitialDateRange;

@property (nonatomic, strong) NSArray *dataCollection;
@property (nonatomic, strong) NSArray *afterData;
@property (nonatomic, strong) NSArray *beforeData;
@property (nonatomic, strong) NSArray *seriesNames;
@property (nonatomic, strong) NSDateFormatter *dateFormatter;

@end

Data Source .m file

    #import "ScatterHRModifiedLineGraphDataSource.h"

@implementation ScatterHRModifiedLineGraphDataSource


-(id)init {
    if(self = [super init])
    {
        self.seriesNames = @[@"before", @"after"];

        //date formatter
        self.dateFormatter = [[NSDateFormatter alloc]init];
        [self.dateFormatter setDateFormat:@"MM-dd-yyyy"];

        //data
        NSString *path = [[NSBundle mainBundle] pathForResource:@"scatter-HRModified-data" ofType:@"plist"];
        if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
            NSArray * tempData = [[NSMutableArray alloc] initWithContentsOfFile:path];

            if ( [tempData count] == 2)
            {
                self.dataCollection = tempData;
                self.beforeData = [self.dataCollection objectAtIndex:0];
                self.afterData = [self.dataCollection objectAtIndex:1];

                NSLog(@"Data: %@", self.dataCollection);
            }
        }

    }
    return self;
}

#pragma mark - Graph Helpers

//assuming all data points have the same dates
-(NSDate *)getDateFromIndex:(NSInteger)index
{
    NSDate * date = [NSDate date];
    if (index < [self.afterData count])
    {
        NSDictionary * dateData = [self.afterData objectAtIndex:index];
        NSString * dateString = [dateData objectForKey:@"Date"];
        date = [self.dateFormatter dateFromString:dateString];
    }

    return date;
}//eom

-(id)getBeforeHeartRateValueForIndex:(NSInteger)dataIndex
{
    NSDictionary * currData = self.beforeData[dataIndex];

    id yValue = currData[@"Value"];

    return yValue;
}//eom


-(id)getAfterHeartRateValueForIndex:(NSInteger)dataIndex
{
    NSDictionary * currData = self.afterData[dataIndex];

    id yValue = currData[@"Value"];

    return yValue;
}//eom


#pragma mark - Multi part methods
-(SChartDateRange *)getInitialDateRange
{
    NSInteger lastIndex = [self.afterData count];
    lastIndex = lastIndex-1;

    NSDate * minDate = [self getDateFromIndex:0];
    NSDate * maxDate = [self getDateFromIndex:lastIndex];
    SChartDateRange * range = [[SChartDateRange alloc]initWithDateMinimum:minDate andDateMaximum:maxDate];

    return range;
}//eom

#pragma mark - Datasource methods
-(NSInteger)numberOfSeriesInSChart:(ShinobiChart *)chart
{
    NSInteger total = 0;

    //making sure data is avaliable
    if ([self.afterData count] > 0) {
        total = 2 + [self.afterData count];
    }

    return total;
}//eom

-(SChartSeries *)sChart:(ShinobiChart *)chart seriesAtIndex:(NSInteger)index
{
    UIColor * shinobiBlueColor = [UIColor colorWithRed:1/255.f *.8 green:122/255.f *.8 blue:255/255.f *.8 alpha:1.f];
    UIColor * shinobiGreenColor = [UIColor colorWithRed:76/255.f *.8 green:217/255.f *.8 blue:100/255.f *.8 alpha:1.f];
    UIColor * lightGrayColor = [UIColor colorWithRed:238/255.f  green:238/255.f blue:238/255.f alpha:1.0f];

    SChartSeries * series = nil;

    //scatter
    if (index < 2)
    {
        NSString * seriesTitle;
        UIColor * seriesColor;

        if (index == 0)
        {
            seriesTitle = @"Before";
            seriesColor =  shinobiBlueColor;
        }
        else {
            seriesTitle = @"After";
            seriesColor = shinobiGreenColor;
        }

        SChartScatterSeries * beforeAndAfterSeries = [SChartScatterSeries new];

        //Styling
        beforeAndAfterSeries.title = seriesTitle;

        //Points
        beforeAndAfterSeries.style.pointStyle.showPoints = YES;
        beforeAndAfterSeries.style.pointStyle.radius = @10;
        beforeAndAfterSeries.style.pointStyle.innerColor = seriesColor;

        //labels
        beforeAndAfterSeries.style.dataPointLabelStyle.showLabels = YES;
        beforeAndAfterSeries.style.dataPointLabelStyle.offsetFromDataPoint = CGPointMake(0, -15);
        beforeAndAfterSeries.style.dataPointLabelStyle.displayValues = SChartDataPointLabelDisplayValuesY;


        series = beforeAndAfterSeries;
    }
    //lines
    else
    {
        SChartLineSeries * lineSeries = [SChartLineSeries new];

        SChartLineSeriesStyle * seriesStyle = [[SChartLineSeriesStyle alloc]init];
        seriesStyle.lineWidth = @3;
        seriesStyle.lineColor = [UIColor darkGrayColor];

        [lineSeries set_style:seriesStyle];

        lineSeries.showInLegend = false;


        series = lineSeries;
    }

    //crosshair
    series.crosshairEnabled = true;

    return series;
}//eom



-(id<SChartData>)sChart:(ShinobiChart *)chart
       dataPointAtIndex:(NSInteger)dataIndex
       forSeriesAtIndex:(NSInteger)seriesIndex
{
    SChartDataPoint *dp = [SChartDataPoint new];

    NSDate * date = [self getDateFromIndex:dataIndex];

    //heart rate values

    id beforeHeartRateValue = 0;
    id afterHeartRateValue = 0;
    id heartRateValue = 0;

    //scatter points
    if(seriesIndex < 2)
    {

        if (seriesIndex == 0)
        {
            heartRateValue = [self getBeforeHeartRateValueForIndex:dataIndex];;
        }
        else if (seriesIndex == 1)
        {
            heartRateValue = [self getAfterHeartRateValueForIndex:dataIndex];
        }
    }
    //lines connecting data points
    else
    {
        //series index == array index
        //data index == before or after array

        NSInteger currSeriesIndex = seriesIndex-2;
        date = [self getDateFromIndex:currSeriesIndex];


        if (dataIndex == 0)
        {
            heartRateValue = [self getBeforeHeartRateValueForIndex:currSeriesIndex];
        }
        else if (dataIndex == 1)
        {
            heartRateValue = [self getAfterHeartRateValueForIndex:currSeriesIndex];
        }
    }

    dp.xValue = date;
    dp.yValue = heartRateValue;

    return dp;
}//eom




-(NSInteger)sChart:(ShinobiChart *)chart
numberOfDataPointsForSeriesAtIndex:(NSInteger)seriesIndex
{
    //assuming all series have the same amount of data
    if (seriesIndex < 2)
    {
        return [self.afterData count];
    }
    //line series only need to high/low
    else
    {
        return 2;
    }

}//eom



@end

P list data

<plist version="1.0">
<array>
    <array>
        <dict>
            <key>Value</key>
            <integer>94</integer>
            <key>Date</key>
            <string>08-19-2016</string>
        </dict>
        <dict>
            <key>Value</key>
            <integer>90</integer>
            <key>Date</key>
            <string>08-20-2016</string>
        </dict>
        <dict>
            <key>Value</key>
            <integer>90</integer>
            <key>Date</key>
            <string>08-22-2016</string>
        </dict>
        <dict>
            <key>Value</key>
            <integer>89</integer>
            <key>Date</key>
            <string>08-23-2016</string>
        </dict>
    </array>
    <array>
        <dict>
            <key>Value</key>
            <integer>70</integer>
            <key>Date</key>
            <string>08-19-2016</string>
        </dict>
        <dict>
            <key>Value</key>
            <integer>75</integer>
            <key>Date</key>
            <string>08-20-2016</string>
        </dict>
        <dict>
            <key>Value</key>
            <integer>68</integer>
            <key>Date</key>
            <string>08-22-2016</string>
        </dict>
        <dict>
            <key>Value</key>
            <integer>87</integer>
            <key>Date</key>
            <string>08-23-2016</string>
        </dict>
    </array>
</array>
</plist>
0
MrAPolk On

DISCIAMER: I work for ShinobiControls.

I'd recommend implementing this with an SChartCandlestickSeries.

A candlestick series takes four values: high, open, low & close.

If you set the high & open value to be equal along with the low and closed value. This should produce the floating bar series you're after.