Arbeide med CorePlot Opprette et kakediagram

Når du arbeider med dataintensive applikasjoner, må en utvikler ofte gjøre mer enn bare å vise lister over dataposter i en tabellvisning. CorePlot-biblioteket lar deg legge til fantastiske datavisualiseringer i dine applikasjoner. Finn ut hvordan i denne Tuts + Premium-serien!


Også tilgjengelig i denne serien:

  1. Arbeide med CorePlot: Prosjektoppsett
  2. Arbeide med CorePlot: Plot Fundamentals
  3. Arbeider med CorePlot: Styling og Add Plots
  4. Arbeide med CorePlot: Opprette et strekdiagram
  5. Arbeide med CorePlot: Opprette et kakediagram

Hvor vi forlot

Sist gang vi kom inn på hvordan du oppretter et strekdiagram, hvordan du tilpasser stangfarger og hvordan du legger til egendefinerte etiketter på aksen hvis vi vil vise egendefinert tekst i stedet for bare tall.


Hva vi skal dekke i dag

Denne gangen vil vi dekke hvordan vi abstrakt logikken ut av vår kontroller til et mer gjenbrukbart datakildeobjekt. Når vi har mestret dette, går vi over hvordan du viser de samme dataene som linjediagrammet, bortsett fra denne gangen vises det som en kakediagram!


Trinn 1: Oppsett

Før vi kommer inn i abstrahering av datalogikken, skal vi lage våre grunnklasser for kakediagrammet. På samme måte som forrige gang, må vi opprette en ny visningskontroller for grafen. La oss kalle det 'STPieGraphViewController'.


Legg merke til at vi ikke trenger å lage en visning denne gangen fordi vi vil kunne bruke 'STGraphView'. Før vi begynner å sette opp ting, la oss hoppe inn i STStudentListViewController.h og importere STPieGraphViewController.h. Vi må også overholde protokollen STPieGraphViewControllerDelegate (som vi vil lage senere):

 @interface STStudentListViewController: UIViewController 

Bytt til .m-filen. Vi må legge til en knapp i handlingsarket. Finn metoden graphButtonWasSelected:. Vi skal redigere den andre knappeteksten og legge til en tredje:

 - (ugyldig) graphButtonWasSelected: (id) avsender UIActionSheet * graphSelectionActionSheet = [[[UIActionSheet alloc] initWithTitle: @ "Velg en graf" delegert: self cancelButtonTitle: @ "Cancel" destructiveButtonTitle: ingen andreButtonTitles: @ "Registrering over tid" "Emne totaler - Bar", @ "Emne totaler - Pie", null) autorelease]; [graphSelectionActionSheet showInView: [[UIApplication sharedApplication] keyWindow]]; 

Nå hoppe inn i actionSheet: clickedButtonAtIndex: metode og legg til en klausul for buttonIndex == 2:

 ellers hvis (buttonIndex == 2) STPieGraphViewController * graphVC = [[STPieGraphViewController alloc] init]; [graphVC setModalTransitionStyle: UIModalTransitionStyleFlipHorizontal]; [graphVC setModalPresentationStyle: UIModalPresentationFullScreen]; [graphVC setDelegate: self]; [graphVC setManagedObjectContext: [self managedObjectContext]]; [self presentModalViewController: graphVC animated: YES]; [graphVC release]; 

På samme måte som forrige gang, vil det vise noen advarsler fordi STPieGraphViewController ikke har en delegat eller managedObjectContext-egenskap.

Så hopp inn i STPieGraphViewController.h. Importer 'CorePlot-CocoaTouch.h' og legg til følgende egenskaper og protokolldeklarasjoner:

 @protocol STPieGraphViewControllerDelegate @required - (void) doneButtonWasTapped: (id) avsender; @end @interface STPieGraphViewController: UIViewController  @property (nonatomic, strong) CPTGraph * graf; @property (nonatomic, assign) id delegat; @property (nonatomic, strong) NSManagedObjectContext * managedObjectContext; @slutt

Det er viktig å påpeke at vi ikke overholder CPTPieChartDataSource denne gangen. Dette skyldes at vi skal abstrahere grafdatalogikken fra STBarGraphViewController til en egen datakildeklasse. Før vi gjør det skjønt, la oss fullføre oppsettet. I .m-filen, importere 'STGraphView.h', syntetiser egenskapene og implementer deallokmetoden.

Endelig sett opp loadView og viewDidLoad-metodene som nedenfor:

 - (ugyldig) loadView [super loadView]; [self setTitle: @ "Registrering etter emne"]; [self setView: [[[STGraphView alloc] initWithFrame: self.view.frame] autorelease]]; CPTTheme * defaultTheme = [CPTTheme themeNamed: kCPTPlainWhiteTheme]; [self setGraph: (CPTGraph *) [defaultTheme newGraph]];  - (void) viewDidLoad [super viewDidLoad]; STGraphView * graphView = (STGraphView *) [selvvisning]; [[graphView chartHostingView] setHostedGraph: [selvgrafikk]]; // Tillat brukeren å gå tilbake UINavigationItem * navigationItem = [[[UINavigationItem alloc] initWithTitle: self.title] autorelease]; [navigasjonItem setHidesBackButton: JA]; UINavigationBar * navigationBar = [[[UINavigationBar alloc] initWithFrame: CGRectMake (0, 0, self.view.frame.size.width, 44.0f)] autorelease]; [navigasjonBar pushNavigationItem: navigasjonItem animert: NEI]; [self.view addSubview: navigasjonBar]; [navigasjonItem setRightBarButtonItem: [[[UIBarButtonItem alloc] initWithTitle: @ "Ferdig" stil: UIBarButtonItemStyleDone mål: [self delegate] handling: @selector (doneButtonWasTapped :)] autorelease] animated: NO]; 

Ovenstående skal være kjent nå. Så la oss se på å abstrahere graflogikken til en egen klasse.


Trinn 2: Separere graflogikken

Vi har allerede skrevet logikken for å få data for totalt antall studenter i alle fagene; Vi ønsker ikke å skrive det igjen, heldigvis behøver vi ikke. Alle datakilde protokollene for plottene arve fra 'CPTPlotDataSource', og det er denne protokollen som inneholder numberOfRecordsForPlot: og numberForPlot: fieldEnum: recordIndex metoder.

Opprett en klasse som heter 'STAbstractSubjectDataSource.h' (arve fra NSObject) i en ny gruppe kalt 'DataSource' i grafegruppen. For headerfilen importerer 'CorePlot-CocoaTouch.h' og legger til følgende egenskaper og metodedeklarasjoner:

 @interface STAbstractSubjectEnrollementDataSource: NSObject  @property (nonatomic, strong) NSManagedObjectContext * managedObjectContext; - (id) initWithManagedObjectContext: (NSManagedObjectContext *) aManagedObjectContext; - (float) getTotalSubjects; - (float) getMaxEnrolled; - (NSArray *) getSubjectTitlesAsArray; @slutt

Vi abonnerer på protokollen 'CPTPlotDataSource'. Vi lager en tilpasset init metode som går gjennom en managedObjectContext slik at objektet kan få tilgang til datalageret. Til slutt er det tre hjelpemetoder som kan hjelpe deg med å få informasjon om emner og innmelding. Dette er de samme metodene som eksisterer i STBarGraphViewController. Vi skal flytte de ut og inn i datakildemetoden.

Bortsett fra init-metoden inneholder ikke .m-filen noen ny kode som du ikke har sett før. Det handler bare om å flytte all eksisterende kode fra STBarGraphViewController til dataSource-objektet. Metodene du bør flytte er:

  • (float) getTotalSubjects
  • (Float) getMaxEnrolled
  • (NSArray *) getSubjectTitlesAsArray
  • (NSUInteger) numberOfRecordsForPlot: (CPTPlot *) plot
  • (NSNummer *) numberForPlot: (CPTPlot *) plottfelt: (NSUInteger) -feltEn recordIndex: (NSUInteger) indeks

Pass også på at du legger til i den tilpassede init-metoden:

 - (id) initWithManagedObjectContext: (NSManagedObjectContext *) aManagedObjectContext self = [super init]; hvis (selv) [self setManagedObjectContext: aManagedObjectContext];  returner selv; 

Nå har vi et datakildeobjekt som kan gi basisdataene for både kaken og stangtabellen. Den abstrakte datakilden gir oss ikke alt vi trenger, men barFillForBarPlot: recordIndex kan ikke implementeres fordi det er en del av CPTBarPlotDataSource. Vi må utvide vår abstrakte klasse til noe spesifikt for barplott.

Opprett et nytt objekt i datakildegruppen som heter 'STBarGraphSubjectEnrollementDataSource' som utvider vår abstrakte klasse. I overskriften abonnerer du på 'CPTBarPlotDataSource:

 - (id) initWithManagedObjectContext: (NSManagedObjectContext *) aManagedObjectContext @interface STBarGraphSubjectEnrollementDataSource: STAbstractSubjectEnrollementDataSource 

Og i .m-filen, implementer barFillForBarPlot-metoden:

 #pragma mark - CPTBarPlotDataSource Methods - (CPTFill *) barFillForBarPlot: (CPTBarPlot *) barPlot recordIndex: (NSUInteger) indeks CPTColor * areaColor = nil; bytte (indeks) case 0: areaColor = [CPTColor redColor]; gå i stykker; tilfelle 1: areaColor = [CPTColor blueColor]; gå i stykker; tilfelle 2: areaColor = [CPTColor orangeColor]; gå i stykker; tilfelle 3: areaColor = [CPTColor greenColor]; gå i stykker; standard: areaColor = [CPTColor purpleColor]; gå i stykker;  CPTFill * barFill = [CPTFill fillWithColor: areaColor]; return barFill; 

Gå nå tilbake til STBarGraphViewControllers header-filen og importer den nye bargrafikkdatakilden. Du kan nå fjerne 'CPTBarPlotDataSource' abonnementet. Hopp inn i .m filen og slett alle metoder unntatt loadView, viewDidLoad og dealloc. Vi trenger dem ikke lenger.

Vi må opprettholde en peker til datakilden og deretter slippe pekeren når visningen er ferdig med den. I det private grensesnittet erklærer du eiendommen og deretter syntetiserer:

 @interface STBarGraphViewController () @property (ikkeatomisk, behold) STBarGraphSubjectEnrollementDataSource * barGraphDataSource; @end @implementation STBarGraphViewController @synthesize delegate; @synthesize managedObjectContext; @synthesize graph; @synthesize barGraphDataSource;

Pass på at du slipper den i deallokmetoden også. Opprett en ny forekomst og sett den som vår eiendom i loadView-metoden:

 [self setBarGraphDataSource: [[[STBarGraphSubjectEnrollementDataSource alloc] initWithManagedObjectContext: [self managedObjectContext]] autorelease]];

Nå i viewDidLoad-metoden må vi bruke hjelpekildens hjelpemetoder for å beregne tomtplassen og de egendefinerte etikettene:

 CPTXYPlotSpace * studentPlotSpace = (CPTXYPlotSpace *) [graph defaultPlotSpace]; [studentPlotSpace setXRange: [CPTPlotRange plotRangeWithLocation: CPTDecimalFromInt (0) lengde: CPTDecimalFromInt ([[self barGraphDataSource] getTotalSubjects] + 1)]]; [studentPlotSpace setYRange: [CPTPlotRange plotRangeWithLocation: CPTDecimalFromInt (0) lengde: CPTDecimalFromInt ([[self barGraphDataSource] getMaxEnrolled] + 1)]];
 NSArray * subjectsArray = [[self barGraphDataSource] getSubjectTitlesAsArray];

Lagre, bygge og kjøre. Alt skal fungere som før. Hvis det gjør det, kan vi komme i gang med å lage vår kaken grafikk!


Trinn 3: Opprette Pie Graph

Vi vil opprette en bestemt datakilde for kakediagrammet, akkurat som vi gjorde for linjediagrammet, dersom vi trenger å implementere spesifikke datakildemetoder for kakediagram. Opprett en klasse kalt 'STPieGraphSubjectEnrollementDataSource' som arver fra 'STAbstractSubjectEnrollementDataSource'. I headerfilen, abonner på protokollen 'CPTPieChartDataSource'. Vi vil ikke implementere noen spesifikke kai-kart datakildemetoder ennå, vi kommer tilbake til det senere.

Nå som vi har datakilder, er det enkelt å lage kaken grafen! Hopp inn i STBPieGraphViewController.m og importer inn kildegrafikkdatakildobjektet. Erklære det som en eiendom i .m-filen, som vi gjorde sist:

 @interface STPieGraphViewController () @property (ikkeatomisk, sterk) STPieGraphSubjectEnrollementDataSource * pieChartDataSource; @end @implementation STPieGraphViewController @synthesize managedObjectContext; @synthesize delegat; @synthesize graph; @synthesize pieChartDataSource;

Opprett og sett det nå i loadView:

 [self setPieChartDataSource: [[[STPieGraphSubjectEnrollementDataSource alloc] initWithManagedObjectContext: [self managedObjectContext]] autorelease]];

Til slutt, i viewDidLoad-metoden trenger vi å opprette vårt tårnkart, legg det til vår GraphView og fjern standardaksen:

 STGraphView * graphView = (STGraphView *) [selvvisning]; [[graphView chartHostingView] setHostedGraph: [selvgrafikk]]; CPTPieChart * pieChart = [[CPTPieChart alloker] initWithFrame: [graph bounds]]; [pieChart setPieRadius: 100,00]; [pieChart setIdentifier: @ "Subject"]; [pieChart setStartAngle: M_PI_4]; [pieChart setSliceDirection: CPTPieDirectionCounterClockwise]; [pieChart setDataSource: pieChartDataSource]; [graph addPlot: pieChart]; [graf setAxisSet: null]; [graf settBorderLineStyle: null];

De fleste av de ovennevnte bør se kjent ut. Legg merke til at det ikke er eksplisitt kalt et "plott" fordi det ikke stole på en x-akse eller y-akse, men vi behandler det fortsatt mye det samme. Det er noen kakediagramspesifikke ting vi også gjør her. Vi lager en pairadius og startvinkel. Vi satte også en skiveretning. Endelig setter vi 'axisSet' av grafen til null slik at vi ikke får x- og y-linjene.

Og det burde være alt. Bygg og løp for å se kaken din.


Dette er bra, men det kan gjøre med en slags indikasjon på hva hver farge representerer. En god måte å gjøre dette på er å bruke legender. For å gjøre dette oppretter vi et "CPTLegend" -objekt som vi legger til i grafen vår, og implementerer en delegatemetode som returnerer den aktuelle tittelen for legenden.

La oss lage CPTLegend-objektet først. I vår viewDidLoad-metode legger du inn følgende kode under der vi oppretter vårt kakediagram:

 CPTLegend * theLegend = [CPTLegend legendWithGraph: [selvgraf]]; [theLegend setNumberOfColumns: 2]; [[selvgrafikk] setLegend: theLegend]; [[selvgrafikk] setLegendAnchor: CPTRectAnchorBottom]; [[selvgrafikk] setLegendDisplacement: CGPointMake (0.0, 30.0)];

Dette skaper en legende og legger den til vår grafobjekt. Antall kolonner bestemmer hvordan det vil legge ut legendets titler. Vi angir deretter noen attributter på grafobjektet som bestemmer hvor legenden skal plasseres (bunnen) og noen forskyvning for å sikre at den viser fullt ut i visningen.

Vi trenger fortsatt å gi legen med titler skjønt. Det er en metode spesifikk for CPTPieChartDataSource som lar oss gjøre dette. Gå inn i kakediagramdatakilden og implementer følgende kode:

 #pragma mark - CPTPieChartDataSource - (NSString *) legendTitleForPieChart: (CPTPieChart *) pieChart recordIndex: (NSUInteger) indeks NSError * error = nil; NSFetchRequest * request = [[NSFetchRequest alloker] init]; NSEntityDescription * entity = [NSEntityDescription entityForName: @ "STSubject" inManagedObjectContext: [self managedObjectContext]]; NSPredicate * predicate = [NSPredicate predicateWithFormat: @ "subjectID ==% d", indeks]; [be om setEntity: entity]; [forespørsel setResultType: NSDictionaryResultType]; [request setPredicate: predicate]; [request setReturnsDistinctResults: NO]; [request setPropertiesToFetch: [NSArray arrayWithObject: @ "subjectName"]]; NSArray * titleStrings = [[self managedObjectContext] executeFetchRequest: forespørselfeil: & feil]; NSDictionary * fetchedSubject = [titleStrings objectAtIndex: 0]; returnere [fetchedSubject objectForKey: @ "subjectName"]; 

Denne metoden får bare indeksen til legenden og får tittelen fra datalageret som en streng og returnerer den.

Bygg og kjør, og du bør ha en informativ kaken graf!



Wrap up

Vi har dekket hvordan å abonnere datalogikken fra kontrolleren til en egen gjenstand som er enklere å administrere og utvide. Vi har også dekket grunnleggende om å lage et kakediagram.

Det bringer oss til slutten av serien. Jeg håper du har funnet disse opplæringene nyttige. Det er mye mer som CorePlot kan gjøre, men dette bør gi deg et solid grunnlag for å bygge på. Lykke til å legge til grafer til dine egne prosjekter!