1

I would like to draw surface contour plot like the picture below for an iOS mobile application (swift)

enter image description here

If someone can put me on the right track, I will appreciate it.

I searched on Internet, I didn't find any obvious solution. I consider to use SceneKit or SciChart.iOS package but I'm not sure.

Jeff 974
  • 69
  • 1
  • 4

3 Answers3

2

Charts were introduced by Apple on iOS16 and every other Apple platform (see here for a short official description: https://developer.apple.com/documentation/charts)

I found a GitHub project that aims at replicating the nice-looking charts that Apple teased at the WWDC 2022 (see here the video showing briefly the charts https://developer.apple.com/videos/play/wwdc2022/10137/)

enter image description here

Here is the link to the GitHub project by Jordi Bruin: https://github.com/jordibruin/Swift-Charts-Examples

I could extract a simplified one-file HeatMap that is close to a ContourPlot, so I guess you could start from that.

import SwiftUI
import Charts

struct Grid {
    let numRows: Int
    let numCols: Int
    var points = [Point]()

    init(numRows: Int, numCols: Int) {
        self.numRows = numRows
        self.numCols = numCols
        generateData()
    }
    
    mutating func generateData() {
        for rowIndex in 0..<numRows {
            for colIndex in 0..<numCols {
                let maxValue = numRows + numCols - 2
                let variance = Double.random(in: 0..<20) - 10
                let value = (Double(rowIndex + colIndex) * 100)/Double(maxValue) + variance
                let point = Point(x: Double(colIndex), y: Double(rowIndex), val: value)
                points.append(point)
            }
        }
    }
}

struct ContentView: View {
    @State var grid = Grid(numRows: 20, numCols: 20)
    
    var gradientColors: [Color] = [.blue, .green, .yellow, .orange, .red]

    var body: some View {
        Chart(grid.points) { point in
            Plot {
                let xVal = Int(point.x)
                let yVal = Int(point.y)
                let val = Int(point.val)
                RectangleMark(
                    xStart: PlottableValue.value("xStart", xVal),
                    xEnd: PlottableValue.value("xEnd", xVal + 1),
                    yStart: PlottableValue.value("yStart", yVal),
                    yEnd: PlottableValue.value("yEnd", yVal + 1)
                )
                .foregroundStyle(by: .value("Value", val))
            }
        }
        .chartForegroundStyleScale(range: Gradient(colors: gradientColors))
        .chartYAxis {
            AxisMarks(values: .automatic(desiredCount: grid.numRows, roundLowerBound: false, roundUpperBound: false)) { _ in
                AxisGridLine()
                AxisTick()
                AxisValueLabel(centered: true)
            }
        }
        .chartXAxis {
            AxisMarks(values: .automatic(desiredCount: grid.numCols, roundLowerBound: false, roundUpperBound: false)) { _ in
                AxisGridLine()
                AxisTick()
                AxisValueLabel(centered: true)
            }
        }
        .aspectRatio(1, contentMode: .fit)
    }

}

struct Point: Hashable, Identifiable {
    let id = UUID()
    let x: Double
    let y: Double
    let val: Double
}

Here is the result of this code on an iPhone 14 Pro simulator (iOS 16.0). I will be different for every iteration of the code you will execute since the values are input as random, just for you to get an idea.

enter image description here

Guillaume
  • 33
  • 5
  • Dear Guillaume, Thanks a lot for your answer. I'm considering also Mapbox and Google Maps SDK but not so easy to implement. Regards. – Jeff 974 Dec 21 '22 at 17:19
  • Hello Jeff, you're welcome! I'm also interested in other methods (less squares and more interpolation) so if you want to share more details about what you found in Mapbox and Google Maps, it would be much appreciated. I'm more often working with Python, and an equivalent to matplotlib contourf would be really nice (https://www.tutorialspoint.com/matplotlib/matplotlib_contour_plot.htm). – Guillaume Dec 22 '22 at 19:42
  • Dear Guillaume, I used the shepard's method interpolation to modify the code you provided. This method is very well documented on internet and it looks working pretty well. I you want the modified code, let me know. However, I have a question regarding the code you sent me : I am unabled to pass the array of data from the content view to the Grid structure. I would like to modify the code you provided like this : Grid(numRows: 200, numCols: 200, data : heatmapData). If you have an idea.. Many thanks for you help! Best regards. Jeff – Jeff 974 Jan 09 '23 at 15:05
1

You tagged [scichart] so I can post an answer.

While the WPF and Javascript versions of SciChart support contours in 2d charts, it seems SciChart's ios/android heatmap does not.

But it does have this 3d contour plot which can be viewed from above by setting Orthogonal projection & position of the camera in the 3D scene.

enter image description here

You can learn more about the 3d camera properties here. Property projectionMode sets orthogonal mode, and position / target allow you to control the view from above.

There is also a demo on the scichart examples app which allows you manipulate the 3d camera dynamically. see it here.

Dr. Andrew Burnett-Thompson
  • 20,980
  • 8
  • 88
  • 178
0

I did some work on coreplot & DGCharts framework for contouring: https://github.com/swainwri/core-plot-release-2.4-sw (objc) && https://github.com/swainwri/DCGCharts (swift). These are not complete in that not covered all bases for discontinuities in the contour function. enter image description here

swainwri
  • 66
  • 7