How to zoom Orthographic projection with geoviews? - matplotlib

I know with matplotlib i can zoom on a orthographic projection with something like that :
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, projection=ccrs.Orthographic(-40, 20)
ax.set_extent([-110, 30, -20, 65])
How can i do this with hvplot / Geoviews / Holoviews ? All exemples i have found don't zoom on this specific projection,
actual example :
import xarray as xr
import hvplot.pandas
import holoviews as hv
import geoviews.feature as gf
import cartopy.crs as ccrs
proj = ccrs.Orthographic(-40, 20)
lon_range = (-110, 30)
lat_range = (-20, 65)
ds = xr.open_mfdataset(liste_files, engine="netcdf4")
pd_times = ds.to_dataframe() # <-- i cannot plot points with xarray directly, don't know why
points = pd_times.hvplot.points(x="longitude", y="latitude", c="sat1", projection=proj)
points = hv.Overlay(aff)
layout = (gf.ocean
* points
* gf.land.options(scale="50m")
* gf.coastline.options(scale="50m")
* gf.rivers
* gf.lakes
).opts(
width=500,
projection=proj
)
Thanks

Founded : you need to add xlim and/or ylim in the argument of hvplot.
points = pd_times.hvplot.points(x="longitude", y="latitude", c="sat1", projection=proj, xlim=lon_range, ylim=lat_range)

Related

Flight Path by shapely LineString is not correct

I want to connect airplanes in origin (lat_1 lon_1) to dest(lat_2 lon_2). I use these data.
callsign
latitude_1
longitude_1
latitude_2
longitude_2
0
HBAL102
-4.82114
-76.3194
-4.5249
-79.0103
1
AUA1028
-33.9635
151.181
48.1174
16.55
2
ABW120
41.9659
-87.8832
55.9835
37.4958
3
CSN461
33.9363
-118.414
50.0357
8.5723
4
ETH3730
25.3864
55.4221
50.6342
5.43903
But unfortunately, I would get an incorrect result when creating LineString with shapely. I used everything like rotate and affine but it didn't correct.
Code:
cols = pd.read_csv("/content/dirct_lines.csv",sep=";")
line = cols[["callsign","latitude_1","longitude_1","latitude_2","longitude_2"]].dropna()
line['geometry'] = line.apply(lambda x: [(x['latitude_1'],
x['longitude_1']),
(x['latitude_2'],
x['longitude_2'])], axis = 1)
geoline = gpd.GeoDataFrame(line,geometry="geometry",
crs="EPSG:4326")
import matplotlib.pyplot as plt
world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres'))
ax = world.plot(figsize=(14,9),
color='white', edgecolor='black')
geoline.plot(figsize=(14,9),ax=ax,facecolor = 'lightgrey', linewidth = 1.75,
edgecolor = 'red',
alpha = 2)
plt.show()
Shapely Output:
something that was interesting for me was that when I use Matplotlib to create lines everything is correct.
Code:
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(12, 8))
ax = fig.add_subplot(projection=ccrs.PlateCarree())
ax.stock_img()
org_lon, org_lat = cols["longitude_1"], cols["latitude_1"]
dst_lon, dst_lat = cols["longitude_2"], cols["latitude_2"]
plt.plot([org_lon, dst_lon], [org_lat, dst_lat],
color='black', linewidth=0.5, marker='_',
transform=ccrs.PlateCarree()
)
plt.savefig(f"fight_path.png",dpi=60,facecolor = None, bbox_inches = 'tight', pad_inches = None)
plt.show()
Matplotlib Output:
What is the problem?
why isn't correct by shapely?
it's just the way you are creating the geometry. Below works correctly.
import io
import geopandas as gpd
import pandas as pd
import shapely.geometry
df = pd.read_csv(
io.StringIO(
"""callsign,latitude_1,longitude_1,latitude_2,longitude_2
HBAL102,-4.82114,-76.3194,-4.5249,-79.0103
AUA1028,-33.9635,151.181,48.1174,16.55
ABW120,41.9659,-87.8832,55.9835,37.4958
CSN461,33.9363,-118.414,50.0357,8.5723
ETH3730,25.3864,55.4221,50.6342,5.43903
"""
)
)
geoline = gpd.GeoDataFrame(
geometry=[
shapely.geometry.LineString(points)
for points in zip(
gpd.points_from_xy(df["longitude_1"], df["latitude_1"]),
gpd.points_from_xy(df["longitude_2"], df["latitude_2"]),
)
],
data=df,
)
import matplotlib.pyplot as plt
world = gpd.read_file(gpd.datasets.get_path("naturalearth_lowres"))
ax = world.plot(figsize=(14, 9), color="white", edgecolor="black")
geoline.plot(
figsize=(14, 9),
ax=ax,
facecolor="lightgrey",
linewidth=1.75,
edgecolor="red",
)
plt.show()

Show exponentiated values along opposite side of log color scale

With a horizontal log-scaled color bar and logged labels along the bottom, is it possible to show the exponentiated (original) values along the top?
So in this example, there should be ticks and labels along the top of the color bar going from mat.min() = 0.058 to mat.max() = 13.396
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
mat = np.exp(np.random.randn(20, 20))
plt.matshow(mat)
norm = mpl.colors.Normalize(1, np.log(mat.max()))
plt.colorbar(plt.cm.ScalarMappable(norm=norm), orientation="horizontal")
plt.savefig("rand_mat.png", dpi=200)
Here is the best answer for your response. I've customized it based on that. Does this result match the intent of your question? The color bar and the size of the figure are not the same, so I adjusted them.
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(20210404)
mat = np.exp(np.random.randn(20, 20))
norm = mpl.colors.Normalize(1, np.log(mat.max()))
fig, (ax, cax) = plt.subplots(nrows=2, gridspec_kw=dict(height_ratios=[15,1],hspace=0.5))
im = ax.matshow(mat)
cbar = plt.colorbar(plt.cm.ScalarMappable(norm=norm), orientation="horizontal", cax=cax)
cax2 = cax.twiny()
cbar.ax.xaxis.set_label_position("bottom")
iticks = np.arange(mat.min(), mat.max(), 2)
cax2.set_xticks(iticks)
ax_pos = ax.get_position()
cax_pos = cbar.ax.get_position()
new_size = [ax_pos.x0, cax_pos.y0, ax_pos.x1 - ax_pos.x0, cax_pos.y1 - cax_pos.y0]
cbar.ax.set_position(new_size)
plt.show()
At the risk of committing a faux pas, I'll answer my own question with the solution that best suits my needs:
cb.ax.secondary_xaxis("top", functions=(np.exp, np.log))
which gives
Full Code
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
mat = np.exp(np.random.randn(20, 20))
plt.matshow(mat)
norm = mpl.colors.Normalize(np.log(mat.min()), np.log(mat.max()))
cb = plt.colorbar(plt.cm.ScalarMappable(norm=norm), orientation="horizontal")
cb_ax_top = cb.ax.secondary_xaxis("top", functions=(np.exp, np.log))
cb_ax_top.set_xticks([0.1, 0.5, 1, 4, 10, 20])

Matplotlib-Basemap: how to hide the text out of axes?

I want to hide the text outside of the axes, and show only what is inside. I have tried to do it with zorder, but just the text in the axes are gone instead!
import pandas as pd
import numpy as np
import numpy.ma as ma
import matplotlib.pyplot as plt
from matplotlib import cm as CM
from mpl_toolkits.basemap import Basemap
from matplotlib.patches import Polygon
names=['stat','latd', 'longd', 'AQI', 'Grade', 'PM25', 'PM10', 'CO', 'NO2', 'O3', 'O3_8h', 'SO2']
cities=pd.read_table('2013061713.000',sep='\s+',names=names,skiprows=[0],na_values=[9999])
namesa=['LOC1','LOC2','LOC3','LOC4','LOC5','LOC6','LOC7','LOC8']
LOC=pd.read_table('loc/location_use13-06-17.txt',sep='\s+',names=namesa,na_values=[9999])
# Extract the data we're interested in
lat = cities['latd'].values
lon = cities['longd'].values
pm25 = cities['PM25'].values
aqi = cities['AQI'].values
pm25_max=np.nanmax(pm25)
pm25_min=np.nanmin(pm25)
latmax=LOC.iloc[:,:4].max().max()
latmin=LOC.iloc[:,:4].min().min()
lonmax=LOC.iloc[:,4:8].max().max()
lonmin=LOC.iloc[:,4:8].min().min()
llcrnrlon=lonmin-0.5
llcrnrlat=latmin-0.5
urcrnrlon=lonmax+0.5
urcrnrlat=latmax+0.5
fig = plt.figure(figsize=(8, 8))
m = Basemap(llcrnrlon=llcrnrlon,llcrnrlat=llcrnrlat,urcrnrlon=urcrnrlon,urcrnrlat=urcrnrlat, epsg=4269)
m.shadedrelief()
m.drawparallels(np.arange(20.,40,2.5),linewidth=1, dashes=[4, 2], labels=[1,0,0,0], color= 'gray',zorder=0, fontsize=10)
m.drawmeridians(np.arange(100.,125.,2.),linewidth=1, dashes=[4, 2], labels=[0,0,0,1], color= 'gray',zorder=0, fontsize=10)
y_offset = 0.05
rotation = 30
x, y = m(lon, lat)
for i,j,k,a in zip(x[::2],y[::2],pm25[::2],aqi[::2]):
m.scatter(i, j,c=k, s=a, cmap=CM.get_cmap('tab20b',20), alpha=0.5)
plt.text(i, j+y_offset, k,rotation=rotation,fontsize=6,color='w')
for i,j,k,a in zip(x[1::2],y[1::2],pm25[1::2],aqi[1::2]):
m.scatter(i, j,c=k, s=a, cmap=CM.get_cmap('tab20b',20), alpha=0.5)
plt.text(i, j-y_offset, k,rotation=rotation,fontsize=6,color='b')
plt.savefig('PM25_showtext130617.png',dpi=600)
plt.show()
Here is the image with all the text, the text ouside the axes should be hidden:
And this is my current output, when I use the zorder, which is the opposite of what I try to achieve:
plt.text(i, j+y_offset, k,rotation=rotation,fontsize=6,color='w',zorder=-1000)

Map offsite with matplotlib(using geopandas and cartopy)

I have created a map like this:
The problem with it is that on the right side of the map is always a little bit offsite. I have set the bounds to:
ax.set_xlim(-215800,
1000000)
ax.set_ylim(3402659,
4879248)
No matter how I increase the xlim, or set margin the right side is still outside the bounds of the canvas. Can somebody help?
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
from osgeo import ogr
import matplotlib.pyplot as plt
import matplotlib as mpl
import rasterio
import cartopy.crs as ccrs
import geopandas
from geopandas import *
from matplotlib import colors
MediumApple='#55FF00'
Cantaloupe='#FFA77F'
Marsred='#FF0000'
crs = ccrs.UTM(zone=10)
ax = plt.axes(projection=crs)
import matplotlib.patches as mpatches
for county in CAcountylist:
with rasterio.drivers():
with rasterio.open(r"CA\%s \%s.tif"%(county,county),"r") as src:
meta = src.meta
im=src.read().astype('f')
im=np.transpose(im,[1,2,0])
print im.shape
print im.min(),im.max()
im[im==0]=np.nan
im=im.squeeze()
xmin = src.transform[0]
xmax = src.transform[0] + src.transform[1]*src.width
print src.width,src.height
ymin = src.transform[3] + src.transform[5]*src.height
ymax = src.transform[3]
colors=[MediumApple,Cantaloupe,Marsred]
cmap=mpl.colors.ListedColormap([MediumApple,Cantaloupe,Marsred])
bounds_color=[1,1,2,2,3,3]
norm=mpl.colors.BoundaryNorm(bounds_color,cmap.N)
print xmin,xmax,ymin,ymax
ax.imshow(im, origin='upper', extent=[xmin,xmax,ymin,ymax], transform=crs, interpolation='nearest',cmap=cmap,norm=norm)
df=GeoDataFrame.from_file(r"\CACounty.shp")
df=df.to_crs(epsg=26910)
df.plot(axes=ax,alpha=0)
bounds = df.geometry.bounds
ax.set_xlim(-215800,
1000000)
ax.set_ylim(3402659,
4879248)
low_patch = mpatches.Patch(color='#55FF00', label='Low')
Moderate_patch = mpatches.Patch(color='#FFA77F', label='Moderate')
High_patch = mpatches.Patch(color='#FF0000', label='High')
plt.legend(handles=[low_patch,Moderate_patch,High_patch],loc=3)
plt.show()

Limit extent of orthograpic projection (zooming)

I would like to produce orthographic (polar) plots of Antarctica that are 'zoomed' with respect to the default settings. By default I get this:
Antarctica polar
The following script produced this.
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
ax = plt.axes(projection=ccrs.Orthographic(central_longitude=0.0, central_latitude=-90.))
ax.stock_img()
plt.show()
My best attempt to tell Cartopy 'limit the latitude to 60S to 90S' was:
ax.set_extent([-180,180,-60,-90], ccrs.PlateCarree())
unfortunately it does not give the desired result. Any ideas? Thanks in advance.
I'm not sure I fully understand what you're trying to do. Your example looks like a bounding box that was defined, but you'd like it rounded like your first example?
cartopy documentation has an example of this http://scitools.org.uk/cartopy/docs/latest/examples/always_circular_stereo.html:
import matplotlib.path as mpath
import matplotlib.pyplot as plt
import numpy as np
import cartopy.crs as ccrs
import cartopy.feature
def main():
fig = plt.figure(figsize=[10, 5])
ax1 = plt.subplot(1, 2, 1, projection=ccrs.SouthPolarStereo())
ax2 = plt.subplot(1, 2, 2, projection=ccrs.SouthPolarStereo(),
sharex=ax1, sharey=ax1)
fig.subplots_adjust(bottom=0.05, top=0.95,
left=0.04, right=0.95, wspace=0.02)
# Limit the map to -60 degrees latitude and below.
ax1.set_extent([-180, 180, -90, -60], ccrs.PlateCarree())
ax1.add_feature(cartopy.feature.LAND)
ax1.add_feature(cartopy.feature.OCEAN)
ax1.gridlines()
ax2.gridlines()
ax2.add_feature(cartopy.feature.LAND)
ax2.add_feature(cartopy.feature.OCEAN)
# Compute a circle in axes coordinates, which we can use as a boundary
# for the map. We can pan/zoom as much as we like - the boundary will be
# permanently circular.
theta = np.linspace(0, 2*np.pi, 100)
center, radius = [0.5, 0.5], 0.5
verts = np.vstack([np.sin(theta), np.cos(theta)]).T
circle = mpath.Path(verts * radius + center)
ax2.set_boundary(circle, transform=ax2.transAxes)
plt.show()
if __name__ == '__main__':
main()