How to plot a point on a time series in python - python

I am facing an issue with plotting points in a time series since I cannot identify the y-axis value. I have 2 datasets: one NetCDF file with satellite data (sea surface temperature), and another CSV file with storm track data (time, longitude, latitude, wind speed, etc.). I can plot the desired temperature time series for all storm track locations located in the ocean. However, I want to indicate the time of the storm footprint occurrence within each time series line. So, one line represents one location and the changing temperature over time, but I also want to show WHEN the storm occurred at that location.
This is my code so far (it works):
lati = stormtrack_lat.values
loni = stormtrack_lon.values
for i, dummy in enumerate(lati):
dsloc = SSTskin_file.sel(lon=loni[i], lat=lati[i], method='nearest')
dsloc['analysed_sst'].plot()
#plt.plot(dsloc,stormtrack_time[i], "or") #here I want to add one point to each line indicating the time when the storm occured at this location
plt.title('My title')
plt.xlabel('time')
plt.ylabel('SST skin in K')
The netcdf file contains the time data as datetime coordinate, but my CSV file contains this data:
| da | INDEX | SIZE | AREA | x | y | RADIUS | MEANV
2020021018 1505 2934 177.363 -2.82 49.87 1782.18 16.18
2020021100 1505 3812 220.078 5.25 49.57 2811.51 16.17
...
where 'da' represents the date and time (YYYYMMDDHH). So, I think I need to (1) convert the CSV 'da' values into a datetime format in order to use them for the line plt.plot(dsloc,stormtrack_time[i], "or") and then (2) to find those datetime values within the netcdf file and then (3) use than time point for plotting the corresping SST value/time point.
The problem is that I do not know HOW to do this. Can anyone help?
Thanks!

I have found the way to do this:
lati = stormtrack_lat.values
loni = stormtrack_lon.values
timei = stormtrack_datetime.values
fig2 = plt.figure(figsize=(20, 20), dpi=300)
for i, dummy in enumerate(lati):
dsloc = SSTskin_file.sel(lon=loni[i], lat=lati[i], method='nearest')
dstime = SSTskin_file.sel(time=timei[i], lon=loni[i], lat=lati[i], method='nearest')
skin_celsius = (dsloc['analysed_sst']) - 273.15
timesteps = dsloc.time.values
timestep = dstime.time.values
timevalue = ((dstime['analysed_sst']).values) - 273.15
lineplot = plt.plot(timesteps, skin_celsius )
dotplot = plt.plot(timestep, timevalue, "or")
plt.title('Skin SST over time at storm track locations', fontsize = 20 )
plt.xlabel('Date', fontsize = 16)
plt.ylabel('Skin SST in $^{\circ}C$', fontsize = 16)
plt.xticks(fontsize = 16)
plt.yticks(fontsize = 16)
#plt.legend(lineplot) #Here I would like to plot the legend for the line plots (time series data). I want to indicate the location (longitude and latitude) of the time series
plt.legend(dotplot[:1], ['Storm track at location and time'], fontsize = 16);
fig2.savefig('SSTskin_storm_timeseries_test.png', bbox_inches='tight')

Related

How to detect time-periods present in a signal using FFT?

I'm trying to determine the periodicities present in a given waveform.
This is my signal, which is a sinusoidal waveform:
t_week = np.linspace(1,480, 480)
t_weekend=np.linspace(1,192,192)
T=96 #Time Period
x_weekday = 10*np.sin(2*np.pi*t_week/T)+10
x_weekend = 2*np.sin(2*np.pi*t_weekend/T)+10
x_daily_weekly_sinu = np.concatenate((x_weekday, x_weekend))
#Creating the Signal
x_daily_weekly_long_sinu = np.concatenate((x_daily_weekly_sinu,x_daily_weekly_sinu,x_daily_weekly_sinu,x_daily_weekly_sinu,x_daily_weekly_sinu,x_daily_weekly_sinu,x_daily_weekly_sinu,x_daily_weekly_sinu,x_daily_weekly_sinu,x_daily_weekly_sinu))
#Visualization
plt.plot(x_daily_weekly_long_sinu)
plt.show()
In order to determine the two periods present, which are 96 & 672, I'm creating the FFT of the waveform as follows:
f, Pxx = signal.periodogram(x_daily_weekly_long_sinu, fs = 96, window='hanning', scaling='spectrum')
#Visualization
plt.figure(figsize = (10, 8))
plt.plot(f, Pxx)
plt.xlim(0, 10)
plt.yscale('log')
plt.xlabel('Frequency (cycles/day)')
plt.ylabel('Spectrum Amplitude')
The following is the plot of frequencies that I get.
Can anyone tell why is it showing so many frequencies instead of just two distinct frequencies of 96 & 672?
I then try to extract the top frequencies from the FFT:
for amp_arg in np.argsort(np.abs(Pxx))[::-1][1:6]:
day = 1 / f[amp_arg]
print(day)
But my output gives the following values as the top frequencies instead of 96 & 672:
1.0144927536231885
0.9859154929577465
1.1666666666666667
0.875
1.4
Why is this happening? Can anyone please help me to determine the correct periods?
It would be great if I just get a final list of values representing the exact set of periods only.

How to retrieve from lat, lon value using pygrib

I'm starting in python programming and I would like to make a small script which displays the data of "Local temperature diagnosed at 2m height above the relief", "Zonal component of the west-east horizontal wind diagnosed at 10 m height" and the "Meridian component of the horizontal wind diagnosed at 10 m height" as a function of longitude and latitude.
For this, I download a file from the open data site of Meteofrance OPEN DATA by selecting:
Domain: "France - 0.01 °", Sub Package: "SP1 - Current surface parameters", Deadline group "0h" and Run date "2020-02-10 00 UTC"
So I have a file in grib2 format that I am trying to process with the pygrib library
To start simple, I'm just trying to get the temperature for a given point (longitude = 0.25, latitude = 49.21)
I created an index to read the file (It seems that it is the fastest)
indx = pygrib.index('./AROME_0.01_SP1_00H_2020021000.grib2', 'typeOfLevel', 'level', 'name')
I select the records which correspond to the temperature and I recover the values:
msg = indx.select(level=2, typeOfLevel="heightAboveGround", name="2 metre temperature")
temp2m = msg[0].values
The problem is that from there, I fumble and I don't find how to retrieve from this variable (numpy.ma.core.MaskedArray) the value that corresponds to my longitude = 0.25 and latitude = 49.21
If someone has an idea, I'm interested
import pygrib
indx = pygrib.index('./AROME_0.01_SP1_00H_2020021000.grib2', 'typeOfLevel', 'level', 'name')
msg = indx.select(level=2, typeOfLevel="heightAboveGround", name="2 metre temperature")
temp2m = msg[0].values
You could use the pygrib.data() method to create a bounding box around your lat/lon and then take the mean of the values within that box. Just adjust the tolerance to control how big the box is.
lat, lon, tolerence = 49.21, 0.25, 0.1
data, lats, lons = grb.data(lat1=lat-tolerence,lat2=lat+tolerence,
lon1=lon-tolerence,lon2=lon+tolerence)
data.mean()
You should be able to get your lat and lon by using .latlons() from your variable that you selected (not the values). From there you can get your index corresponding your point.
import pygrib
indx = pygrib.index('./AROME_0.01_SP1_00H_2020021000.grib2', 'typeOfLevel', 'level', 'name')
msg = indx.select(level=2, typeOfLevel="heightAboveGround", name="2 metre temperature")
lat,lon = msg.latlons()
temp2m = msg[0].values

Time series dataframe. Plot two distinct time ranges with a relative starting point

I have a dataframe with a time series (daily prices of a single stock). I want to take two distinct time ranges and overlay them on plot with a relative starting point of 0 instead of a date.
In the example below, if I plot 1962 and 2018, it uses the date as the x axis instead of a relative starting point.
SPY = pd.read_csv('GSPC.csv', parse_dates=['dDate'], index_col='dDate')
SPY1962 = SPY['1962']
SPY2018 = SPY['2018']
firstprice62 = SPY1962['nAdjClose'].iloc[0]
firstprice18 = SPY2018['nAdjClose'].iloc[0]
normal62 = SPY1962['nAdjClose'].div(firstprice62).mul(100)
normal18 = SPY2018['nAdjClose'].div(firstprice18).mul(100)
A picture of what I'm trying to accomplish
Figured it out.
normal18 = normal18.reset_index()
normal62 = normal62.reset_index()
normal62['nAdjClose'].plot()
normal18['nAdjClose'].plot()
plt.show()

Matplotlib/Basemap plotting wind barbs at equal distances apart

I'm trying to plot wind barbs, which are spaced 100km by 100km from each other. The data I have is for the northern hemisphere (0.25 degree). I tried to reproduce the problem in the code below:
import numpy as np
from mpl_toolkits.basemap import Basemap
lons,lats = np.meshgrid(np.linspace(-180,180,1440),np.linspace(0,90,360))
m = Basemap(projection='merc',resolution='l',llcrnrlat=33,llcrnrlon=-50,urcrnrlat=68,urcrnrlon=40)
m.drawcoastlines(linewidth=0.6)
X, Y = m(lons,lats)
UWind = np.ones((360,1440))
VWind = np.zeros((360,1440))
xx = np.arange(0, X.shape[1], 8)
yy = np.sin(np.deg2rad(np.linspace(0,90,45)))
yy = yy*360
yy[-1] = 359
yy = yy.astype(int)
points = np.meshgrid(yy, xx)
m.barbs(X[points], Y[points], UWind[points], VWind[points],length=4,linewidth=0.6,pivot='middle')
plt.show()
xx is chosen to plot a barb every 2 degrees (8 boxes at 0.25 degrees resolution). Of course, in this projection, latitude spacing will increase as latitude increases. So, to avoid this, I created yy which varies with sin (to counteract this). It doesn't seem to do anything. Any help is very welcome. The current plot this produces which isn't equal spacing (from a distance, not degrees, perspective).
Replace the m.barbs and add a new line above which does the transform:
uproj,vproj,xx,yy = m.transform_vector(UWind,VWind,np.linspace(-180,180,1440),np.linspace(0,90,360),31,31,returnxy=True,masked=True)
m.barbs(xx,yy,uproj,vproj,length=4,linewidth=0.6,pivot='middle')
Reference: https://matplotlib.org/basemap/users/examples.html
More Information here: https://matplotlib.org/basemap/api/basemap_api.html#module-mpl_toolkits.basemap

Basemap not plotting to left of 0 degrees longitude

I'm reasonably new to Python, and I'm trying to plot long-term mean rainfall data for the African continent. I have various NetCDF files, which have already been cut to just contain the long term mean value - I just need to plot it.
My issue is that the data is only plotting to the right of the 0 degree longitude line. I gather this is due to Basemap wanting -180 to 180 coordinates, and my data is 0 to 360. However, nothing I've tried seems to work.
Here's the code (which gives the correct plot, just cut off to the left of 0 degrees):
nc = Dataset(GISS-E2-H_MAM_plots.nc)
prcp = nc.variables['pr'][0,:,:]
pr = 86400*prcp[:]
lon=nc.variables['lon']
lat=nc.variables['lat']
[lonall, latall] = np.meshgrid(lon, lat)
fig = plt.figure()
m = Basemap(projection='cyl', llcrnrlat=-25, urcrnrlat=15, llcrnrlon=-20, urcrnrlon=60)
m.drawcoastlines()
m.drawcountries()
m.drawparallels(np.arange(-90.,90.,10.), labels = [1,0,0,0], fontsize = 10)
m.drawmeridians(np.arange(-180., 180., 10.), labels = [0,0,0,1], fontsize = 10)
levels=np.arange(2, 11.6, 0.8)
mymapf = plt.contourf(lonall, latall, pr, levels, cmap=plt.cm.gist_rainbow_r)
I've tried to shift the data by 180 using the following, and then np.roll to move it all along.
lonall= lonall-180
nlon=len(lonall)
pr=np.roll(pr, nlon/2, axis=1)
This worked for a colleague in a similar instance, but hasn't worked for me.
Any help would be greatly appreciated!
I think the problem is that you don't have [:] after you read in latitude and longitude. I.e. change the above lines to:
lon=nc.variables['lon'][:]
lat=nc.variables['lat'][:]
Also, you don't need the brackets around [lonall,latall]

Categories