Apply a renderer to a sublayer.
Use case
A layer showing animal populations contains sublayers for different species. A renderer could be applied which gives each sublayer a different color, so that populations of each species can be compared visually.
How to use the sample
Tap on the "Apply renderer" button to apply a class breaks renderer based on population for each county. Tap on the "Reset" button to reset to original renderer.
How it works
- Create an
AGSArcGISMapImageLayer
from its URL. - After it is done loading, get the counties sublayer from the map image layer's
mapImageSublayers
array. - After the sublayer loads, get its original
AGSRenderer
. - Create an
AGSClassBreaksRenderer
with a collection ofAGSClassBreak
s for different population ranges. - Set the results as the sublayer's new
AGSRenderer
.
Relevant API
- AGSArcGISMapImageLayer
- AGSArcGISMapImageSubLayer
- AGSClassBreak
- AGSClassBreaksRenderer
About the data
This application displays census data from an ArcGIS Server map service. It contains various population statistics, including total population for each county in 2007.
Additional information
The service hosting the layer must support dynamic layers to be able to change the rendering of sublayers.
Tags
class breaks, dynamic layer, dynamic rendering, renderer, sublayer, symbology, visualization
Sample Code
// Copyright 2017 Esri.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import UIKit
import ArcGIS
class ChangeSublayerRendererViewController: UIViewController {
@IBOutlet private var mapView: AGSMapView!
@IBOutlet private var resetBarButtonItem: UIBarButtonItem!
@IBOutlet private var applyRendererBarButtonItem: UIBarButtonItem!
/// Map image layer.
private let mapImageLayer = AGSArcGISMapImageLayer(url: URL(string: "https://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer")!)
/// The counties sublayer of the map image layer.
private var countiesSublayer: AGSArcGISMapImageSublayer?
private var originalRenderer: AGSRenderer?
override func viewDidLoad() {
super.viewDidLoad()
// Add the source code button item to the right of navigation bar.
(self.navigationItem.rightBarButtonItem as! SourceCodeBarButtonItem).filenames = ["ChangeSublayerRendererViewController"]
// Initialize map with basemap.
let map = AGSMap(basemapStyle: .arcGISStreets)
// Add map image layer to the map.
map.operationalLayers.add(mapImageLayer)
// Set map on the map view.
mapView.map = map
// Set viewpoint.
let envelope = AGSEnvelope(xMin: -13834661.666904, yMin: 331181.323482, xMax: -8255704.998713, yMax: 9118038.075882, spatialReference: .webMercator())
mapView.setViewpoint(AGSViewpoint(targetExtent: envelope))
// Load map image layer to access sublayers.
self.mapImageLayer.load { [weak self] (error: Error?) in
guard let self = self else { return }
if let error = error {
print("Error loading map image layer: \(error)")
} else {
self.mapImageLayerDidLoad()
}
}
}
/// Called in response to the map image layer loading successfully.
func mapImageLayerDidLoad() {
// Get the counties sublayer.
let mapImageSublayers = mapImageLayer.mapImageSublayers
guard mapImageSublayers.count >= 3,
let sublayer = mapImageSublayers[2] as? AGSArcGISMapImageSublayer else {
return
}
countiesSublayer = sublayer
// Load the sublayer to get the original renderer.
sublayer.load { [weak self] (error) in
guard let self = self else { return }
if let error = error {
print("Error loading map image sublayer: \(error)")
} else {
self.countiesSublayerDidLoad()
}
}
}
/// Called in response to the counties sublayer loading successfully.
func countiesSublayerDidLoad() {
originalRenderer = countiesSublayer?.renderer
// Enable bar button items.
applyRendererBarButtonItem.isEnabled = true
resetBarButtonItem.isEnabled = true
}
/// Creates a class breaks renderer for counties in the US based on their
/// population in 2007.
///
/// - Returns: An `AGSClassBreaksRenderer` object.
private func makeClassBreakRenderer() -> AGSClassBreaksRenderer {
// Outline symbol.
let lineSymbol = AGSSimpleLineSymbol(style: .solid, color: UIColor(white: 0.6, alpha: 1), width: 0.5)
// Symbols for each class break.
let symbol1 = AGSSimpleFillSymbol(style: .solid, color: UIColor(red: 0.89, green: 0.92, blue: 0.81, alpha: 1), outline: lineSymbol)
let symbol2 = AGSSimpleFillSymbol(style: .solid, color: UIColor(red: 0.59, green: 0.76, blue: 0.75, alpha: 1), outline: lineSymbol)
let symbol3 = AGSSimpleFillSymbol(style: .solid, color: UIColor(red: 0.38, green: 0.65, blue: 0.71, alpha: 1), outline: lineSymbol)
let symbol4 = AGSSimpleFillSymbol(style: .solid, color: UIColor(red: 0.27, green: 0.49, blue: 0.59, alpha: 1), outline: lineSymbol)
let symbol5 = AGSSimpleFillSymbol(style: .solid, color: UIColor(red: 0.16, green: 0.33, blue: 0.47, alpha: 1), outline: lineSymbol)
// Class breaks.
let classBreak1 = AGSClassBreak(description: "-99 to 8560", label: "-99 to 8560", minValue: -99, maxValue: 8560, symbol: symbol1)
let classBreak2 = AGSClassBreak(description: "> 8,560 to 18,109", label: "> 8,560 to 18,109", minValue: 8561, maxValue: 18109, symbol: symbol2)
let classBreak3 = AGSClassBreak(description: "> 18,109 to 35,501", label: "> 18,109 to 35,501", minValue: 18110, maxValue: 35501, symbol: symbol3)
let classBreak4 = AGSClassBreak(description: "> 35,501 to 86,100", label: "> 35,501 to 86,100", minValue: 35502, maxValue: 86100, symbol: symbol4)
let classBreak5 = AGSClassBreak(description: "> 86,100 to 10,110,975", label: "> 86,100 to 10,110,975", minValue: 86101, maxValue: 10110975, symbol: symbol5)
// Create a class break renderer using the class breaks above.
let classBreakRenderer = AGSClassBreaksRenderer(fieldName: "POP2007", classBreaks: [ classBreak1, classBreak2, classBreak3, classBreak4, classBreak5])
return classBreakRenderer
}
// MARK: - Actions
@IBAction private func applyRenderer() {
countiesSublayer?.renderer = makeClassBreakRenderer()
}
@IBAction private func reset() {
countiesSublayer?.renderer = originalRenderer
}
}