Align frequency scale on specgram and PSD plot - python-3.x

I would like to know if the frequency scale on the PSD plot to the left of the image is a 1:1 mapping of the specgram spectrogram frequency scale to the right?
The code that I am using to plot this is:
import matplotlib.pyplot as plt
from matplotlib import transforms
import numpy as np
import librosa
import librosa.display
x2=np.random.random(10000)
fs2=1000
Pxx2, freq2 = plt.psd(x, 512, fs2)
fig = plt.figure(figsize=(9, 8),constrained_layout=True)
gs = GridSpec(6,5, figure=fig)
ax2 = plt.subplot(gs.new_subplotspec((0, 0), rowspan=4))
ax2.plot(10*np.log10(Pxx2), freq2)
x_ticks = (min(10*np.log10(Pxx2)), max(10*np.log10(Pxx2)))
ax2.set_xticks(x_ticks)
ax2.invert_xaxis()
plt.xlabel("(dB/Hz)")
plt.ylabel('Frequency (Hz)')
# plt.yticks(np.arange(0,22050, 5000))
plt.ylim([0, max(freq2)])
ax3 = plt.subplot(gs.new_subplotspec((0, 1), rowspan=4, colspan=4))
ax3.specgram(x2, Fs=2);
plt.show()
If the scales is not, how do I go about matching the frequency scale on the PSD and the spectrogram plots?
Thanks for your help and time!

Related

Is there a library that will help me fit data easily? I found fitter and i will provide the code but it shows some errors

So, here is my code:
import pandas as pd
import scipy.stats as st
import matplotlib.pyplot as plt
from matplotlib.ticker import AutoMinorLocator
from fitter import Fitter, get_common_distributions
df = pd.read_csv("project3.csv")
bins = [282.33, 594.33, 906.33, 1281.33, 15030.33, 1842.33, 2154.33, 2466.33, 2778.33, 3090.33, 3402.33]
#declaring
facecolor = '#EAEAEA'
color_bars = '#3475D0'
txt_color1 = '#252525'
txt_color2 = '#004C74'
fig, ax = plt.subplots(1, figsize=(16, 6), facecolor=facecolor)
ax.set_facecolor(facecolor)
n, bins, patches = plt.hist(df.City1, color=color_bars, bins=10)
#grid
minor_locator = AutoMinorLocator(2)
plt.gca().xaxis.set_minor_locator(minor_locator)
plt.grid(which='minor', color=facecolor, lw = 0.5)
xticks = [(bins[idx+1] + value)/2 for idx, value in enumerate(bins[:-1])]
xticks_labels = [ "{:.0f}-{:.0f}".format(value, bins[idx+1]) for idx, value in enumerate(bins[:-1])]
plt.xticks(xticks, labels=xticks_labels, c=txt_color1, fontsize=13)
#beautify
ax.tick_params(axis='x', which='both',length=0)
plt.yticks([])
ax.spines['bottom'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
for idx, value in enumerate(n):
if value > 0:
plt.text(xticks[idx], value+5, int(value), ha='center', fontsize=16, c=txt_color1)
plt.title('Histogram of rainfall in City1\n', loc = 'right', fontsize = 20, c=txt_color1)
plt.xlabel('\nCentimeters of rainfall', c=txt_color2, fontsize=14)
plt.ylabel('Frequency of occurrence', c=txt_color2, fontsize=14)
plt.tight_layout()
#plt.savefig('City1_Raw.png', facecolor=facecolor)
plt.show()
city1 = df['City1'].values
f = Fitter(city1, distributions=get_common_distributions())
f.fit()
fig = f.plot_pdf(names=None, Nbest=4, lw=1, method='sumsquare_error')
plt.show()
print(f.get_best(method = 'sumsquare_error'))
The issue is with the plots it shows. The first histogram it generates is
Next I get another graph with best fitted distributions which is
Then an output statement
{'chi2': {'df': 10.692966790090342, 'loc': 16.690849400411103, 'scale': 118.71595997157786}}
Process finished with exit code 0
I have a couple of questions. Why is chi2, the best fitted distribution not plotted on the graph?
How do I plot these distributions on top of the histograms and not separately? The hist() function in fitter library can do that but there I don't get to control the bins and so I end up getting like 100 bins with some flat looking data.
How do I solve this issue? I need to plot the best fit curve on the histogram that looks like image1. Can I use any other module/package to get the work done in similar way? This uses least squares fit but I am OK with least likelihood or log likelihood too.
Simple way of plotting things on top of each other (using some properties of the Fitter class)
import scipy.stats as st
import matplotlib.pyplot as plt
from fitter import Fitter, get_common_distributions
from scipy import stats
numberofpoints=50000
df = stats.norm.rvs( loc=1090, scale=500, size=numberofpoints)
fig, ax = plt.subplots(1, figsize=(16, 6))
n, bins, patches = ax.hist( df, bins=30, density=True)
f = Fitter(df, distributions=get_common_distributions())
f.fit()
errorlist = sorted(
[
[f._fitted_errors[dist], dist]
for dist in get_common_distributions()
]
)[:4]
for err, dist in errorlist:
ax.plot( f.x, f.fitted_pdf[dist] )
plt.show()
Using the histogram normalization, one would need to play with scaling to generalize again.

Bar missing while plotting using Matplotlib's Twinx

I'm using matplotlib.axes.Axes.twinx to have a shared x-axis in matplotlib for both . I dont know why instead of 13 bars to be plotted, only 12 of them are getting plotted.
Link of Data set
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
dataFrame=pd.read_csv("NEM.csv",sep=',')
dataFrame['ratio']=dataFrame['Expert']/dataFrame['Novice']
fig, ax1 = plt.subplots(figsize=(9, 6))
ax1.set_title('N-E Analysis')
xticklabels=dataFrame['Task'].tolist()
ax1.plot('Novice', data=dataFrame, marker='', color='dodgerblue', linewidth=2,label='Novice',zorder=100)
ax1.plot('Expert', data=dataFrame, marker='', color='darkorange', linewidth=2,label='Expert',zorder=200)
plt.ylim(0,120)
ax2 = ax1.twinx()
ax2.bar('Task','ratio', data=dataFrame, color='gray',width=0.35,label='NE',zorder=0)
ax1.spines['top'].set_visible(False)
ax1.spines['right'].set_visible(False)
ax1.spines['left'].set_visible(False)
ax2.spines['top'].set_visible(False)
ax2.spines['right'].set_visible(False)
ax2.spines['left'].set_visible(False)
ax1.set_xticklabels(xticklabels, rotation = 45, ha="right")
ax1.yaxis.grid()
ax1.tick_params(left='off',bottom='off')
ax2.tick_params(right='off')
plt.ylim(0,12)
h1, l1 = ax1.get_legend_handles_labels()
h2, l2 = ax2.get_legend_handles_labels()
p=ax1.legend(h2+h1, l2+l1, loc=2,frameon=False)
fig.tight_layout()
plt.show()
When using plots, it could be good practice to say explicitily how many bars or points you are going to plot. For instance, you can create an x-axis this way:
x_axis = np.arange(len(dataFrame[Task].tolist())
then:
ax1.plot(x_axis, dataFrame['Novice'].tolist(), ...)
after that you rename the xticklabels like this:
ax1.set_xticks(x_axis)
ax1.set_xticklabels(dataFrame[Task].tolist())
Do the same with the bar graph:
ax2.bar(x_axis, dataFrame['Ratio'].tolist(), ...)
This should do the trick.
Hope it helps.

How to plot Ocean Currents with Cartopy

I am trying to plot a netCDF4 file containing ocean currents from a NASA database for a project, but I keep getting errors such as "x and y coordinates are not compatible with the shape of the vector components".
I have tried changing the streamplot to a contourf (when I did it said that it needed to be a 2d array) which I tried to change but I could not get it to work.
import os
import matplotlib.pyplot as plt
from netCDF4 import Dataset as netcdf_dataset
import numpy as np
import cartopy.crs as ccrs
fname = "oscar_vel2019.nc.gz.nc"
data=netcdf_dataset(fname)
v = data.variables['v'][0, :, :, :]
vf = data.variables['vm'][0, :, :, :]
u = data.variables['u'][0, :, :, :]
uf = data.variables['um'][0, :, :, :]
lats = data.variables['latitude'][:]
lons = data.variables['longitude'][:]
ax = plt.axes(projection=ccrs.PlateCarree())
mymap=plt.streamplot(lons, lats, u, v, 60, transform=ccrs.PlateCarree())
ax.coastlines()
plt.show()
I would like it to work such that the ocean currents are visible on the plot and to show the movement of particles in the currents through an animation. I really don't have much knowledge with this which is why I am asking. Here is the link from which I got the file: https://podaac-opendap.jpl.nasa.gov/opendap/hyrax/allData/oscar/preview/L4/oscar_third_deg/oscar_vel2019.nc.gz.html
OK, I downloaded the data. The problem is that u and v are 4-dimensional, so you need to squeeze out the "depth" dimension. Cartopy also doesn't accept longitudes greater than 180, and you probably won't get away with stream plotting the whole thing. Also, density=60 will take forever...
This is ugly, but gives you the idea.
import xarray as xr
import numpy as np
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
with xr.open_dataset('/Users/jklymak/downloads/oscar_vel2019.nc.gz.nc') as ds:
print(ds)
ax = plt.axes(projection=ccrs.PlateCarree())
dec = 10
lon = ds.longitude.values[::dec]
lon[lon>180] = lon[lon>180] - 360
mymap=plt.streamplot(lon, ds.latitude.values[::dec], ds.u.values[0, 0, ::dec, ::dec], ds.v.values[0, 0, ::dec, ::dec], 6, transform=ccrs.PlateCarree())
ax.coastlines()
plt.show()

How to achieve the Fiji "HiLo" colormap in matplotlib image plots, to mark under and overexposed pixels

Matplotlib's colormaps do not provide the HiLo colormap for images, which is often used in microscopy. HiLo shows a gray-level gradient from low to high values, but values at the low-end are shown in blue and ones at the upper end in red.
How can one get this color-map for matplotlib images?
To achieve this one can use the 'set_under' and 'set_over' methods of the LinearSegmentedColormap class, of which the colormaps are inherited.
# minimal example
from matplotlib import cm
import matplotlib.pyplot as plt
from numpy import arange
im_array = arange(0, 256)
cmap = cm.gray
cmap.set_over(color='red')
cmap.set_under(color='blue')
fig = plt.figure()
ax = fig.add_subplot(111)
vmin = im_array.min() + 1
vmax = im_array.max() - 1
ax.imshow(im_array.reshape((16, 16)), cmap=cmap, vmin=vmin, vmax=vmax)
May be this helps someone.
Cheers!
S

How can I add a normal distribution curve to multiple histograms?

With the following code I create four histograms:
import numpy as np
import pandas as pd
data = pd.DataFrame(np.random.normal((1, 2, 3 , 4), size=(100, 4)))
data.hist(bins=10)
I want the histograms to look like this:
I know how to make it one graph at the time, see here
But how can I do it for multiple histograms without specifying each single one? Ideally I could use 'pd.scatter_matrix'.
Plot each histogram seperately and do the fit to each histogram as in the example you linked or take a look at the hist api example here. Essentially what should be done is
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab
fig = plt.figure()
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224)
for ax in [ax1, ax2, ax3, ax4]:
n, bins, patches = ax.hist(**your_data_here**, 50, normed=1, facecolor='green', alpha=0.75)
bincenters = 0.5*(bins[1:]+bins[:-1])
y = mlab.normpdf( bincenters, mu, sigma)
l = ax.plot(bincenters, y, 'r--', linewidth=1)
plt.show()

Resources