Last time we saw how we can add attributes to the edges NetworkX in order to represent different values that they might have on the network. Here we have an example of a network where the color of the edges represents the relationship between the nodes, and there's a number on the edges that represent how many times they had lunch together. In the previous video, we saw that to construct this graph, we can add attributes to the edges when we create them. Here, we're adding the edge AB with the attribute weight of six and the attribute relation of family, and same thing for other edges, we'll also add the edge B and C with weight 13 and relation friend. In this video, we're going to look at how to add an access attributes of both edges and nodes in different types of graphs. Let's say you have a network and the edges have multiple attributes. How do we access these attributes? Well, let's start with the edges. Let's say you just want a list of all of the edges. For that, you can use the function edges without any input and this will give us a list of all of the edges in the network without any of the attributes. Since we only have two edges in this network that we've added, our list is pretty short. Now, if you want to get a little more data on these edges, then you would use the same function, but now you would say data equals true and now you get all of the edges and their attributes. For each edge, you would get triplets with the nodes A and B as the first two entries, those are the endpoints of the edge, and then you get a dictionary as the third entry. The dictionary has the attribute name says the keys, so in this case we have weight and relation and the corresponding value, so in this case we have weight of six and relation, family, and same thing for all of the other edges. Now, let's say that we're only interested in a particular attribute. Then you can say data equals relation, for example, and now you get triplets that will have the two nodes and the value of the attribute for the two nodes, so we have the note A and B, and then the relation is family. But what if we want to access the attributes of a specific edge without listing all of the attributes of all of the edges. This could be useful in particular, if you are working with a very large network, think of a network with millions and millions of edges. You wouldn't want to list all over those edges. But maybe you want to access a particular one. You can do that by passing the two nodes you are interested in two edges, and this returns a dictionary with each of the attributes as keys and their value, and if you're only interested in a specific attribute, you can, of course, access its value in the dictionary. For example, you can access the weight of the edge BC and get the value 13. Notice that because this graph is undirected, the order in which we place the endpoints of the edge does not matter, so if you were to ask for the weight of the edge CB instead of BC, the answer is still 13. But what if we have a directed network? Let's change our network so that the edges now have direction. We would now construct a network using the directed graph class that we saw before, and then we would add the edges and their attributes in the exact same way we did before, like this. But now we have to pay attention to the direction. When we're adding the edge AB, we have to add it in this specific order, AB and BA, since the edge goes in this direction. We could also access the attributes of the edges in the same way, so here we're asking for the weight of the edge CB, which is 13. But if we switch the order and ask for the weight of the edge BC, you would get an error because this edge doesn't exist. When we're using a directed graph, the order really matters because the edges have a very specific direction. Now, let's see how this works for multiGraphs. As we saw before, the way you would represent a network that has multiple edges between the same pair of nodes, is by using the multiGraph class. Now, we can add multiple edges connecting the same pair of nodes multiple times, and you can give them different attributes. Here we're going to be adding an edge that connects the end points A and B, and it's going to have a weight of six and a relation family. Now, we're going to be adding another edge connecting the same end points, but now is going to have weight of 18 and relation friend. We're also going to add a third edge BC. Now, how do we access the attributes of these edges? Well, if we ask for the attributes of the edge AB, we will get a dictionary of the attributes for each of the edges that connect the endpoint AB. Here is a dictionary for the first edge which is labeled zero because that's the first one we entered, and this one has relation family and weight of six. Then we get another entry with a dictionary that contains information for the second edge that we entered, which has the weight of 18 and relation friend. If we're interested in the specific attributes for a specific edge, let's say the first one that we added, then we can access it directly like this. Here we're asking for the weight of the first edge between nodes A and B, which is six and the zero here indicates that we're asking for the first edge. If we were to change this zero to a one, then we would get the weight for the other edge, which is 18. Note that because this is an undirected graph, the order in which we enter the endpoints doesn't matter. Now let's consider a multiGraph that is both weighted and also directed. For this kind of graph, we'll actually use a class we haven't seen before. It is a multiDigraph, which stands for multi directed graph and of course now the edges have direction and there can be multiple edges between any two pair of nodes. Let's add the edges in the same way we did before, but now we have to be careful about how do we add them. We have to make sure we had them in the right direction. Here we're adding the edge AB, another edge AB as we did before, and then the edge CB, and we can access the attributes of these edges in the same way we did before, but now the order matters. If we ask for the weight of the first edge, we get six, and if we were to ask for the weight of the edge BA, then would get an error because this edge doesn't exist. Again, order matters now that the graph is directed. So far, we have talked about how to add an access attribute of edges, but you could also imagine having attribute stored on the nodes. Let's go back to this example of how many times co-workers had lunch together and what kind of relationship they have. We could imagine that the nodes can also have attributes of interest. For example, imagine that they are colored by their role in the company. Let's say this is a hedge fund in some of the nodes or managers, or there are traders and other our analysts. This adds a little bit more information that we may want to capture when we construct their network. How can we do this? Well, we can begin to construct the network by adding the edges as we did before. Now, we also want to add attributes on the nodes. To do this, we can use the function add node. Here, we're adding node A and we're given it the role trader. Note that even though this node A is already in the graph, because we already added the edge AB, we can add it again to set the attribute of the node without interfering with the edge, so the edges are still going to be there even though you're adding this node A again. Now, let's add the role of node B, who's a trader, and the role of node C who's a manager. Then to access these attributes would do it in the following way. First, if we just want the list of all of the nodes without any of the attributes, we can use the function nodes with no input and we get our three nodes that we've added. But if we wanted the attributes of the nodes, then just like we did for edges, we would say data equals true. Now we get a dictionary with the attributes of each of the nodes. We can also access the role of a specific node without generating a list of all of them. For example, here we're accessing the role of node C, who's a manager, and so we get that value of manager. In summary, in this lecture, we looked at how we can add an access attribute for nodes and edges. Depending on what we're doing and the size of the network, sometimes we want to list all of the nodes and all of the edges with and without their attributes. But sometimes we want to access the attributes of a specific node and a specific edge. Thank you for listening to this video, and I hope to see you in the next one.