How to plot multiple numpy array in one figure? - python

I know how to plot a single numpy array
import matplotlib.pyplot as plt
plt.imshow(np.array)
But is there any way to plot multiple numpy array in one figure? I know plt.subplots() can display multiple pictures. But it seems hard in my case. I have tried to use a for loop.
fig, ax = plt.subplots()
for i in range(10):
ax.imshow(np.array) # i_th numpy array
This seems to plot a single numpy array one by one. Is there any ways to plot all my 10 numpy arrays in one figure?
PS: Here each my 2d numpy array represents the pixel of a picture. plot seems to plot lines which is not suitable in my case.

The documentation for plt.subplots() (here) specifies that it takes an nrows and ncols arguments and returns a fig object and an array of ax objects. For your case this would look like this:
fig, axs = plt.subplots(3, 4)
axs now contains a 2D array filled with ax objects that you can use to plot various things, e.g. axs[0,1].plot([1,2],[3,4,]) would plot something on the first row, second column.
If you want to remove a particular ax object you can do that with .remove(), e.g. axs[0,1].remove().
For .imshow it works in exactly the same way as .plot: select the ax you want and call imshow on it.
A full example with simulated image data for your case would be:
import numpy as np
import matplotlib.pyplot as plt
fig, axs = plt.subplots(3, 4)
images = [np.array([[1,2],[3,4]]) for _ in range(10)]
for i, ax in enumerate(axs.flatten()):
if i < len(images):
ax.imshow(images[i])
else:
ax.remove()
plt.show()
With as the result:

Related

Creating multiple plot using for loop from dataframe

I am trying to create a figure which contains 9 subplots (3 x 3). X, and Y axis data is coming from the dataframe using groupby. Here is my code:
fig, axs = plt.subplots(3,3)
for index,cause in enumerate(cause_list):
df[df['CAT']==cause].groupby('RYQ')['NO_CONSUMERS'].mean().axs[index].plot()
axs[index].set_title(cause)
plt.show()
However, it does not produce the desired output. In fact it returned the error. If I remove the axs[index]before plot() and put inside the plot() function like plot(ax=axs[index]) then it worked and produces nine subplot but did not display the data in it (as shown in the figure).
Could anyone guide me where am I making the mistake?
You need to flatten axs otherwise it is a 2d array. And you can provide the ax in plot function, see documentation of pandas plot, so using an example:
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
cause_list = np.arange(9)
df = pd.DataFrame({'CAT':np.random.choice(cause_list,100),
'RYQ':np.random.choice(['A','B','C'],100),
'NO_CONSUMERS':np.random.normal(0,1,100)})
fig, axs = plt.subplots(3,3,figsize=(8,6))
axs = axs.flatten()
for index,cause in enumerate(cause_list):
df[df['CAT']==cause].groupby('RYQ')['NO_CONSUMERS'].mean().plot(ax=axs[index])
axs[index].set_title(cause)
plt.tight_layout()

Sub Plots using Seaborn

I am trying to plot box plots and violin plots for three variables against a variable in a 3X2 subplot formation. But I am not able to figure out how to include sns lib with subplot function.
#plots=plt.figure()
axis=plt.subplots(nrows=3,ncols=3)
for i,feature in enumerate(list(df.columns.values)[:-1]):
axis[i].plot(sns.boxplot(data=df,x='survival_status_after_5yrs',y=feature))
i+=1
axis[i].plot(sns.violinplot(data=df,x='survival_status_after_5yrs',y=feature))
plt.show()```
I am expecting 3X2 subplot, x axis stays same all the time y axis rolls over the three variables I have mentioned.
Thanks for your help.
I think you have two problems.
First, plt.subplots(nrows=3, ncols=2) returns a figure object and an array of axes objects so you should replace this line with:
fig, ax = plt.subplots(nrows=3, ncols=2). The ax object is now a 3x2 numpy array of axes objects.
You could turn this into a 1-d array with ax = ax.flatten() but given what I think you are trying to do I think it is easier to keep as 3x2.
(Btw I assume the ncols=3 is a typo)
Second, as Ewoud answer mentions with seaborn you pass the axes to plot on as an argument to the plot call.
I think the following will work for you:
fig, ax = plt.subplots(nrows=3, ncols=2)
for i, feature in enumerate(list(df.columns.values)[:-1]):
# for each feature create two plots on the same row
sns.boxplot(data=df, x='survival_status_after_5yrs',y=feature, ax=ax[i, 0])
sns.violinplot(data=df, x='survival_status_after_5yrs', y=feature, ax=ax[i, 1])
plt.show()
Most seaborn plot functions have an axis kwarg, so instead of
axis[i].plot(sns.boxplot(data=df,x='survival_status_after_5yrs',y=feature))
try
sns.boxplot(data=df,x='survival_status_after_5yrs',y=feature,axis=axis[i])

Matplotlib: collecting lines onto the same axis

I'm just starting using Matplotlib the "right" way. I'm writing various programs that will each give me back a time series, and I'm looking to superimpose the graphs of the various time series, like this:
I think what I want is a single Axes instance defined in the main function, then I call each of my little functions, and they all return a Line2D instance, and then I'll put them all on the Axes object I created.
But I'm having trouble taking an existing Line2D object and adding it to an existing Axes object (like I'd want to do with the output of my function.) I thought of taking a Line2D called a and say ax.add_line(a).
import matplotlib.pyplot as plt
a, = plt.plot([1,2,3], [3,4,5], label = 'a')
fig, ax = plt.subplots()
ax.add_line(a)
Gives me a RuntimeError: "Can not put single artist in more than one figure."
I'm guessing that over time Matplotlib has stopped wanting users to be able to add a given line to any Axes they want. A similar thing is discussed in the comments of this answer, except there they're talking about an Axes object in two different Figure objects.
What's the best way to accomplish what I want? I'd rather keep my main script tidy, and not say ax.plot(some_data) over and over when I want to superimpose these lines.
Indeed, you cannot add the same artist to more than one axes or figure.
But for what I understand from your question, that isn't really necessary.
So let's just do as you propose;
"I thought of taking a Line2D called a and say ax.add_line(a)."
import numpy as np
import matplotlib.pyplot as plt
def get_line(label="a"):
return plt.Line2D(np.linspace(0,1,10), np.random.rand(10), label = label)
fig, ax = plt.subplots()
ax.add_line(get_line(label="a"))
ax.add_line(get_line(label="b"))
ax.add_line(get_line(label="z"))
ax.legend()
plt.show()
The way matplotlib would recommend is to create functions that take an axes as input and plot to that axes.
import numpy as np
import matplotlib.pyplot as plt
def plot_line(ax=None, label="a"):
ax = ax or plt.gca()
line, = ax.plot(np.linspace(0,1,10), np.random.rand(10), label = label)
return line
fig, ax = plt.subplots()
plot_line(ax, label="a")
plot_line(ax, label="b")
plot_line(ax, label="z")
ax.legend()
plt.show()
A possible work around for your problem:
import matplotlib.pyplot as plt
x = np.array([1,2,3])
y = np.array([3,4,5])
label = '1'
def plot(x,y,label):
a, = plt.plot(x,y, label = label)
return a
fig, ax = plt.subplots()
plot(x,y,label)
plot(x,1.5*y,label)
You can put your plot command now in a loop with changing labels. You can still use the ax handle to modify/define the plot parameters.

How to remove an histogram in Matplotlib

I am used to work with plots that change over the time in order to show differences when a parameter is changed. Here I provide an easy example
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111)
ax.grid(True)
x = np.arange(-3, 3, 0.01)
for j in range(1, 15):
y = np.sin(np.pi*x*j) / (np.pi*x*j)
line, = ax.plot(x, y)
plt.draw()
plt.pause(0.5)
line.remove()
You can clearly see that increasing the paramter j the plot becames narrower and narrower.
Now if I want to do the some job with a counter plot than I just have to remove the comma after "line". From my understanding this little modification comes from the fact that the counter plot is not an element of a tuple anymore, but just an attribute as the counter plot completely "fill up" all the space available.
But it looks like there is no way to remove (and plot again) an histogram. Infact if type
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111)
ax.grid(True)
x = np.random.randn(100)
for j in range(15):
hist, = ax.hist(x, 40)*j
plt.draw()
plt.pause(0.5)
hist.remove()
It doesn't matter whether I type that comma or not, I just get a message of error.
Could you help me with this, please?
ax.hist doesn't return what you think it does.
The returns section of the docstring of hist (access via ax.hist? in an ipython shell) states:
Returns
-------
n : array or list of arrays
The values of the histogram bins. See **normed** and **weights**
for a description of the possible semantics. If input **x** is an
array, then this is an array of length **nbins**. If input is a
sequence arrays ``[data1, data2,..]``, then this is a list of
arrays with the values of the histograms for each of the arrays
in the same order.
bins : array
The edges of the bins. Length nbins + 1 (nbins left edges and right
edge of last bin). Always a single array even when multiple data
sets are passed in.
patches : list or list of lists
Silent list of individual patches used to create the histogram
or list of such list if multiple input datasets.
So you need to unpack your output:
counts, bins, bars = ax.hist(x, 40)*j
_ = [b.remove() for b in bars]
Here the right way to iteratively draw and delete histograms in matplotlib
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize = (20, 10))
ax = fig.add_subplot(111)
ax.grid(True)
for j in range(1, 15):
x = np.random.randn(100)
count, bins, bars = ax.hist(x, 40)
plt.draw()
plt.pause(1.5)
t = [b.remove() for b in bars]

Iterating through a Numpy array of plots and using element methods

In trying to do some small multiple stuff, I want to make a bunch of subplots with Matplotlib and toss in varying data to each. pyplot.subplots() gives me a Figure and Numpy array of Axes, but in trying to iterate over the axes, I am stumped on how to actually get at them.
I'm trying something akin to:
import numpy as np
import matplotlib.pyplot as plt
f, axs = plt.subplots(2,2)
for ax in np.nditer(axs, flags=['refs_ok']):
ax.plot([1,2],[3,4])
However, the type of ax in each iteration is not an Axes, but rather an ndarray, so attempting to plot fails with:
AttributeError: 'numpy.ndarray' object has no attribute 'plot'
How can I loop over my axes?
You can do this more simply:
for ax in axs.ravel():
ax.plot(...)
Numpy arrays have a .flat attribute that returns a 1-D iterator:
for ax in axs.flat:
ax.plot(...)
Another option is reshaping the array to a single dimension:
for ax in np.reshape(axs, -1):
ax.plot(...)

Categories

Resources