# Use images to cluster point data

> **Note (legacy): A newer version of the Maps SDK is available**
> 
> This page uses v6.4.1 of the Mapbox Maps SDK. A newer version of the SDK is available. Learn about the latest version, v11.33.0, in the [Maps SDK documentation](https://docs.mapbox.com/ios/maps/guides/).

![](https://docs.mapbox.com/ios/assets/ideal-img/maps-examples-clustering-with-images.0772901.480.png)

Download the [point GeoJSON and icon asset catalog](pathname:///files/cluster-images.zip) and add it to your project.

For more information on styling data at runtime, see our [Information for style authors](https://docs.mapbox.com/ios/maps/api/6.4.1/for-style-authors.html) guide.

**Swift**

Title: `ViewController`

[View on GitHub](https://github.com/mapbox/ios-sdk-examples/tree/298e050be7352eb28cee6f03e02945593140c1f3/Examples/Swift/ClusteringWithImagesExample.swift)

```swift
import Mapbox

class ViewController: UIViewController, MGLMapViewDelegate {

    var mapView: MGLMapView!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Initialize the Map
        mapView = MGLMapView(frame: view.bounds, styleURL: MGLStyle.lightStyleURL)
        mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        mapView.delegate = self
        view.addSubview(mapView)
    }

    func mapView(_ mapView: MGLMapView, didFinishLoading style: MGLStyle) {
        // Define an initial icon to help set source attributes
        let icon = UIImage(named: "squircle")!

        // Retrieve data and set as source. This associates the data with the map, but style layers are still required to make data visible.
        let url = URL(fileURLWithPath: Bundle.main.path(forResource: "ports", ofType: "geojson")!)
        let source = MGLShapeSource(identifier: "clusteredPorts",
                                    url: url,
                                    options: [.clustered: true, .clusterRadius: icon.size.width])
        style.addSource(source)

        // Show unclustered features as icons. The `cluster` attribute is built into clustering-enabled source features.
        // This example requires two style layers to work properly: one for clustered points and one for unclustered points
        let markerLayer = MGLSymbolStyleLayer(identifier: "ports", source: source)
        markerLayer.iconImageName = NSExpression(forConstantValue: "marker")
        markerLayer.predicate = NSPredicate(format: "cluster != YES")
        style.addLayer(markerLayer)
        style.setImage(UIImage(named: "marker")!, forName: "marker")

        // Create style layer to cluster features as images with labels
        let clusterLayer = MGLSymbolStyleLayer(identifier: "clusteredPortsNumbers", source: source)
        clusterLayer.textColor = NSExpression(forConstantValue: UIColor.white)
        clusterLayer.textFontSize = NSExpression(forConstantValue: NSNumber(value: Double(icon.size.width) / 2))
        clusterLayer.iconAllowsOverlap = NSExpression(forConstantValue: true)

        // Style image clusters
        style.setImage(UIImage(named: "squircle")!, forName: "squircle")
        style.setImage(UIImage(named: "circle")!, forName: "circle")
        style.setImage(UIImage(named: "rectangle")!, forName: "rectangle")
        style.setImage(UIImage(named: "star")!, forName: "star")
        style.setImage(UIImage(named: "oval")!, forName: "oval")

        let stops = [
            10: NSExpression(forConstantValue: "circle"),
            25: NSExpression(forConstantValue: "rectangle"),
            75: NSExpression(forConstantValue: "star"),
            150: NSExpression(forConstantValue: "oval")
        ]

        // Use expressions to set each cluster's image based on defined stops and display the point count over the corresponding image
        let defaultShape = NSExpression(forConstantValue: "squircle")
        clusterLayer.iconImageName = NSExpression(format: "mgl_step:from:stops:(point_count, %@, %@)", defaultShape, stops)
        clusterLayer.text = NSExpression(format: "CAST(point_count, 'NSString')")

        style.addLayer(clusterLayer)
    }

}
```

**Objective C**

Title: `ViewController`

[View on GitHub](https://github.com/mapbox/ios-sdk-examples/tree/298e050be7352eb28cee6f03e02945593140c1f3/Examples/ObjectiveC/ClusteringWithImagesExample.m)

```swift

#import "ViewController.h"
@import Mapbox;
@interface ViewController () <MGLMapViewDelegate>

@property (nonatomic) MGLMapView *mapView;
@property (nonatomic) UIImage *icon;
@property (nonatomic) UIImage *marker;

@end

@implementation ViewController


- (void)viewDidLoad {
    [super viewDidLoad];
    
    // Initialize the Map
    self.mapView = [[MGLMapView alloc] initWithFrame:self.view.bounds
                                            styleURL:[MGLStyle lightStyleURL]];
    self.mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    self.mapView.delegate = self;
    
    [self.view addSubview:self.mapView];
}

- (void)mapView:(MGLMapView *)mapView didFinishLoadingStyle:(MGLStyle *)style {
    // Define an initial icon to help set source attributes
    self.icon = [UIImage imageNamed:@"squircle"];
    
    NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"ports" ofType:@"geojson"]];
    
    // Retrieve data and set as source. This associates the data with the map, but style layers are still required to make data visible.
    MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"clusteredPorts" URL:url options:@{
                              MGLShapeSourceOptionClustered:@(YES),
                              MGLShapeSourceOptionClusterRadius: @(self.icon.size.width)
    }];
    [style addSource:source];
    
    // Show unclustered features as icons. The `cluster` attribute is built into clustering-enabled source features.
    // This example requires two style layers to work properly: one for clustered points and one for unclustered points
    MGLSymbolStyleLayer *markerLayer = [[MGLSymbolStyleLayer alloc] initWithIdentifier:@"ports" source:source];
    markerLayer.iconImageName = [NSExpression expressionForConstantValue:@"marker"];
    markerLayer.predicate = [NSPredicate predicateWithFormat:@"cluster != YES"];
    [style addLayer:markerLayer];
    [style setImage:[UIImage imageNamed:@"marker"] forName:@"marker"];
    
    // Create image cluster style layer
    MGLSymbolStyleLayer *clusterLayer = [[MGLSymbolStyleLayer alloc] initWithIdentifier:@"clusteredPortsNumbers" source:source];
    clusterLayer.textColor = [NSExpression expressionForConstantValue:[UIColor whiteColor]];
    clusterLayer.textFontSize = [NSExpression expressionForConstantValue:@(self.icon.size.width / 2)];
    clusterLayer.iconAllowsOverlap = [NSExpression expressionForConstantValue:@(YES)];
    
    // Style image clusters
    [style setImage:[UIImage imageNamed:@"squircle"] forName:@"squircle"];
    [style setImage:[UIImage imageNamed:@"circle"] forName:@"circle"];
    [style setImage:[UIImage imageNamed:@"rectangle"] forName:@"rectangle"];
    [style setImage:[UIImage imageNamed:@"star"] forName:@"star"];
    [style setImage:[UIImage imageNamed:@"oval"] forName:@"oval"];
    
    NSDictionary *stops = @{ @10: [NSExpression expressionForConstantValue:@"circle"],
                             @25: [NSExpression expressionForConstantValue:@"rectangle"],
                             @75: [NSExpression expressionForConstantValue:@"star"],
                             @150: [NSExpression expressionForConstantValue:@"oval"] };

    // Use expressions to set each cluster's image based on defined stops and display the point count over the corresponding image
    NSExpression *defaultShape = [NSExpression expressionForConstantValue:@"squircle"];
    clusterLayer.iconImageName = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(point_count, %@, %@)", defaultShape, stops];
    clusterLayer.text = [NSExpression expressionWithFormat:@"CAST(point_count, 'NSString')"];
    
    [style addLayer:clusterLayer];
}

@end
```