Graphs

Graphing features are available within the AerisUI component of the SDK and allows you to visualize nearly any type of weather data our API provides. You can plot temperature trends over the past 24 hours, show precipitation forecasts in a bar graph, and more.

Currently, only line and bar graphs are supported, but more graph rendering types are planned for future releases of the SDK.

 
 
 
 
 
 
 
 
 
 
 
 
 
 

When creating your own graphs, you will be working primarily with three separate classes: AWFGraphView, AWFGraphSeries and AWFSeriesItem.

AWFGraphView is your graph’s main view object and is responsible for managing the graph’s series, axis and renderers.

AWFGraphSeries is your graph’s primary series object which is responsible for managing individual series items (datasets) and performing the necessary range calculations for your graph’s data. This object also loads API data using AWFObjectLoader instances as needed and based on your series item configuration.

AWFSeriesItem represents a single dataset in your graph, such as max temperature or precipitation totals. This object is where most of your graph’s configuration and styling will take place as you will define how data points for this dataset will be rendered and what those data points are, either static values or loaded from the API using AWFObjectLoader instances.

Creating a Graph

To create your graph, start by defining your first dataset you wish to plot using a new AWFSeriesItem instance and giving it a title:

AWFSeriesItem *sampleItem = [[AWFSeriesItem alloc] init];
sampleItem.title = NSLocalizedString(@"Sample Data", nil);
let sampleItem = AWFSeriesItem()
sampleItem.title = "Sample Data"

Now provide the static data for the dataset, which can either be an array of arrays for the x and y values, an array of AWFSeriesPoint instances, or an array of AWFObject instances:

// an array of arrays containing x,y values
sampleItem.data = [[0,23], [1,15], [2,79]];

// an array of AWFSeriesPoint instances
NSMutableArray *dataPoints = [NSMutableArray arrayWithCapacity:3];
[dataPoints addObject:[AWFSeriesPoint pointWithX:0 y:23];
[dataPoints addObject:[AWFSeriesPoint pointWithX:1 y:15];
[dataPoints addObject:[AWFSeriesPoint pointWithX:2 y:79];
sampleItem.data = [NSArray arrayWithArray:dataPoints];
// an array of arrays containing x,y values
sampleItem.data = [[0,23], [1,15], [2,79]]

// an array of AWFSeriesPoint instances
var dataPoints = [AWFSeriesPoint]()
dataPoints.append(AWFSeriesPoint(x: 0, y: 23))
dataPoints.append(AWFSeriesPoint(x: 1, y: 15))
dataPoints.append(AWFSeriesPoint(x: 2, y: 79))
sampleItem.data = dataPoints

If you provide an array of AWFObject instances as the data for your series item, you must also provide the key paths to the properties on those objects to use for both the x and y values. This is done by setting the xAxisPropertyName and xAxisPropertyName` properties on your series item:

sampleItem.xAxisPropertyName = @"ob.timestamp";
sampleItem.yAxisPropertyName = @"ob.tempF";
sampleItem.xAxisPropertyName = "ob.timestamp"
sampleItem.yAxisPropertyName = "ob.tempF"

You also need to tell the graph how to render this series item using the item’s rendererType property, which must be a valid AWFGraphRendererType. Series items will be rendered using the AWFGraphRendererTypeLine, or line graph, by default:

sampleItem.rendererType = AWFGraphRendererTypeBar;
sampleItem.rendererType = .bar

Along with specifying the renderer type, you can also set the item’s styles for the renderer. Note that some style properties are not used for all renderer types:

sampleItem.strokeColor = [UIColor greenColor];
sampleItem.strokeWidth = 3.0;
sampleItem.strokeColor = .green
sampleItem.strokeWidth = 3.0

Now that you have your first dataset, you can setup your graph view. A graph view requires a series to be setup with the series items for each dataset you want to display:

AWFGraphSeries *series = [AWFGraphSeries seriesWithItems:@[sampleItem]];
AWFGraphView *graphView = [AWFGraphView alloc] initWithFrame:CGRectMake(0, 0, 300, 200)];
graphView.series = series;
[self.view addSubview:graphView];
let series = AWFGraphSeries(items: [sampleItem])
let graphView = AWFGraphView(frame: CGRect(origin: .zero, size: CGSize(width: 300, height: 200)))
graphView.series = series
view.addSubview(graphView)

Then when your graph is setup with its series items, make sure to tell it to render. Calling reloadData on a graph view instance will force it to redraw its renderers to redraw each series item’s data.

[graphView reloadData];
graphView.reloadData()

Populating a Graph View with Aeris Data

Instead of providing a graph view’s series with static data, you can have the series load data from the Aeris API by assigning an AWFObjectLoader instance to each of your series items you want to load data for. If you use this method to populate your graph, you must also provide the necessary key path values on your series item to associate your series x and y values to properties of an AWFObject instance.

First create the AWFObjectLoader instance for the data you want to request as well as any request options. For instance, we want to display the last 20 observed temperatures and feels like temperatures for Seattle, WA:

AWFObservationsLoader *obsLoader = [AWFObservationsLoader alloc] init];
obsLoader.options.place = [AWFPlace placeWithCity:@"seattle" state:@"wa" country:@"us"];
obsLoader.options.limit = 20;
obsLoader.options.dataType = AerisAPIObservationDataTypeRecent;
let obsLoader = AWFObservationsLoader()
obsLoader.options.place = AWFPlace(city: "seattle", state: "wa", country: "us")
obsLoader.options.limit = 1
obsLoader.options.dataType = AerisAPIObservationDataTypeRecent

Then associate this object loader with your series items. Note that a single object loader can be associated with multiple series items:

tempItem.objectLoader = obsLoader;
feelslikeItem.objectLoader = obsLoader;
tempItem.objectLoader = obsLoader
feelslikeItem.objectLoader = obsLoader

If you have many series items in your graph but only a single object loader and/or place should be used for all of them, you can assign these using a single method on your AWFGraphSeries instance:

[series setLoaderForAllSeriesItems:obsLoader];
[series setPlaceForAllSeriesItemLoaders:place];
series?.setLoaderForAllSeriesItems(obsLoader)
series?.setPlaceForAllSeriesItemLoaders(place)

This will update the objectLoader property on each item in the series and set the object loaders’ place to that specified.

Make sure you also define the x and y properties to use from the AWFObject instances returned by the request. In this case, we expect to receive instances of AWFObservation back when the request is completed, so we reference properties of that object:

tempItem.xAxisPropertyName = @"periods.#.timestamp";
tempItem.yAxisPropertyName = @"periods.#.tempF";
feelslikeItem.xAxisPropertyName = @"periods.#.timestamp";
feelslikeItem.yAxisPropertyName = @"periods.#.feelslikeF";
tempItem.xAxisPropertyName = "periods.#.timestamp"
tempItem.yAxisPropertyName = "periods.#.tempF"
feelslikeItem.xAxisPropertyName = "periods.#.timestamp"
feelslikeItem.yAxisPropertyName = "periods.#.feelslikeF"

If a property on an AWFObject is an array but you need to reference a property on each item within that array for your series, you can use a hash (#) symbol before the sub-object’s key path. This will tell the graph to use the key path property values for each point in the series.

When you are ready to load or reload data for your graph, just call reloadData on your graph view instance:

[graphView reloadData];
graphView.reloadData()

Graph Axis

A graph view automatically sets up both x and y axis objects when you initialize a graph view. By default, the x-axis will be an instance of AWFGraphTimeAxis and expects all x values in your series to be a valid timestamp. The y-axis object will default to AWFGraphAxis, which is just a simple value-based axis.

If you need to change one or both of these default axis objects to a different type or to a custom subclass, you can set the axis instances directly on your graph view through the xAxis and yAxis properties. You can also access the graph’s axis object to change the default configuration for them, specifically properties related to the formatting and layout of ticks and labels along each axis.

For basic axis label and line/grid styling, you can override the default values for textStyle, tickColor and gridColor. For textStyle, provide an AWFTextStyleSpec instance that will be applied to the axis labels. The color values you provide for tickColor and gridColor control the line color used for rendering the axis tick marks and background grid lines respectively.

Review the API documentation for both AWFGraphAxis and AWFGraphTimeAxis for more information about using the available properties and methods.

Graph Value Callout

A graph’s data point values are automatically displayed using an instance of AWFGraphCalloutView, and there are two ways in which these values are displayed on a graph. The primary method is by tapping an element on a graph, which can either be a point for a line graph or a bar for a bar graph. If the graph renderer associated with the tapped series point supports selections, the graph callout view will be presented from that element within the view and displays the series item title and value at that point.

Alternatively, performing a long-press gesture anywhere on the graph will display the values for all series items in the graph at the gesture’s location within the view. If the point occurs beyond the bounds of a series item, then no value will be displayed for that item in the set. Panning horizontally in the graph view while pressing will continuously update the graph’s callout view with the data values along the graph.

If you need to customize your graph’s callout view, you can subclass AWFGraphCalloutView to perform your own implementations and set your graph view’s calloutView property with and instance of your custom object. Note that you must override the public methods with your own methods to handle the necessary drawing and laying out.

Zooming a Graph View

By default, a graph view supports zooming in a similar manner to that of MKMapView — a pinch gesture inwards on the graph view will zoom into the graph, whereas a pinch gesture outwards will zoom back out. Additionally, you can perform a double-tap gesture on the graph view to zoom in one level, and then tap with two fingers to zoom back out that same level. These are the same types of gestures used for zooming a map view, so they should feel natural for your own users.

Currently zooming is only supported for the x-axis.

You can disable zooming for a specific graph view using its zoomEnabled property:

graphView.zoomEnabled = NO;
graphView.zoomEnabled = false

If zooming is disabled, the entire series will be rendered to fit within the bounds of the graph. This may not work well with your specific datasets, especially if your x-axis values span a large range and points are too close together. Thus, you can set the zoom scale of a graph view directly, which will allow your graph view to scroll so the user can still view the data.

graphView.zoomScale = 3.0;
graphView.zoomScale = 3.0

Last modified: November 02, 2017