I am trying to draw graph with different colours edges by using graphviz in Python. I am creating colour list and using in edge colour. However, it looks like it does not support in graphviz. I am not sure how to set different colour of edges. Here is my code:
import graphviz as gv
d = gv.Digraph()
colors = ['green','red']
d.attr('edge', color = colors)
d.edge('hello','world')
d.edge('world','hello')
d.view()
Looking for valuable comments. Thanks
import graphviz as gv
colors = ['green','red']
def create_graph(colors, d):
d.edge('hello','world', color=colors[0])
d.edge('world','hello', color=colors[1])
d.view()
if __name__ == '__main__':
d = gv.Digraph()
create_graph(colors, d)
I don't really know the python wrapper for graphviz,but if by different colour of edges you mean multiple colors (?), you may try the following:
d.attr('edge', color = 'green:red')
Otherwise, if you'd like to have a green and a red edge, the following may work:
d.edge('hello','world', color='green' )
d.edge('world','hello', color='red' )
Related
I'm using the Louvain Algorithm below for community detection using graphs that I insert manually.
I have 2 problems here. The first one is about the color of the nodes. The color of each community of nodes, as you see below, is a bit dark or white and it is not clear as which are the exact communities.
So, which is the way to draw each community of nodes into brighter colors?
And my last question, any ideas to save the results into a new .txt after the community detection is done?
partition = community.best_partition(G)
values = [partition.get(node) for node in G.nodes()]
#drawing
size = float(len(set(partition.values())))
posi = nx.spring_layout(G)
count = 0
for com in set(partition.values()):
count = count + 1.
list_nodes = [nodes for nodes in partition.keys()
if partition[nodes] == com]
nx.draw_networkx_nodes(G, posi, list_nodes, node_size = 25, node_color=str(count/size))
#nx.draw_spring(G, cmap = plt.get_cmap('hsv'), node_color = values, node_size=30, with_labels=False)
nx.draw_networkx_edges(G, posi, alpha=0.5)
plt.show()
You can use the cmap parameter of draw_networkx_nodes, which allows you to specify any matplotlib.colormap. See here or here1 for example.
Minimal working colouring example:
import networkx as nx
import matplotlib.pylab as pl
graph = nx.karate_club_graph()
colors = []
for node in graph:
if graph.nodes[node]["club"] == "Mr. Hi":
colors.append(0)
else:
colors.append(1)
colors[0] = -1
colors[-1] = 2
nx.draw_networkx(graph, node_color=colors, vmin=min(colors), vmax=max(colors), cmap=pl.get_cmap("viridis"))
pl.axis("off")
pl.show()
For the saving of your graph, you can either choose a suitable graph format, such as GML. Then you first need to add the partition as node attribute to your graph:
for node in partition:
G.nodes[node]["cluster"] = partition[node]
# save file
nx.write_gml(G, "path_to_save_file")
# load file
saved_graph = nx.read_gml("path_to_save_file")
and afterwards save the graph together with the partition. Alternatively, you can only save the retrieved partition as json or (unsafe) via pickle.
I'm trying to plot a network where edges have different colors according to their Opens street map attribute ('highway'). It works if I use ox.graph, however, this generates a static map. If I use ox.plot.plot_graph_folium() I only get an interactive map if I set all edges to have the same color. If I assign to edge_color a list of colors it doesn't work.
import osmnx as ox
address_name='19, Molstraat, Van Leeuwenhoekkwartier, Delft, South Holland, Netherlands, 2611EM, Netherlands'
graph=ox.graph_from_address(address_name, distance=300)
ec = ['skyblue' if data['highway']=='footway'
else 'paleturquoise' if data['highway']=='residential'
else 'orange' if data['highway']=='cycleway'
else 'sienna' if data['highway']=='service'
else 'lightgreen' if data['highway']=='living street'
else 'grey' if data['highway']=='secondary'
else 'lightskyblue' if data['highway']=='pedestrian'
else 'black' for u, v, key, data in graph.edges(keys=True, data=True)]
#this works, but is static
ox.plot_graph(graph,fig_height=8,fig_width=8,node_size=0, edge_color=ec)
#this does not work
import folium
ox.plot.plot_graph_folium(graph, popup_attribute='highway',edge_color=ec)
#this works, but is one color only
import folium
ox.plot.plot_graph_folium(graph,popup_attribute='highway',edge_color='blue')
This similar question (stackoverflow) suggests adding a new column to each edge and then modify the plot_graph_folium function. Also, this modification is not working. Could someone provide me with an example of how to make an interactive map with edges of different colors?
Yes, you can use OSMnx to create an interactive Leaflet web map with edges colored by type.
The OSMnx plot_graph_folium function can accept an edge color argument as a keyword argument (see the docs) that it just passes along to folium.PolyLine (see here). According to the folium docs, folium in turn just passes the keyword argument along to Leaflet. See the Leaflet docs here. Thus, there is no built-in way for OSMnx (as of the current release, v1.0.1) to create a Leaftlet web map with each edge given its own color. However, you can create an interactive Leaflet web map with edges colored by type (i.e., their highway value) with OSMnx, using a bit of code like this:
import osmnx as ox
address = '19, Molstraat, Van Leeuwenhoekkwartier, Delft'
G = ox.graph_from_address(address, dist=300)
# define the colors to use for different edge types
hwy_colors = {'footway': 'skyblue',
'residential': 'paleturquoise',
'cycleway': 'orange',
'service': 'sienna',
'living street': 'lightgreen',
'secondary': 'grey',
'pedestrian': 'lightskyblue'}
# return edge IDs that do not match passed list of hwys
def find_edges(G, hwys):
edges = []
for u, v, k, data in G.edges(keys=True, data='highway'):
check1 = isinstance(data, str) and data not in hwys
check2 = isinstance(data, list) and all([d not in hwys for d in data])
if check1 or check2:
edges.append((u, v, k))
return set(edges)
# first plot all edges that do not appear in hwy_colors's types
G_tmp = G.copy()
G_tmp.remove_edges_from(G.edges - find_edges(G, hwy_colors.keys()))
m = ox.plot_graph_folium(G_tmp, popup_attribute='highway', weight=5, color='black')
# then plot each edge type in hwy_colors one at a time
for hwy, color in hwy_colors.items():
G_tmp = G.copy()
G_tmp.remove_edges_from(find_edges(G_tmp, [hwy]))
if G_tmp.edges:
m = ox.plot_graph_folium(G_tmp,
graph_map=m,
popup_attribute='highway',
weight=5,
color=color)
m
Note that this solution can handle both simplified and unsimplified OSMnx edges (simplified edges can have multiple highway values). It will draw the edge each time it finds one of its edge types in the dictionary of types:colors. You can make this more precise by using an unsimplified graph (see OSMnx docs for details).
The goal is to create a networkx graph based on eigenvalue centrality and highlight the top five nodes of highest centrality measure with a different node color.
Below is my current script. It's working fine and everything's just set to one color for now.
#import packages
import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt
import collections
#read data into nx graph
G = nx.from_pandas_dataframe(df, 'col1', 'col2')
#get dictionary of centrality measures and order it
eig = nx.eigenvector_centrality(G)
ordered = collections.OrderedDict(sorted(eig.items(), reverse = True, key=lambda t: t[1]))
#draw graph
nx.draw_spring(G, k=1, node_color = 'skyblue',
node_size = 200, font_size = 6, with_labels = True)
plt.show()
Below is what I'm experimenting with for the node coloring. I'm attempting to append the first five ordered dictionary key names to the color_map, setting them to a different color from the rest. Please let me know if you have any suggestions here or if another method would simpler. If possible, I'd prefer to stick to the packages I'm using.
#adjust color of top three
color_map = []
for key, value in ordered:
if key < 5:
color_map.append('blue')
else: color_map.append('green')
Figured it out. There's no need to create a separate OrderedDict. Applying the key=eig.get argument to sorted() allows you to sort a dictionary by value (the biggest obstacle for this problem). Then I can just filter this and apply it to cmap.
Not a bad question, but I am pretty sure its a duplicate...Either way, I'll try to answer it. You will have to forgive me for being vague because I can't run your code and I've not tried to write an example of your problem. I will update my answer when I can run an example of your code later. However, for now I believe changing the node colour is similar to changing the edge colour. Going from that, you need to focus on the this line of your code to change the node colour;
#draw graph
nx.draw_spring(G, k=1, node_color = 'skyblue',
node_size = 200, font_size = 6, with_labels = True)
and this is an example of how you could do this;
# depending on how your graph is being read from the pandas-
# dataframe this should pull out the correct value to associate-
# the colour with
nodes = G.nodes()
# Just a list to hold all the node colours
node_colours = []
for node in nodes:
if node < 5:
node_colours.append('blue')
else:
node_colours.append('green')
#draw graph, substitute the single colour with ur list of colours
nx.draw_spring(G, k=1, node_color = node_colours,
node_size = 200, font_size = 6, with_labels = True)
I hope this helps! I will get back to it later when I test an example of this on my own machine.
-Edit-
Since the OP has answered his own question, I will not elaborate further with my example. However, if anyone is interested in my example (but if it unfortunately throws any error) and wants me to fix it and expand on it, just leave me a comment.
Tiz
I want to create a graph and draw it, so far so good, but the problem is that i want to draw more information on each node.
I saw i can save attributes to nodes\edges, but how do i draw the attributes?
i'm using PyGraphviz witch uses Graphviz.
An example would be
import pygraphviz as pgv
from pygraphviz import *
G=pgv.AGraph()
ndlist = [1,2,3]
for node in ndlist:
label = "Label #" + str(node)
G.add_node(node, label=label)
G.layout()
G.draw('example.png', format='png')
but make sure you explicitly add the attribute label for extra information to show as Martin mentioned https://stackoverflow.com/a/15456323/1601580.
You can only add supported attributes to nodes and edges. These attributes have specific meaning to GrpahViz.
To show extra information on edges or nodes, use the label attribute.
If you already have a graph with some attribute you want to label you can use this:
def draw_nx_with_pygraphviz_attribtes_as_labels(g, attribute_name, path2file=None):
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
# https://stackoverflow.com/questions/15345192/draw-more-information-on-graph-nodes-using-pygraphviz
if path2file is None:
path2file = './example.png'
path2file = Path(path2file).expanduser()
g = nx.nx_agraph.to_agraph(g)
# to label in pygrapviz make sure to have the AGraph obj have the label attribute set on the nodes
g = str(g)
g = g.replace(attribute_name, 'label') # it only
print(g)
g = pgv.AGraph(g)
g.layout()
g.draw(path2file)
# https://stackoverflow.com/questions/20597088/display-a-png-image-from-python-on-mint-15-linux
img = mpimg.imread(path2file)
plt.imshow(img)
plt.show()
# remove file https://stackoverflow.com/questions/6996603/how-to-delete-a-file-or-folder
path2file.unlink()
# -- tests
def test_draw():
# import pylab
import networkx as nx
g = nx.Graph()
g.add_node('Golf', size='small')
g.add_node('Hummer', size='huge')
g.add_node('Soccer', size='huge')
g.add_edge('Golf', 'Hummer')
draw_nx_with_pygraphviz_attribtes_as_labels(g, attribute_name='size')
if __name__ == '__main__':
test_draw()
result:
in particular note that the two huge's did not become a self loop and they are TWO different nodes (e.g. two sports can be huge but they are not the same sport/entity).
related but plotting with nx: Plotting networkx graph with node labels defaulting to node name
I have a series of lines that each need to be plotted with a separate colour. Each line is actually made up of several data sets (positive, negative regions etc.) and so I'd like to be able to create a generator that will feed one colour at a time across a spectrum, for example the gist_rainbow map shown here.
I have found the following works but it seems very complicated and more importantly difficult to remember,
from pylab import *
NUM_COLORS = 22
mp = cm.datad['gist_rainbow']
get_color = matplotlib.colors.LinearSegmentedColormap.from_list(mp, colors=['r', 'b'], N=NUM_COLORS)
...
# Then in a for loop
this_color = get_color(float(i)/NUM_COLORS)
Moreover, it does not cover the range of colours in the gist_rainbow map, I have to redefine a map.
Maybe a generator is not the best way to do this, if so what is the accepted way?
To index colors from a specific colormap you can use:
import pylab
NUM_COLORS = 22
cm = pylab.get_cmap('gist_rainbow')
for i in range(NUM_COLORS):
color = cm(1.*i/NUM_COLORS) # color will now be an RGBA tuple
# or if you really want a generator:
cgen = (cm(1.*i/NUM_COLORS) for i in range(NUM_COLORS))