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
Related
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')
I have a satellite image file. Loaded into dask array. I want to get pixel value (nearest) of a latitude, longitude of interest.
Satellite image is in GEOS projection. I have longitude and latitude information as 2D numpy arrays.
Satellite Image file
I have loaded it into a dask data array
from satpy import Scene
import matplotlib as plt
import os
cwd = os.getcwd()
fn = os.path.join(cwd, 'EUMETSAT_data/1Jan21/MSG1-SEVI-MSG15-0100-NA-20210101185741.815000000Z-20210101185757-1479430.nat')
files = [fn]
scn = Scene(filenames=files, reader='seviri_l1b_native')
scn.load(["VIS006"])
da = scn['VIS006']
This is what the dask array looks like:
I read lon lats from the area attribute with the help of satpy:
lon, lat = scn['VIS006'].attrs['area'].get_lonlats()
print(lon.shape)
print(lat.shape)
(1179, 808)
(1179, 808)
I get a 2d numpy array each, for longitude and latitude that are coordinates but I can not use them for slicing or selecting.
What is the best practice/method to get nearest lat long, pixel information?
How do I project the data onto lat long coordinates that I can then use for indexing to arrive at the pixel value.
At the end, I want to get pixel value (nearest) of lat long of interest.
Thanks in advance!!!
The AreaDefinition object you are using (.attrs['area']) has a few methods for getting different coordinate information.
area = scn['VIS006'].attrs['area']
col_idx, row_idx = area.get_xy_from_lonlat(lons, lats)
scn['VIS006'].values[row_idx, col_idx]
Note that row and column are flipped. The get_xy_from_lonlat method should work for arrays or scalars.
There are other methods for getting X/Y coordinates of each pixel if that is what you're interesting in.
You can find the location with following:
import numpy as np
px,py = (23.0,55.0) # some location to take out values:
dist = np.sqrt(np.cos(lat*np.pi/180.0)*(lon-px)**2+(lat-py)**2); # this is the distance matrix from point (px,py)
kkout = np.squeeze(np.where(np.abs(dist)==np.nanmin(dist))); # find location where distance is minimum
print(kkout) # you will see the row and column, where to take out data
#serge ballesta - thanks for the direction
Answering my own question.
Project the latitude and longitude (platecaree projection) onto the GEOS projection CRS. Find x and y. Use this x and y and nearest select method of xarray to get pixel value from dask array.
import cartopy.crs as ccrs
data_crs = ccrs.Geostationary(central_longitude=41.5, satellite_height=35785831, false_easting=0, false_northing=0, globe=None, sweep_axis='y')
lon = 77.541677 # longitude of interest
lat = 8.079148 # latitude of interst
# lon lat system in
x, y = data_crs.transform_point(lon, lat, src_crs=ccrs.PlateCarree())
dn = ds.sel(x=x,y=y, method='nearest')
I am fairly new to arcpy and I've literally spent the day trying to figure out how to add a point with XY coordinates inside a Feature Class in arcpy. Here's the code I have right now:
coordinates = raw_input("Please enter longitude and latitude as floats split by a space: ")
c_split = coordinates.split()
lng = float(c_split[0])
lat = float(c_split[1])
spatial_reference = arcpy.SpatialReference(3857)
arcpy.CreateFeatureclass_management('D:\Documents\GIS_DATA\buildings_sample_8', "center.shp", "POINT", "", "DISABLED", "DISABLED", spatial_reference)
center = "center.shp"
cursor = arcpy.da.InsertCursor('D:\Documents\GIS_DATA\buildings_sample_8\center.shp', ["SHAPE#XY"])
xy = (lng, lat)
cursor.insertRow([xy])
This manages to create the shapefile center.shp within the appropriate directory, but I am not able to add the user-entered longitude and latitude values to the point, making the point appear at the default 0, 0.
This is probably a super easy question, but I haven't been able to find the documentation online.
Thank you!
try changing this:
xy = (lng, lat)
to this:
xy = arcpy.Point(lng, lat)
I'm guessing your coordinate floating point is indeed a point (.) and not a comma (,) otherwise you'll get an error trying to create the Point (Input value is not numeric).
I have FITS file in pixel coordinates. I want to basically read in its latitude and longitude.
I know we can use something following:
from astropy import WCS
w = WCS('sample.fits')
lat, long = w.all_pix2world(90, 38, 1)
But instead of one RA(=90), DEC(=38) value inside
w.all_pix2world
I want to fetch latitudes and longitudes (in Galactic coordinate system) of the entire field of sample.fits.
header
NAXIS = 2
NAXIS1 = 150
NAXIS2 = 150
Please let me know if any other information is needed. Any help is appreciated.
Thanks.
I am trying to read data from a nc file, which has the following variables:
['latitude',
'longitude',
'latitude_bnds',
'longitude_bnds',
'time',
'minimum',
'maximum',
'average',
'stddev',
'AirTemperature']
What I am trying to achieve is to extract the AirTemperature data for any given (time, latitude and longitude):
And for that, I am doing something like this:
df = Dataset('data_file.nc', 'r')
lat = df.variables['latitude'][:]
lon = df.variables['longitude'][:]
temp = df.variables['AirTemperature'][:,:,:]
#(lat, lon) for Coffee, TN
test_lat = 35.45
test_lon = -86.05
#getting the indices for the (lat, lon) using numpy.where
lat_idx = np.where(lat==test_lat)[0][0]
lon_idx = np.where(lon==test_lon)[0][0]
#extracting data for all the times for given indices
tmp_crd = temp[:,lat_idx,lon_idx]
Up till this point, it all goes fine. However, when I print the data, I see all the identical values being printed.. (for any lat, lon that I have been testing..)
print tmp_crd.data
>>> [-9999. -9999. -9999. ..., -9999. -9999. -9999.]
Which I don't seem to understand..why the air temperature is always shown as -9999.0? I have tested for a lot of other (lat, lon) points, and it seems for every location point, the air temperature is -9999.0. How can I extract the real data from this file?
Please help :-(.
Thank You
Okay..I think I figured out. Here is what was happening:
The nc file i have has a different precision for latitude and longitudes, and I was apparently passing much more rounded sets of (lat, lon) points. Once I figured out the right precision, it works fine for me. The -9999.0 value was basically the _fill_value for the numpy's masked array (which indicated that if there is no record matching the given set of lat and long, return the masked values).
Thanks every one.