Dynamic spectrum using plotly - python

I want to plot time vs frequency as x and y axis, but also a third parameter that is specified by the intensity of plot at (x, y) rather (time, frequency) point. [Actually, instead of going up with third axis in 3D visualisation, I want something like a 2D plot, with amplitude of third axis governed by the intensity(color) value at (x,y)].
Can someone please suggest me something similar that I am looking for? These plots are actually called dynamical spectrum.
PS: I am plotting in python offline. I have gone through https://plot.ly/python/, but still I am not sure which will serve my purpose.
Please suggest something that will help me accomplish the above :)

This is the code to compute and visualize the spectrogram with plotly, i tested the code with this audio file: vignesh.wav
The code was tested in Jupyter notebook using python 3.6
# Full example
import numpy as np
import matplotlib.pyplot as plt
# plotly offline
import plotly.offline as pyo
from plotly.offline import init_notebook_mode #to plot in jupyter notebook
import plotly.graph_objs as go
init_notebook_mode() # init plotly in jupyter notebook
from scipy.io import wavfile # scipy library to read wav files
AudioName = "vignesh.wav" # Audio File
fs, Audiodata = wavfile.read(AudioName)
Audiodata = Audiodata / (2.**15) # Normalized between [-1,1]
#Spectrogram
from scipy import signal
plt.figure()
N = 512 #Number of point in the fft
w = signal.blackman(N)
freqs, bins, Pxx = signal.spectrogram(Audiodata, fs,window = w,nfft=N)
# Plot with plotly
trace = [go.Heatmap(
x= bins,
y= freqs,
z= 10*np.log10(Pxx),
colorscale='Jet',
)]
layout = go.Layout(
title = 'Spectrogram with plotly',
yaxis = dict(title = 'Frequency'), # x-axis label
xaxis = dict(title = 'Time'), # y-axis label
)
fig = go.Figure(data=trace, layout=layout)
pyo.iplot(fig, filename='Spectrogram')

I'd suggest the pcolormesh plot
import matplotlib.pyplot as mp
import numpy as np
# meshgrid your timevector to get it in the desired format
X, Y = np.meshgrid(timevector, range(num_of_frequency_bins))
fig1, ax1 = mp.subplots()
Plothandle = mp.pcolormesh(X, Y, frequencies, cmap=mp.cm.jet, antialiased=True, linewidth=0)
Whereas num_of_frequency_bins the amount of frequencies to display on your y-axis. For example from 0Hz to 1000Hz with 10Hz resolution you'll have to do: range(0,1000,10)
Antialiased is just for the looks, same with linewidth.
Colormap jet is usually not recommended due to non-linear gray-scale, but in frequency-domains it is regularly used. Thus I used it here. But python has some nice linear gray-scale colormaps as well!
To the topic of using plotly: If you just want a static image, you don't have to use plotly. If you want to have an interactive image where you can drag around axes and stuff like this, you should take a look at plotly.

Related

Geopandas plot shapefile on xarray with same legend

I'm trying to create some maps of precipitation data (xarray) with a shapefile of the region of interest on top. However, when Python plots the figures, I get two seperate figures:
When I open the data in QGIS they do appear on top of each other, so the coordinate systems do check out. Then I have an additional bonus question: I have to create multiple precipitation maps, on for a visual analysis it would be ideal if I could have the same legend (thus the same min/max for the colorbar) for each map. Anyone an idea how to proceed further?
My code so far:
def chirps_to_map(input1, input2, title):
projection = input1 + input2
plt.figure(figsize=(9, 9))
projection['pr'].plot()
watershed.plot()
plt.title(title)
plt.show()
plt.close()
projection.to_netcdf(str(path)+str(title)+".nc")
return projection
This is a case where it's simpler to use the Matplotlib object-oriented API.
A nice general workflow might be
fig, ax = plt.subplot()
gdf.plot(ax=ax) # Plot the vector data on the subplot
raster.plot(ax=ax) # Plot the raster data on the same subplot
Example
First, we get some sample raster+vector data
import xarray as xr
import geopandas as gpd
import matplotlib.pyplot as plt
da = xr.tutorial.load_dataset('ROMS_example').zeta.isel(ocean_time=0)
gdf = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres'))
usa = gdf.loc[gdf['name'].eq('United States of America')]
Next, we plot both of the data on the same AxesSubplot
fig, ax = plt.subplots(figsize=(15, 10))
da.plot.pcolormesh(x='lon_rho', y='lat_rho', ax=ax)
usa.plot(ax=ax, edgecolor='red', color='none')
# Focus on the raster extent
ax.set_xlim(-95, -87)
ax.set_ylim(26, 32)
Bonus: hvPlot way
hvPlot provides a nice unified API for interactive plotting with pandas, xarray, and many other libraries, and might be of interest to people stumbling upon this answer.
Plotting both vector and raster data is rather easy, simply use the * operator.
import hvplot.pandas
import hvplot.xarray
usa.hvplot(geo=True) * da.hvplot.quadmesh(x='lon_rho', y='lat_rho', geo=True)

4D Density Plot in Python

I am looking to plot some density maps from some grid-like data:
X,Y,Z = np.mgrids[-5:5:50j, -5:5:50j, -5:5:50j]
rho = np.random.rand(50,50,50) #for the sake of argument
I am interested in producing an interpolated density plot as shown below, from Mathematica here, using Python.
Is there any solution in Matplotlib or another plotting suite for this sort of plot?
To be clear, I do not want a scatterplot of coloured points, which is not suitable the plot I am trying to make. I would like a 3D interpolated density plot, as shown below.
Plotly
Plotly Approach from https://plotly.com/python/3d-volume-plots/ uses np.mgrid
import plotly.graph_objects as go
import numpy as np
X, Y, Z = np.mgrid[-8:8:40j, -8:8:40j, -8:8:40j]
values = np.sin(X*Y*Z) / (X*Y*Z)
fig = go.Figure(data=go.Volume(
x=X.flatten(),
y=Y.flatten(),
z=Z.flatten(),
value=values.flatten(),
isomin=0.1,
isomax=0.8,
opacity=0.1, # needs to be small to see through all surfaces
surface_count=17, # needs to be a large number for good volume rendering
))
fig.show()
Pyvista
Volume Rendering example:
https://docs.pyvista.org/examples/02-plot/volume.html#sphx-glr-examples-02-plot-volume-py
3D-interpolation code you might need with pyvista:
interpolate 3D volume with numpy and or scipy

pyplot order of magnitude fontsize modification when using scientific ticks python [duplicate]

I am attempting to plot differential cross-sections of nuclear decays and so the magnitudes of the y-axis are around 10^-38 (m^2) pylab as default plots the axis as 0.0,0.2,0.4... etc and has a '1e-38' at the top of the y-axis.
I need to increase the font size of just this little bit, I have tried adjusting the label size
py.tick_params(axis='y', labelsize=20)
but this only adjusts the labels 0.0,0.2,0.4....
Many thanks for all help
You can access the text object using the ax.yaxis.get_offset_text().
import numpy as np
import matplotlib.pyplot as plt
# Generate some data
N = 10
x = np.arange(N)
y = np.array([i*(10**-38) for i in x])
fig, ax = plt.subplots()
# Plot the data
ax.plot(x,y)
# Get the text object
text = ax.yaxis.get_offset_text()
# Set the size.
text.set_size(30) # Overkill!
plt.show()
I've written the solution above using matplotlib.pyplot rather than pylab though if you absolutely have to use pylab then it can be changed (though I'd recommend you use matplotlib.pyplot in any case as they are pretty much identical you can just do a lot more with pyplot easier).
Edit
If you were to use pylab then the code would be:
pylab.plot(x, y)
ax = pylab.gca() # Gets the current axis object
text = ax.yaxis.get_offset_text() # Get the text object
text.set_size(30) # # Set the size.
pylab.show()
An example plot with an (overkill!) offset text.

Is there a way to add a margin line in Python-Plotly charts?

By default, Plotly charts does not have "lines" in the margins of the plot area.
I can define lines in the axis X and Y, but not in all plot area.
Using "template": "simple_white" in the layout, I can obtain the image bellow.
import numpy as np
import plotly.graph_objs as go
x = np.linspace(0,10,1000)
y = np.sin(x)
layout = {"template":"simple_white"}
data = go.Scatter(x=x,y=y)
fig = go.Figure(data,layout)
fig.show()
Image obtained with Plotly
Is there a way to obtain a image with Plotly like the one bellow, i.e. with lines around the plot area?
It is made with matplotlib package. I mean: can I have a image like this, but with Plotly package?
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0,10,1000)
y = np.sin(x)
plt.plot(x,y)
plt.show()
Image obtained with Matplotlib
EDIT:
A similar question can be found at:
Plotly: How to add borders and sidelabels to subplots, and syncronize panning?
However, I would like to maintain this one for other users, because it is right straight to the point of putting borders in a single plot. The other question includes other features.
The key is to use another well-hidden Plotly attribute mirror. Update your layout like this:
import numpy as np
import plotly.graph_objs as go
x = np.linspace(0, 10, 1000)
y = np.sin(x)
layout = dict(
template="simple_white",
xaxis=dict(ticks="outside", mirror=True, showline=True),
yaxis=dict(ticks="outside", mirror=True, showline=True),
)
data = go.Scatter(x=x, y=y)
fig = go.Figure(data, layout)
fig.show()
This shows:

ploting a bar plot for large amount of data

I have a 752 data points which i need to plot,
I have plotted the data on bar plot using seaborn library in python , but graph i get is very unclear and I am not able to analyze anything through graph , is there any way i can view this graph more clearly and all data points fit with labels seen clearly in python

code written is following
import seaborn as sns
sns.set_style("whitegrid")
ax = sns.barplot(x="Events", y = "Count" , data = Unique_Complaints)
It is always difficult to visualise so many points. Nihal, has rightly pointed that it is best to use Pandas and statistical analysis to extract information from your data. Having said this, IDEs like Spyder and Pycharm and packages like Bokeh allow interactive plots where you can zoom to different parts of the plot. Here is an example with Pycharm:
Code:
# Import libraries
import seaborn as sns
import numpy as np
import matplotlib.pyplot as plt
# Exponential decay function
x = np.arange(1,10, 0.1)
A = 7000
y = A*np.exp(-x)
# Plot the exponential function
sns.barplot(x = x, y = y)
plt.show()
Figure without magnification
Magnified figure
To see a large amount of data you can use the figure from matplotlib.pyplot like this
from matplotlib.pyplot import figure
figure(num=None, figsize=(20,18), dpi=80, facecolor='w', edgecolor='r')
sns.barplot(x="Events", y = "Count" , data = Unique_Complaints)
plt.show()
I am using this to see a graph with 49 variables and the result is:
My code is
from matplotlib.pyplot import figure
figure(num=None, figsize=(20,18), dpi=256, facecolor='w', edgecolor='r')
plt.title("Missing Value Prercentage")
sns.barplot(miss_val_per, df.columns)
plt.show()
Data I am using is:
https://www.kaggle.com/sobhanmoosavi/us-accidents
just swap x and y and try to increase the fig size

Categories

Resources