I have a bar graph which I’ve created. Each bar is a UIView. You can tap on each bar and it’ll display its value in a label above. How make it so that you could just slide/pan over the bars and it would select whichever bar your finger is over at that moment.
Post
Replies
Boosts
Views
Activity
I'm trying to create a model to predict a user's screen time based on a variety of factors. I created a model in Create ML which works for me but this obviously wouldn't work for anyone else. How do I basically create a new model in the app using a new csv table and keep on updating that model as the user records more data and updates the csv file?
This is possible in playgrounds since I can use the CreateML framework but this isn't available on iOS.
When I edit my main.swift file to hide parts of my code it hides some parts and some parts are still viewable. I'm having the same issue without other markup functions. Some titles are set some just display the comments.
When ever I tap the sumitBtn to train the model, I get an error for exampleDrawings.addDrawing(drawing) it is getting the drawing as an image properly so I'm not sure why its getting nil there.
struct ExampleDrawingSet {
/// The desired number of drawings to update the model
private let requiredDrawingCount = 3
/// Collection of the training drawings
private var trainingDrawings = [UserDrawing]()
/// The emoji or sticker that the model should predict when passed similar images
//let emoji: Character
let key = "Test Key"
/// A Boolean that indicates whether the instance has all the required drawings.
var isReadyForTraining: Bool { trainingDrawings.count == requiredDrawingCount }
var count: Int {
trainingDrawings.count
}
/*
init(for emoji: Character) {
self.emoji = emoji
}*/
/// Creates a batch provider of training data given the contents of `trainingDrawings`.
/// - Tag: DrawingBatchProvider
var featureBatchProvider: MLBatchProvider {
var featureProviders = [MLFeatureProvider]()
let inputName = "drawing"
let outputName = "label"
for drawing in trainingDrawings {
let inputValue = drawing.featureValue
let outputValue = MLFeatureValue(string: key)
//let outputValue = MLFeatureValue(string: String(emoji))
let dataPointFeatures: [String: MLFeatureValue] = [inputName: inputValue,
outputName: outputValue]
if let provider = try? MLDictionaryFeatureProvider(dictionary: dataPointFeatures) {
featureProviders.append(provider)
}
}
return MLArrayBatchProvider(array: featureProviders)
}
/// Adds a drawing to the private array, but only if the type requires more.
mutating func addDrawing(_ drawing: UserDrawing) {
if trainingDrawings.count requiredDrawingCount {
trainingDrawings.append(drawing)
}
}
}
class Page6MachinLearning: UIViewController, PKCanvasViewDelegate {
@IBOutlet var canvasView: PKCanvasView!
@IBOutlet var submitBtn: UIButton!
var submitWorkItem: DispatchWorkItem?
var exampleDrawings: ExampleDrawingSet!
var drawingCount = Int()
override func viewDidLoad() {
super.viewDidLoad()
configureCanvasView()
}
@IBAction func submitBtn(_ sender: Any) {
print("User tapped \"Done\"; kicking off model update...")
submitDrawing(canvasView: canvasView)
drawingCount+=1
print(drawingCount)
if drawingCount == 3 {
// Convert the drawings into a batch provider as the update input.
let drawingTrainingData = exampleDrawings.featureBatchProvider
// Update the Drawing Classifier with the drawings.
DispatchQueue.global(qos: .userInitiated).async {
ModelUpdater.updateWith(trainingData: drawingTrainingData) {
DispatchQueue.main.async { self.dismiss(animated: true, completion: nil) }
}
}
} // End If
}
/// Configures the `PKCanvasView`
func configureCanvasView() {
canvasView.backgroundColor = .clear
canvasView.isOpaque = false
canvasView.tool = PKInkingTool(.pen, color: .white, width: 20)
canvasView.delegate = self
canvasView.allowsFingerDrawing = true
}
// MARK: - PKCanvasViewDelegate
func canvasViewDidBeginUsingTool(_ canvasView: PKCanvasView) {
// Cancel the submission of the previous drawing when a user begins drawing
// This lets the user draw another stroke without a time limit of 0.5 seconds
submitWorkItem?.cancel()
}
func canvasViewDrawingDidChange(_ canvasView: PKCanvasView) {
let drawingRect = canvasView.drawing.bounds
guard drawingRect.size != .zero else {
return
}
// Check if the user is crossing out previous stickers
let intersectingViews = canvasView.subviews
.compactMap { $0 as? UILabel }
.filter { $0.frame.intersects(drawingRect) }
guard intersectingViews.isEmpty else {
// If the current drawing intersects with existing stickers,
// remove those stickers
intersectingViews.forEach { $0.removeFromSuperview() }
canvasView.drawing = PKDrawing()
return
}
submitWorkItem = DispatchWorkItem { self.submitDrawing(canvasView: canvasView) }
DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + 5, execute: submitWorkItem!)
}
func submitDrawing(canvasView: PKCanvasView) {
// Get the rectangle containing the drawing
let drawingRect = canvasView.drawing.bounds.containingSquare
// Turn the drawing into an image
// Because this image may be displayed at a larger scale in the training view,
// a scale of 2.0 is used for smooth rendering.
let image = canvasView.drawing.image(from: drawingRect, scale: UIScreen.main.scale * 2.0)
// Store the white tinted version and the rectangle in a drawing object
let drawing = UserDrawing(image: image.cgImage!, rect: drawingRect)
didProduce(drawing: drawing, sender: self)
DispatchQueue.main.async {
canvasView.drawing = PKDrawing()
}
}
}
extension Page6MachinLearning: DrawingDelegate {
func didProduce(drawing: UserDrawing, sender: Any?) {
DispatchQueue.main.async { self.addDrawing(drawing) }
}
func addDrawing(_ drawing: UserDrawing) {
print("drawing - \(drawing)")
exampleDrawings.addDrawing(drawing) //Error here
}
}
When I try update my model I just get a nil error here.
private static func saveUpdatedModel(_ updateContext: MLUpdateContext) {
let updatedModel = updateContext.model
let fileManager = FileManager.default
do {
// Create a directory for the updated model.
try fileManager.createDirectory(at: tempUpdatedModelURL,
withIntermediateDirectories: true,
attributes: nil)
// Save the updated model to temporary filename.
try updatedModel.write(to: tempUpdatedModelURL)
print("tempUpdatedModelURL - \(tempUpdatedModelURL)")
// Replace any previously updated model with this one.
_ = try fileManager.replaceItemAt(updatedModelURL,
withItemAt: tempUpdatedModelURL)
print("Updated model saved to:\n\t\(updatedModelURL)")
} catch let error {
print("Could not save updated model to the file system: \(error)")
return
}
}
It creates the update task fine and the printed URL below is correct.
extension UpdatableDrawingClassifier {
/// Creates an update model from a given model URL and training data.
///
/// - Parameters:
/// - url: The location of the model the Update Task will update.
/// - trainingData: The training data the Update Task uses to update the model.
/// - completionHandler: A closure the Update Task calls when it finishes updating the model.
/// - Tag: CreateUpdateTask
static func updateModel(at url: URL,
with trainingData: MLBatchProvider,
completionHandler: @escaping (MLUpdateContext) - Void) {
// Create an Update Task.
guard let updateTask = try? MLUpdateTask(forModelAt: url,
trainingData: trainingData,
configuration: nil,
completionHandler: completionHandler)
else {
print("Could't create an MLUpdateTask.")
return
}
updateTask.resume()
print("Updating Model - updateTask.resume()")
print("URL - \(url)")
}
}
I've got a view where I need the animation to repeat with a completion handler and update labels. The animation only runs once and then it doesn't repeat.
let sums = ["add(5, 7)", "mult(6, 20)", "div(15, 3)", "mult(2, 1)"]
let answers = [12, 120, 5, 2]
func sumAnimation() {
for i in 0...sums.count-1 {
inputLbl.text = sums[i]
inputLbl.frame = CGRect(x: 0, y: 13, width: Int(inputLbl.frame.width), height: Int(inputLbl.frame.height)) // move to 340
UIView.animate(withDuration: 3 - clockSpeed/2) {
self.inputLbl.transform = CGAffineTransform(translationX: 700, y: 0)
} completion: { (true) in
self.outputLbl.text = "ansr(\(self.answers[i]))"
} // End Completion
} // End Loop
} // End Func