3

I was looking to get some help or clarification of the limitations of using PythonKit in Swift. Well I say PythonKit, I actually installed the Tensorflow toolchain in Xcode as I couldn't get Pythonkit to work on its own as a single dependancy (MacBook would spin its wheels with fans blasting trying to import numpy).

Anyway I wanted to say its brilliant that I can use Python modules in Swift, makes it much easier to potentially start using swift for more than just iOS apps.

My issue is that I have imported Python modules fine but its not clear how much functionality they will have. I assume ones like numpy will be pretty much the same but as a scientist I use netcdf files a lot so have been trying to use netCDF4. This imports fine and I can load the data object and attributes etc fine but I can't get the actual array out.

Here is an example:

import PythonKit
PythonLibrary.useVersion(3, 7)

let nc = Python.import("netCDF4")

var Data = nc.Dataset("ncfile path")
var lat_z = Data.variables["lat_z"][:]

The [:] is causing an error that is picked up by Xcode, removing it allows the script to run but results in the variable object rather than the array. I can add stuff to the end to get the attributes etc e.g. lat_z.long_name but not sure of how to extract the array without using [:]

I am hoping this is just a syntax difference that I need to learn with swift (very much early days with using it) or is it a limitation of the PythonKit? I have not found anyone atcually using netcdf4 (examples are mostly numpy and Matplotlib) If so are there some general limitations with using python modules in swift?

I am also trying to get Matplotlib to work but am pretty sure thats due to using an commandline tool project in Xcode which hasn't got a view so makes sense it can't show me an image.

Any pointers and maybe links to upto date documentation would be great there seems to be some changes that have occurred e.g. import PythonKit rather than import Python.

Many Thanks

marc-medley
  • 8,931
  • 5
  • 60
  • 66
thopri
  • 33
  • 3
  • The documentation says that this object is like a numpy array, have you tried to import numpy and do numpy operations on it? – Louis Lac Apr 29 '20 at 17:15
  • Because lat_z is a PythonObject you have two choices: cast this object to a Swift structure (like an Array) or use python methods such as numpy ones. – Louis Lac Apr 29 '20 at 17:16
  • You cannot use [:] in Swift, it does not have the same meaning as in python. You can use numpy ranges (np.range()) instead. – Louis Lac Apr 29 '20 at 17:17
  • Ah cool, I had never realised that. Will give that ago – thopri Apr 29 '20 at 17:39

1 Answers1

1

You can use the count property on a python iterable, which is equivalent to len. You can index Numpy array in two ways: (i) with Swift range syntax and (ii) with Numpy range objects:

import Foundation
import PythonKit

let np = Python.import("numpy")
let array = np.array([1, 2, 3, 4, 5])

print(array)  // [1, 2, 3, 4, 5]

let subArray = array[0..<array.count] 
print(subArray)  // [1, 2, 3, 4, 5]

let subArray2 = array[np.arange(0, 2)]
print(subArray2)  // [1, 2]

// Swift equivalent of Python ":"
let subArray3 = array[...]

You can also convert numpy arrays to Swift arrays and use Swift methods and subscripts:

let swiftArray = Array(array)
let swiftSubArray = swiftArray[0..<3]

print(swiftSubArray)  // [1, 2, 3]

Note that you should prefer using Python.len(...) over the count property while working with PythonObjects because count will incur performance penalty because of the implementation of PythonKit that does not automatically conforms Python Object to RandomAccessCollection (thus count is O(n)).

Louis Lac
  • 5,298
  • 1
  • 21
  • 36