<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>http://gfi.wiki.uib.no/index.php?action=history&amp;feed=atom&amp;title=MaskCode</id>
	<title>MaskCode - Revision history</title>
	<link rel="self" type="application/atom+xml" href="http://gfi.wiki.uib.no/index.php?action=history&amp;feed=atom&amp;title=MaskCode"/>
	<link rel="alternate" type="text/html" href="http://gfi.wiki.uib.no/index.php?title=MaskCode&amp;action=history"/>
	<updated>2026-11-09T20:45:30Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.46.2</generator>
	<entry>
		<id>http://gfi.wiki.uib.no/index.php?title=MaskCode&amp;diff=1433&amp;oldid=prev</id>
		<title>Hso039: Created page with &quot;&lt;pre&gt; #!/usr/bin/env python3 # -*- coding: utf-8 -*- &quot;&quot;&quot; Created on Mon Jan 11 16:54:46 2021  @author: mika &quot;&quot;&quot; #mask creation: import numpy as np import shapely as shp #no ca...&quot;</title>
		<link rel="alternate" type="text/html" href="http://gfi.wiki.uib.no/index.php?title=MaskCode&amp;diff=1433&amp;oldid=prev"/>
		<updated>2021-01-15T08:40:35Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;&amp;lt;pre&amp;gt; #!/usr/bin/env python3 # -*- coding: utf-8 -*- &amp;quot;&amp;quot;&amp;quot; Created on Mon Jan 11 16:54:46 2021  @author: mika &amp;quot;&amp;quot;&amp;quot; #mask creation: import numpy as np import shapely as shp #no ca...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
Created on Mon Jan 11 16:54:46 2021&lt;br /&gt;
&lt;br /&gt;
@author: mika&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
#mask creation:&lt;br /&gt;
import numpy as np&lt;br /&gt;
import shapely as shp #no canonical shortname&lt;br /&gt;
import shapely.vectorized #vectorized version has to be loaded in separately&lt;br /&gt;
import pandas as pd #optional, only for loading in coordinates from csv&lt;br /&gt;
&lt;br /&gt;
#netcdf file creation:&lt;br /&gt;
import netCDF4 as nc4&lt;br /&gt;
&lt;br /&gt;
#plotting:&lt;br /&gt;
import matplotlib.pyplot as plt&lt;br /&gt;
import matplotlib.colors as mcolors&lt;br /&gt;
import cartopy.crs as ccrs&lt;br /&gt;
import cartopy.feature as cfeature&lt;br /&gt;
import matplotlib.patches as mpatches #for artificial legends&lt;br /&gt;
import matplotlib.lines as mlines #for artificial legends&lt;br /&gt;
&lt;br /&gt;
#unsure:&lt;br /&gt;
#from cartopy import config&lt;br /&gt;
#import copy #from python, but because of cmap copying&lt;br /&gt;
&lt;br /&gt;
#if warning due to cartopy and matplotlib versions clashing: &lt;br /&gt;
#whether you have this problem and need this will depend on your specific cartopy and matplotlib versions&lt;br /&gt;
from matplotlib.axes import Axes&lt;br /&gt;
from cartopy.mpl.geoaxes import GeoAxes&lt;br /&gt;
GeoAxes._pcolormesh_patched = Axes.pcolormesh&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# %% setup global grid and polygon&lt;br /&gt;
&lt;br /&gt;
#global grid, points to check for:&lt;br /&gt;
    &lt;br /&gt;
res=0.25 # resolution in degrees&lt;br /&gt;
global_lats=np.arange(-90,90+res,res)&lt;br /&gt;
global_lons=np.arange(-180,180+res,res)&lt;br /&gt;
x, y = np.meshgrid(global_lons,global_lats) #creates meshgrid of size lats*lons&lt;br /&gt;
&lt;br /&gt;
# the polygon, our mask:&lt;br /&gt;
#df=pd.read_csv(&amp;#039;coords_scandinavia.csv&amp;#039;)&lt;br /&gt;
#coordinates=list(zip(df.lon,df.lat))&lt;br /&gt;
&lt;br /&gt;
#if not loading in a csv-file. coordinates needs to be a python LIST of TUPLE pairs of (lon,lat) (x,y)&lt;br /&gt;
coordinates=\&lt;br /&gt;
[(31.25, 69.75), (23.75, 66.0), (20.0, 62.0), (20.0, 55.25), (15.0, 54.75),(13.0, 55.0),&lt;br /&gt;
 (12.0, 54.5), (10.75, 54.0), (8.75, 54.0), (8.5, 54.4), (4.0, 54.5), (4.0, 72.0), (31.0, 72.0)]&lt;br /&gt;
&lt;br /&gt;
nodes=coordinates.copy() #needs to be copy or otherwise appends updates with the appending below&lt;br /&gt;
nodes.append(coordinates[0]) #polygon needs to be closed, so first point is endpointt&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#create polygon:&lt;br /&gt;
geom=shp.geometry.Polygon(nodes)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# %% calcuate boolean mask:&lt;br /&gt;
mask_inner=shapely.vectorized.contains(geom, x, y) # - for interior points&lt;br /&gt;
mask_edge=shapely.vectorized.touches(geom, x, y) #- for edge points&lt;br /&gt;
mask_full=mask_inner|mask_edge # | is boolean OR bitwise (elementwise) operator. if either of the elements are true, result is true. if both are false, false.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# %% super quick plotting for checking&lt;br /&gt;
&lt;br /&gt;
#matplotlibs imshow is by far the quickest for such dense plotting (1M points if res=0.25&lt;br /&gt;
#quicklook plot, NOT in geographical projection&lt;br /&gt;
#imshow uses ij indexing, so we use the origin argument&lt;br /&gt;
    &lt;br /&gt;
fig, ax = plt.subplots(3, 1, figsize=(14,25))&lt;br /&gt;
cmap=&amp;#039;bwr&amp;#039;&lt;br /&gt;
ax[0].imshow(mask_inner,origin=&amp;#039;lower&amp;#039;,cmap=cmap)&lt;br /&gt;
ax[1].imshow(mask_edge,origin=&amp;#039;lower&amp;#039;,cmap=cmap)&lt;br /&gt;
ax[2].imshow(mask_full,origin=&amp;#039;lower&amp;#039;,cmap=cmap)&lt;br /&gt;
&lt;br /&gt;
ax[0].set_title(&amp;#039;inner mask&amp;#039;)&lt;br /&gt;
ax[1].set_title(&amp;#039;edge mask&amp;#039;)&lt;br /&gt;
ax[2].set_title(&amp;#039;combined mask&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
# for ax in axs.ravel():&lt;br /&gt;
#     ax.grid(b=True,which=&amp;#039;major&amp;#039;,axis=&amp;#039;x&amp;#039;,color=&amp;#039;k&amp;#039;,alpha=0.4,linestyle=&amp;#039;--&amp;#039;)&lt;br /&gt;
#     ax.set_xticks(months)&lt;br /&gt;
#     ax.set_xticklabels([x[0:3] for x in monthnames],rotation=90,ha=&amp;#039;center&amp;#039;)&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
# %% geographical global map:&lt;br /&gt;
 &lt;br /&gt;
dataproj=ccrs.PlateCarree()&lt;br /&gt;
mapproj=ccrs.PlateCarree() #regular, fine for global&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
fig, ax = plt.subplots(1, 1, subplot_kw=dict(projection=mapproj), figsize=(14,14))&lt;br /&gt;
ax.set_global()&lt;br /&gt;
#ax.set_extent((3,27,53,73),crs=dataproj) #fine for scandinavia&lt;br /&gt;
ax.coastlines(&amp;#039;10m&amp;#039;) #choices 110m, 50m and 10m. m does not mean meter, but 1:Xmillion.&lt;br /&gt;
ax.add_feature(cfeature.BORDERS, linestyle=&amp;#039;:&amp;#039;)&lt;br /&gt;
ax.gridlines(color=&amp;#039;k&amp;#039;,alpha=0.3,linestyle=&amp;#039;:&amp;#039;)&lt;br /&gt;
pixelplot=ax.pcolormesh(global_lons,global_lats,mask_full,transform=dataproj,cmap=&amp;#039;bwr&amp;#039;)&lt;br /&gt;
ax.set_title(&amp;#039;global map proj \n full mask&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# %% zoom-in geographical map standard projection&lt;br /&gt;
&lt;br /&gt;
#we find coordinates to zoom by based on polygon bounds:&lt;br /&gt;
minlon,maxlon,minlat,maxlat=geom.bounds&lt;br /&gt;
zoomin=geom.bounds&lt;br /&gt;
pad=2 #padding in degrees, adjust as needed&lt;br /&gt;
&lt;br /&gt;
dataproj=ccrs.PlateCarree()&lt;br /&gt;
mapproj=ccrs.PlateCarree() #regular, fine for global&lt;br /&gt;
&lt;br /&gt;
fig, ax = plt.subplots(1, 1, subplot_kw=dict(projection=mapproj), figsize=(14,14))&lt;br /&gt;
#ax.set_global()&lt;br /&gt;
ax.set_extent((minlon-pad, maxlon+pad, minlat-pad, maxlat+pad),crs=dataproj) &lt;br /&gt;
ax.coastlines(&amp;#039;10m&amp;#039;) #choices 110m, 50m and 10m. m does not mean meter, but 1:Xmillion.&lt;br /&gt;
ax.add_feature(cfeature.BORDERS, linestyle=&amp;#039;:&amp;#039;)&lt;br /&gt;
ax.gridlines(color=&amp;#039;k&amp;#039;,alpha=0.3,linestyle=&amp;#039;:&amp;#039;)&lt;br /&gt;
pixelplot=ax.pcolormesh(global_lons,global_lats,mask_full,transform=dataproj,cmap=&amp;#039;bwr&amp;#039;)&lt;br /&gt;
ax.set_title(&amp;#039;zoom-in standard map proj \n full mask&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
#as you will see, this is not very good unless global mask or close to equator&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
# %% closeup-geograpical, better projection choice&lt;br /&gt;
&lt;br /&gt;
#when switching to LambertConformal projection, or others, it can no longer handle a input data set that is global.&lt;br /&gt;
#it will simply plot nothing. Known bug/undesired behavoir in cartopy from cyclic points and transformations, or something like that&lt;br /&gt;
#we will therefore make a subset of the data based &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
minlon,maxlon,minlat,maxlat=geom.bounds&lt;br /&gt;
zoomin=geom.bounds&lt;br /&gt;
pad=5 #padding in degrees&lt;br /&gt;
&lt;br /&gt;
#xs and ys to subset data with&lt;br /&gt;
xss1=np.where(global_lons==(minlon-pad))[0][0]&lt;br /&gt;
xss2=np.where(global_lons==(maxlon+pad))[0][0]&lt;br /&gt;
yss1=np.where(global_lats==(minlat-pad))[0][0]&lt;br /&gt;
yss2=np.where(global_lats==(maxlat+pad))[0][0]&lt;br /&gt;
mask_inner_subset=mask_inner[yss1:yss2+1,xss1:xss2+1]&lt;br /&gt;
mask_edge_subset=mask_edge[yss1:yss2+1,xss1:xss2+1]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
dataproj=ccrs.PlateCarree()&lt;br /&gt;
#mapproj=ccrs.PlateCarree()&lt;br /&gt;
#this specific mapproj and settings are nice for Scandinavia, specifically.&lt;br /&gt;
#test different projections/settings to fit your mask&lt;br /&gt;
&lt;br /&gt;
mapproj=ccrs.LambertConformal(central_longitude=8, central_latitude=60, &lt;br /&gt;
    false_easting=0.0, false_northing=0.0, secant_latitudes=None,&lt;br /&gt;
    standard_parallels=None, globe=None, cutoff=-30)&lt;br /&gt;
&lt;br /&gt;
fig, ax = plt.subplots(1, 1, subplot_kw=dict(projection=mapproj), figsize=(14,14))&lt;br /&gt;
#ax1.set_global()&lt;br /&gt;
ax.set_extent((3,27,53,73),crs=dataproj) #fine for scandinavia&lt;br /&gt;
ax.coastlines(&amp;#039;10m&amp;#039;) #choices 110m, 50m and 10m. m does not mean meter, but 1:Xmillion.&lt;br /&gt;
ax.add_feature(cfeature.BORDERS, linestyle=&amp;#039;:&amp;#039;)&lt;br /&gt;
ax.gridlines(color=&amp;#039;k&amp;#039;,alpha=0.3,linestyle=&amp;#039;:&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#matplotlib.colors.to_rgba(c, alpha=None)&lt;br /&gt;
&lt;br /&gt;
alpha=0.3&lt;br /&gt;
edgeplot=ax.pcolormesh(global_lons[xss1:xss2+1],global_lats[yss1:yss2+1],mask_inner_subset,&lt;br /&gt;
                          transform=dataproj,cmap=&amp;#039;Reds&amp;#039;,shading=&amp;#039;auto&amp;#039;,edgecolor=&amp;#039;lightgrey&amp;#039;,alpha=alpha,label=&amp;#039;_inner&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
innerplot=ax.pcolormesh(global_lons[xss1:xss2+1],global_lats[yss1:yss2+1],mask_edge_subset,&lt;br /&gt;
                          transform=dataproj,cmap=&amp;#039;Blues&amp;#039;,shading=&amp;#039;auto&amp;#039;,edgecolor=&amp;#039;lightgrey&amp;#039;,alpha=alpha,label=&amp;#039;_edge&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
xs=[x[0] for x in coordinates]&lt;br /&gt;
ys=[y[1] for y in coordinates]&lt;br /&gt;
nodesplot=ax.scatter(xs,ys,s=50,c=&amp;#039;yellow&amp;#039;,transform=dataproj,marker=&amp;#039;o&amp;#039;,label=&amp;#039;_nodes&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
pathplot=ax.add_geometries([geom],dataproj,facecolor=&amp;#039;none&amp;#039;, edgecolor=&amp;#039;green&amp;#039;,label=&amp;#039;_path&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
ax.set_title(&amp;#039;better projection zoom in \n inner, edge, nodes and path&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# #make artifical legend elements:&lt;br /&gt;
# note: the hidden _labels in the plots are because else it makes plotting really, really show as it checks for a label first&lt;br /&gt;
&lt;br /&gt;
red_patch = mpatches.Patch(color=mcolors.to_rgba(&amp;#039;red&amp;#039;,alpha=alpha), label=&amp;#039;inner points&amp;#039;)&lt;br /&gt;
blue_patch = mpatches.Patch(color=mcolors.to_rgba(&amp;#039;blue&amp;#039;,alpha=alpha), label=&amp;#039;edge points&amp;#039;)&lt;br /&gt;
yellow_dots = mlines.Line2D([],[],color=&amp;#039;yellow&amp;#039;,marker=&amp;#039;o&amp;#039;,linestyle=None, label=&amp;#039;nodes&amp;#039;)&lt;br /&gt;
black_line = mlines.Line2D([],[],color=&amp;#039;green&amp;#039;,marker=None,linestyle=&amp;#039;-&amp;#039;, label=&amp;#039;path&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
ax.legend(handles=[red_patch,blue_patch,yellow_dots,black_line],loc=&amp;#039;upper right&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# %% make netcdf file&lt;br /&gt;
&lt;br /&gt;
#outcommented now. only comment in when making.&lt;br /&gt;
#remember you cannot change in an already created netcdf file, so make sure you create a new one first&lt;br /&gt;
&lt;br /&gt;
# homemade_mask=nc4.Dataset(&amp;#039;homemade_mask.nc&amp;#039;,&amp;#039;w&amp;#039;,format=&amp;#039;NETCDF4&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
# lon = homemade_mask.createDimension(&amp;quot;lon&amp;quot;, global_lons.size)&lt;br /&gt;
# lon = homemade_mask.createVariable(&amp;quot;lon&amp;quot;, &amp;quot;f8&amp;quot;,(&amp;quot;lon&amp;quot;), zlib=True)&lt;br /&gt;
# lon[:]=global_lons #put data in&lt;br /&gt;
&lt;br /&gt;
# lon.units=&amp;quot;degrees_east&amp;quot;&lt;br /&gt;
# lon.standard_name=&amp;quot;longitude&amp;quot;&lt;br /&gt;
# lon.long_name=&amp;quot;longitude&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# lat = homemade_mask.createDimension(&amp;quot;lat&amp;quot;, global_lats.size)&lt;br /&gt;
# lat = homemade_mask.createVariable(&amp;quot;lat&amp;quot;, &amp;quot;f8&amp;quot;,(&amp;quot;lat&amp;quot;), zlib=True)&lt;br /&gt;
# lat[:]=global_lats #put data in&lt;br /&gt;
&lt;br /&gt;
# lat.units=&amp;quot;degrees_north&amp;quot;&lt;br /&gt;
# lat.standard_name=&amp;quot;laitude&amp;quot;&lt;br /&gt;
# lat.long_name=&amp;quot;laitude&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# time = homemade_mask.createDimension(&amp;quot;time&amp;quot;,None)&lt;br /&gt;
# time = homemade_mask.createVariable(&amp;quot;time&amp;quot;, &amp;quot;f8&amp;quot;, (&amp;quot;time&amp;quot;), zlib=True)&lt;br /&gt;
&lt;br /&gt;
# tunits=&amp;#039;days since 0001-01-01&amp;#039;&lt;br /&gt;
# calendar=&amp;#039;standard&amp;#039;&lt;br /&gt;
# time.units=tunits&lt;br /&gt;
# time.calendar=calendar&lt;br /&gt;
# time.standard_name=&amp;quot;time&amp;quot;&lt;br /&gt;
# time[:]=0 #it needs atleast one time to work with watersip&lt;br /&gt;
&lt;br /&gt;
# mask = homemade_mask.createVariable(&amp;quot;mask&amp;quot;, &amp;quot;f8&amp;quot;, (&amp;quot;time&amp;quot;,&amp;quot;lat&amp;quot;,&amp;quot;lon&amp;quot;), zlib=True)&lt;br /&gt;
# mask[0,:,:]=mask_full #put the mask data in&lt;br /&gt;
# mask.units=&amp;quot;mm/day&amp;quot;&lt;br /&gt;
# mask.xmin=-180&lt;br /&gt;
# mask.xmax=180&lt;br /&gt;
# mask.xstag=180&lt;br /&gt;
# mask.ymin=-90&lt;br /&gt;
# mask.ymax=90&lt;br /&gt;
# mask.ystag=90&lt;br /&gt;
&lt;br /&gt;
# # time = mob_flux.createDimension(&amp;quot;time&amp;quot;,None)&lt;br /&gt;
&lt;br /&gt;
# # times = mob_flux.createVariable(&amp;quot;time&amp;quot;,&amp;quot;f8&amp;quot;,(&amp;quot;time&amp;quot;),zlib=True)&lt;br /&gt;
&lt;br /&gt;
# # times.units = tunits&lt;br /&gt;
# # times.calendar = calendar&lt;br /&gt;
# # dates=fluxdata_5s.index.to_pydatetime()&lt;br /&gt;
# # times[:] = nc4.date2num(dates, units=tunits, calendar=calendar)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# homemade_mask.close() #remember to close the file&lt;br /&gt;
&lt;br /&gt;
# %% OUTSIDE PYTHON&lt;br /&gt;
&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
in a terminal, navigate to where you newly created mask file is&lt;br /&gt;
then use&lt;br /&gt;
&amp;quot;cdo -f nc2 copy mask-from-python.nc mask-to-watersip.nc&lt;br /&gt;
&amp;quot;&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hso039</name></author>
	</entry>
</feed>