Plotting networkx and nxvis graph side by side - python

I want to plot these two images side by side:
import networkx as nx
import matplotlib.pyplot as plt
import nxviz as nv
test_G = nx.tutte_graph()
nx.draw(test_G)
plt.show()
m = nv.MatrixPlot(test_G)
m.draw()
plt.show()
I tried using:
fig = plt.figure(figsize=(2,1))
sub1 = fig.add_subplot(211)
...
but this creates a new set of axes, is there a standard way to plot images side by side, plt.figure approach seems to work only when I want to create the plot (such as plotting tuples).

nxvis is badly designed. It creates its own hardcoded 111 subplot in a fresh figure. An option may be to first create the nxvis plot and then change its position according to a gridspec.
(Again I haven't tested this, because I cannot install this nxviz package)
import networkx as nx
import matplotlib.pyplot as plt
import nxviz as nv
import matplotlib.gridspec
test_G = nx.tutte_graph()
m = nv.MatrixPlot(test_G)
m.draw()
gs = matplotlib.gridspec.GridSpec(2,1)
plt.gca().set_position(gs[1].get_position(plt.gcf()))
plt.gca().set_subplotspec(gs[1])
plt.subplot(gs[0])
nx.draw(test_G)
plt.show()

Related

Make width of seaborn facets proportional to the range of data along the x axis

I have used FacetGrid() from the seaborn module to break a line graph into segments with labels for each region as the title of each subplot. I saw the option in the documentation to have the x-axes be independent. However, I could not find anything related to having the plot sizes correspond to the size of each axis.
The code I used to generate this plot, along with the plot, are found below.
import matplotlib.pyplot as plt
import seaborn as sns
# Added during Edit 1.
sns.set()
graph = sns.FacetGrid(rmsf_crys, col = "Subunit", sharex = False)
graph.map(plt.plot, "Seq", "RMSF")
graph.set_titles(col_template = '{col_name}')
plt.show()
Plot resulting from the above code
Edit 1
Updated plot code using relplot() instead of calling FacetGrid() directly. The final result is the same graph.
import matplotlib.pyplot as plt
import seaborn as sns
# Forgot to include this in the original code snippet.
sns.set()
graph = sns.relplot(data = rmsf_crys, x = "Seq", y = "RMSF",
col = "Subunit", kind = "line",
facet_kws = dict(sharex=False))
graph.set_titles(col_template = '{col_name}')
plt.show()
Full support for this would need to live at the matplotlib layer, and I don't believe it's currently possible to have independent axes but shared transforms. (Someone with deeper knowledge of the matplotlib scale internals may prove me wrong).
But you can get pretty close by calculating the x range you'll need ahead of time and using that to parameterize the gridspec for the facets:
import numpy as np, seaborn as sns
tips = sns.load_dataset("tips")
xranges = tips.groupby("size")["total_bill"].agg(np.ptp)
xranges *= 1.1 # Account for default margins
sns.relplot(
data=tips, kind="line",
x="total_bill", y="tip",
col="size", col_order=xranges.index,
height=3, aspect=.65,
facet_kws=dict(sharex=False, gridspec_kws=dict(width_ratios=xranges))
)

Power BI shows only one patch from Matplotlib patch collection

I am trying to show a matplotlib plot in Power BI (desktop). It includes Patchcollection. Running the standalone python code gives this:
But in Power BI, the same code results in this:
Attaching sample code:
from matplotlib import pyplot as plt
from matplotlib.patches import Rectangle
from matplotlib.patches import Circle
import matplotlib.collections
import numpy as np
N = dataset.shape[0]
patches = []
# code to fill in the list patches goes here
fig = plt.figure()
ax = fig.add_subplot(111, aspect='equal')
colors = 100*np.random.random(N)
p = matplotlib.collections.PatchCollection(patches, cmap=matplotlib.cm.jet, alpha=0.4)
p.set_array(colors)
ax.add_collection(p)
plt.autoscale(enable='True', axis='both')
plt.show()
Any help will be appreciated. Thank you!
Edit: Just noticed that the values got doubled for that single patch. Very strange.
Figured out the issue. I had to choose 'Don't Summarize' in the values tab for each field.

Programmatically drawing overlaid offset plots in matplotlib

I have 3 different plots that are currently each saved as separate figures. However, due to space constraints I would like to layer them behind each other and offset like so:
I am trying to convey that a similar pattern exists across each plot and this is a nice and compact way of doing so. I would like to programmatically draw such a figure using matplotlib, but I'm not sure how to layer and offset the graphs using the usual pyplot commands. Any suggestions would be helpful. The following code is a skeleton of what I have currently.
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
window = 100
xs = np.arange(100)
ys = np.zeros(100)
ys[80:90] = 1
y2s = np.random.randn(100)/5.0+0.5
with sns.axes_style("ticks"):
for scenario in ["one", "two", "three"]:
fig = plt.figure()
plt.plot(xs, ys)
plt.plot(xs, y2s)
plt.title(scenario)
sns.despine(offset=10)
You can manually create the axes to plot into and position them as you like.
To highlight this approach modified your example as follows
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
window = 100
xs = np.arange(100)
ys = np.zeros(100)
ys[80:90] = 1
y2s = np.random.randn(100)/5.0+0.5
fig = plt.figure()
with sns.axes_style("ticks"):
for idx,scenario in enumerate(["one", "two", "three"]):
off = idx/10.+0.1
ax=fig.add_axes([off,off,0.65,0.65], axisbg='None')
ax.plot(xs, ys)
ax.plot(xs, y2s)
ax.set_title(scenario)
sns.despine(offset=10)
which gives a plot like
Here, I used fig.add_axes to add manually created axes objects to the predefined figure object. The arguments specify the position and size of the newly created axes, see docs.
Note that I also set the axes background to be transparent (axisbg='None').

matplotlib FuncAnimation input [duplicate]

What I want to do is create an animation in which the nodes of a graph change color with time. When I search for information on animation in matplotlib, I usually see examples that look something like this:
#!/usr/bin/python
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.animation import ArtistAnimation
fig = plt.figure(figsize=(8,8))
images = []
for i in range(10):
data = np.random.random(100).reshape(10,10)
imgplot = plt.imshow(data)
images.append([imgplot])
anim = ArtistAnimation(fig, images, interval=50, blit=True)
anim.save('this-one-works.mp4')
plt.show()
So I thought I could just do something like this:
#!/usr/bin/python
import numpy as np
import networkx as nx
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.animation import ArtistAnimation
G = nx.Graph()
G.add_edges_from([(0,1),(1,2),(2,0)])
fig = plt.figure(figsize=(8,8))
pos=nx.graphviz_layout(G)
images = []
for i in range(10):
nc = np.random.random(3)
imgplot = nx.draw(G,pos,with_labels=False,node_color=nc) # this doesn't work
images.append([imgplot])
anim = ArtistAnimation(fig, images, interval=50, blit=True)
anim.save('not-this-one.mp4')
plt.show()
What I'm stuck on is how, after drawing the graph using nx.draw(), I can get an object of the appropriate type to put in the array being passed to ArtistAnimation. In the first example, plt.imshow() returns an object of type matplot.image.AxesImage, but nx.draw() doesn't actually return anything. Is there a way that I can get my hands on a suitable image object?
Completely different approaches are welcome, of course (it seems like there's always many different ways to do the same thing in matplotlib), as long as I can save my animation as an mp4 when I'm done.
Thanks!
--craig
import numpy as np
import networkx as nx
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
G = nx.Graph()
G.add_edges_from([(0,1),(1,2),(2,0)])
fig = plt.figure(figsize=(8,8))
pos=nx.graphviz_layout(G)
nc = np.random.random(3)
nodes = nx.draw_networkx_nodes(G,pos,node_color=nc)
edges = nx.draw_networkx_edges(G,pos)
def update(n):
nc = np.random.random(3)
nodes.set_array(nc)
return nodes,
anim = FuncAnimation(fig, update, interval=50, blit=True)
nx.draw does not return anything, hence why your method didn't work. The easiest way to do this is to draw the nodes and edges using nx.draw_networkx_nodes and nx.draw_networkx_edges which return PatchCollection and LineCollection objects. You can then update the color of the nodes using set_array.
Using the same general frame work you can also move the nodes around (via set_offsets for the PatchCollection and set_verts or set_segments for LineCollection)
best animation tutorial I have seen: http://jakevdp.github.io/blog/2012/08/18/matplotlib-animation-tutorial/

Using NetworkX with matplotlib.ArtistAnimation

What I want to do is create an animation in which the nodes of a graph change color with time. When I search for information on animation in matplotlib, I usually see examples that look something like this:
#!/usr/bin/python
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.animation import ArtistAnimation
fig = plt.figure(figsize=(8,8))
images = []
for i in range(10):
data = np.random.random(100).reshape(10,10)
imgplot = plt.imshow(data)
images.append([imgplot])
anim = ArtistAnimation(fig, images, interval=50, blit=True)
anim.save('this-one-works.mp4')
plt.show()
So I thought I could just do something like this:
#!/usr/bin/python
import numpy as np
import networkx as nx
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.animation import ArtistAnimation
G = nx.Graph()
G.add_edges_from([(0,1),(1,2),(2,0)])
fig = plt.figure(figsize=(8,8))
pos=nx.graphviz_layout(G)
images = []
for i in range(10):
nc = np.random.random(3)
imgplot = nx.draw(G,pos,with_labels=False,node_color=nc) # this doesn't work
images.append([imgplot])
anim = ArtistAnimation(fig, images, interval=50, blit=True)
anim.save('not-this-one.mp4')
plt.show()
What I'm stuck on is how, after drawing the graph using nx.draw(), I can get an object of the appropriate type to put in the array being passed to ArtistAnimation. In the first example, plt.imshow() returns an object of type matplot.image.AxesImage, but nx.draw() doesn't actually return anything. Is there a way that I can get my hands on a suitable image object?
Completely different approaches are welcome, of course (it seems like there's always many different ways to do the same thing in matplotlib), as long as I can save my animation as an mp4 when I'm done.
Thanks!
--craig
import numpy as np
import networkx as nx
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
G = nx.Graph()
G.add_edges_from([(0,1),(1,2),(2,0)])
fig = plt.figure(figsize=(8,8))
pos=nx.graphviz_layout(G)
nc = np.random.random(3)
nodes = nx.draw_networkx_nodes(G,pos,node_color=nc)
edges = nx.draw_networkx_edges(G,pos)
def update(n):
nc = np.random.random(3)
nodes.set_array(nc)
return nodes,
anim = FuncAnimation(fig, update, interval=50, blit=True)
nx.draw does not return anything, hence why your method didn't work. The easiest way to do this is to draw the nodes and edges using nx.draw_networkx_nodes and nx.draw_networkx_edges which return PatchCollection and LineCollection objects. You can then update the color of the nodes using set_array.
Using the same general frame work you can also move the nodes around (via set_offsets for the PatchCollection and set_verts or set_segments for LineCollection)
best animation tutorial I have seen: http://jakevdp.github.io/blog/2012/08/18/matplotlib-animation-tutorial/

Categories

Resources