Trying to plot DATA POINTS on BASEMAP (Python) - python

I have some meteorological data about some stations in Tenerife Island (this Dataframe has lat,lon and temperature in certain points of the island) (The source of the data is AEMET opendata, so they are supposed to be trustworthy)
I have plotted the Basemap successfully, but when I wanted to plot the points in my Dataframe over the Basemap, the come really weird.
Here the data I have:
I changed the order so, when I use imshow the order is x,y,temperature, where x are latitudes and y are longitudes.
To plot the map I have written:
m = Basemap(llcrnrlon=-17,llcrnrlat=27.8,urcrnrlon=-16,urcrnrlat=28.7,resolution='i',projection='merc')
im = m.imshow(temp, cmap='BuPu')
cbi=plt.colorbar(im,shrink=0.7,format='%.1f')
plt.show()
The result is giving me:
But, I wanna plot only points over their location, e.g., if the point is in the coordinates x,y it should only appeared a little point over this position in the map.
Any helping hand?
Thanks!

Check this code:
import pandas as pd
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
df = pd.read_csv('data.csv')
m = Basemap(llcrnrlon = -17, llcrnrlat = 27.8, urcrnrlon = -16, urcrnrlat = 28.7, resolution = 'i', projection = 'merc')
m.drawcoastlines(color = 'black')
x, y = m(list(df['x']), list(df['y']))
m.scatter(x, y,
c = df['temperatura'],
s = 100,
cmap = 'RdBu_r')
plt.colorbar()
plt.show()
which gives this map:
You used imshow(), but this funciton is useful for plotting image from a NxM matrix, so you will always get a colored rectangle, as in you purple image.
You have data in a x-y (lon-lat) coordinate format, so you could plot a scatterplot, showing the temperature in those point on the map, like my code does, where those temperature where measured.
If you want a distributed colored map (in techincal terms a temperature field), like this:
you need a distributed data like a meshgrid.

Related

Plot Circles in GeopPandas with a ground-radius: results are not correct

I try to plot flight distances on a map. In order to do this, I need to respect the projection of the map of course.
It seems that the circles are somehow distorted --> looks like a projection
It is just that the result does not make any sense, the circles I create are too small.
On the example below: the West-Coast should be within the circle (4800km) around New York City.
But it clearly is not.
I cannot find any comment in GeoPandas that the circle (buffer) shall not be used for something like this.
import geopandas as gpd
lat = 33.975
lon = -118.405
world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres'))
data=[]
dic={}
dic["lat"]= lat
dic["lon"]=lon
dic["city"]="SFA"
data.append(dic.copy())
df = gpd.GeoDataFrame(data)
df["geometry"]=gpd.points_from_xy(df.lon, df.lat)
df["center"]=df["geometry"]
df.crs="EPSG:4326" # initiat a CRS
df = df.to_crs("epsg:3395") # change to 3395 for circle creation
df["geometry"]= df.geometry.buffer(4800*1000) #4800km range
df=df.to_crs("EPSG:4326") #switch back to orginal CRS
ax = df.plot(facecolor='none', edgecolor='red',figsize=(15,15)) #plot circle
df.center.plot(ax=ax,color="r") #plot center point
world.plot(ax=ax,alpha=.5) #plot map
I played around with differen coordinate systems. But I never get the desired result.
I also tried to create the buffer/circle using angles in the EPSG:4326 CRS and haversine formula. --> identical result, circle is too small
you might be interested in giving EOmaps a try...
I guess it provides all the functionalities you're seeking :-)
(Note however that there's a bug if you want to draw geodesic circles that extend outside the crs-bounds...)
from eomaps import Maps
x = [-60, -40, 40, 70]
y = [-60, 40, 70, 20]
m = Maps(Maps.CRS.Mollweide())
m.add_feature.preset.land()
m.add_feature.preset.ocean()
m.set_data(data=None, x=x, y=y, crs=4326)
m.set_shape.geod_circles(radius=2e6)
m.plot_map(fc="none", ec="r", set_extent=False)
m.add_line(xy=list(zip(x, y)),
mark_points="ro",
connect="geod",
color="r", lw=1, ls="--",
)

Smooth Contourf plot completely filled

I have the data with (X,Y,Z) values. I tried to make a density plot with Z values for intensity. However the plot I get is not smooth and and has polytope i.e not completely filled.
The following is the code with the Data
but I want to obtain smooth and completely filled plot
import numpy as np
from scipy.interpolate import griddata
import matplotlib.pyplot as plt
import xlrd
location = "~/Desktop/Data.xlsx"
data = xlrd.open_workbook(location)
sheet = data.sheet_by_index(0)
sample=2000
x=np.array(sheet.col_values(0))[0:sample]
y=np.array(sheet.col_values(1))[0:sample]
z=np.hamming(9000)[0:sample]
print z
def plot_contour(x,y,z,resolution = 500,contour_method='cubic'):
resolution = str(resolution)+'j'
X,Y = np.mgrid[min(x):max(x):complex(resolution), min(y):max(y):complex(resolution)]
points = [[a,b] for a,b in zip(x,y)]
Z = griddata(points, z, (X, Y), method=contour_method)
return X,Y,Z
X,Y,Z = plot_contour(x,y,z,resolution = 500,contour_method='linear')
plt.style.context("seaborn-deep")
plt.contourf(X,Y,Z)
plt.colorbar()
plt.show()
This is the output:
This is what I want to achieve using contourplotf:
plt.contourf() is not the main problem here, it's just working with the data it has. The problem is the linear interpolation in scipy.interpolate.griddata().
I recommend not using griddata, but instead using one of the following methods:
scipy.interpolate.Rbf() — this is what you were using before (see my previous answer).
verde — an awesome gridding package.
sklearn.gaussian_process — or some other prediction model.
All of these methods will fill in the grid. If you plot the result with plt.imshow() you'll get the type of plot you show in your question — that is not a plt.contourf() plot.
Here's a demo notebook showing all of these approaches (including griddata).

How to plot contours from a polar stereographic grib2 file in Python

I am trying to plot a CMC grib2 pressure forecast file using matplotlib to plot the pressure contours. The description of the grib2 grid can be found here: https://weather.gc.ca/grib/grib2_reg_10km_e.html. The grib2 file is found in this directory: http://dd.weather.gc.ca/model_gem_regional/10km/grib2/00/000/ and starts with CMC_reg_PRMSL_MSL_0_ps10km followed by the date. It is a grib file containing pressure at mean sea level.
My problem is that I end up having some straight line contours that follow the lines of latitude on top of the actual pressure contours. I thought it might be because I am plotting in PlateCarree as opposed to Geodetic but the contour plot will not allow using Geodetic. The result of my plot is:
Code is as follows:
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import datetime as dt
import cartopy
import cartopy.crs as ccrs
import Nio
gr = Nio.open_file('./data/CMC_reg_PRMSL_MSL_0_ps10km_2018111800_P000.grib2', 'r')
print(gr)
names = gr.variables.keys()
print("Variable Names:", names)
dims = gr.dimensions
print("Dimensions: ", dims)
attr = gr.attributes.keys()
print("Attributes: ", attr)
obs = gr.variables['PRMSL_P0_L101_GST0'][:]
lats = gr.variables["gridlat_0"][:]
lons = gr.variables["gridlon_0"][:]
fig = plt.figure(figsize=(15, 2))
intervals = range(95000, 105000, 400)
ax=plt.axes([0.,0.,1.,1.],projection=ccrs.PlateCarree())
obsobj = plt.contour(lons, lats, obs, intervals, cmap='jet',transform=ccrs.PlateCarree())
states_provinces = cartopy.feature.NaturalEarthFeature(
category='cultural',
name='admin_1_states_provinces_lines',
scale='50m',
facecolor='none')
ax.add_feature(cartopy.feature.BORDERS)
ax.coastlines(resolution='10m')
ax.add_feature(states_provinces,edgecolor='gray')
obsobj.clabel()
colbar =plt.colorbar(obsobj)
Any suggestions would be appreciated.
UPDATE
For anyone without PyNIO the following can be used to reproduce using the dump files in the comments section.
Just remove all the references to NIO and replace the lats, lons, obs assignment with the following.
lats = np.load('lats.dump')
lons = np.load('lons.dump')
obs = np.load('obs.dump')
The problem
The problem is that the grid winds around the earth. Hence there will be points on the grid at -180° whose nearst neighbor sits at +180°, i.e. the grid wraps around the antimeridian. The following plots the grid index along both directions. One can see that the first grid row (black) appears on both sides of the plot.
Hence a contour line following the pacific westwards needs to then cross straight through the plot to continue towards japan on the other side of the plot. This will lead to the undesired lines
A solution
A solution is to mask the outer points of the PlateCarree out. Those occur in the middle of the grid. Cutting the grid at coordinates of longitude larger than 179° or smaller than -179°, as well as leaving the north pole out would look like
where the blue denotes the cut out points.
Applying this to the contour plot gives:
import matplotlib.pyplot as plt
import numpy as np
import cartopy
import cartopy.crs as ccrs
lats = np.load('data/lats.dump')
lons = np.load('data/lons.dump')
obs = np.load('data/obs.dump')
intervals = range(95000, 105000, 400)
fig, ax = plt.subplots(figsize=(15,4), subplot_kw=dict(projection=ccrs.PlateCarree()))
fig.subplots_adjust(left=0.03, right=0.97, top=0.8, bottom=0.2)
mask = (lons > 179) | (lons < -179) | (lats > 89)
maskedobs = np.ma.array(obs, mask=mask)
pc = ax.contour(lons, lats, maskedobs, intervals, cmap='jet', transform=ccrs.PlateCarree())
ax.add_feature(cartopy.feature.BORDERS)
ax.coastlines(resolution='10m')
colbar =plt.colorbar(pc)
plt.show()
If you are sum up your longitude by +180 to avoid negative coordinates, your code should be running. A coordinate transformation should be legit from my point of view.

Plotting over a background python basemap

How do you go about plotting data over a background image in Python?
For example if I had some gridded pressure data of shape [180,360] (lat,lon)
I could easily plot data by;
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
import numpy as np
m = Basemap(projection='ortho',resolution='c',lat_0=45,lon_0=0)
lat = np.linspace(-90,90,180)
lon = np.linspace(-180,180,360)
lon,lat = np.meshgrid(lon,lat)
X, Y = m(lon, lat)
m.contourf(X,Y,Pressure)
plt.show()
etc etc. But if I add a background , e.g.
m.bluemarble()
I cant plot on top of this layer. I've heard of imshow, but how does that take into account gridded data? Not sure how to plot pressure on top of this. Or possibly the alpha attribute in plotting. Thanks!
For example setting alpha to 0.5 in the plt function, I get some horrible mix of colours (and white lines randomly appear);

Changing axis options for Polar Plots in Matplotlib/Python

I have a problem changing my axis labels in Matplotlib. I want to change the radial axis options in my Polar Plot.
Basically, I'm computing the distortion of a cylinder, which is nothing but how much the radius deviates from the original (perfectly circular) cylinder. Some of the distortion values are negative, while some are positive due to tensile and compressive forces. I'm looking for a way to represent this in cylindrical coordinates graphically, so I thought that a polar plot was my best bet. Excel gives me a 'radar chart' option which is flexible enough to let me specify minimum and maximum radial axis values. I want to replicate this on Python using Matplotlib.
My Python script for plotting on polar coordinates is as follows.
#!usr/bin/env python
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-180.0,190.0,10)
theta = (np.pi/180.0 )*x # in radians
offset = 2.0
R1 = [-0.358,-0.483,-0.479,-0.346,-0.121,0.137,0.358,0.483,0.479,0.346,0.121,\
-0.137,-0.358,-0.483,-0.479,-0.346,-0.121,0.137,0.358,0.483,0.479,0.346,0.121,\
-0.137,-0.358,-0.483,-0.479,-0.346,-0.121,0.137,0.358,0.483,0.479,0.346,0.121,\
-0.137,-0.358]
fig1 = plt.figure()
ax1 = fig1.add_axes([0.1,0.1,0.8,0.8],polar=True)
ax1.set_rmax(1)
ax1.plot(theta,R1,lw=2.5)
My plot looks as follows:
But this is not how I want to present it. I want to vary my radial axis, so that I can show the data as a deviation from some reference value, say -2. How do I ask Matplotlib in polar coordinates to change the minimum axis label? I can do this VERY easily in Excel. I choose a minimum radial value of -2, to get the following Excel radar chart:
On Python, I can easily offset my input data by a magnitude of 2. My new dataset is called R2, as shown:
#!usr/bin/env python
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-180.0,190.0,10)
theta = (np.pi/180.0 )*x # in radians
offset = 2.0
R2 = [1.642,1.517,1.521,1.654,1.879,2.137,2.358,2.483,2.479,2.346,2.121,1.863,\
1.642,1.517,1.521,1.654,1.879,2.137,2.358,2.483,2.479,2.346,2.121,1.863,1.642,\
1.517,1.521,1.654,1.879,2.137,2.358,2.483,2.479,2.346,2.121,1.863,1.642]
fig2 = plt.figure()
ax2 = fig2.add_axes([0.1,0.1,0.8,0.8],polar=True)
ax2.plot(theta,R2,lw=2.5)
ax2.set_rmax(1.5*offset)
plt.show()
The plot is shown below:
Once I get this, I can MANUALLY add axis labels and hard-code it into my script. But this is a really ugly way. Is there any way I can directly get a Matplotlib equivalent of the Excel radar chart and change my axis labels without having to manipulate my input data?
You can just use the normal way of setting axis limits:
#!usr/bin/env python
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-180.0,190.0,10)
theta = (np.pi/180.0 )*x # in radians
offset = 2.0
R1 = [-0.358,-0.483,-0.479,-0.346,-0.121,0.137,0.358,0.483,0.479,0.346,0.121,\
-0.137,-0.358,-0.483,-0.479,-0.346,-0.121,0.137,0.358,0.483,0.479,0.346,0.121,\
-0.137,-0.358,-0.483,-0.479,-0.346,-0.121,0.137,0.358,0.483,0.479,0.346,0.121,\
-0.137,-0.358]
fig1 = plt.figure()
ax1 = fig1.add_axes([0.1,0.1,0.8,0.8],polar=True)
ax1.set_ylim(-2,2)
ax1.set_yticks(np.arange(-2,2,0.5))
ax1.plot(theta,R1,lw=2.5)

Categories