I have some code:
import matplotlib.pyplot as plt
def print_fractures(fractures):
xpairs = []
ypairs = []
plt.figure(2)
plt.subplot(212)
for i in range(len(fractures)):
xends = [fractures[i][1][0], fractures[i][2][0]]
yends = [fractures[i][1][1], fractures[i][2][1]]
xpairs.append(xends)
ypairs.append(yends)
for xends,yends in zip(xpairs,ypairs):
plt.plot(xends, yends, 'b-', alpha=0.4)
plt.show()
def histogram(spacings):
plt.figure(1)
plt.subplot(211)
plt.hist(spacings, 100)
plt.xlabel('Spacing (m)', fontsize=15)
plt.ylabel('Frequency (count)', fontsize=15)
plt.show()
histogram(spacings)
print_fractures(fractures)
This code will produce the following output:
My questions are:
1) Why are two separate figures being created? I thought the subplot command would combine them into one figure. I thought it might be the multiple plt.show() commands, but I tried commenting those out and only calling it once from outside my functions and I still got 2 windows.
2) How can I combine them into 1 figure properly? Also, I would want figure 2 axes to have the same scale (i.e. so 400 m on the x axis is the same length as 400 m on the y-axis). Similarly, I'd like to stretch the histogram vertically as well - how is this accomplished?
As you observed already, you cannot call figure() inside each function if you intend to use only one figure (one Window). Instead, just call subplot() without calling show() inside the function. The show() will force pyplot to create a second figure IF you are in plt.ioff() mode. In plt.ion() mode you can keep the plt.show() calls inside the local context (inside the function).
To achieve the same scale for the x and y axes, use plt.axis('equal'). Below you can see an illustration of this prototype:
from numpy.random import random
import matplotlib.pyplot as plt
def print_fractures():
plt.subplot(212)
plt.plot([1,2,3,4])
def histogram():
plt.subplot(211)
plt.hist(random(1000), 100)
plt.xlabel('Spacing (m)', fontsize=15)
plt.ylabel('Frequency (count)', fontsize=15)
histogram()
print_fractures()
plt.axis('equal')
plt.show()
Related
How to change the length of one plot in a subplot?
It may be a simple problem but I have difficulty solving this.
To represent the result of signal analysis, I represented three plots in a subplot.
But, because the third graph had a colorbar, only this is short.
How can I solve this problem?
I added some parts that draw each plot in a subplot in my code except detail.
To avoid misunderstanding, I added figure.
In the below figure, the length of the spectrogram plot in the python figure(left) is shorter than the above two plots. But the length of the spectrogram plot in the Matlab figure(right) is equal to the above plots. How can make the length of the third plot be equal with the above plots, like the result of Matlab?
import matplotlib.pyplot as plt
fig, (ax1, ax2, ax3, cbar) = plt.subplots(3, 2)
ax1.plot(sb['Seconds'], sb['Real'], 'dodgerblue', linewidth = 0.5)
ax2.plot(f2, np.log(P3), 'k', linewidth = 0.5)
s, freqs, bins, im = ax3.specgram(y, NFFT = N, Fs=Fs1, cmap='jet')
cbar = plt.colorbar(im, ax=ax3, orientation = 'vertical', pad = 0.009)
If you already have the figure object use:
f.set_figheight(15)
f.set_figwidth(15)
But if you use the .subplots() command (as in the examples you're showing) to create a new figure you can also use:
f, axs = plt.subplots(2,2,figsize=(15,15))
For example: -
Alternatively, create a figure() object using the figsize argument and then use add_subplot to add your subplots. E.g.
import matplotlib.pyplot as plt
import numpy as np
f = plt.figure(figsize=(10,3))
ax = f.add_subplot(121)
ax2 = f.add_subplot(122)
x = np.linspace(0,4,1000)
ax.plot(x, np.sin(x))
ax2.plot(x, np.cos(x), 'r:')
Benefits of this method are that the syntax is closer to calls of subplot() instead of subplots(). E.g. subplots doesn't seem to support using a GridSpec for controlling the spacing of the subplots, but both subplot() and add_subplot() do.
I have the following code for plotting two variables 'field_size' and 'field_mean_LAI':
plt.figure(figsize=(20,10))
plt.scatter(df.field_size, df.field_lai_mean)
plt.title("Field Size and LAI Plot")
plt.xlabel("Field Size")
plt.ylabel("Mean LAI")
plt.show()
The outcome is a scatter plot:
"
How can I configure the x and y intervals and change color of the plot?? I am very beginner in python plotting.
So I modified my code like below:
plt.figure(figsize=(20,10))
plt.scatter(df.field_size, df.field_lai_mean)
plt.title("Field Size and LAI Plot")
plt.xlabel("Field Size")
plt.ylabel("Mean LAI")
plt.xticks(np.arange(0.00000,0.00013,step=0.000008))
plt.yticks(np.arange(0,8.5,step=0.5))
plt.show()
Now I have a plot like this:
Just defined the xticks and yticks functions and it is done smoothly! :)
To change the color of plot points, you can use color attribute (see below).
To set limits of both axes, you can pass xlim and ylim parameters
while creating the subplot.
Note also that I passed here also rot parameter, to set x labels rotation.
And to configure x and y intervals, you can use e.g. MultipleLocator,
for both major and minor ticks. There are other locators too,
search the Web for details.
Additional element which you can set is also the grid (like I did).
So you can change your code to:
import matplotlib.pyplot as plt
import matplotlib.ticker as tck
fig = plt.figure(figsize=(10,5))
ax = plt.subplot(xlim=(-0.000003, 0.000123), ylim=(-0.5, 9))
df.plot.scatter(x='field_size', y='field_lai_mean', rot=30, color='r', ax=ax)
plt.title("Field Size and LAI Plot")
plt.xlabel("Field Size")
plt.ylabel("Mean LAI")
ax = plt.gca()
ax.yaxis.set_major_locator(tck.MultipleLocator(2))
ax.yaxis.set_minor_locator(tck.MultipleLocator(0.4))
ax.xaxis.set_major_locator(tck.MultipleLocator(0.00001))
ax.xaxis.set_minor_locator(tck.MultipleLocator(0.0000025))
ax.grid()
plt.show()
Of course, adjust passed values to your needs.
For a very limited set of points, I got the following picture:
I want to see how a plot varies with different values using a loop. I want to see it on the same plot. But i do not want to remains of the previous plot in the figure. In MATLAB this is possible by creating a figure and just plotting over the same figure. Closing it when the loop ends.
Like,
fh = figure();
%for loop here
%do something with x and y
subplot(211), plot(x);
subplot(212), plot(y);
pause(1)
%loop done
close(fh);
I am not able to find the equivalent of this in matplotlib. Usually all the questions are related to plotting different series on the same plot, which seems to come naturally on matplotlib, by plotting several series using plt.plot() and then showing them all finally using plt.show(). But I want to refresh the plot.
There are essentially two different ways to create animations in matplotlib
interactive mode
Turning on interactive more is done using plt.ion(). This will create a plot even though show has not yet been called. The plot can be updated by calling plt.draw() or for an animation, plt.pause().
import matplotlib.pyplot as plt
x = [1,1]
y = [1,2]
fig, (ax1,ax2) = plt.subplots(nrows=2, sharex=True, sharey=True)
line1, = ax1.plot(x)
line2, = ax2.plot(y)
ax1.set_xlim(-1,17)
ax1.set_ylim(-400,3000)
plt.ion()
for i in range(15):
x.append(x[-1]+x[-2])
line1.set_data(range(len(x)), x)
y.append(y[-1]+y[-2])
line2.set_data(range(len(y)), y)
plt.pause(0.1)
plt.ioff()
plt.show()
FuncAnimation
Matplotlib provides an animation submodule, which simplifies creating animations and also allows to easily save them. The same as above, using FuncAnimation would look like:
import matplotlib.pyplot as plt
import matplotlib.animation
x = [1,1]
y = [1,2]
fig, (ax1,ax2) = plt.subplots(nrows=2, sharex=True, sharey=True)
line1, = ax1.plot(x)
line2, = ax2.plot(y)
ax1.set_xlim(-1,18)
ax1.set_ylim(-400,3000)
def update(i):
x.append(x[-1]+x[-2])
line1.set_data(range(len(x)), x)
y.append(y[-1]+y[-2])
line2.set_data(range(len(y)), y)
ani = matplotlib.animation.FuncAnimation(fig, update, frames=14, repeat=False)
plt.show()
An example to animate a sine wave with changing frequency and its power spectrum would be the following:
import matplotlib.pyplot as plt
import matplotlib.animation
import numpy as np
x = np.linspace(0,24*np.pi,512)
y = np.sin(x)
def fft(x):
fft = np.abs(np.fft.rfft(x))
return fft**2/(fft**2).max()
fig, (ax1,ax2) = plt.subplots(nrows=2)
line1, = ax1.plot(x,y)
line2, = ax2.plot(fft(y))
ax2.set_xlim(0,50)
ax2.set_ylim(0,1)
def update(i):
y = np.sin((i+1)/30.*x)
line1.set_data(x,y)
y2 = fft(y)
line2.set_data(range(len(y2)), y2)
ani = matplotlib.animation.FuncAnimation(fig, update, frames=60, repeat=True)
plt.show()
If you call plt.show() inside the loop you will see the plot for each element on the loop as long as you close the window containing the figure. The process, will be plot for the first element, then if you close the window you will see the plot for the second element in the loop, etc
import numpy as np
import matplotlib.pyplot as plt
plt.figure(1)
plt.subplot(211)
xs = np.linspace(-5,5,500)
ys = np.sqrt(5**2 - xs**2)
plt.plot(xs,ys)
plt.plot(xs,-ys)
plt.subplot(212)
plt.plot(xs, xs**2)
plt.show()
here is the code i generate, was wondering that if i want keep the upper plot x and y ratio be 1:1 so that the ball will always look round no matter how many subplot inside this figure.
I tried to find it from the website, seems not a simple solution..
When you create your subplot, you can tell it:
plt.subplot(211, aspect='equal')
If you've already created the subplot, you have to grab the current axes, which you can do using plt.gca, then call the set_aspect method:
plt.gca().set_aspect('equal')
Or, you can keep track of the axes from the beginning:
ax = plt.subplot(211)
ax.set_aspect('equal')
You may have to call
plt.draw()
In order to update the plot.
I am trying to produce a scatter plot that has two different y-axes and also a colorbar.
Here is the pseudo-code used:
#!/usr/bin/python
import matplotlib.pyplot as plt
from matplotlib import cm
fig = plt.figure()
ax1 = fig.add_subplot(111)
plt.scatter(xgrid,
ygrid,
c=be, # set colorbar to blaze efficiency
cmap=cm.hot,
vmin=0.0,
vmax=1.0)
cbar = plt.colorbar()
cbar.set_label('Blaze Efficiency')
ax2 = ax1.twinx()
ax2.set_ylabel('Wavelength')
plt.show()
And it produces this plot:
My question is, how do you use a different scale for the "Wavelength" axes, and also, how do you move the colorbar more to right so that it is not in the Wavelength's way?
#OZ123 Sorry that I took so long to respond. Matplotlib has extensible customizability, sometimes to the point where you get confused to what you are actually doing. Thanks for the help on creating separate axes.
However, I didn't think I needed that much control, and I ended up just using the PAD keyword argument in
fig.colorbar()
and this provided what I needed.
The pseudo-code then becomes this:
#!/usr/bin/python
import matplotlib.pyplot as plt
from matplotlib import cm
fig = plt.figure()
ax1 = fig.add_subplot(111)
mappable = ax1.scatter(xgrid,
ygrid,
c=be, # set colorbar to blaze efficiency
cmap=cm.hot,
vmin=0.0,
vmax=1.0)
cbar = fig.colorbar(mappable, pad=0.15)
cbar.set_label('Blaze Efficiency')
ax2 = ax1.twinx()
ax2.set_ylabel('Wavelength')
plt.show()
Here is to show what it looks like now::
the plt.colorbar() is made for really simple cases, e.g. not really thought for a plot with 2 y-axes.
For a fine grained control of the colorbar location and properties you should almost always rather work with colorbar specifying on which axes you want to plot the colorbar.
# on the figure total in precent l b w , height
cbaxes = fig.add_axes([0.1, 0.1, 0.8, 0.05]) # setup colorbar axes.
# put the colorbar on new axes
cbar = fig.colorbar(mapable,cax=cbaxes,orientation='horizontal')
Note that colorbar takes the following keywords:
keyword arguments:
cax
None | axes object into which the colorbar will be drawn ax
None | parent axes object from which space for a new
colorbar axes will be stolen
you could also see here a more extended answer of mine regarding figure colorbar on separate axes.