Core Graphics Tutorial Part 2: Gradients and Contexts

@msheaver - The line

let context = UIGraphicsGetCurrentContext()

only gives you a handle to the current context being used by draw(_:). draw(_:) always draws into its context, so the context is always there.

@caroline, I thought that that was the case, and many thanks for confirming it for me!

1 Like

Thanks for the great tutorial.I have to set the Y axis minimum and maximum value .How can i do that?

I don’t think I understand the question. The y axis maxValue is taken from the maximum value in graphPoints, but you could change that, and you could set a minimum value and change the position calculations accordingly.

yes ,i need to set custom y axis min value
Currently its 0
I have no idea to change that minimum value.

@anishparajuli - I still don’t understand. Even with a minimum value, the graph would look the same, just the label containing 0 on the right hand side would have a different value.

The y points are calculated here:

   let columnYPoint = { (graphPoint:Int) -> CGFloat in
      var y:CGFloat = CGFloat(graphPoint) /
        CGFloat(maxValue) * graphHeight
      y = graphHeight + topBorder - y // Flip the graph
      return y

I guess you could add a minimum value to the returned y point if that’s what you’re after.

@caroline
Ok i will be more simpler

//Weekly sample data
var graphPoints:[Int] = [4, 2, 6, 4, 5, 8, 3]

As in the tuorial the y axis range is from 0 to 8


How can i set graph y-axis values between 2 to 6?

@anishparajuli - I’m not very good at maths, but something like this seems to work:

let maxValue = 6
let minValue = 2
let columnYPoint = { (graphPoint:Int) -> CGFloat in
  var y:CGFloat = CGFloat(graphPoint - minValue) /
    CGFloat(maxValue - minValue) * graphHeight
  y = graphHeight + topBorder - y // Flip the graph
  return y
}
1 Like

@caroline Wow
Thanks a lot.It works.
I appreciate your time.Have a nice day

1 Like

When you drag the UITapGestureRecognizer to the Container view, why does it show up at the very bottom of the object hierarchy, instead of being “inside” the Container view object? (well, that answer is obvious - “it just does
”) That would seem that having the gesture recognizer create/indicate a recognizer that only functioned within a particular view.

(If Cocoa Touch can do this that is. Of course, Apple already did 20 years ago on the Newton with TRecognizer::EnableArea(RecArea*, RefArg)
 (I’m guessing, since TRecognizer is sadly isn’t documented, as with the rest of the NewtonOS) Maybe they’ve forgotten? :slight_smile:

@jimw338 - It just does :stuck_out_tongue_winking_eye:

It annoys me too. But I guess objects that aren’t views don’t go into the hierarchy.

Firstly, thank you for this wonderful tutorial. This is the best and in-depth tutorial I could find online about plotting.

My question is regarding the block of code below:

//Draw the circles on top of graph stroke
for i in 0..<graphPoints.count {
  var point = CGPoint(x:columnXPoint(i), y:columnYPoint(graphPoints[i]))
  point.x -= 5.0/2
  point.y -= 5.0/2

  let circle = UIBezierPath(ovalInRect: 
           CGRect(origin: point, 
                    size: CGSize(width: 5.0, height: 5.0)))
  circle.fill()
}

How can I modify this code to add different labels to each data point like the one below:

Could you please help me in this regard.

I have posted this in StackOverFlow with many related questions. It would be great if you can help with them as well.

I’ve up to the point that sets the UILabels text, after figuring out what changes Apple has made to the calendar classes. I want to programmatically space the labels out. I can set the view.center coordinates easily enough, so that’s one way.

I read somewhere (can’t find it right now) that there’s not a way to “evenly space views” with auto-constraints, without using transparent “spacer” views between then. The view in question was a keyboard and the question was about spacing the keys.

Can I use auto-constraint to make (in IB or in code) a single constraint that would apply to multiple views? In this case, it would be a vertical-center-to-GraphView-edge constraint on all the labels at once.

Also, is there a method called when the view is resized? (Although the iOS doesn’t [yet?] have a multiple-window interface except for side-by-side mode). Is this “layoutMarginsDidChange”? Or is “draw” just called again?

@jimw338 - you don’t have to use “spacer” views any more - iOS 9 introduced layout guides.

I wrote a tutorial on coding constraints, but it doesn’t mention layout guides very much:

https://www.raywenderlich.com/125718/coding-auto-layout

You might be looking for layoutSubviews(). This is called after constraints have been calculated, and calculates frames for views. (This is mentioned in the above tutorial.)

@ecoapps - thank you for the kind words.

You have the x and y points where the circles are drawn. So all you have to do is either draw the text as in my example below, or if you want labels or buttons, put them in an array and work out the corresponding points and change the center property of the labels.

I added a property to the view:

var labelText: [NSString] = ["A", "B", "C", "D", "E", "F", "G"]

Then in the for loop that you quoted above, I added this at the end:

  let textPoint = CGPoint(x: point.x, y: point.y + 8)
  labelText[i].draw(at: textPoint, withAttributes: nil)

This resulted in this graph:

This obviously needs a bit of cleaning up as to exact text positions and colors, but that’s the general principle.

Edit: SwiftCharts looks pretty good.

@caroline
Thank you for your reply and sharing the code to add labels at data points. I tried adding your code in the locations below. However, as you can see, I am getting an error message. Not sure how to resolve it. Could you please help.

Ah - I was using Xcode 8 and Swift 3. If you’re on Swift 2, then it’s drawAtPoint. This one:
https://developer.apple.com/reference/foundation/nsstring/1533109-drawatpoint

    labelText[i].drawAtPoint(textPoint, withAttributes: nil)

(I think)

Hi Caroline!
Thank you for the great tutorial!
Do you know if i can use the graph in this style for one of my apps or will apple reject it when i submit it to the app store because it looks like their graphs in the health app?

@max_w - I haven’t submitted myself, but from memory there are a number of apps that use the same style of graph (I can’t find one now!). I don’t think it would be grounds for rejection if the app is not a complete clone.

However - the style of apps has slightly changed now to use fewer gradients. For example the graph in this app from Runtastic: