Bars independently on chart


#1

Hello all,

are any of the existing series can be combine or tweak like the graph image below?

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

Thank you in advance! 

 


#2

Hi.

Could you please have another attempt at attaching the image - it does not seem to have uploaded correctly.

Thanks,

Kai.


#3

Hi Kai,

just tried posting the image again, also paste the URL of the image.

Thanks in advance,


#4

Resolved the problem by combing Scatter Series and Line Series

   

  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 (strong, nonatomic) NSMutableArray *ranges;

    @property (assign, nonatomic) CGRect chartFrame;

    // Dictionary mapping series indices to mutable arrays of data point indices

    @property (strong, nonatomic) NSMutableDictionary *selectedDonutIndices;

    // Dictionary mapping series indices to rotation angles

    @property (strong, nonatomic) NSMutableDictionary *rotations;

    @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];

        /*

        // Save the current state

        self.chartFrame = self.chart.frame;

        self.ranges = [NSMutableArray new];

        for (SChartAxis *axis in self.chart.allAxes) 

         {

            [self.ranges addObject:axis.axisRange];

        }//eofl

        

        for (NSInteger i=0; i < self.chart.series.count; i++) 

         {

            SChartSeries* series = self.chart.series[i];

            if ([series isKindOfClass:[SChartDonutSeries class]]) 

         {

                self.rotations[@(i)] = @(((SChartDonutSeries *)series).rotation);

            }

        }//eofl

        */

        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

    

    #pragma mark - SChartDelegate methods

    //

    //- (void)sChartDidFinishLoadingData:(ShinobiChart *)chart {

    //    // Restore the previous state of the chart

    //    

    //    // Ranges first

    //    if (self.ranges)

    //    {

    //        for (int i=0; i<self.chart.allAxes.count && i<self.ranges.count; i++) {

    //            if (self.ranges[i]) {

    //                SChartRange *range = (SChartRange *)self.ranges[i];

    //                [self.chart.allAxes[i] setRangeWithMinimum:range.minimum andMaximum:range.maximum];

    //            }

    //        }

    //    }

    //    

    //    // Now donut series selection and rotation (if applicable)

    //    for (NSInteger i=0; i < self.chart.series.count; i++)

    //    {

    //        SChartSeries* series = self.chart.series[i];

    //        NSNumber *seriesIndex = @(i);

    //        if ([series isKindOfClass:[SChartDonutSeries class]] && self.selectedDonutIndices[seriesIndex])

    //        {

    //            SChartDonutSeries *donutSeries = (SChartDonutSeries *) series;

    //            for (NSNumber *index in self.selectedDonutIndices[seriesIndex])

    //            {

    //                // Grab the appropriate data point and set it to be selected

    //                // NB: the docs tell you not to modify the data in SChartSeries.dataSeries but:

    //                // a) we can’t really change the data source from here - we don’t want to have

    //                // the charts based on this superclass to concern themselves with preserving the

    //                // chart state

    //                // b) we’re not actually changing the data itself so we don’t need to worry about

    //                // inconsistencies with the data source

    //                SChartDataPoint *dp = series.dataSeries.dataPoints[[index integerValue]];

    //                dp.selected = YES;

    //            }

    //            donutSeries.style.initialRotation = self.rotations[seriesIndex];

    //        }

    //    }

    //    

    //    [self setupAfterDataLoad];

    //}//eom

    //

    //

    //- (void)sChart:(ShinobiChart *)chart

    //        toggledSelectionForRadialPoint:(SChartRadialDataPoint *)dataPoint

    //              inSeries:(SChartRadialSeries *)series

    //            atPixelCoordinate:(CGPoint)pixelPoint

    //{

    //    

    //    // Keep track of the selected indices

    //    NSNumber *seriesIndex = @([chart.series indexOfObject:series]);

    //    if (!self.selectedDonutIndices[seriesIndex])

    //    {

    //        self.selectedDonutIndices[seriesIndex] = [NSMutableArray new];

    //    }

    //    

    //    if (dataPoint.selected)

    //    {

    //        [self.selectedDonutIndices[seriesIndex] addObject:@(dataPoint.index)];

    //    } else {

    //        [self.selectedDonutIndices[seriesIndex] removeObject:@(dataPoint.index)];

    //    }

    //}//eom

    //

    //#pragma mark - Optionals

    //-(void)setupAfterDataLoad

    //{

    //

    //}//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>


#5

Hi luoandre29_hotmail,

Glad to hear you got this sorted!

Just wondered whether you had looked at the CandlestickSeries? That might be an alternative way to achieve want you want.

Kind regards,

Patrick