How to use a binary netcdf mask in python? - python

Im fairly new to using the cartopy package. I wanted to use a land sea mask from a given binary map in netcdf format. Here lsm_set is my netcdf file that contains that binary map and t2m_set is the data that I'd like to map. I'm still playing around with cartopy a little bit to get the hang of it, but I can't seem to figure out how to use the land sea mask. I've read several related questions here, but they didn't work on my code because my t2m variables did not have the attribute mask.
My teacher said I could use it to mark the sea values as "NaN" but I didn't know an efficient way to do it. I tried it with a while loop but that's super slow when you're working with this much data :')
I used data found from the copernicus institute on the following link: https://cds.climate.copernicus.eu/cdsapp#!/dataset/reanalysis-uerra-europe-single-levels?tab=form
import os
import numpy as np
import matplotlib.pyplot as plt
import netCDF4 as nc
from netCDF4 import Dataset
import xarray as xr
from cartopy import config
import cartopy.crs as ccrs
import cartopy.io.shapereader as shpreader
filepath1 = '... file path... '
lsm_set = xr.open_dataset(filepath1)
filepath2 = '... file path...'
t2m_set= xr.open_dataset(filepath2)
lons = lsm_set.variables['longitude']#[:]
lats = lsm_set.variables['latitude']#[:]
lsm = lsm_set.variables['lsm']
t2m = t2m_set.variables['t2m']
plt.figure(figsize=(8, 8))
ax = plt.axes(projection = ccrs.Mercator())
ax.contourf(lons[200:400,100:300], lats[100:300,200:400], t2m[100:300,100:300],transform=ccrs.Mercator())
lsm_set.close()
t2m_set.close()
plt.show()
Any nudge in the right direction is appreciated, thanks!
Solved!
Turns out the solution was a lot easier than I thought.
lons = t2m_set.variables['longitude']#[:]
lats = t2m_set.variables['latitude']#[:]
lsm = lsm_set.variables['lsm']
t2m = t2m_set.variables['t2m']
lsm_masked = lsm.where(lsm!=0.)
mapdata = t2m+lsm_masked
And than plot mapdata instead of just t2m

You could use the where method of xarray :
t2m_set.where(lsm_set)
It should give you a nicely masked xarray.Dataset.

Let me assume you have the land/sea data as 1's and 0's and the same size as your data... Then you can easily make a plot like this:
#!/usr/bin/env ipython
# --------------------
import matplotlib as mpl
mpl.rcParams['font.size'] = 18
import matplotlib.pylab as plt
import numpy as np
# -----------------------------
xx = np.linspace(9.,30,100);
yy = np.linspace(54.0,66.0,100);
xm,ym = np.meshgrid(xx,yy);
zz = 50.0 + 10.0*np.random.random((np.size(yy),np.size(xx)));
# -----------------------------
# let me have some random landmask/seamask data:
smask = np.zeros(np.shape(zz));smask[0:10,0:10]=1.0;smask[60:90,60:90]=1.0;
# -----------------------------
# let us set 0.0 to NaNs in seamask:
smask[smask==0]=np.nan;
smask=np.ma.array(smask,mask=np.isnan(smask))
# -----------------------------
# let us make a plot:
fig = plt.figure();ax=fig.add_subplot(111);
ax.pcolormesh(xx,yy,zz);
ax.pcolormesh(xx,yy,smask,vmin=0.0,vmax=8.0,cmap='Greys');
plt.show()
# ------------------------------------------------------------

Related

Scatterplot Matrices in Matplotlib: "singular matrix" Error

I have the following .csv data:
Simulation Run,[urea] (μM),[NO3-] (μM),[NH4+] (μM),[NO2-] (μM),[O2] (μM),[HCO3-] (μM),[OH-] (μM),[H+] (μM),[H2O] (μM)
/Run_01,1124.3139186264032,49.79709670397852,128.31458304321205,0.0,4.0,140000.0,0.1,0.1,55000000.0
/Run_02,1.0017668367460492e-159,2426.7395169966485,3.1544859186304598e-09,1.975005700484566e-10,4.0,140000.0,0.1,0.1,55000000.0
/Run_03,9.905001536507822e-160,2426.739516996945,2.861369463189477e-09,1.7910618538551373e-10,4.0,140000.0,0.1,0.1,55000000.0
/Run_04,1123.3362048916795,49.7956932352008,130.27141398143655,0.0,4.0,140000.0,0.1,0.1,55000000.0
/Run_05,1101.9594005273052,49.792379912298884,173.02833603309404,0.0,4.0,140000.0,0.1,0.1,55000000.0
I would like to plot it in a series of scatterplot matrices to look at the relationships between the different variables. Much like how it is done here. NOTE: In the linked example the person is asking how to accomplish this in altair. I want to do this in Matplotlib.
Using the above code as reference, here is the code I'm working with:
import pandas as pd
from pandas.plotting import scatter_matrix
import matplotlib.pyplot as plt
from matplotlib.backends.backend_pdf import PdfPages
from math import ceil
def graph_data(f: str):
"""
Represents the data
as a series of scatter-plot matrices.
"""
df = pd.read_csv(f)
NROWS = ceil((len(df.columns) - 1) / 3)
# Although the number of variables could vary,
# I would like no more than 3 charts per row.
NCOLS = 3
fname = f[:-4] + '.pdf'
with PdfPages(fname) as pdf:
scatter_matrix(df, alpha=0.2, figsize=(NROWS, NCOLS), diagonal='kde')
pdf.savefig(bbox_inches='tight')
plt.close()
When I try to run this, here is the error I get:
[LOTS OF TRACEBACK]...numpy.linalg.LinAlgError: singular matrix
Is this happening because the number of variables isn't a perfect square number (thereby not yielding a square matrix)? Is there a way to avoid this?
EDIT:
I forgot to specify my import statements so I have those in now.

Python : How to place a shapefile on top of raster file in one plot, and then save the plot in a Jpeg file format

I am posting this question after three days searching the net but no success. Hope can get the answer here. Please do NOT delete the post as I did not find an answer for it here also. Thanks.
I have 2 files:
A raster image file (i.e., Air temperature 2020-01-01.tif)
World countries boundary shapefile ((i.e., World_Countries_base_map.shp)
Goal: I want to plot the shapefile on top of raster file, and then save the plot in a Jpeg file format to get something like this eventually:
I am quite new in Python, and used Spyder to prepare this simple code to do so:
# Import needed packages
import os
import rasterio
import matplotlib.pyplot as plt
import geopandas as gpd
import earthpy as et
from matplotlib import pyplot
## list all raster images in tiff format in the folder:
list_files = [f for f in
os.listdir('C:/Users/Desktop/Question/Raster_Air_temp')
if '.tif' in f]
print(list_files[1]) # checking the 1st file in the list
## reading the first tiff file:
raster_image = rasterio.open(list_files[1])
## plot it
draft_output = pyplot.imshow(raster_image.read(1), cmap='jet')
## importing world shapefile
World_map = gpd.read_file('C:/Users/Desktop/Question/World_shapefile/World_Countries_base_map.shp')
# plot World shapefile
fig, ax = plt.subplots(figsize = (30,30)) # image size and quality can be controled by figsize
ax.set_title('The Glob Map', fontsize=50);
World_map.plot(ax=ax, color='white', edgecolor='black') # colors note at https://matplotlib.org/tutorials/colors/colormaps.html
plt.show()
## Plot both World shapefile and raster image in one graph:
????
However, this code just produces 2 separated plots in the console for me as can be seen above.
Question: How can I type a proper code in ???? section of the code to get to my Goal (mentioned above)?
Thanks to all comments and helps.
Here, I share the two files in order to make it easier for those who want help.
Download the files from my Dropbox
.
since i have no access to your data I am showing the principle with some sample data from geopandas and a random numpy ndarray as a tiff surrogate.
the key point is to show the tiff with rasterios rasterplot and don't forget to set the extent of your DEM!
import rasterio
import numpy as np
from rasterio import plot as rasterplot
import geopandas as gpd
from matplotlib import pyplot as plt
# this is how you'd open the raster dataset if you have one
#tiff = rasterio.open('example.tif')
#tiff_extent = [tiff.bounds[0], tiff.bounds[2], tiff.bounds[1], tiff.bounds[3]]
# i am making this array up
tiff_band_1 = np.random.randint(0, 10, size=(65, 64))
tiff_extent = [4159200.0, 4808100.0, 2828000.0, 3482600.0]
shapefile = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres'))
shapefile = shapefile.to_crs('epsg:3035')
shapefile = shapefile[shapefile.name == 'Germany']
f, ax = plt.subplots()
# plot DEM
rasterplot.show(
tiff_band_1, # use tiff.read(1) with your data
extent=tiff_extent,
ax=ax,
)
# plot shapefiles
shapefile.plot(ax=ax, facecolor='w', edgecolor='k')
plt.savefig('test.jpg')
plt.show()

3D graph in yt module

could you help me with this code, please? I am trying to integrate the force line in the given point. I don't know where is a mistake - there is no streamline in the plot.
Data - dipole magnetic field are here
I tried this example with the change of data and the change of number of streamlines.
import numpy as np
import matplotlib.pyplot as plt
from numpy import array
import matplotlib as mpl
from mpl_toolkits.mplot3d import Axes3D # 3d graph
from mpl_toolkits.mplot3d import proj3d # 3d graph
import math
from matplotlib import patches
import code
import yt
from yt import YTArray # arrays in yt module
from yt.visualization.api import Streamlines # force lines
import matplotlib.pylab as pl# Choose point in field
X_point = 0.007089085922957821
Y_point = 0.038439192046320805
Z_point = 0# Load data (dictionary)
try:
import cPickle as pickle
except ImportError: # python 3.x
import picklewith open('data.p', 'rb') as fp:
data = pickle.load(fp)Bx_d = data["Bx"]
By_d = data["By"]
Bz_d = data["Bz"]# 3d array of dipole magnetic field
print(type(data))
bbox = np.array([[-0.15, 0.15], [0, 0.2], [-0.1, 0.1]]) # box, border
ds = yt.load_uniform_grid(data, Bx_d.shape, length_unit="Mpc", bbox=bbox, nprocs=100) # data, dimensionc = YTArray([X_point, Y_point, Z_point], 'm') # Define c: the center of the box, chosen point
c1 = ds.domain_center
print('c1', c1)
print(type(c1))
print('center',c)
N = 1 # N: the number of streamlines
scale = ds.domain_width[0] # scale: the spatial scale of the streamlines relative to the boxsize,
pos = c# Create streamlines of the 3D vector velocity and integrate them through
# the box defined above
streamlines = Streamlines(ds, pos, 'Bx', 'By', 'Bz', length=None) # length of integration
streamlines.integrate_through_volume()# Create a 3D plot, trace the streamlines through the 3D volume of the plot
fig=pl.figure()
ax = Axes3D(fig)
ax.scatter(X_point, Y_point, Z_point, marker = 'o', s=40, c='green')
print('tisk', streamlines.streamlines)for stream in streamlines.streamlines:
stream = stream[np.all(stream != 0.0, axis=1)]
ax.plot3D(stream[:,0], stream[:,1], stream[:,2], alpha=0.1)# Save the plot to disk.
pl.savefig('streamlines.png')
plt.show()
Output:
Without knowing more about the data, as well as what the output of the print call is, it's not entirely clear what the error is. If the streamlines have meaningful values (i.e., the values of stream[:,0] etc are within the bounds of your Axes3D, it should produce results.
Options for debugging would start with examining the individual values, then proceeding to plotting them in 2D (using pairs of components of each stream -- (0,1), (1,2) and (0,2)), and then examining what happens if you allow Axes3D to autoscale the xyz axes. You may also experiment with the alpha value, to see if the lines are simply too light to see.
An example image that this produces would also help, so that it can be made clear a few things about the properties matplotlib assigns to the Axes3D object.

How to use numpy to build a 3D-model?

Original(2018.11.01)
I have 3 numpy:x、y、z,created by my laser scanner(40 degree / 1 step).
I want to used them to build a 3D model.
I think it must should be use matplotlib.tri
But I have no idea to decide triangulated data
Here is my data :https://www.dropbox.com/s/d9p62kv9jcq9bwh/xyz.zip?dl=0
And Original model:https://i.imgur.com/XSyONff.jpg
Code:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.tri as mtri
x_all=np.load("x.npy")
y_all=np.load("y.npy")
z_all=np.load("z.npy")
tri = #I have no idea...
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_trisurf(x_all,y_all,z_all,triangles=tri.triangles)
Thank so much.
Update(2018.11.02)
I try this way to decide triangulated data
Delaunay Triangulation of points from 2D surface in 3D with python?
code:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.tri as mtri
from stl import mesh
x_all=np.load("x.npy")
y_all=np.load("y.npy")
z_all=np.load("z.npy")
model=np.vstack((x_all,y_all,z_all))
model=np.transpose(model)
model -= model.mean(axis=0)
rad = np.linalg.norm(model, axis=1)
zen = np.arccos(model[:,-1] / rad)
azi = np.arctan2(model[:,1], model[:,0])
tris = mtri.Triangulation(zen, azi)
plt.show()
And my model looks like:
https://i.stack.imgur.com/KVPHP.png
https://i.stack.imgur.com/LLQsQ.png
https://i.stack.imgur.com/HdzFm.png
Even though it has better surface on it,but there is a big hole over my model.Any idea to fixs it?
Assuming you want to reduce the complexity, i.e find triangles in your files to reduce the complexity. You may look into fitting a convex hull to your points, see here fore more info
Based on the file you provided this produces a surf plot of the object.
from numpy import load, stack
from matplotlib.pyplot import subplots
from mpl_toolkits.mplot3d import Axes3D
from scipy import spatial
x = load("x.npy")
y = load("y.npy")
z = load("z.npy")
points = stack((x,y,z), axis = -1)
v = spatial.ConvexHull(points)
fig, ax = subplots(subplot_kw = dict(projection = '3d'))
ax.plot_trisurf(*v.points.T, triangles = v.simplices.T)
fig.show()

How to plot coordinates from 2 excel-columns with basemap (float-error)

I'm new to python and to this community. I have to plot a lot a lot of cities on a global map with Basemap in Python (Robinson projection). Coordinates are given in an excel-file with about 10 columns, in 2 columns (latitude and longitude).I managed to only select these 2 columns, but when I perform the projection, I get "TypeError: a float is required". This is my code:
from IPython import get_ipython
get_ipython().magic('reset -sf')
get_ipython().magic('matplotlib')
from mpl_toolkits.basemap import Basemap
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from pandas import Series, DataFrame
import xlrd
plt.close('all')
#%%
dirname=('C:\\Users\\Guido\\Documents\\Geologie\\Programmeren\\Scripts van mij\\Deftig\\')
filename='WUP2014-F12-Cities_Over_300K.xls'
xlsfile = pd.ExcelFile(dirname + filename)
dframe = xlsfile.parse("DATA")
urbpop = DataFrame(dframe)
lat = urbpop[['Unnamed: 6']]
lon = urbpop[['Unnamed: 7']]
m = Basemap(projection='robin',lon_0=0,resolution='c')
m.drawcoastlines()
m.fillcontinents(zorder = 0)
lons,lats = m(list(lon), list(lat))
m.scatter(lons, lats, color ='red')
The problem arises in the following line:
lons,lats = m(list(lon), list(lat))
This is a picture of the excel-file
Anybody an idea?
Try beating them into floats.
lons,lats = m([float(i) for i in lon], [float(i) for i in lat])
Disclaimer: I didn't try running this.

Categories