Learn the basics of graphs
- Basic knowledge of Swift (understand how to code in swift)
- Basic knowledge of SwiftUI (understand the basic components in SwiftUI and how to use them)
- The will to learn!
Have you ever opened a website and come across a graph visualization such as this one?
This is called a Network Graph, and is commonly used to model relationships between many items. Some applications of such a graph are to visualize friends in a social network, interconnecting cities, or even the typical food chain you find in any Biology textbook. A Network Graph consists of two components, the vertex (or vertices) and the edges. A vertex represents the items that are visualized in the graph, and the edges show the relationships between similar items.
But have you ever wondered how such graphs are made? How do you lay out each items in the graph? I won’t go into too much detail about graph theory and whether you need one in your app, but what I will show you in this article is the technical details behind showing such a visualization for your SwiftUI app.
Before we get to deep on how to build complex graph visualizations with many vertices and edges, let’s first start with a basic graph. This simple graph has two vertices and one edge. It will look something like this:
First, we start with our background. Setup a SwiftUI project in Xcode (if you don’t know how to, check out tutorials from YouTube such as this one). You should start with an empty
To give the background for our graph, start by creating a
ZStack with a Rectangle as the first item. For the
ZStack, we will give it the
topLeading alignment for our coordinate system (I will explain this in a bit) and for the rectangle, just give it a fill with the color you desire for the background of your graph. I chose white.
Our graph works by plotting each vertex into a two-dimensional coordinate system in the
ZStack. Because we gave it the
topLeading alignment, the coordinate (0, 0) will start at the top left of the device screen.
Each pixel on your device screen represents a point in the coordinate system, where adding a value to the x coordinate moves our point to the right, and adding a value to the y coordinate moves our point down.
Now that we have our coordinate system, we can start by placing a vertex in the graph by using the Circle shape in SwiftUI (in reality, any shape would work but most graphs use a circle to represent a vertex).
We will modify two properties in our circle, the frame (how tall and wide our circle is) and the offset. The x and y values in the offset property of our circle dictates where the circle is placed within our graph’s coordinate system.
For example, if you input 50 for the x and y value, our circle should show up somewhere near the top left edge of our device’s screen. You can experiment with different x and y values, but you should remember that the greater the x, the more further right our circle will show up, and the greater the y, the further down our circle will be placed.
Now you should be able to see your vertex in the preview, however, you can see it’s a bit lonely on its own. So, let’s give it a friend somewhere else within the coordinate system of our graph. For this friend, I will color her red by giving the red value to the circle’s fill property.
Your screen should look something like this now:
If it doesn’t yet, don’t worry, stay calm and review the code that you have written with the snippets above.
Now, we will make these two vertices look like they are connected to each other by drawing a line between them. First, we will create a new Swift file and name it
EdgeShape.swift. In this file, we will add a new shape component to SwiftUI by creating a new Struct and making it conform to the
Shape protocol and call it
This struct will have two properties, start (the starting coordinate of the edge) and end (the ending coordinate of the edge). These will be of type
To conform to the Shape protocol, this struct must have one method, which is
path(in rect:). This method defines how to draw this shape in the UI. In this method’s implementation, we will do four things:
- Create a path object
- Move our path to the starting coordinate by using the
- Add a line from the starting coordinate by using the
- Return our path inside the method
The code for our EdgeShape should look something like this:
Now we can go back to our
ContentView.swift file and add the
EdgeShape component inbetween our two Circle components in the
ZStack to draw an Edge. First, give a start and end value to the
EdgeShape constructor by creating two
For the start
CGPoint, give its start x and y the same values as our black vertex’s coordinate. Then for the end
CGPoint, give its start x and y the same values as our red vertex’s coordinate.
Notice how the line has still not been drawn yet even though we already used our EdgeShape component. That’s because we have only drawn a path, but we haven’t given it any color or thickness. To do so, give our
EdgeShape a stroke, with optional color.
Yay! You have successfully connected your two vertices with an edge. However, you may notice that your edge seems to be out of place even though you placed your start and end coordinates correctly.
No worries, this behavior is totally expected, because the vertex is aligned by its top left corner to the coordinate we gave it, not the center. We will fix this, along with refactoring our code for our vertex view.
First, create a new Swift file named
VertexView.swift. Import SwiftUI in the file, then create a new struct that extends
VertexView with a body attribute of type some View.
This struct will have three other attributes,
radius of type
Double, color of type
Color, and the coordinate of type
- In the body property, we will define a Circle as we have done previously for our vertices then add a color property from our color attribute.
- Then, give the circle its frame attribute with the width and height being the radius multiplied by 2, and an offset attribute with the x and y attributes of the respective coordinate.
- However, we will now subtract the x and y values with the circle’s radius, to offset the circle according to its center.
Your code should look something like this:
Now, go back to the
ContentView.swift file, then replace each one of our Circle components with our newly built
VertexView. Make sure to give the same
CGPoint x and y values to each of the first
VertexView to the start of our
EdgeShape, and the second VertexView to the end of our
The code should look something like this:
Now, our UI should look something like this:
Next, you can experiment with the graph by adding as many vertices and edges as you’d like! Once you have done so, you can try the challenge of automatically showing the vertices and edges of the graph from an array of
CGPoint objects! (hint: use an array of
CGPoints with the
ForEach component in SwiftUI).
If you got stuck at any point during the tutorial, here’s the full source code of the project.
Also, if you’d like, it would be really nice if you could check out this project I made using to build a Force-Directed Graph in SwiftUI from the Graph basics we have learned!