Arbeiten mit CorePlot Erstellen eines Balkendiagramms

Wenn Sie mit datenintensiven Anwendungen arbeiten, muss ein Entwickler oft mehr als nur Listen von Datensätzen in einer Tabellensicht anzeigen. Mit der CorePlot-Bibliothek können Sie Ihren Anwendungen beeindruckende Datenvisualisierungen hinzufügen. In dieser Tuts + Premium-Serie erfahren Sie, wie es geht!


Auch in dieser Serie erhältlich:

  1. Arbeiten mit CorePlot: Projekteinrichtung
  2. Arbeiten mit CorePlot: Plot-Grundlagen
  3. Arbeiten mit CorePlot: Gestaltung und Hinzufügen von Plots
  4. Arbeiten mit CorePlot: Erstellen eines Balkendiagramms
  5. Mit CorePlot arbeiten: Kreisdiagramm erstellen

Wo wir aufgehört haben

Letztes Mal haben wir uns mit dem Anpassen von Aussehen und Stil eines Liniendiagramms (oder eines Streudiagramms) mit Klassen wie CPTMutableTextStyle und CPTMutableLineStyle beschäftigt. Wir haben gelernt, wie Sie die X- und Y-Achseninkremente und Zahlenstile mithilfe der Klassen CPTXYAxisSet und CPTXYAxis anpassen können. Außerdem haben wir untersucht, wie Sie mehrere Diagramme zu Ihrem Diagramm hinzufügen und die Datenquellenmethoden so ändern können, dass die richtigen Daten für die richtigen Diagramme mithilfe von Diagrammkennungen bereitgestellt werden.


Was wir heute abdecken werden

Heute arbeiten wir mit einer völlig neuen Grafik. Wir erstellen ein Balkendiagramm, das die Gesamtzahl der Schüler in jedem Fach zeigt, wobei jeder Balken ein Fach darstellt. Wir werden auch prüfen, wie Sie das Aussehen und Verhalten der Grafik anpassen können. Lass uns anfangen!


Schritt 1: Einrichten

Als Erstes müssen wir die relevanten Klassen zu unserem Projekt hinzufügen. Erstellen wir einen ViewController namens 'STBarGraphViewController' und eine 'STGraphView'. (Stellen Sie sicher, dass Sie sie in die entsprechenden Gruppen aufnehmen)


Beachten Sie die Benennung der Ansicht in 'STGraphView' anstelle von 'STBarGraphView'. In Zukunft werden wir diese Ansicht verwenden, um die Balken- und Kreisdiagramme anzuzeigen.

Bevor wir mit Code arbeiten können, müssen wir dem Aktionsblatt unserer Schülerlistenansicht eine Schaltfläche hinzufügen. Öffnen Sie zunächst 'STStudentListViewController.h' und importieren Sie STBarGraphViewController. Fügen Sie STBarGraphViewControllerDelegate zur Liste der registrierten Protokolle hinzu (das Protokoll ist zwar noch nicht vorhanden, wird aber später erstellt):

 @Interface STStudentListViewController: UIViewController 

Springen Sie als Nächstes in die .m-Datei und suchen Sie die Methode 'graphButtonWasSelected:'. Fügen Sie "Registrierung nach Betreff" der Liste "otherButtonTitles:" hinzu:

 UIActionSheet * graphSelectionActionSheet = [[[UIActionSheet-Zuordnung] initWithTitle: @ "Diagramm auswählen" delegieren: self cancelButtonTitle: @ "Abbrechen" destructiveButtonTitle: nil otherButtonTitles: @ "Registrierung über Zeit", @ "Registrierung über Zeit", @ ;

Suchen Sie nun die Methode 'actionSheet: clickedButtonAtIndex:' und ändern Sie sie, um mit buttonIndex == 1 zu arbeiten:

 if (buttonIndex == 0) STLineGraphViewController * graphVC = [[STLineGraphViewController-Zuordnung] init]; [graphVC setModalTransitionStyle: UIModalTransitionStyleFlipHorizontal]; [graphVC setModalPresentationStyle: UIModalPresentationFullScreen]; [graphVC setDelegate: self]; [graphVC setManagedObjectContext: [self managedObjectContext]]; [self presentModalViewController: graphVC animiert: JA]; [graphVC release];  else if (buttonIndex == 1) STBarGraphViewController * graphVC = [[STBarGraphViewController-Zuordnung] init]; [graphVC setModalTransitionStyle: UIModalTransitionStyleFlipHorizontal]; [graphVC setModalPresentationStyle: UIModalPresentationFullScreen]; [graphVC setDelegate: self]; [graphVC setManagedObjectContext: [self managedObjectContext]]; [self presentModalViewController: graphVC animiert: JA]; [graphVC release]; 

Auch hier werden einige Warnungen angezeigt, da wir die Delegate- oder managedObjectContext-Eigenschaften noch nicht in STBarGraphViewController implementiert haben.

Springen Sie jetzt in STBarGraphViewController.h. Importieren Sie CorePlot-CocoaTouch.h und fügen Sie die folgende Eigenschaftsdeklaration hinzu:

 @Protokoll STBarGraphViewControllerDelegate @required - (void) doneButtonWasTapped: (ID) Absender; @Ende

Fügen Sie nun die folgenden Eigenschaften hinzu:

 @ Eigenschaft (nichtatomisch, stark) CPTGraph * Graph; @ property (nichtatomisch, zuweisen) id delegieren; @ property (nicht atomar, stark) NSManagedObjectContext * managedObjectContext;

Registrieren Sie abschließend, dass diese Klasse den folgenden Protokollen folgt:

 @Interface STBarGraphViewController: UIViewController 

Beachten Sie, dass diese Klasse, abgesehen von der Konformität mit verschiedenen Protokollen, mit STLineViewController identisch ist. Im Idealfall verfügen Sie über eine Basisklasse, die über diese Eigenschaften verfügt, die Sie zur Reduzierung der Codewiederholung subklassen würden. Dieses Tutorial konzentriert sich nur auf die Kerndarstellung. Daher konzentrieren wir uns nur darauf, wie Sie mit dem CorePlot-Framework am besten arbeiten. Wenn Sie über das Wissen und die Zeit verfügen, können Sie die Basisklasse erstellen und die Vererbung verwenden. Im Beispielcode hier möchten wir es jedoch einfach halten.

Springen Sie als Nächstes in die .m-Datei, synthetisieren Sie die Eigenschaften und geben Sie sie in der dealloc-Methode frei.

Verbinden wir nun die Ansichtsklasse als Ansicht des Controllers. Importieren Sie 'STBarGraphView.h' und fügen Sie die folgende Methode hinzu:

 - (void) loadView [super loadView]; [self setTitle: @ "Einschreibung nach Betreff"]; [self-setView: [[[STGraphView-Zuordnung] initWithFrame: self.view.frame] Autorelease]]; CPTTheme * defaultTheme = [CPTTheme themeName: kCPTPlainWhiteTheme]; [self setGraph: (CPTGraph *) [defaultTheme newGraph]]; 

Jetzt können wir mit der Ansicht arbeiten. Öffnen Sie STGraphView.h, importieren Sie das Core-Plot-Framework (CorePlot-CocoaTouch.h) und fügen Sie die folgende Eigenschaftsdeklaration hinzu:

 @ property (nichtatomisch, stark) CPTGraphHostingView * chartHostingView;

Springen Sie in die .m-Datei, synthetisieren Sie die Eigenschaft und geben Sie sie in der Dealloc-Methode frei. Dann erstellen Sie die CPTGraphHostingView in der Methode 'initWithFrame:':

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

Erstellen Sie schließlich die Methode 'layoutSubviews' mit folgendem Code:

 - (void) 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: [selbst zentrieren]]; 

Sie werden feststellen, dass der zum Erstellen dieser Ansicht verwendete Code genau der von STLineGraphView ist. Wir können diese Basisansicht verwenden, um zukünftig mit allen Diagrammansichten zu arbeiten.

Springen Sie zurück in die Ansicht 'STBarGraphViewController.m' und suchen Sie die Methode 'viewDidLoad'. Zuerst möchten wir ein CPTBarPlot erstellen und es unserem Diagramm hinzufügen:

 [[graphView chartHostingView] setHostedGraph: [Selbstdiagramm]]; CPTBarPlot * subjectBarPlot = [[Zuweisung von CPTBarPlot] initWithFrame: [Diagrammgrenzen]]; [subjectBarPlot setIdentifier: @ "subjectEnrollement"]; [subjectBarPlot setDelegate: self]; [subjectBarPlot setDataSource: self]; [[self graph] addPlot: subjectBarPlot];

Schließlich fügen wir eine Navigationsleiste mit einer Schaltfläche "Fertig" hinzu, damit der Benutzer zurückkehren kann:

 UINavigationItem * navigationItem = [[[UINavigationItem-Zuordnung] initWithTitle: self.title] autorelease]; [navigationItem setHidesBackButton: YES]; UINavigationBar * navigationBar = [[[UINavigationBar Allocation] initWithFrame: CGRectMake (0, 0, self.view.frame.size.width, 44.0f)] Autorelease]; [navigationBar pushNavigationItem: navigationItem animated: NO]; [self.view addSubview: navigationBar]; [navigationItem setRightBarButtonItem: [[[UIBarButtonItem-Zuordnung] initWithTitle: @ "Done" -Stil: UIBButtonItemStyleDone-Ziel: [Selbstdelegierter] Aktion: @selector (doneButtonWasTapped :)] autorelease] animated: NO];

Beginnen wir nun mit der Arbeit an den Datenquellenmethoden:


Schritt 2: Angabe der Balkendiagrammdaten

Der Prozess wird ähnlich wie bei der Erstellung des Liniendiagramms sein, aber wir werden die Dinge ein bisschen dynamischer gestalten. Wir werden benutzerdefinierte Methoden erstellen, die einen geeigneten Plotraum bieten. Wir werden auch einige zusätzliche Datenquellenmethoden hinzufügen, um eine bestimmte Farbe für jeden Balken sowie Titel der X-Achse bereitzustellen.

Bevor wir uns die Diagrammdaten ansehen, müssen wir die Achsen- und sichtbaren Bereiche einrichten. Dazu benötigen wir zwei Methoden, die den maximalen x- und den maximalen y-Wert berechnen. Deklarieren Sie die folgenden Methoden am Anfang der .m-Datei:

 [[graphView chartHostingView] setHostedGraph: [Selbstdiagramm]]; @interface STBarGraphViewController () - (float) getTotalSubjects; - (Float) getMaxEnrolled; @Ende

Implementiere sie jetzt wie folgt:

 #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 Fehler: & Fehler];  - (float) getMaxEnrolled float maxEnrolled = 0; NSError * error = nil; für (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' erhält einfach eine Zählung aller Subjekte im Kerndatenspeicher. 'getMaxEnrolled' durchläuft alle Fächer und sucht nach der höchsten Anzahl von Schülern in jedem Fach und liefert den höchsten Wert.

Wenn diese Methoden abgeschlossen sind, können wir zu unserer 'viewDidLoad' -Methode zurückkehren und den folgenden Code unten hinzufügen, wo wir das Balkendiagramm zu unserem Diagramm hinzufügen:

 CPTXYPlotSpace * studentPlotSpace = (CPTXYPlotSpace *) [Graph defaultPlotSpace]; [studentPlotSpace setXRange: [CPTPlotRange plotRangeWithLocation: CPTDecimalFromInt (0) Länge: CPTDecimalFromInt ([self getTotalSubjects] + 1)]]; [studentPlotSpace setYRange: [CPTPlotRange plotRangeWithLocation: CPTDecimalFromInt (0) Länge: CPTDecimalFromInt ([self getMaxEnrolled] + 1)]]; [[graph plotAreaFrame] setPaddingLeft: 40.0f]; [[graph plotAreaFrame] setPaddingTop: 10.0f]; [[graph plotAreaFrame] setPaddingBottom: 120.0f]; [[graph plotAreaFrame] setPaddingRight: 0.0f]; [[graph plotAreaFrame] setBorderLineStyle: nil]; CPTMutableTextStyle * textStyle = [CPTMutableTextStyle textStyle]; [textStyle setFontSize: 12.0f]; [textStyle setColor: [CPTColor colorWithCGColor: [[UIColor grayColor] CGColor]]; CPTXYAxisSet * axisSet = (CPTXYAxisSet *) [Diagramm 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];

Die meisten der oben genannten Punkte sollten aus dem letzten Mal bekannt sein. Anstatt hartcodierte Werte für die Länge des x- und y-Max-Plotbereichs festzulegen, verwenden wir unsere neuen Methoden, um die Werte dynamisch zu erstellen. Danach richten wir einfach eine grundlegende Achsenformatierung ein und geben dem Plotrahmen eine Auffüllung, damit die Achse entsprechend angezeigt wird.

Jetzt müssen wir dem Diagramm Daten unter Verwendung der Datenquellenmethoden zur Verfügung stellen. Die Anzahl der Datensätze anzugeben ist einfach:

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

Geben Sie nun die x- und y-Werte für die Datensätze an:

 - (NSNumber *) numberForPlot: (CPTPlot *) Zeichnungsfeld: (NSUInteger) fieldEnum recordIndex: (NSUInteger) index int x = index + 1; int y = 0; NSError * Fehler; NSFetchRequest * fetchRequest = [[NSFetchRequest Allocation] init]; NSEntityDescription * entity = [NSEntityDescription entityForName: @ "STStudent" inManagedObjectContext: managedObjectContext]; NSPredicate * predicate = [NSPredicate predicateWithFormat: @ "subjectID ==% d", index]; [fetchRequest setEntity: entity]; [fetchRequest setPredicate: prädikat]; y = [managedObjectContext countForFetchRequest: fetchRequest-Fehler: & Fehler]; [fetchRequest-Version]; switch (fieldEnum) case CPTScatterPlotFieldX: return [NSNumber numberWithInt: x]; brechen; case CPTScatterPlotFieldY: return [NSNumber numberWithInt: y]; brechen; Standard: Pause;  return nil; 

Die obige Methode ähnelt sehr der Bereitstellung von Daten für ein Streudiagramm. Wir ändern den Anruf in den Datenspeicher, sodass wir eine Zählung aller Schüler erhalten, die in einem Fach angemeldet sind. Wir setzen auch den x-Wert auf +1. Der Balken beginnt also bei '1' und bietet ein wenig Abstand zwischen dem ersten Balken und der y-Achsenlinie.

Speichern Sie das Projekt und führen Sie es aus… Sie sollten Ihr Balkendiagramm sehen!



Schritt 3: Fertigstellen

Wir können noch ein bisschen mehr tun, um dies einfacher zu sehen. Wir möchten jedem Balken eine andere Farbe geben und den Namen des Motivs als Bezeichnung der X-Achse anstelle einer Zahl angeben. Wir können die erste mit einer CPTBarPlotDataSource-Methode namens 'barFillForBarPlot: recordIndex' durchführen:

 -(CPTFill *) barFillForBarPlot: (CPTBarPlot *) barPlot recordIndex: (NSUInteger) index CPTColor * areaColor = nil; Schalter (Index) Fall 0: areaColor = [CPTColor redColor]; brechen; Fall 1: areaColor = [CPTColor blueColor]; brechen; Fall 2: areaColor = [CPTColor orangeColor]; brechen; Fall 3: areaColor = [CPTColor greenColor]; brechen; Voreinstellung: areaColor = [CPTColor purpleColor]; brechen;  CPTFill * barFill = [CPTFill fillWithColor: areaColor]; return barFill; 

Dadurch wird für jeden Balken in unserem Diagramm eine andere Farbe angezeigt. Wenn Sie es noch stilvoller gestalten möchten, können Sie es tatsächlich zu einem Farbverlauf machen. Es ist auch ein Teil unseres Diagramms, das nicht vollständig dynamisch ist, denn wenn jemand ein neues Thema hinzufügt, wird die Standardfarbe verwendet. Eine Möglichkeit, dies in einer realen Anwendung zu umgehen, wäre möglicherweise eine Farbe, wenn Sie einen neuen Betreff erstellen, der im Datenspeicher gespeichert ist


Schließlich fügen wir noch einige benutzerdefinierte X-Achsentitel hinzu. Dazu müssen wir mit der x-Achse arbeiten. Suchen Sie nach der Stelle, an der wir die X-Achse eingerichtet haben, und ändern Sie den Code, um folgende Schritte auszuführen:

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

Der obige Code enthält einige Änderungen. Erstens ändern wir die Kennzeichnungsrichtlinie in keine. Dadurch wird sichergestellt, dass CorePlot das Etikett nicht selbst ausdrucken kann, sondern das, was wir ihm geben. Als Nächstes setzen wir die Etikettrotation so, dass sie besser mit dem Diagramm übereinstimmt. Schließlich legen wir die Eigenschaft 'Axis labels' fest, die ein NSSet von NSString-Werten annimmt. Wir erstellen das NSSet mit einem NSArray, der mit der Methode 'getSubjectTitlesAsArray' erstellt wurde. Diese Methode existiert noch nicht, also erstellen wir sie. Fügen Sie die Deklaration oben in der .m-Datei hinzu und schreiben Sie dann die folgende Implementierung:

 - (NSArray *) getSubjectTitlesAsArray NSError * error = nil; NSFetchRequest * request = [[NSFetchRequest-Zuordnung] init]; NSSortDescriptor * sortDescriptor = [NSSortDescriptor sortDescriptorWithKey: @ "subjectID" aufsteigend: 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: Anforderungsfehler: & Fehler]; NSMutableArray * labelArray = [NSMutableArray-Array]; CPTMutableTextStyle * textStyle = [CPTMutableTextStyle textStyle]; [textStyle setFontSize: 10]; für (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]; 

Im obigen Code ist viel los. Um einem Diagramm benutzerdefinierte Beschriftungen zu geben, müssen wir ein NSSet übergeben, das Objekte des Typs 'CPTAxisLabel' enthält. Zunächst erhalten wir ein Array aller Betreffnamen, die nach subjectID geordnet sind, so dass sie in derselben Reihenfolge wie der Graph angezeigt wird. Für die Anzahl der Namen, die wir zurückerhalten, durchlaufen wir eine Schleife und erstellen ein CPTAxisLabel mit der Betreffnamenzeichenfolge und einem vordefinierten Textstil. Der "Tick-Ort" gibt an, für welchen Tick es angezeigt wird. Wir müssen 1 zu unserem Wert addieren, da wir unseren ersten Takt mit 1 anstatt mit 0 beginnen. Dann setzen wir eine Drehung und einen Versatz und fügen sie einem Array hinzu. Zum Schluss geben wir das Array von axisLabels zurück.

Wenn wir das Projekt speichern und ausführen, haben wir ein fertiges, farbiges Balkendiagramm mit benutzerdefinierten Beschriftungen!



Nächstes Mal

Wir haben in dieser Sitzung eine Menge über CorePlot gelernt. Wir haben gelernt, wie man ein Balkendiagramm erstellt, die Farben des Balkens ändert und sogar benutzerdefinierte Beschriftungen zur Achse hinzufügt.

Beim nächsten Mal erfahren Sie, wie Sie ein fantastisches Kreisdiagramm erstellen, das die gleichen Daten wie das Balkendiagramm enthält. Fang dich das nächste Mal!