Matplotlib adjacent plots - python

I've written a Python library that uses Matplotlib and Astropy to generate spectra from data of solar radio emissions. I'm satisfied with how it's plotting data from a single FITS file, but now I'm trying to plot data from multiple FITS files in a single figure adjacently. I've read some of Matplotlib's documentation and some questions related to this like How do I get multiple subplots in matplotlib?.
Here's part of the code that plots data from a single FITS file:
def plot_freq_range_db_above_background(self, start_freq, end_freq):
plt.figure(1, figsize=(11, 6))
plt.imshow(self.hdul_dataset['db'] - self.hdul_dataset['db_median'],
cmap='magma', norm=plt.Normalize(self.hdul_dataset['v_min'],
self.hdul_dataset['v_max']
),
aspect='auto', extent=[self.hdul_dataset['time_axis'][0],
self.hdul_dataset['time_axis']
[-1000],
self.hdul_dataset['frequency'][-1],
self.hdul_dataset['frequency'][0]])
plt.ylim(start_freq, end)
plt.gca().invert_yaxis()
plt.colorbar(label='dB above background')
plt.xlabel('Time (UT)', fontsize=15)
plt.ylabel('Frequency (MHz)', fontsize=15)
plt.title(self.filename, fontsize=16)
plt.tick_params(labelsize=14)
plt.show()
And this is an example of a plot generated by the method above:
So, what I'm trying to do now is to plot data from different files, and have all of them adjacent to each other in a single figure. The X-axis(frequency) is the same for every single plot, and the Y-axis(time) is continuous from one file to the next one.
Here's the method I've written trying to accomplish what I just described:
def plot_fits_files_list(files_list, start_freq, end_freq):
dim = len(files_list)
plt_index = 1
plt.figure(1)
for file in files_list:
fits_filename = file.split(os.sep)[-1]
fitsfile = ECallistoFitsFile(fits_filename)
fitsfile.set_file_path()
fitsfile.set_hdul_dataset()
plt.subplot(dim, dim, plt_index)
plt_index += 1
plt.imshow(
fitsfile.hdul_dataset['db'] -
fitsfile.hdul_dataset['db_median'],
cmap='magma',
norm=plt.Normalize(fitsfile.hdul_dataset['v_min'],
fitsfile.hdul_dataset['v_max']),
aspect='auto', extent=[fitsfile.hdul_dataset['time_axis'][0],
fitsfile.hdul_dataset['time_axis']
[-1000],
fitsfile.hdul_dataset['frequency'][-1],
fitsfile.hdul_dataset['frequency'][0]])
plt.ylim(start_freq, end_freq)
plt.gca().invert_yaxis()
plt.colorbar(label='dB above background')
plt.xlabel('Time (UT)', fontsize=15)
plt.ylabel('Frequency (MHz)', fontsize=15)
plt.title("Multiple Plots Test", fontsize=16)
plt.tick_params(labelsize=14)
plt.show()
And here's the plot it's generating at the moment:

Related

Matplotlib scatter plot dual y-axis

I try to figure out how to create scatter plot in matplotlib with two different y-axis values.
Now i have one and need to add second with index column values on y.
points1 = plt.scatter(r3_load["TimeUTC"], r3_load["r3_load_MW"],
c=r3_load["r3_load_MW"], s=50, cmap="rainbow", alpha=1) #set style options
plt.rcParams['figure.figsize'] = [20,10]
#plt.colorbar(points)
plt.title("timeUTC vs Load")
#plt.xlim(0, 400)
#plt.ylim(0, 300)
plt.xlabel('timeUTC')
plt.ylabel('Load_MW')
cbar = plt.colorbar(points1)
cbar.set_label('Load')
Result i expect is like this:
So second scatter set should be for TimeUTC vs index. Colors are not the subject;) also in excel y-axes are different sites, but doesnt matter.
Appriciate your help! Thanks, Paulina
Continuing after the suggestions in the comments.
There are two ways of using matplotlib.
Via the matplotlib.pyplot interface, like you were doing in your original code snippet with .plt
The object-oriented way. This is the suggested way to use matplotlib, especially when you need more customisation like in your case. In your code, ax1 is an Axes instance.
From an Axes instance, you can plot your data using the Axes.plot and Axes.scatter methods, very similar to what you did through the pyplot interface. This means, you can write a Axes.scatter call instead of .plot and use the same parameters as in your original code:
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
ax1.scatter(r3_load["TimeUTC"], r3_load["r3_load_MW"],
c=r3_load["r3_load_MW"], s=50, cmap="rainbow", alpha=1)
ax2.plot(r3_dda249["TimeUTC"], r3_dda249.index, c='b', linestyle='-')
ax1.set_xlabel('TimeUTC')
ax1.set_ylabel('r3_load_MW', color='g')
ax2.set_ylabel('index', color='b')
plt.show()

Combining a boxplot and a histogram into one plot

I'm trying to plot a boxplot and a histgramm as you can see in the following image.
boxplot and histogramm combinaion
I have this for the moment:
fig,ax=plt.subplots()
fig.set_size_inches(10,7)
ax = fig.add_axes([0,0,1,1])
ax.set_title('Heating need [kWh/m^2]')
ax.set_xlabel('Cluster')
ax.set_ylabel('Heating need')
bp1=ax.boxplot([heating0,heating1945,heating1960,heating1970,heating1980,heating1990,heating2000],labels=['<1945', '1945-1959', '1960-1969', '1970-1979', '1980-1989', '1990-1999', '>=2000'],showfliers=False,patch_artist=True)
plt.setp(bp1['boxes'], color='blue')
ax.plot([200,200,220,230,230,170,130,100,30,30],label='underline for swiss energetic index') #underline for the norms
ax.plot([230,230,250,260,260,200,160,130,60,60],label='upperline for swiss energetic index') #upperline for the norms
#plt.yticks([0,200,400,600,800])
plt.legend(loc='upper right')
The result is :
and I want to replace the plot line by a histogramm.
I think you're looking for plt.bar
A minimal example:
fig,ax=plt.subplots()
ax.boxplot([100,200,300,400,500],1)
data = [200,200]
ax.bar(range(0,len(data)*2,2),data)

Matplotlib multiple graphs, extra space underneath x-axis

Trying mathplotlib for the first time. I want to create two separate graphs. I'm able to get both graphs to show, however, the second graph has extra space underneath the x-axis and makes the x-axis scale labels/axis label show way below. If I comment out the first graph, the extra space disappears.
I've attempted using plt.tight_layout() and that made the rest of the graph tight (labels were laying over-each other), but did not help w/ my extra space at the bottom. see the right graph with the red marking
Note: I changed the configuration on the right graph to show the extra space, so that's why it'll look different than the ranges I included in the code.
#left graph
fig_Sub = plt.figure(1)
fig_Sub.suptitle('Subreddits', fontsize=14, fontweight='bold')
ax1 = fig_Sub.add_subplot(111)
fig_Sub.subplots_adjust(top=0.85)
ax1.set_title('axes title')
ax1.set_xlabel('Word')
y_rotate=ax1.set_ylabel('Instances')
y_rotate.set_rotation(0)
ax1.axis([0, 1000, 0, 1000])
plt.rc('xtick', color='k', labelsize='medium', direction='out')
plt.rc('xtick.major', size=10, pad=100) #size of tick, interval
plt.rc('xtick.minor', size=10, pad=100)
#right graph
fig_user = plt.figure(2)
fig_user.suptitle('Users', fontsize=14, fontweight='bold')
ax2 = fig_user.add_subplot(111)
fig_user.subplots_adjust(top=0.85)
ax2.set_title('axes title')
ax2.set_xlabel('Word')
y2_rotate=ax2.set_ylabel('Instances')
y2_rotate.set_rotation(0)
ax2.axis([0, 1000, 0, 1000])
plt.rc('xtick', color='k', labelsize='medium', direction='out')
plt.rc('xtick.major', size=0, pad=0)
plt.rc('xtick.minor', size=0, pad=0)
plt.show()
Per #ImportanceOfBeingErnest, get rid of pad in plt.rc().

How to plot a Spectrogram with very small values? [duplicate]

I am using matplotlib.pyplot.specgram and matplotlib.pyplot.pcolormesh to make spectrogram plots of a seismic signal.
Background information -The reason for using pcolormesh is that I need to do arithmitic on the spectragram data array and then replot the resulting spectrogram (for a three-component seismogram - east, north and vertical - I need to work out the horizontal spectral magnitude and divide the vertical spectra by the horizontal spectra). It is easier to do this using the spectrogram array data than on individual amplitude spectra
I have found that the plots of the spectrograms after doing my arithmetic have unexpected values. Upon further investigation it turns out that the spectrogram plot made using the pyplot.specgram method has different values compared to the spectrogram plot made using pyplot.pcolormesh and the returned data array from the pyplot.specgram method. Both plots/arrays should contain the same values, I cannot work out why they do not.
Example:
The plot of
plt.subplot(513)
PxN, freqsN, binsN, imN = plt.specgram(trN.data, NFFT = 20000, noverlap = 0, Fs = trN.stats.sampling_rate, detrend = 'mean', mode = 'magnitude')
plt.title('North')
plt.xlabel('Time [s]')
plt.ylabel('Frequency [Hz]')
plt.clim(0, 150)
plt.colorbar()
#np.savetxt('PxN.txt', PxN)
looks different to the plot of
plt.subplot(514)
plt.pcolormesh(binsZ, freqsZ, PxN)
plt.clim(0,150)
plt.colorbar()
even though the "PxN" data array (that is, the spectrogram data values for each segment) is generated by the first method and re-used in the second.
Is anyone aware why this is happening?
P.S. I realise that my value for NFFT is not a square number, but it's not important at this stage of my coding.
P.P.S. I am not aware of what the "imN" array (fourth returned variable from pyplot.specgram) is and what it is used for....
First off, let's show an example of what you're describing so that other folks
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(1)
# Brownian noise sequence
x = np.random.normal(0, 1, 10000).cumsum()
fig, (ax1, ax2) = plt.subplots(nrows=2, figsize=(8, 10))
values, ybins, xbins, im = ax1.specgram(x, cmap='gist_earth')
ax1.set(title='Specgram')
fig.colorbar(im, ax=ax1)
mesh = ax2.pcolormesh(xbins, ybins, values, cmap='gist_earth')
ax2.axis('tight')
ax2.set(title='Raw Plot of Returned Values')
fig.colorbar(mesh, ax=ax2)
plt.show()
Magnitude Differences
You'll immediately notice the difference in magnitude of the plotted values.
By default, plt.specgram doesn't plot the "raw" values it returns. Instead, it scales them to decibels (in other words, it plots the 10 * log10 of the amplitudes). If you'd like it not to scale things, you'll need to specify scale="linear". However, for looking at frequency composition, a log scale is going to make the most sense.
With that in mind, let's mimic what specgram does:
plotted = 10 * np.log10(values)
fig, ax = plt.subplots()
mesh = ax.pcolormesh(xbins, ybins, plotted, cmap='gist_earth')
ax.axis('tight')
ax.set(title='Plot of $10 * log_{10}(values)$')
fig.colorbar(mesh)
plt.show()
Using a Log Color Scale Instead
Alternatively, we could use a log norm on the image and get a similar result, but communicate that the color values are on a log scale more clearly:
from matplotlib.colors import LogNorm
fig, ax = plt.subplots()
mesh = ax.pcolormesh(xbins, ybins, values, cmap='gist_earth', norm=LogNorm())
ax.axis('tight')
ax.set(title='Log Normalized Plot of Values')
fig.colorbar(mesh)
plt.show()
imshow vs pcolormesh
Finally, note that the examples we've shown have had no interpolation applied, while the original specgram plot did. specgram uses imshow, while we've been plotting with pcolormesh. In this case (regular grid spacing) we can use either.
Both imshow and pcolormesh are very good options, in this case. However,imshow will have significantly better performance if you're working with a large array. Therefore, you might consider using it instead, even if you don't want interpolation (e.g. interpolation='nearest' to turn off interpolation).
As an example:
extent = [xbins.min(), xbins.max(), ybins.min(), ybins.max()]
fig, ax = plt.subplots()
mesh = ax.imshow(values, extent=extent, origin='lower', aspect='auto',
cmap='gist_earth', norm=LogNorm())
ax.axis('tight')
ax.set(title='Log Normalized Plot of Values')
fig.colorbar(mesh)
plt.show()

add frame and remove background colour and grids using seaborn.kdeplot

I have written a class to plot some data points. I used seaborn to make kernel density plot and it caused that (1) the frame gets disappeared and I would like a rigid frame and (2) there are grids in the plot with (3)a background colour which I would like to get rid of them. How should it be done? In addition, how could I get star-shape and polygon-shape markers for the scatter plot ?
import seaborn
import pandas
import pylab as P
import numpy as np
class PlotLocus(object):
def __init__(self, colorX, colorY, colorpX, colorpY ,excluded_points,lcolorx1,lcolorx2,lcolory1,lcolory2,correspondence_Matrix):
self.exarr=excluded_points #scatter points excluded by kde
self.colorx=colorX
self.colory=colorY
self.colorpx=colorpX
self.colorpy=colorpY
r=np.arange(self.colorx.shape[0])
self.arr=np.setxor1d(r,self.exarr)
self.lx1=lcolorx1
self.lx2=lcolorx2
self.ly1=lcolory1
self.ly2=lcolory2
correspondence_indicies = np.where(M > 0.99)
self.colorx_corr=self.colorx[correspondence_indicies[0]]
self.colory_corr=self.colory[correspondence_indicies[0]]
self.colorpx_corr=self.colorpx[correspondence_indicies[1]]
self.colorpy_corr=self.colorpy[correspondence_indicies[1]]
def plot_before_colors(self):
fig=P.figure(1, figsize=(8,8), dpi=100)
ax = fig.add_subplot(111)
X=np.vstack((self.colorx, self.colory)).T
data = pandas.DataFrame(X, columns=["X", "Y"])
seaborn.kdeplot(data.X,data.Y,bw='scott',shade=False, cmap="Purples")
ax.tick_params(axis='both', which='major', direction='in', length=6, width=2)
ax.scatter(self.colorx[self.exarr], self.colory[self.exarr], s=30, c='g', marker='o', edgecolors='k',facecolors='none')
ax.scatter(self.colorx, self.colory ,marker='.',s=15,color='b')
ax.scatter(self.colorpx, self.colorpy, s=15, c='r', marker='d', edgecolor='r')
for i in range(len(self.colorx_corr)):
ax.annotate("",
xy=(self.colorpx_corr[i], self.colorpy_corr[i]), xycoords='data',
xytext=(self.colorx_corr[i], self.colory_corr[i]), textcoords='data',
arrowprops=dict(arrowstyle="->",
connectionstyle="arc3"),
color='0.3'
)
ax.set_xlabel("%s - %s"%(self.lx1,self.lx2), size='medium')
ax.set_ylabel("%s - %s"%(self.ly1,self.ly2), size='medium')
ax.set_aspect('auto')
if __name__ == "__main__":
colorx=np.array([0.4,0.5,-0.3,1.5,0.91,0.66,0.59,-0.11,-0.08,0.12])
colory=np.array([0.22,-1.15,0.44,0.7,-0.65,-0.21,0.8,-1.1,1.01,0.8])
colorpx=np.array([0.48,0.45,-0.38,0.5,0.98,0.62,0.77,-0.15,-0.12,0.8])
colorpx=np.array([0.48,0.45,-0.38,0.5,0.98,0.62,0.77,-0.15,-0.12,0.8,1.8])
colorpx=np.array([0.48,0.45,-0.38,0.5,0.98,0.62,0.77,-0.15,-0.12,0.8,1.8,2.4])
colorpy=np.array([0.26,-0.98,-0.1,0.66,-0.7,-0.5,0.84,-0.88,-1.2,0.9,-2.1,1.3])
lcolorx1='u'
lcolorx2='i'
lcolory1='i'
lcolory2='g'
M=np.zeros((10,12),float)
M[1,4]=1
M[3,5]=1
M[9,7]=1
M[0,2]=1
M[4,10]=1
p=PlotLocus(colorx,colory,colorpx,colorpy,np.array([2,6,8]),lcolorx1,lcolorx2,lcolory1,lcolory2,M)
p.plot_before_colors()
P.show()
You can remove the grey background and white grid by using seaborn.set_style(style='white') at the beginning of your code. This will also add a rigid black border to your plot.
For the markers you can get star shapes using marker='*' in the scatter call or by using the matplotlib.markers api.
Below is the plot I get if I add the seaborn.set_style call to your code, I've not changed the markers as I don't know which markers you wish to change.
The accepted answer doesn't work with recent seaborn versions.
Use ax.set_facecolor('white') instead of seaborn.set_style(style='white').

Categories

Resources