How to Plot 2 Lines on Log X-axis in Python? - python

I'm trying to plot blackbody wavelength vs flux for 288 Kelvin temperature (the Earth) and 6000 Kelvin temperature (the sun). I want both of these to be on the same plot and know I will need a log x-axis but I keep having issues having both lines appear. This is the code I have so far:
# Import libraries
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
# Constants
c = 3.0e8 # m/s
h = 6.626e-34 # Js
k = 1.38e-23 # J/K
c1 = 2*np.pi*h*c**2
c2 = (h*c)/k
T1 = 6000
T2 = 288
lam = np.logspace(-8,-3,2000) # Generate x-axis values
F1 = c1/(lam**5*(np.exp(c2/(lam*T1))-1)) # Calculate y-values
F1 = F1/1e9
F2 = c1/(lam**5*(np.exp(c2/(lam*T2))-1)) # Calculate y-values
F2 = F2/1e9
# Create plot
ax = plt.gca()
plt.xlabel(r'$\lambda$ (nm)')
plt.ylabel(r'$F_{BB\lambda}(W\/m^{-2}nm^{-1})$')
plt.text(0.05,.8, 'T = {0:d}K'.format(T1), transform = ax.transAxes, size = 'small')
plt.text(0.05,.3, 'T = {0:d}K'.format(T2), transform = ax.transAxes, size = 'small')
plt.xticks(), plt.yticks()
plt.semilogx(lam*1e9, F1, lam*1e9, F2, color= 'black') # Create figure and axis objects
plt.xlim(10,1e6)
plt.ylim(0,)
plt.show() # Display plot to screen
This plots the attached picture which is correct for 6000K but for some reason it's not plotting the 288K curve and I'm not sure how to fix it.

Related

Scatter data not overlaying properly on radar data... cartopy issue

I'm trying to plot scatter data of storm reports on top of radar gridded data and I seem to be getting strange plotting issues related to mapping using cartopy. See example image attached. It appears that the scatter data plots on a separate axis than the radar data, but I'm not sure why given that the plotting module for the radar data uses the same user input for min/max lat/lon and the chosen projection. Additionally, the lat/lon range on the map is dynamic as I loop through time stamps. I know I can use an ax.set_extent to create fixed coordinates, but this does not solve my issue of the plotting being done on a separate axis. Does anyone have any suggestions? They should overlay on the same axis.
Here is the code:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
import matplotlib.dates as mdates
import cartopy.crs as ccrs
import pyart
import pandas as pd
import nexradaws
import tempfile
import pytz
templocation = tempfile.mkdtemp()
import cartopy.feature as cfeature
from metpy.plots import USCOUNTIES
### Define the radar, start time and end time
radar_id = 'KDVN'
start = pd.Timestamp(2020,8,10,16,30).tz_localize(tz='UTC')
end = pd.Timestamp(2020,8,10,21,0).tz_localize(tz='UTC')
### Bounds of map we want to plot
min_lon = -93.25
max_lon = -88.
min_lat = 40.35
max_lat = 43.35
# ### Bounds of map we want to plot
# min_lon = -80.8
# max_lon = -77.
# min_lat = 34
# max_lat = 37
#### and get the data
conn = nexradaws.NexradAwsInterface()
scans = conn.get_avail_scans_in_range(start, end, radar_id)
print("There are {} scans available between {} and {}\n".format(len(scans), start, end))
print(scans[0:4])
## download these files
#results = conn.download(scans[0:2], templocation)
results = conn.download(scans, templocation)
#%%
#Now get the severe reports from the SPC site. This assumes you're plotting a year far #enough in the past that
# SPC has official records available. If plotting a more recent time period, then the #local storm reports archive
#[![enter image description here][1]][1] at IEM is a good source
### wind reports
wind_rpts = pd.read_csv("https://www.spc.noaa.gov/wcm/data/"+str(start.year)+"_wind.csv")
wind_rpts['datetime'] = pd.to_datetime(wind_rpts.date + ' ' + wind_rpts.time) ## convert to datetime
wind_rpts.set_index("datetime",inplace=True)
### times in the file are given in central standard time (UTC+6). Localize, and convert to UTC
wind_rpts.index = wind_rpts.index.tz_localize("Etc/GMT+6",ambiguous='NaT',nonexistent='shift_forward').tz_convert("UTC")
## subset down to 30 minutes before/after the radar times we're plotting
wind_rpts = wind_rpts[((start-pd.Timedelta(minutes=30)).strftime("%Y-%m-%d %H:%M")):((end+pd.Timedelta(minutes=30)).strftime("%Y-%m-%d %H:%M"))]
wind_rpts
### repeat for tornado reports
tor_rpts = pd.read_csv("https://www.spc.noaa.gov/wcm/data/"+str(start.year)+"_torn.csv")
tor_rpts['datetime'] = pd.to_datetime(tor_rpts.date + ' ' + tor_rpts.time) ## convert to datetime
tor_rpts.set_index("datetime",inplace=True)
### times in the file are given in central standard time (UTC+6). Localize, and convert to UTC
tor_rpts.index = tor_rpts.index.tz_localize("Etc/GMT+6",ambiguous='NaT',nonexistent='shift_forward').tz_convert("UTC")
## subset down to 30 minutes before/after the radar times we're plotting
tor_rpts = tor_rpts[((start-pd.Timedelta(minutes=30)).strftime("%Y-%m-%d %H:%M")):((end+pd.Timedelta(minutes=30)).strftime("%Y-%m-%d %H:%M"))]
tor_rpts
### repeat for hail
hail_rpts = pd.read_csv("https://www.spc.noaa.gov/wcm/data/"+str(start.year)+"_hail.csv")
hail_rpts['datetime'] = pd.to_datetime(hail_rpts.date + ' ' + hail_rpts.time) ## convert to datetime
hail_rpts.set_index("datetime",inplace=True)
### times in the file are given in central standard time (UTC+6). Localize, and convert to UTC
hail_rpts.index = hail_rpts.index.tz_localize("Etc/GMT+6",ambiguous='NaT',nonexistent='shift_forward').tz_convert("UTC")
## subset down to 30 minutes before/after the radar times we're plotting
hail_rpts = hail_rpts[((start-pd.Timedelta(minutes=30)).strftime("%Y-%m-%d %H:%M")):((end+pd.Timedelta(minutes=30)).strftime("%Y-%m-%d %H:%M"))]
hail_rpts
#%%
'''Now we plot the maps and animate'''
### loop over the radar images that have been downloaded
for i,scan in enumerate(results.iter_success(),start=1):
#for i in range(0,1):
## skip the files ending in "MDM"
if scan.filename[-3:] != "MDM":
print(str(i))
print("working on "+scan.filename)
this_time = pd.to_datetime(scan.filename[4:17], format="%Y%m%d_%H%M").tz_localize("UTC")
radar = scan.open_pyart()
#display = pyart.graph.RadarDisplay(radar)
fig = plt.figure(figsize=[15, 7])
map_panel_axes = [0.05, 0.05, .4, .80]
x_cut_panel_axes = [0.55, 0.10, .4, .25]
y_cut_panel_axes = [0.55, 0.50, .4, .25]
projection = ccrs.PlateCarree()
## apply gatefilter (see here: https://arm-doe.github.io/pyart/notebooks/masking_data_with_gatefilters.html)
#gatefilter = pyart.correct.moment_based_gate_filter(radar)
gatefilter = pyart.filters.GateFilter(radar)
# Lets remove reflectivity values below a threshold.
gatefilter.exclude_below('reflectivity', -2.5)
display = pyart.graph.RadarMapDisplay(radar)
### set up plot
ax1 = fig.add_axes(map_panel_axes, projection=projection)
# Add some various map elements to the plot to make it recognizable.
ax1.add_feature(USCOUNTIES.with_scale('500k'), edgecolor="gray", linewidth=0.4)
#ax1.coastlines('50m', edgecolor='black', linewidth=0.75)
ax1.add_feature(cfeature.STATES.with_scale('10m'), linewidth=1.0)
cf = display.plot_ppi_map('reflectivity', 0, vmin=-7.5, vmax=65,
min_lon=min_lon, max_lon=max_lon, min_lat=min_lat, max_lat=max_lat,
title=radar_id+" reflectivity and severe weather reports, "+this_time.strftime("%H%M UTC %d %b %Y"),
projection=projection, resolution='10m',
gatefilter=gatefilter,
cmap='pyart_HomeyerRainbow',
colorbar_flag=False,
lat_lines=[0,0], lon_lines=[0,0]) ## turns off lat/lon grid lines
#display.plot_crosshairs(lon=lon, lat=lat)
## plot horizontal colorbar
display.plot_colorbar(cf,orient='horizontal', pad=0.07)
# Plot range rings if desired
#display.plot_range_ring(25., color='gray', linestyle='dashed')
#display.plot_range_ring(50., color='gray', linestyle='dashed')
#display.plot_range_ring(100., color='gray', linestyle='dashed')
ax1.set_xticks(np.arange(min_lon, max_lon, .5), crs=ccrs.PlateCarree())
ax1.set_yticks(np.arange(min_lat, max_lat, .5), crs=ccrs.PlateCarree())
## add marker points for severe reports
wind_rpts_now = wind_rpts[((start-pd.Timedelta(minutes=30)).strftime("%Y-%m-%d %H:%M")):this_time.strftime("%Y-%m-%d %H:%M")]
ax1.scatter(wind_rpts_now.slon.values.tolist(), wind_rpts_now.slat.values.tolist(), s=20, facecolors='none', edgecolors='mediumblue', linewidths=1.8)
tor_rpts_now = tor_rpts[((start-pd.Timedelta(minutes=30)).strftime("%Y-%m-%d %H:%M")):this_time.strftime("%Y-%m-%d %H:%M")]
ax1.scatter(tor_rpts_now.slon.values.tolist(), tor_rpts_now.slat.values.tolist(), s=20, facecolors='red', edgecolors='black', marker="v",linewidths=1.5)
hail_rpts_now = hail_rpts[((start-pd.Timedelta(minutes=30)).strftime("%Y-%m-%d %H:%M")):this_time.strftime("%Y-%m-%d %H:%M")]
ax1.scatter(hail_rpts_now.slon.values.tolist(), hail_rpts_now.slat.values.tolist(), s=20, facecolors='none', edgecolors='green', linewidths=1.8)
plt.savefig(scan.radar_id+"_"+scan.filename[4:17]+"_dz_rpts.png",bbox_inches='tight',dpi=300,
facecolor='white', transparent=False)
#plt.show()
plt.close('all')

Python: Save plot maximised

I want to save a plot in python as a PDF. My problem ist, when I run my code I get a plot that looks like this:
When I now maximise the window I get a plot that looks like this:
Note that the second one looks much better, because it is not so "cramped". If I now save the plot using plt.savefig('floors.pdf') the saved plot looks like the first picture. I need a way to save it so that it looks like in the second picture.
I found this: How to make savefig() save image for 'maximized' window instead of default size but it is not helping because I don't want to save a set resolution in pixels. I want to save it as an PDF, because that way it stays a vector graphic.
My code:
import os
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
from uncertainties import ufloat
os.chdir('PlayGround/SAOIF floors')
# data ------------------------------------------
floors = np.array([1,2,3,4,5,6,7,8,9,10,11,12,13,14,20,25,27,35,40,47,48,50,55,61,68,74,75,77,81])
N = np.arange(len(floors))+1
# plot raw data ---------------------------------
fig = plt.figure()
plt.suptitle('SAOIF Floors')
ax1 = plt.subplot(121)
ax1.plot(N,floors,'o-')
ax1.set_title('All Floors')
ax1.set_ylabel('Floor Number')
ax1.set_xticks(np.arange(1, len(N)+1, len(N)//8))
ax1.set_yticks(np.arange(floors[0], floors[-1]+1, (floors[-1] - floors[0])//8))
ax1.grid()
# fit data --------------------------------------
floors = floors[13::]
N = N[13::]
x = N
y = floors
linera_function = lambda x, m, b: m*x+b
popt, pcov = curve_fit(linera_function, x, y)
error = np.sqrt(np.diag(pcov))
m = round(popt[0],2)
b = round(popt[1],2)
dm = round(error[0],2)
db = round(error[1],2)
# plot fit --------------------------------------
ax2 = plt.subplot(122)
ax2.set_title('Floors 14-81')
ax2.plot(x, y,'o', label='data') # plot data
ax2.plot(x, linera_function(x, *popt), label=f'fit: $f(x)=m \cdot x + b$ \n$m={m}\pm{dm}$ \n$b={b}\pm{db}$') # plot fit
# predicting next floor -------------------------
m = ufloat(m, dm)
b = ufloat(b, db)
next_floor = linera_function(N[-1]+1, m, b)
print('m = {:L}'.format(m))
print('b = {:L}'.format(b))
print('Next floor: {:L}'.format(next_floor))
# plot prediction -------------------------------
x = list(x)
y = list(y)
x.append(x[-1]+1)
y.append(next_floor.n)
next_floor_n = int(round(next_floor.n))
next_floor_s = int(round(next_floor.s))
ax2.errorbar(N[-1]+1, next_floor.n, yerr=next_floor.s, label=f'predicted next floor \nnumber$={next_floor_n} \pm {next_floor_s}$', capsize=5, fmt='o')
ax2.plot([N[-1], N[-1]+1.7], [linera_function(N[-1], m, b).n, linera_function(N[-1]+1.7, m, b).n],'--', color='#ff7f0e')
ax2.set_xticks(np.arange(x[0], x[-1]+1, round((x[-1] - x[0])/8)))
ax2.set_yticks(np.arange(y[0], y[-1]+1, round((y[-1] - y[0])/8)))
ax2.legend()
plt.gcf()
fig.supxlabel('common_x')
plt.savefig('floors.pdf')
plt.show()

Animating and exporting the cartopy Nightshade feature

I am trying to plot the groundtrack of a satellite through a combination of packages, animate the satellite movement, mark a field of view from the subsatellite point (which is just arbitrary circles in this code) and then export the file as a video of some kind. So far, I have been able to do all of this except that when I try to export the video, the Nightshade feature doesn't animate so much as overlay and eventually blacks out most of the screen. Is there something I'm missing on how to properly animate the Nightshade feature? I know that I'm essentially recreating a new feature inside the update function everytime it runs a frame but I could not figure out how to update it as I do the scatter plots.
I've included my sample code below.
import pandas as pd
from sgp4.api import WGS72
from sgp4.api import Satrec
from skyfield.api import EarthSatellite, load, N, W, wgs84
import datetime
import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import matplotlib.animation as animation
from cartopy.feature.nightshade import Nightshade
# CREATE THE SATELLITE DATA
epoch = datetime.date(1949, 12, 31)
sat = Satrec()
sat.sgp4init(
WGS72, # gravity model
'i', # 'a' = old AFSPC mode, 'i' = improved mode
5, # satnum: Satellite number
(datetime.date.today() - epoch).days, # epoch: days since 1949 December 31 00:00 UT
0, # bstar: drag coefficient (1/earth radii)
6.969196665e-13, # ndot (NOT USED): ballistic coefficient (revs/day)
0.0, # nddot (NOT USED): mean motion 2nd derivative (revs/day^3)
0.1, # ecco: eccentricity
280 * np.pi / 180, # argpo: argument of perigee (radians)
50 * np.pi / 180, # inclo: inclination (radians)
275 * np.pi / 180, # mo: mean anomaly (radians)
0.0472294454407, # no_kozai: mean motion (radians/minute)
50 * np.pi / 180, # nodeo: right ascension of ascending node (radians)
)
# DEFINE A FEW BASIC PARAMETERS FOR THE PROGRAM
P = sat.mo / sat.no_kozai # min, period of orbit. LEOs orbit between 84-127 minutes
ts = load.timescale()
sat1 = EarthSatellite.from_satrec(sat, ts)
hours = np.arange(0, 6, 0.05)
time = ts.utc(2021, 6, 31, hours)
pos = sat1.at(time).position.km
pos_ec = sat1.at(time).ecliptic_position().km
sp = wgs84.subpoint(sat1.at(time))
latitude = sp.latitude
longitude = sp.longitude
elev = sp.elevation
# CREATE A DATAFRAME OF THE DATA FOR REVIEW LATER IF NEEDED
df = pd.DataFrame([time.utc_datetime(), latitude.degrees, longitude.degrees, elev.km],
index=['DTS', 'lat', 'lon', 'elev']).T
df.lat = df.lat.astype('float32')
df.lon = df.lon.astype('float32')
df.elev = df.elev.astype('float32')
df.set_index('DTS', inplace=True)
# ASSIGN RELEVANT DATA FOR THE SUBSATELLITE POINT
ssp = np.transpose(np.array([longitude.degrees, latitude.degrees]))
line = ssp.copy()
pos = np.where(np.diff(np.abs(line[:, 0] >= 0)))[0]
line[pos, :] = np.nan
# CREATE DATE TIME RANGES FOR USE WITH THE NIGHTSHADE FEATURE
base = datetime.datetime(2000, 1, 1)
dates = np.array([base + datetime.timedelta(hours=i) for i in range(len(hours))])
shades = [Nightshade(date, alpha=0.2) for date in dates]
### CREATE FIGURE AND IMAGE
fig = plt.figure(figsize=(16, 8))
ax = fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree())
ax.stock_img()
# plot lines that will show the ground track that will be animated
ax.plot(line[:, 0], line[:, 1], '--k')
# create a blank scatter to start
scatter = ax.scatter(None, None, color='r', s=30)
# initiate the circles around the scatter point
circle1 = plt.Circle((longitude.degrees[0], latitude.degrees[0]), radius=30, color='blue', alpha=0.3)
circle2 = plt.Circle((longitude.degrees[0], latitude.degrees[0]), radius=40, color='yellow', alpha=0.3)
# add the circles to the axis
ax.add_patch(circle1)
ax.add_patch(circle2)
# Add the nightshade feature (but set it to be invisible so it doesn't stay through the whole animation)
ns = ax.add_feature(Nightshade(base, alpha=0.0))
# Create all the updates for the animation
def update(i):
lon = ssp[i, 0]
lat = ssp[i, 1]
scatter.set_offsets(np.c_[lon, lat])
# add a feature for the next Nightshade feature
ns = ax.add_feature(shades[i], alpha=0.2)
circle1.center = (lon, lat)
circle2.center = (lon, lat)
return scatter, circle1, circle2, ns
# Run the animation
anim = animation.FuncAnimation(plt.gcf(), update, frames=df.shape[0],init_func=None, interval=250, blit=True)
plt.show()
# WRITE THE VIDEO
Writer = animation.writers['ffmpeg']
writer = Writer(fps=10, metadata=dict(artist='Me'), bitrate=1800)
anim.save('gt.mp4', writer=writer)

Dynamic Visualisation of Global Plots

I have produced 17 global plots that show the decadal averages in maximum surface ozone from 1850-2015. Rather than plotting them individually, I wish to create an animation that cycles through them (almost like a gif), i.e. have the same coastlines, axes and colour bar throughout but change what is being plotted as the contour.
Any help on how to adapt my code to do this would be greatly appreciated - thank you in advance!!
import numpy as np
import netCDF4 as n4
import matplotlib.pyplot as plt
from matplotlib import colorbar, colors
import matplotlib.cm as cm
import cartopy as cart
import cartopy.crs as ccrs
from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER
import cartopy.feature as cfeature
nc = n4.Dataset('datafile.nc','r')
# daily maximum O3 VMR (units: mol mol-1)
sfo3max = nc.variables['sfo3max']
lon = nc.variables['lon'] # longitude
lat = nc.variables['lat'] # latitude
# (I manipulate the data to produce 17 arrays containing the decadal average O3 VMR which are
# listed below in sfo3max_avg)
sfo3max_avg = [sfo3max_1850_1860_avg, sfo3max_1860_1870_avg, sfo3max_1870_1880_avg,
sfo3max_1880_1890_avg, sfo3max_1890_1900_avg, sfo3max_1900_1910_avg,
sfo3max_1910_1920_avg, sfo3max_1920_1930_avg, sfo3max_1930_1940_avg,
sfo3max_1940_1950_avg, sfo3max_1950_1960_avg, sfo3max_1960_1970_avg,
sfo3max_1970_1980_avg, sfo3max_1980_1990_avg, sfo3max_1990_2000_avg,
sfo3max_2000_2010_avg, sfo3max_2010_2015_avg]
# find overall min & max values for colour bar in plots
min_sfo3max_avg = np.array([])
for i in sfo3max_avg:
sfo3max_avg_min = np.amin(i)
min_sfo3max_avg = np.append(min_sfo3max_avg, sfo3max_avg_min)
overall_min_sfo3max_avg = np.amin(min_sfo3max_avg)
max_sfo3max_avg = np.array([])
for i in sfo3max_avg:
sfo3max_avg_max = np.amax(i)
max_sfo3max_avg = np.append(max_sfo3max_avg, sfo3max_avg_max)
overall_max_sfo3max_avg = np.amax(max_sfo3max_avg)
# finally plot the 17 global plots of sfo3max_avg
for k in sfo3max_avg:
fig = plt.figure()
ax = plt.axes(projection=ccrs.PlateCarree())
ax.coastlines() # Adding coastlines
cs = ax.contourf(lon[:], lat[:], k[:], cmap='magma')
ax.set_title('Decadal Average of Maximum O3 Volume Mixing Ratio')
m = plt.cm.ScalarMappable(cmap=cm.magma)
m.set_array(i[:])
m.set_clim(overall_min_sfo3max_avg, overall_max_sfo3max_avg)
# Additional necessary information
cbar = plt.colorbar(m, boundaries=np.arange(overall_min_sfo3max_avg, overall_max_sfo3max_avg
+ 0.5e-08, 0.5e-08))
cbar.set_label('mol mol-1')
# Adding axis labels - latitude & longitude
gridl = ax.gridlines(color="black", linestyle="dotted", draw_labels=True)
gridl.xformatter=LONGITUDE_FORMATTER
gridl.yformatter=LATITUDE_FORMATTER
gridl.xlabels_top = False
gridl.ylabels_right = False
fig.set_size_inches(w=20,h=10)
plt.show() # show global plot
Several elements in your plotting can be kept out of the loop because they only need to be set up once. After you set up the plot elements you can update the plot and animate by looping over the list. This can be achieved by making use of matplotlib's interactive mode as shown in the code below:
import numpy as np
import netCDF4 as n4
import matplotlib
matplotlib.use("nbagg")
import matplotlib.pyplot as plt
from matplotlib import colorbar, colors
import matplotlib.cm as cm
import cartopy as cart
import cartopy.crs as ccrs
from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER
import cartopy.feature as cfeature
nc = n4.Dataset('datafile.nc','r')
# daily maximum O3 VMR (units: mol mol-1)
sfo3max = nc.variables['sfo3max']
lon = nc.variables['lon'] # longitude
lat = nc.variables['lat'] # latitude
# (I manipulate the data to produce 17 arrays containing the decadal average O3 VMR which are
# listed below in sfo3max_avg)
sfo3max_avg = [sfo3max_1850_1860_avg, sfo3max_1860_1870_avg, sfo3max_1870_1880_avg,
sfo3max_1880_1890_avg, sfo3max_1890_1900_avg, sfo3max_1900_1910_avg,
sfo3max_1910_1920_avg, sfo3max_1920_1930_avg, sfo3max_1930_1940_avg,
sfo3max_1940_1950_avg, sfo3max_1950_1960_avg, sfo3max_1960_1970_avg,
sfo3max_1970_1980_avg, sfo3max_1980_1990_avg, sfo3max_1990_2000_avg,
sfo3max_2000_2010_avg, sfo3max_2010_2015_avg]
# find overall min & max values for colour bar in plots
min_sfo3max_avg = np.array([])
for i in sfo3max_avg:
sfo3max_avg_min = np.amin(i)
min_sfo3max_avg = np.append(min_sfo3max_avg, sfo3max_avg_min)
overall_min_sfo3max_avg = np.amin(min_sfo3max_avg)
max_sfo3max_avg = np.array([])
for i in sfo3max_avg:
sfo3max_avg_max = np.amax(i)
max_sfo3max_avg = np.append(max_sfo3max_avg, sfo3max_avg_max)
overall_max_sfo3max_avg = np.amax(max_sfo3max_avg)
#setup the plot elements
fig = plt.figure()
fig.set_size_inches(w=20,h=10)
ax = plt.axes(projection=ccrs.PlateCarree())
ax.coastlines() # Adding coastlines
ax.set_title('Decadal Average of Maximum O3 Volume Mixing Ratio')
m = plt.cm.ScalarMappable(cmap=cm.magma)
m.set_array(i[:])
m.set_clim(overall_min_sfo3max_avg, overall_max_sfo3max_avg)
# Additional necessary information
cbar = plt.colorbar(m, boundaries=np.arange(overall_min_sfo3max_avg, overall_max_sfo3max_avg
+ 0.5e-08, 0.5e-08))
cbar.set_label('mol mol-1')
# plot here only the 1st item in your sfo3max_avg list.
cs = ax.contourf(lon[:], lat[:], sfo3max_avg[0][:], cmap='magma')
# Adding axis labels - latitude & longitude
gridl = ax.gridlines(color="black", linestyle="dotted", draw_labels=True)
gridl.xformatter=LONGITUDE_FORMATTER
gridl.yformatter=LATITUDE_FORMATTER
gridl.xlabels_top = False
gridl.ylabels_right = False
plt.ion() # set interactive mode
plt.show()
# finally plot the 17 global plots of sfo3max_avg
for k in sfo3max_avg:
cs = ax.contourf(lon[:], lat[:], k[:], cmap='magma')
plt.gcf().canvas.draw()
plt.pause(1) #control the interval between successive displays, currently set to 1 sec.

matplotlib - clip image using line(s)

Is it possible to clip an image generated by imshow() to the area under a line/multiple lines? I think Clip an image using several patches in matplotlib may have the solution, but I'm not sure how to apply it here.
I just want the coloring (from imshow()) under the lines in this plot:
Here is my plotting code:
from __future__ import division
from matplotlib.pyplot import *
from numpy import *
# wavelength array
lambd = logspace(-3.8, -7.2, 1000)
# temperatures
T_earth = 300
T_sun = 6000
# planck's law constants
h = 6.626069e-34
c = 2.997925e8
k = 1.380648e-23
# compute power using planck's law
power_earth = 2*h*c**2/lambd**5 * 1/(exp(h*c/(lambd*k*T_earth)) - 1)
power_sun = 2*h*c**2/lambd**5 * 1/(exp(h*c/(lambd*k*T_sun)) - 1)
# set up color array based on "spectrum" colormap
colors = zeros((1000,1000))
colors[:,:1000-764] = 0.03
for x,i in enumerate(range(701,765)):
colors[:,1000-i] = 1-x/(765-701)
colors[:,1000-701:] = 0.98
figure(1,(4,3),dpi=100)
# plot normalized planck's law graphs
semilogx(lambd, power_earth/max(power_earth), 'b-', lw=4, zorder=5); hold(True)
semilogx(lambd, power_sun/max(power_sun), 'r-', lw=4, zorder=5); hold(True)
# remove ticks (for now)
yticks([]); xticks([])
# set axis to contain lines nicely
axis([min(lambd), max(lambd), 0, 1.1])
# plot colors, shift extent to match graph
imshow(colors, cmap="spectral", extent=[min(lambd), max(lambd), 0, 1.1])
# reverse x-axis (longer wavelengths to the left)
ax = gca(); ax.set_xlim(ax.get_xlim()[::-1])
tight_layout()
show()
What you can do in this case is using the area under the curve as a Patch to apply set_clip_path. All you have to do is call fill_between and extract the corresponding path, like this:
semilogx(lambd, power_earth/max(power_earth), 'b-', lw=4, zorder=5)
# Area under the curve
fillb_earth = fill_between(lambd, power_earth/max(power_earth), color='none', lw=0)
# Get the path
path_earth, = fillb_earth.get_paths()
# Create a Patch
mask_earth = PathPatch(path_earth, fc='none')
# Add it to the current axes
gca().add_patch(mask_earth)
# Add the image
im_earth = imshow(colors, cmap="spectral", extent=[min(lambd), max(lambd), 0, 1.1])
# Clip the image with the Patch
im_earth.set_clip_path(mask_earth)
And then repeat the same lines for the Sun. Here is the result.

Categories

Resources