I need to draw a networkx graph with x axis ranges are repeating, such as 0-100, 0-100,0-100 etc. Nodes are distributed along these x axis domains and there can be edges connecting the nodes between different domains. To make it easier to understand, I share an image below that is similar to how I want x-axis to be, but with matplotlib and/or plotly. Plotly is more important. I label each node with their corresponding domain number, 12 or 13, in a dataframe column. An example is
Node 1 | Node 2 | y axis | x1 | domain
1534 945 20 22803603 13
945 946 10 32494954 12
946 - 9 32530403 12
where the edges are represented with Node1-Node2 and the rest of the columns belong to Node1. The last row doesn't connect to another node. Example code is
import networkx as nx
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(10,10))
ax = fig.add_subplot(111)
G = nx.DiGraph()
G.add_node(1534,pos=(22803603,20))
G.add_node(945,pos=(32494954,10))
G.add_node(946,pos=(32530403,9))
G.add_edge(1534,945)
G.add_edge(945,946)
pos=nx.get_node_attributes(G,'pos')
nx.draw_networkx(G,pos)
ax.tick_params(left=True, right=True, top=True, bottom=True, labelleft=True, labelbottom=True)
In plotly, I follow the example here by just replacing random graph with the G above: https://plotly.com/python/network-graphs/#color-node-points
This is the example figure. I don't care about the shape of the nodes or the curvature of edges. All I care is the x-axis formatting.
Related
I am using igraph to analyze a network and find a specific kind of triad as subgraphs of the main network. I successfully did that but now I'm trying to plot these subgraphs in a multipanel figure using matplotlib.
import pandas as pd
import igraph as ig
import matplotlib.pyplot as plt
import math
# some long hidden code here to generate the main network (g)
# the triad pattern
ffl = g.Isoclass(n=3, cls=7, directed=True)
# finding the subgraphs
sub = g.get_subisomorphisms_vf2(ffl)
# trying to plot the subgraphs
ffls = []
for i in range(len(sub)):
vtx = g.vs.select(sub[i])
ffl = g.subgraph(vtx)
ffl.vs['name'] = g.vs[sub[i]]['name']
ffls.append(ffl)
visual_style = {'layout': 'reingold_tilford',
'vertex_label_size': 15}
fig, axs = plt.subplots(nrows=7, ncols=4, figsize=(15,25))
plt.subplots_adjust(wspace=0.5, hspace=0.5)
axs = axs.ravel()
for ax in axs:
ax.set_axis_off()
for ffl, ax in zip(ffls, axs):
ig.plot(ffl, target=ax, vertex_label=ffl.vs['name'], **visual_style)
plt.show()
The resulting figure shows all the subgraphs as intended but without the colors of the edges (that I already defined in the main network). I know the colors are being captured in the subgraphs because when I plot them individually the colors are there (also the attributes are correctly assigned to the edges). Only when I try to plot them all together that I have this "problem".
What I am doing wrong? It is possible to show the edge colors when using plt.subplots()? Can someone help me?
I've tried setting edge_color, color, face_color in the plot function but none of them worked. Actually only edge_color works but it sets the color for all edges.
The only way that worked was setting the edgecolor in the axes' children directly after plot. Take a look at the solution below:
for ffl, ax in zip(ffls, axs):
ig.plot(ffl, target=ax, vertex_label=ffl.vs['name'], **visual_style)
ax.set_xlim(-1, 1.25)
ax.set_ylim(-0.5, 1.25)
children = ax.get_children()
for i, e in enumerate(ffl.es):
edge = children[i + 4] # Skip the vertex and the 3 labels
edge.set_edgecolor(e['color'])
edge.set_in_layout(True)
This is the resulting screenshot:
I need to plot several circular graphs in a figure having multiple rows and columns. A simple example is given by the following, where I create a subplot with 2 rows and 2 columns. Each entry contains a circle graph having 10, 6, 8, and 8 nodes, respectively.
import networkx as nx
from matplotlib import pyplot as plt
from matplotlib.pyplot import figure
plt.rcParams["figure.figsize"] = (8,8)
n1=10
labels1={k:str(k) for k in range(n1)}
G1=nx.Graph()
G1.add_nodes_from(range(n1))
n2=6
labels2={k:str(k) for k in range(n2)}
G2=nx.Graph()
G2.add_nodes_from(range(n2))
n3=8
labels3={k:str(k) for k in range(n3)}
G3=nx.Graph()
G3.add_nodes_from(range(n3))
n4=8
labels4={k:str(k) for k in range(n4)}
G4=nx.Graph()
G4.add_nodes_from(range(n4))
fig,ax=plt.subplots(2,2)
node_size=250
nx.draw_circular(G1,labels=labels1,node_size=node_size,ax=ax[0,0],node_color='red')
nx.draw_circular(G2,labels=labels2,node_size=node_size,ax=ax[0,1],node_color='gray')
nx.draw_circular(G3,labels=labels3,node_size=node_size,ax=ax[1,0],node_color='yellow')
nx.draw_circular(G4,labels=labels4,node_size=node_size,ax=ax[1,1],node_color='cyan')
plt.show()
The resulting figure is given below. How can I shrink the radii of the circles, which will be useful when I add several more rows and/or columns to my subplots??
Instead of using nx.draw_circular, you can use nx.draw with the node positions set with nx.circular_layout. You can then adjust the radius of nx.circular_layout by changing the scale argument. Finally, when you call plt.subplots, you should change sharex and sharey to True to make sure that the subplots have the same y and x limits.
See code below:
import networkx as nx
from matplotlib import pyplot as plt
from matplotlib.pyplot import figure
plt.rcParams["figure.figsize"] = (8,8)
n1=10
labels1={k:str(k) for k in range(n1)}
G1=nx.Graph()
G1.add_nodes_from(range(n1))
n2=6
labels2={k:str(k) for k in range(n2)}
G2=nx.Graph()
G2.add_nodes_from(range(n2))
n3=8
labels3={k:str(k) for k in range(n3)}
G3=nx.Graph()
G3.add_nodes_from(range(n3))
n4=8
labels4={k:str(k) for k in range(n4)}
G4=nx.Graph()
G4.add_nodes_from(range(n4))
fig,ax=plt.subplots(2,2,sharex=True, sharey=True)
node_size=250
nx.draw(G1,pos=nx.circular_layout(G1,scale=0.2),labels=labels1,node_size=node_size,ax=ax[0,0],node_color='red')
nx.draw(G2,pos=nx.circular_layout(G2,scale=0.4),labels=labels2,node_size=node_size,ax=ax[0,1],node_color='gray')
nx.draw(G3,pos=nx.circular_layout(G3,scale=0.6),labels=labels3,node_size=node_size,ax=ax[1,0],node_color='yellow')
nx.draw(G4,pos=nx.circular_layout(G4,scale=0.8),labels=labels4,node_size=node_size,ax=ax[1,1],node_color='cyan')
plt.show()
And the output:
So I am trying to generate a hexagonal lattice using NetworkX in Python. After using code:
G = nx.hexagonal_lattice_graph(m=2, n=2, periodic=False, with_positions=True, create_using=None)
plt.subplot(111)
nx.draw(G, with_labels=True, font_weight='bold')
plt.show()
I am getting a hexagonal lattice which looks like this:
lattice
As you can see, this lattice is formed from irregular hexagons and everytime the code is ran the shape changes. Is there a way to generate a perfect hexagonal lattice using NetworkX, i.e this, but with only X number of hexagons?
Thanks!
You need to use the with_postion attribute in the hexagonal_lattic_graph function and set it to True. This will store the positions of the nodes in an attribute called pos inside the Graph G itself. You can read more about from the documentation here:
with_positions (bool (default: True)) – Store the coordinates of each node in the graph node attribute ‘pos’. The coordinates provide a lattice with vertical columns of hexagons offset to interleave and cover the plane. Periodic positions shift the nodes vertically in a nonlinear way so the edges don’t overlap so much.
So, you just need to extract the positions from the graph itself, like this:
pos = nx.get_node_attributes(G, 'pos')
Then, pass this with pos while drawing your graph
import networkx as nx
import matplotlib.pyplot as plt
# create the graph and set with_positions=True
G = nx.hexagonal_lattice_graph(m=2, n=2, periodic=False, with_positions=True, create_using=None)
plt.subplot(111)
# Extract the positions
pos = nx.get_node_attributes(G, 'pos')
# Pass the positions while drawing
nx.draw(G, pos=pos, with_labels=True, font_weight='bold')
plt.show()
I have coordinate data with following columns:
lat | lon | hits
I want to plot a choropleth using these data with color on the basis of hits, on top of OSM tile.
plot = figure(
tools= "pan,wheel_zoom",
x_range=[8580732.740161393, 8694052.230954666],
y_range=[3324832.84084286, 3580909.760461876])
plot.add_tile(get_provider(Vendors.OSM))
Till now what I have learned is we need boundaries of regions which are colored, but I don't have geojson for locality boundaries in smaller cities of India. Is there any way possible to plot choropleth using square/rectangular grids or clustering the coordinates?
The only thing in Bokeh that will do automatic binning is hexbin:
import numpy as np
from bokeh.plotting import figure, show
n = 500
x = 2 + 2*np.random.standard_normal(n)
y = 2 + 2*np.random.standard_normal(n)
p = figure(match_aspect=True, background_fill_color='#440154')
p.grid.visible = False
r, bins = p.hexbin(x, y, size=0.5, hover_color="pink", hover_alpha=0.8)
p.circle(x, y, color="white", size=1)
show(p)
If you want something besides hex tiles, you would have to define the boundaries/regions you want explicitly, and bin inside them yourself.
Groups Counts
1 0-9 38
3 10-19 41
5 20-29 77
7 30-39 73
9 40-49 34
I want to create a bar graph using matplotlib.pyplot library with groups on x-axis and Counts on y-axis. I tried it out using following code
ax = plt.subplots()
rects1 = ax.bar(survived_df["Groups"], survived_df["Counts"], color='r')
plt.show()
but I'm getting following error
invalid literal for float(): 0-9
The first array given to the plt.bar function must be numbers corresponding to the x coordinates of the left sides of the bars. In your case, [0-9, 10-19, ...] is not recognized as valid argument.
You can however make the bar plot using the index of your DataFrame, then defining the position of your x-ticks (where you want your label to be positioned on the x axis) and then changing the labels of your x ticks with your Groups name.
fig,ax = plt.subplots()
ax.bar(survived_df.index, survived_df.Counts, width=0.8, color='r')
ax.set_xticks(survived_df.index+0.4) # set the x ticks to be at the middle of each bar since the width of each bar is 0.8
ax.set_xticklabels(survived_df.Groups) #replace the name of the x ticks with your Groups name
plt.show()
Note that you can also use the Pandas plotting capabilities directly with a one liner:
survived_df.plot('Groups', 'Counts', kind='bar', color='r')