Annotating the intersecting point coordinates in the graph (python) - python

In the code, I have figured out the intersection point of two lines (22,50) and I want to show this in the graph (have an arrow pointing at the intersection point with (22,50)) and wondering if the community can help me with this.
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from shapely.geometry import LineString
df = pd.read_csv("C:/Users/rajaa/Desktop/tril.csv")
t = df['time']
mu = df['material uts']
ps = df['pipe stress']
plt.figure(figsize = (8,5), dpi = 100)
fig, ax = plt.subplots()
plt.plot(t,mu,'r', label='Material UTS')
plt.plot(t,ps, 'b--',label=[enter image description here][1]'Pipe Stress as the pipe is depressurized')
plt.title('Graph 1', fontdict={'fontname': 'Arial', 'fontsize': 20})
plt.xticks(np.arange(0,32,2))
plt.yticks(np.arange(0,120,10))
plt.xlabel('Time (minutes)')
plt.ylabel('Pipe stress and UTS (MPa)')
plt.legend()
first_line = LineString(np.column_stack((t, mu)))
second_line = LineString(np.column_stack((t,ps)))
intersection = first_line.intersection(second_line)
plt.plot(*intersection.xy,'ro')
x,y = intersection.xy
plt.show()

ax.arrow(0, 0, 22, 50, head_width=0.05, head_length=0.1, fc='k', ec='k')

Related

How to plot a vertical thermal plot?

How to plot this kind of thermal plot in Python? I tried to search for any sample plot like this but didn't find one.
This image I got from the internet. I want to plot something same like this:
FROM
TO
To represent this type of data the canonical solution is, of course, a heat map. Here it is the code to produce both the figures at the top of this post.
import numpy as np
import matplotlib.pyplot as plt
t = np.linspace(0, 5, 501)
x = np.linspace(0, 1, 201)[:, None]
T = 50 + (30-6*t)*(4*x*(1-x)) + 4*t
fig, ax = plt.subplots(layout='constrained')
hm = ax.imshow(T, cmap='plasma',
aspect='auto', origin='lower', extent=(0, 5, 0, 1))
fig.colorbar(hm)
def heat_lines(x, t, T, n):
from matplotlib.cm import ScalarMappable
from matplotlib.collections import LineCollection
lx, lt = T.shape
ones = np.ones(lx)
norm = plt.Normalize(np.min(T), np.max(T))
plasma = plt.cm.plasma
fig, ax = plt.subplots(figsize=(1+1.2*n, 9), layout='constrained')
ax.set_xlim((-0.6, n-0.4))
ax.set_ylim((x[0], x[-1]))
ax.set_xticks(range(n))
ax.tick_params(right=False,top=False, bottom=False)
ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)
ax.spines["bottom"].set_visible(False)
ax.grid(axis='y')
fig.colorbar(ScalarMappable(cmap=plasma, norm=norm))
dt = round(lt/(n-1))
for pos, ix in enumerate(range(0, len(t)+dt//2, dt)):
points = np.array([ones*pos, x[:,0]]).T.reshape(-1,1,2)
segments = np.concatenate([points[:-1], points[1:]], axis=1)
lc = LineCollection(segments, linewidth=72, ec=None,
color=plasma(norm(T[:,ix])))
lc.set_array(T[:,ix])
ax.add_collection(lc)
heat_lines(x, t, T, 6)

Mask area outside of a shape file with Cartopy and Geopandas

I have a set of data with (lon, lat, temperature) that I have plotted with Cartopy. The minimum example that I can give is the code below (with only 30 data points)
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import matplotlib.pyplot as plt
import matplotlib.colors as clr
import pandas as pd
import numpy as np
from metpy.interpolate import interpolate_to_grid, remove_nan_observations
from cartopy.io.shapereader import Reader
from cartopy.feature import ShapelyFeature
canada_east = -95
canada_west = -101.8
canada_north = 52.8
canada_south = 48.85
central_lon = (canada_east + canada_west)/2
central_lat = (canada_north + canada_south)/2
crs = ccrs.LambertConformal(central_longitude = central_lon, central_latitude = central_lat)
lat = np.array([49.8134 50.904 50.698 49.095 49.436 49.9607 49.9601 49.356 50.116
49.402 52.3472 50.411 49.24 49.876 49.591 49.905 49.498 49.088
49.118 50.5947 49.3776 49.148 49.1631 51.358 49.826 50.4324 49.96
49.68 49.875 50.829 51.572])
lon = np.array([-100.3721 -97.273 -99.068 -97.528 -100.308 -98.9054 -98.6367
-99.248 -96.434 -100.93 -101.1099 -100.893 -100.055 -99.909
-97.518 -99.354 -98.03 -99.325 -99.054 -98.0035 -100.5387
-100.491 -97.1454 -100.361 -96.776 -99.4392 -97.7463 -97.984
-95.92 -98.111 -100.488])
tem = np.array([-8.45 -4.026 -5.993 -3.68 -7.35 -7.421 -6.477 -8.03 -3.834
-13.04 -4.057 -8.79 -6.619 -10.89 -4.465 -8.41 -4.861 -9.93
-7.125 -4.424 -11.95 -9.56 -3.86 -7.17 -4.193 -7.653 -4.883
-5.631 -3.004 -4.738 -8.81])
xp, yp, _ = crs.transform_points(ccrs.PlateCarree(), lon, lat ).T
xp, yp, tem = remove_nan_observations(xp, yp, tem)
alt_x, alt_y, data = interpolate_to_grid( xp, yp, tem, minimum_neighbors=2, search_radius=240000, interp_type = 'barnes', hres = 1000)
# Create the figure and grid for subplots
fig = plt.figure(figsize=(17, 12))
# Main ax
ax = plt.subplot(111, projection=crs)
ax.set_extent([canada_west, canada_east, canada_south, canada_north], ccrs.PlateCarree())
# Ading province borders and country borders
provinces_bdr = cfeature.NaturalEarthFeature(category = 'cultural',
name = 'admin_1_states_provinces_lines',
scale = '50m',
linewidth = 0.6,
facecolor='none',
) # variable to add provinces border
country_bdr = cfeature.NaturalEarthFeature(category= 'cultural',
name = 'admin_0_boundary_lines_land',
scale = '50m',
linewidth = 1.5,
facecolor = 'none',
edgecolor = 'k')
ax.add_feature(provinces_bdr, linestyle='--')
ax.add_feature(country_bdr, linestyle='--')
ax.add_feature(cfeature.LAND)
ax.add_feature(cfeature.OCEAN)
ax.add_feature(cfeature.BORDERS)
cf = ax.pcolormesh(alt_x, alt_y, data, cmap=plt.cm.rainbow)
# Read the shape file and add it
shape_feature = ShapelyFeature(Reader('MB_AGregion_Perim_South.shp').geometries(), ccrs.epsg(26914), linewidth = 1, facecolor = (1, 1, 1, 0), edgecolor = (0.5, 0.5, 0.5, 1))
ax.add_feature(shape_feature)
plt.show()
which gives this result:
where the gray line inside is produced by the shape file. Now I want to limit the coloring to be only inside the shape file (so area that's outside of the gray line should not be colored by pcolormesh) but I can not find a way that work. I have read this example and this example but I cannot understand both of them. Is there a simple way to do this using geopandas and/or cartopy alone?
Sorry I cannot upload the shape file here, this is the best minimal example I could have done. If there are any improvements I should have done please tell me. I'm new to stack overflow and I'm open to critiques.
Edit1:
To clarify, the shape file I want the color to be limited to is the 'MB_AGregion_Perim_South.shp' that I read with ShapelyFeature (the last 4 lines of my code), and it draw the grey line that bounds most part of my coloring.
Edit 2:
As #Michael Delgado suggested, I have added this lines of code:
cat_gdf = geopandas.read_file('MB_AGregion_Perim_South.shp')
cat_gdf = cat_gdf.to_crs(epsg = 4326)
mask = shapely.vectorized.contains(cat_gdf.dissolve().geometry.item(), alt_x, alt_y)
where alt_x and alt_y is the interpolated result (please look at my example above). The shape file has epsg = 26914 originally, so I transform it into 4326.
The problem is that the mask contains all false values (which means it mask everything). I doubted that it's because alt_x and alt_y are coordinates that has been transformed with crs.transform_points(ccrs.PlateCarree(), lon, lat ).T (as my code showed above). I have search around and try to get the shape file into different epsg values but it doesn't work. Also, cat_gdf.geometry is a multi polygons. Could it be the cause here?
For anyone who's struggling with this in the future, here is a detailed explanation of the solution
Quick MRE:
import numpy as np, pandas as pd, geopandas as gpd
import matplotlib.pyplot as plt
x = np.arange(-126, -105, 0.1)
y = np.arange(25, 46, 0.1)
xx, yy = np.meshgrid(x, y)
xnorm = (xx - xx.min()) / (xx.max() - xx.min())
ynorm = (yy - yy.min()) / (yy.max() - yy.min())
v = np.cos((xnorm * 2 - 1) * np.pi) + np.sin((ynorm * 2 - 1) * np.pi)
gdf = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres'))
fig, ax = plt.subplots()
ax.pcolormesh(xx, yy, v)
xlim, ylim = ax.get_xlim(), ax.get_ylim()
gdf.plot(ax=ax, color='none', edgecolor='k')
ax.set_xlim(*xlim)
ax.set_ylim(*ylim)
You can use shapely.vectorized to mask a set of x, y points using a shapely.geometry object:
import shapely.vectorized
mask = shapely.vectorized.contains(gdf.dissolve().geometry.item(), xx, yy)
fig, ax = plt.subplots()
ax.pcolormesh(xx, yy, np.where(mask, v, np.nan))
xlim, ylim = ax.get_xlim(), ax.get_ylim()
gdf.plot(ax=ax, color='none', edgecolor='k')
ax.set_xlim(*xlim)
ax.set_ylim(*ylim)

GOES-East Full Disk domain realtime imagery does not fit actual data

I'm trying to plot GOES-East full disk data using metpy, and Siphon to download the latest data from the THREDDS data server. However, after comparing my plots with the realtime imagery, ther seems to be a large difference.
Below is my code:
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import matplotlib.pyplot as plt
import metpy.calc as mpcalc
from metpy.plots.ctables import registry
from metpy.plots import add_timestamp
from metpy.units import units
from siphon.catalog import TDSCatalog
import xarray as xr
import numpy as np
from xarray.backends import NetCDF4DataStore
from datetime import datetime, timedelta
dt = datetime.utcnow().date()
data = TDSCatalog(f'http://thredds.ucar.edu/thredds/catalog/satellite/goes/east/products/'
f'CloudAndMoistureImagery/FullDisk/Channel09/{dt:%Y%m%d}/catalog.xml')
sat_dataset = data.datasets[0].remote_access(use_xarray = True)
cmi = sat_dataset.metpy.parse_cf('Sectorized_CMI')
x = cmi.coords['x'][:]
y = cmi.coords['y'][:]
timestamp = datetime.strptime(str(cmi.time.values.astype('datetime64[s]')), '%Y-%m-%dT%H:%M:%S')
print(timestamp)
vtime = timestamp.strftime('%Y-%m-%d %H%M%S')
# Create the figure
fig = plt.figure(figsize = [16, 10])
ax = fig.add_subplot(1, 1, 1, projection = cmi.metpy.cartopy_crs)
ax.set_extent([-80, -45, -50, -15], crs = ccrs.PlateCarree())
ax.add_feature(cfeature.BORDERS.with_scale('50m'), edgecolor = 'black', linewidth = 1)
ax.add_feature(cfeature.COASTLINE.with_scale('50m'), edgecolor = 'black', linewidth = 1)
ax.add_feature(cfeature.STATES.with_scale('50m'), edgecolor = 'white', linewidth = 1)
# Add mapping information
ax.add_feature(cfeature.STATES)
ax.add_feature(cfeature.BORDERS, linewidth=2)
# Plot the image with our colormapping choices
wv_norm, wv_cmap = registry.get_with_range('WVCIMSS_r', 193, 283)
im = ax.imshow(cmi, extent=(x[0], x[-1], y[0], y[-1]), origin='upper',
cmap = wv_cmap, norm = wv_norm, transform = cmi.metpy.cartopy_crs)
plt.colorbar(im, ticks = np.arange(193, 293, 10), ax = ax)
plt.title(f'Vapor da Água em Níveis Médios [$K$] \nValid: {vtime} UTC', loc = 'left')
plt.savefig(f'/mnt/c/Users/vitor/Desktop/WV_{vtime}.jpg', bbox_inches = 'tight')
Also below, is a comparison between the output from my code and the actual water vapor imagery from the CODNEXLAB website. I also looked at the metadata of the downloaded files and everything seems to be fine. Not sure if I'm doing something wrong here.
What you're seeing is that your image is flipped (it's easier to identify if you look at the global plot of that data). What's happening is the origin you specified ('upper'/'lower') disagree with what you passed as extent. So either tweak your origin parameter:
im = ax.imshow(cmi, extent=(x[0], x[-1], y[0], y[-1]),
origin='lower', cmap=wv_cmap, norm=wv_norm,
transform=cmi.metpy.cartopy_crs)
or flip the order of your y extents:
im = ax.imshow(cmi, extent=(x[0], x[-1], y[-1], y[0]),
origin='upper', cmap=wv_cmap, norm=wv_norm,
transform=cmi.metpy.cartopy_crs)

Plotting latitude and longitude from csv file

Hello been trying to do this all day!
I have created a map with Basemap and I am trying to plot all the latitude and longitude locations from the CSV file. Any ideas or tips?
Here is an image of the csv file
def map_test():
col_list = ["longitude", "latitude"]
dataset = pd.read_csv('charge_point_registry.csv', usecols=col_list)
latitudes = dataset.loc[:, 'latitude']
longitudes = dataset.loc[:, 'longitude']
# Creates a base map ready for attributes
plt.figure(figsize=(20, 15))
m = Basemap(projection='mill',
# coordinates of a box to contain map of UK
llcrnrlat=48.632909,
llcrnrlon=-14.452873,
urcrnrlon=3.136989,
urcrnrlat=61.648162,
# quality of map
resolution='l')
m.drawcoastlines()
m.drawcounties()
m.fillcontinents(color = "green")
geometry = [Point(xy) for xy in zip(longitudes, latitudes)]
gdf = GeoDataFrame(dataset, geometry=geometry)
gdf.plot(ax=m.plot(figsize=(20, 15)), marker='o', color='red', markersize=15)
# m.bluemarble()
plt.show()
Thanks :)
Matplotlib Basemap is deprecated in favor of Cartopy. Here is some code that will allow you to plot your UK Data.
import numpy as np
import cartopy
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import pandas as pd
long_list = np.arange(-179.5, 180, 1)
lat_list = np.arange(-89.5, 90, 1)
value_dict = {'latitude':[51.0, 51.2, 53.4, 54.5],
'longitude':[-1.1, -1.3, -0.2, -0.9]}
#replace this with your df
df = pd.DataFrame(value_dict)
proj = ccrs.PlateCarree(central_longitude=0)
fig, ax = plt.subplots(subplot_kw=dict(projection=proj), figsize=(16,16))
ax.set_extent([-10, 3, 48, 61], crs=ccrs.PlateCarree())
fig.canvas.draw()
fig.tight_layout()
ax.add_feature(cfeature.LAND, facecolor='0.25')
ax.add_feature(cfeature.BORDERS, zorder=10)
ax.scatter(df['longitude'].values.tolist(), df['latitude'].values.tolist())
gl = ax.gridlines(crs=proj, draw_labels=False, alpha=1, linewidth=0.25)
gl.xlocator = mticker.FixedLocator(long_list)
gl.ylocator = mticker.FixedLocator(lat_list)
plt.show()

How to plot zebra style axis in matplotlib

I want plot the axis in a zebra style similar to this:
Below is my code:
import matplotlib.pyplot as plt
import cartopy.io.shapereader as shpreader
import cartopy.crs as ccrs
from cartopy.feature import ShapelyFeature
fig, ax = plt.figure(figsize=(12,9), dpi=150 )
sFilename_shapefile = './some_shape.shp'
pShapeReader = shpreader.Reader(sFilename_shapefile)
pProjection_map = ccrs.PlateCarree()
aShapeFeature = ShapelyFeature(pShapeReader.geometries(),
pProjection_map, facecolor='grey', edgecolor='grey',
linewidth=0.5)
ax.add_feature(aShapeFeature, zorder = 4)
plt.show()
What I got is like this:
I've got a hacky solution that's working for my purposes:
The example usage:
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
crs = ccrs.PlateCarree()
fig = plt.figure(figsize=(5, 2))
ax = fig.add_subplot(projection=crs)
ax.coastlines()
ax.set_extent((-125, -85, 22, 42))
ax.set_xticks((-120, -110, -100, -90))
ax.set_yticks((25, 30, 35, 40))
add_zebra_frame(ax, crs=crs)
I've put the frame in a function for now. It likely will not work for many polar-type projections that mix lat/lon ticks, and right now it doesn't work that well if you don't specify which tick marks you want (I'm still unclear how Cartopy picks the default ticks).
https://gist.github.com/scottstanie/dff0d597e636440fb60b3c5443f70cae
Basically all I'm doing is turning off the spines and plotting an alternating black/white line between each of the xticks/yticks.
import itertools
import matplotlib.patheffects as pe
import numpy as np
def add_zebra_frame(ax, lw=2, crs="pcarree", zorder=None):
ax.spines["geo"].set_visible(False)
left, right, bot, top = ax.get_extent()
# Alternate black and white line segments
bws = itertools.cycle(["k", "white"])
xticks = sorted([left, *ax.get_xticks(), right])
xticks = np.unique(np.array(xticks))
yticks = sorted([bot, *ax.get_yticks(), top])
yticks = np.unique(np.array(yticks))
for ticks, which in zip([xticks, yticks], ["lon", "lat"]):
for idx, (start, end) in enumerate(zip(ticks, ticks[1:])):
bw = next(bws)
if which == "lon":
xs = [[start, end], [start, end]]
ys = [[bot, bot], [top, top]]
else:
xs = [[left, left], [right, right]]
ys = [[start, end], [start, end]]
# For first and lastlines, used the "projecting" effect
capstyle = "butt" if idx not in (0, len(ticks) - 2) else "projecting"
for (xx, yy) in zip(xs, ys):
ax.plot(
xx,
yy,
color=bw,
linewidth=lw,
clip_on=False,
transform=crs,
zorder=zorder,
solid_capstyle=capstyle,
# Add a black border to accentuate white segments
path_effects=[
pe.Stroke(linewidth=lw + 1, foreground="black"),
pe.Normal(),
],
)

Categories