Lavorare con CorePlot creazione di un grafico a barre

Quando si lavora con applicazioni ad uso intensivo di dati, uno sviluppatore deve spesso fare molto di più che mostrare solo elenchi di record di dati in una vista tabella. La libreria CorePlot ti consentirà di aggiungere incredibili visualizzazioni di dati alle tue applicazioni. Scopri come in questa serie di Tuts + Premium!


Disponibile anche in questa serie:

  1. Lavorare con CorePlot: installazione del progetto
  2. Lavorare con CorePlot: Plot Fundamentals
  3. Lavorare con CorePlot: Styling e aggiunta di grafici
  4. Lavorare con CorePlot: creazione di un grafico a barre
  5. Lavorare con CorePlot: creazione di un grafico a torta

Da dove siamo partiti

L'ultima volta abbiamo esaminato come personalizzare l'aspetto e lo stile di un grafico a linee (o grafico a dispersione) utilizzando classi come CPTMutableTextStyle e CPTMutableLineStyle. Abbiamo imparato come personalizzare gli incrementi dell'asse X e Y e gli stili numerici utilizzando le classi CPTXYAxisSet e CPTXYAxis. Abbiamo anche esaminato come aggiungere più grafici al grafico e modificare i metodi dell'origine dati per fornire i dati corretti per i grafici appropriati utilizzando gli identificatori di stampa.


Cosa copriremo oggi

Oggi lavoreremo con un grafico completamente nuovo. Creeremo un grafico a barre che mostra il numero totale di studenti in ogni materia con ogni barra che rappresenta un soggetto. Vedremo anche come personalizzare l'aspetto grafico del grafico. Iniziamo!


Passaggio 1: impostazione

Per prima cosa dobbiamo aggiungere le classi rilevanti al nostro progetto. Creiamo un ViewController chiamato 'STBarGraphViewController' e un 'STGraphView'. (Assicurati di metterli nei gruppi pertinenti)


Si noti la denominazione della vista su "STGraphView" invece di "STBarGraphView". Andando avanti useremo questa vista per visualizzare la barra e i grafici a torta.

Prima di iniziare a lavorare con qualsiasi codice, dobbiamo aggiungere un pulsante al foglio Azione della nostra visualizzazione elenco studenti. Per prima cosa apri "STStudentListViewController.h" e importa STBarGraphViewController. Aggiungi STBarGraphViewControllerDelegate all'elenco dei protocolli registrati (il protocollo in realtà non esiste ancora ma lo creeremo in seguito):

 @interface STStudentListViewController: UIViewController 

Successivamente, passa al file .m e individua il metodo 'graphButtonWasSelected:'. Aggiungi 'Iscrizione per argomento' alla lista di 'otherButtonTitles:':

 UIActionSheet * graphSelectionActionSheet = [[[UIActionSheet alloc] initWithTitle: @ "Choose a graph" delegate: self cancelButtonTitle: @ "Cancel" distructiveButtonTitle: nil otherButtonTitles: @ "Enrollment over time", @ "Enrollment by subject", nil] autorelease] ;

Ora trova il metodo "actionSheet: clickkedButtonAtIndex:" e modificalo per funzionare con buttonIndex == 1:

 if (buttonIndex == 0) STLineGraphViewController * graphVC = [[STLineGraphViewController alloc] init]; [graphVC setModalTransitionStyle: UIModalTransitionStyleFlipHorizontal]; [graphVC setModalPresentationStyle: UIModalPresentationFullScreen]; [graphVC setDelegate: self]; [graphVC setManagedObjectContext: [self managedObjectContext]]; [auto presenteModalViewController: graphVC animato: YES]; [versione GraphVC];  else if (buttonIndex == 1) STBarGraphViewController * graphVC = [[STBarGraphViewController alloc] init]; [graphVC setModalTransitionStyle: UIModalTransitionStyleFlipHorizontal]; [graphVC setModalPresentationStyle: UIModalPresentationFullScreen]; [graphVC setDelegate: self]; [graphVC setManagedObjectContext: [self managedObjectContext]]; [auto presenteModalViewController: graphVC animato: YES]; [versione GraphVC]; 

Di nuovo, questo mostrerà alcuni avvertimenti perché non abbiamo ancora implementato le proprietà delegate o managedObjectContext su STBarGraphViewController.

Ora salta in STBarGraphViewController.h. Importa CorePlot-CocoaTouch.h e aggiungi la seguente dichiarazione di proprietà:

 @protocol STBarGraphViewControllerDelegate @required - (void) doneButtonWasTapped: (id) mittente; @fine

Ora aggiungi le seguenti proprietà:

 @property (nonatomic, strong) grafico CPTGraph *; @property (nonatomic, assegna) id delegare; @property (nonatomic, strong) NSManagedObjectContext * managedObjectContext;

Infine, registra che questa classe seguirà questi protocolli:

 @interface STBarGraphViewController: UIViewController 

Si noti che, oltre a conformarsi a protocolli diversi, questa classe è la stessa di STLineViewController. Idealmente, si avrebbe una classe base che avrebbe queste proprietà che si sarebbero sottoclasse per ridurre la ripetizione del codice. Questo tutorial si concentra solo sulla trama principale, quindi ci concentriamo solo sul modo migliore di lavorare con il framework CorePlot. Se hai le conoscenze e il tempo, sentiti libero di creare la classe base e utilizzare l'ereditarietà, ma lo terremo nel codice di esempio qui.

Successivamente, passa al file .m, sintetizza le proprietà e rilascialo nel metodo dealloc.

Ora colleghiamo la classe vista come vista del controllore. Importa "STBarGraphView.h" e aggiungi il seguente metodo:

 - (void) loadView [super loadView]; [Self setTitle: @ "Iscrizione per argomento"]; [self setView: [[[STGraphView alloc] initWithFrame: self.view.frame] autorelease]]; CPTTheme * defaultTheme = [CPTTheme themeNamed: kCPTPlainWhiteTheme]; [self setGraph: (CPTGraph *) [defaultTheme newGraph]]; 

Ora siamo pronti per lavorare con la vista. Aprire STGraphView.h, importare il framework del core plot (CorePlot-CocoaTouch.h) e aggiungere la seguente dichiarazione di proprietà:

 @property (nonatomic, strong) CPTGraphHostingView * chartHostingView;

Salta in .m, sintetizza la proprietà e rilascia la proprietà nel metodo dealloc. Quindi crea il CPTGraphHostingView nel metodo 'initWithFrame:':

 - (id) initWithFrame: (CGRect) frame self = [super initWithFrame: frame]; if (self) [self setChartHostingView: [[[CPTGraphHostingView alloc] initWithFrame: CGRectZero] autorelease]]; [chartHostingView setBackgroundColor: [UIColor purpleColor]]; [self addSubview: chartHostingView];  return self; 

Infine, crea il metodo "layoutSubviews" con il seguente codice:

 - (vuoto) layoutSubviews [super layoutSubviews]; float chartHeight = self.frame.size.height; float chartWidth = self.frame.size.width; [[self chartHostingView] setFrame: CGRectMake (0, 0, chartWidth, chartHeight)]; [[self chartHostingView] setCenter: [centro auto]]; 

Noterai che il codice utilizzato per creare questa vista è esattamente lo stesso di STLineGraphView. Possiamo utilizzare questa vista di base per lavorare con tutte le viste del grafico in futuro.

Torna alla vista 'STBarGraphViewController.m' e individua il metodo 'viewDidLoad'. Per prima cosa, vogliamo creare un CPTBarPlot e aggiungerlo al nostro grafico:

 [[graphView chartHostingView] setHostedGraph: [grafico autonomo]]; CPTBarPlot * subjectBarPlot = [[Allocazione CPTBarPlot] initWithFrame: [limiti del grafico]]; [subjectBarPlot setIdentifier: @ "subjectEnrollement"]; [subjectBarPlot setDelegate: self]; [subjectBarPlot setDataSource: self]; [[auto grafico] addPlot: subjectBarPlot];

Infine, aggiungiamo una barra di navigazione con un pulsante eseguito, in modo che l'utente possa tornare:

 UINavigationItem * navigationItem = [[[UINavigationItem alloc] initWithTitle: self.title] autorelease]; [navigationItem setHidesBackButton: YES]; UINavigationBar * navigationBar = [[[UINavigationBar alloc] initWithFrame: CGRectMake (0, 0, self.view.frame.size.width, 44.0f)] autorelease]; [navigationBar pushNavigationItem: navigationItem animato: NO]; [self.view addSubview: navigationBar]; [navigationItem setRightBarButtonItem: [[[UIBarButtonItem alloc] initWithTitle: @ Stile "Done": UIBarButtonItemStyleDone target: [self delegate] action: @selector (doneButtonWasTapped :)] autorelease] animato: NO];

Ora iniziamo a lavorare sui metodi dell'origine dati:


Passaggio 2: dare i dati del grafico a barre

Il processo sarà simile a come abbiamo creato il grafico a linee, ma renderemo le cose un po 'più dinamiche. Creeremo metodi personalizzati che forniranno uno spazio di trama appropriato. Aggiungiamo anche alcuni metodi aggiuntivi di origine dati per fornire un colore specifico per ogni barra e titoli per l'asse x.

Prima di esaminare i dati del grafico, è necessario impostare l'asse e gli intervalli visibili. Per fare questo abbiamo bisogno di due metodi che calcolano il massimo x e il massimo y. Dichiarare i seguenti metodi all'inizio del file .m:

 [[graphView chartHostingView] setHostedGraph: [grafico autonomo]]; @interface STBarGraphViewController () - (float) getTotalSubjects; - (float) getMaxEnrolled; @fine

Ora implementali come di seguito:

 #pragma mark - Private Methods - (float) getTotalSubjects NSError * error = nil; NSFetchRequest * fetchRequest = [[[NSFetchRequest alloc] init] autorelease]; NSEntityDescription * entity = [NSEntityDescription entityForName: @ "STSubject" inManagedObjectContext: managedObjectContext]; [fetchRequest setEntity: entity]; return [managedObjectContext countForFetchRequest: fetchRequest error: & error];  - (float) getMaxEnrolled float maxEnrolled = 0; NSError * error = nil; per (int i = 0; i < [self getTotalSubjects]; i++)  NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; NSEntityDescription *entity = [NSEntityDescription entityForName:@"STStudent" inManagedObjectContext:managedObjectContext]; NSPredicate *predicate = [NSPredicate predicateWithFormat:@"subjectID == %d", i]; [fetchRequest setEntity:entity]; [fetchRequest setPredicate:predicate]; float subjectMax = [managedObjectContext countForFetchRequest:fetchRequest error:&error]; NSLog(@"enrolled for Subject %d is %f", i, subjectMax); [fetchRequest release]; if (subjectMax > maxEnrolled) maxEnrolled = subjectMax;  return maxEnrolled; 

'getTotalSubjects' ottiene semplicemente un conteggio di tutti i soggetti nell'archivio dati principale. 'getMaxEnrolled' scorre tra tutti i soggetti e cerca il numero più alto di studenti in ciascuno e restituisce il valore più alto.

Con questi metodi, possiamo tornare al nostro metodo 'viewDidLoad' e aggiungere il seguente codice qui sotto dove aggiungiamo il diagramma della barra al nostro grafico:

 CPTXYPlotSpace * studentPlotSpace = (CPTXYPlotSpace *) [grafico defaultPlotSpace]; [studentPlotSpace setXRange: [CPTPlotRange plotRangeWithLocation: CPTDecimalFromInt (0) length: CPTDecimalFromInt ([self getTotalSubjects] + 1)]]; [studentPlotSpace setYRange: [CPTPlotRange plotRangeWithLocation: CPTDecimalFromInt (0) length: CPTDecimalFromInt ([self getMaxEnrolled] + 1)]]; [[grafico plotAreaFrame] setPaddingLeft: 40.0f]; [[grafico plotAreaFrame] setPaddingTop: 10.0f]; [[grafico plotAreaFrame] setPaddingBottom: 120.0f]; [[grafico plotAreaFrame] setPaddingRight: 0.0f]; [[grafico plotAreaFrame] setBorderLineStyle: nil]; CPTMutableTextStyle * textStyle = [CPTMutableTextStyle textStyle]; [textStyle setFontSize: 12.0f]; [textStyle setColor: [CPTColor colorWithCGColor: [[UIColor grayColor] CGColor]]]; CPTXYAxisSet * axisSet = (CPTXYAxisSet *) [grafico axisSet]; CPTXYAxis * xAxis = [axisSet xAxis]; [xAxis setMajorIntervalLength: CPTDecimalFromInt (1)]; [xAxis setMinorTickLineStyle: nil]; [xAxis setLabelingPolicy: CPTAxisLabelingPolicyFixedInterval]; [xAxis setLabelTextStyle: textStyle]; CPTXYAxis * yAxis = [axisSet yAxis]; [yAxis setMajorIntervalLength: CPTDecimalFromInt (1)]; [yAxis setMinorTickLineStyle: nil]; [yAxis setLabelingPolicy: CPTAxisLabelingPolicyFixedInterval];

La maggior parte di quanto riportato sopra dovrebbe essere familiare dall'ultima volta, tuttavia, invece di impostare valori codificati rigidi per la lunghezza massima del nostro plottaggio x e y, stiamo usando i nostri nuovi metodi per creare dinamicamente i valori. Dopodiché, impostiamo solo una formattazione degli assi di base e diamo un po 'di padding al frame plot in modo che l'asse sia mostrato in modo appropriato.

Ora dobbiamo fornire al grafico i dati utilizzando i metodi dell'origine dati. Fornire il numero di record è semplice:

 #pragma mark - CPTBarPlotDataSourceMethods - (NSUInteger) numberOfRecordsForPlot: (CPTPlot *) plot return [self getTotalSubjects]; 

Ora per fornire i valori x e y per i record:

 - (NSNumber *) numberForPlot: (CPTPlot *) campo di trama: (NSUInteger) fieldEnum recordIndex: (NSUInteger) index int x = index + 1; int y = 0; Errore NSError *; NSFetchRequest * fetchRequest = [[NSFetchRequest alloc] init]; NSEntityDescription * entity = [NSEntityDescription entityForName: @ "STStudent" inManagedObjectContext: managedObjectContext]; NSPredicate * predicate = [NSPredicate predicateWithFormat: @ "subjectID ==% d", index]; [fetchRequest setEntity: entity]; [fetchRequest setPredicate: predicate]; y = [managedObjectContext countForFetchRequest: fetchRequest error: & error]; [versione fetchRequest]; switch (fieldEnum) case CPTScatterPlotFieldX: return [NSNumber numberWithInt: x]; rompere; case CPTScatterPlotFieldY: return [NSNumber numberWithInt: y]; rompere; default: break;  return nil; 

Il metodo di cui sopra è molto simile a come forniamo i dati a un grafico a dispersione. Modifichiamo la chiamata all'archivio dati in modo da ottenere il conteggio di tutti gli studenti iscritti a un argomento. Impostiamo anche il valore x su +1. Questo è così la barra inizia da "1" e fornisce un po 'di padding tra la prima barra e la linea dell'asse y.

Salva ed esegui il progetto ... dovresti vedere il grafico a barre!



Passaggio 3: Tocchi finali

C'è un po 'di più che possiamo fare per renderlo più facile da guardare. Vogliamo assegnare a ciascuna barra un colore diverso e fornire il nome del soggetto come etichetta dell'asse x anziché un numero. Possiamo fare il primo con un metodo CPTBarPlotDataSource chiamato 'barFillForBarPlot: recordIndex':

 -(CPTFill *) barFillForBarPlot: (CPTBarPlot *) barPlot recordIndex: (NSUInteger) indice CPTColor * areaColor = nil; switch (index) case 0: areaColor = [CPTColor redColor]; rompere; caso 1: areaColor = [CPTColor blueColor]; rompere; caso 2: areaColor = [CPTColor orangeColor]; rompere; case 3: areaColor = [CPTColor greenColor]; rompere; default: areaColor = [CPTColor purpleColor]; rompere;  CPTFill * barFill = [CPTFill fillWithColor: areaColor]; return barFill; 

Ciò restituirà un colore diverso per ogni barra nel nostro grafico. Se si voleva renderlo ancora più elegante, si potrebbe effettivamente renderlo un gradiente. È anche una parte del nostro grafico che non è completamente dinamica, perché se qualcuno aggiunge un nuovo soggetto utilizzerà il colore predefinito. Forse un modo per aggirare questo in un'applicazione di vita reale sarebbe avere un colore quando si crea un nuovo soggetto che è memorizzato nell'archivio dati


Infine, aggiungiamo alcuni titoli personalizzati sull'asse x. Per fare questo, abbiamo bisogno di lavorare con l'asse x. Individua dove impostiamo l'asse xe modifica il codice per fare quanto segue:

 CPTXYAxis * xAxis = [axisSet xAxis]; [xAxis setMajorIntervalLength: CPTDecimalFromInt (1)]; [xAxis setMinorTickLineStyle: nil]; [xAxis setLabelingPolicy: CPTAxisLabelingPolicyNone]; [xAxis setLabelTextStyle: textStyle]; [xAxis setLabelRotation: M_PI / 4]; NSArray * SubjectsArray = [self getSubjectTitlesAsArray]; [xAxis setAxisLabels: [NSSet setWithArray: subjectArray]];

Ci sono alcune modifiche nel codice sopra. Innanzitutto, stiamo modificando la politica di etichettatura su none. Ciò assicurerà che CorePlot non stampi l'etichetta stessa e utilizzerà invece ciò che gli diamo. Successivamente, impostiamo la rotazione dell'etichetta in modo che si allinea meglio con il grafico. Infine, impostiamo la proprietà 'Axis labels' che accetta un valore NSSet di valori NSString. Creiamo NSSet utilizzando un NSArray creato con il metodo 'getSubjectTitlesAsArray'. Quel metodo non esiste ancora, quindi creiamolo. Aggiungi la dichiarazione all'inizio del file .m e poi scrivi la seguente implementazione:

 - (NSArray *) getSubjectTitlesAsArray NSError * error = nil; NSFetchRequest * request = [[NSFetchRequest alloc] init]; NSSortDescriptor * sortDescriptor = [NSSortDescriptor sortDescriptorWithKey: @ "subjectID" ascendente: YES]; NSEntityDescription * entity = [NSEntityDescription entityForName: @ "STSubject" inManagedObjectContext: managedObjectContext]; [request setEntity: entity]; [request setSortDescriptors: [NSArray arrayWithObject: sortDescriptor]]; [request setResultType: NSDictionaryResultType]; [request setReturnsDistinctResults: NO]; [request setPropertiesToFetch: [NSArray arrayWithObject: @ "subjectName"]]; NSArray * titleStrings = [managedObjectContext executeFetchRequest: request error: & error]; NSMutableArray * labelArray = [NSMutableArray array]; CPTMutableTextStyle * textStyle = [CPTMutableTextStyle textStyle]; [textStyle setFontSize: 10]; per (int i = 0; i < [titleStrings count]; i++)  NSDictionary *dict = [titleStrings objectAtIndex:i]; CPTAxisLabel *axisLabel = [[CPTAxisLabel alloc] initWithText:[dict objectForKey:@"subjectName"] textStyle:textStyle]; [axisLabel setTickLocation:CPTDecimalFromInt(i + 1)]; [axisLabel setRotation:M_PI/4]; [axisLabel setOffset:0.1]; [labelArray addObject:axisLabel]; [axisLabel release];  return [NSArray arrayWithArray:labelArray]; 

Ci sono molte cose nel codice sopra. Per dare un grafico alle etichette personalizzate, dobbiamo passare un NSSet contenente oggetti di tipo "CPTAxisLabel". Innanzitutto, otteniamo una matrice di tutti i nomi dei soggetti ordinati per subjectID, quindi sarà nello stesso ordine del grafico. Quindi, per la quantità di nomi che riceviamo, effettuiamo il ciclo e creiamo un CPTAxisLabel con la stringa del nome soggetto e uno stile di testo predefinito. La "posizione del segno di spunta" è il segno di spunta per cui appare. Dobbiamo aggiungere 1 al nostro valore perché stiamo iniziando la nostra prima barra a 1 invece di 0. Quindi impostiamo una rotazione e un offset e lo aggiungiamo a una matrice. Infine, restituiamo la matrice di axisLabels.

Se salviamo ed eseguiamo il progetto, abbiamo un grafico a barre colorato e completo con etichette personalizzate!



La prossima volta

Abbiamo appreso una discreta quantità di CorePlot in questa sessione. Abbiamo imparato come creare un grafico a barre, modificare i colori della barra e persino aggiungere etichette personalizzate all'asse.

La prossima volta vedremo come creare un grafico a torta fantastico che mostri gli stessi dati del grafico a barre. Prenderti la prossima volta!