I am using Basemap with a 3D graph to display ray paths. I would like to implement one of basemap's topo, shaded relief or bluemarble layers but I am running into the same issue over and over again:
NotImplementedError: It is not currently possible to manually set the aspect on 3D axes
I have already implemented fixed_aspect=False into calling the basemap
and have also tried ax.set_aspect('equal') which gives me the same error
I am using matplotlib ==2.2.3
Here is my code:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.basemap import Basemap
import numpy as np
from io import StringIO
import re
f = open("best-working4D.ray_paths", 'r') #125 waves - 125 "lines"
data = f.read()
lines = data.split('\n ')
fig = plt.figure()
ax = plt.axes(projection='3d')
extent = [300, 360, 50, 75]
bm = Basemap(llcrnrlon=extent[0], llcrnrlat=extent[2],
urcrnrlon=extent[1], urcrnrlat=extent[3], resolution='l', fix_aspect= False)
bm.bluemarble()
for i in range(1, 119):
wave = lines[i]
j = wave.split('\n')
k = []
for i in j:
k.append(i.split())
x=[]
y=[]
z=[]
n= 0
for m in k[1:]:
x.append(m[0])
y.append(m[1])
z.append(m[2])
x= np.array(x).astype('float32')
y= np.array(y).astype('float32')
z= np.array(z).astype('float32')
ax.plot3D(x,y,z, color='red')
##Plotting Tropopause
T_hi = 20
xx, yy = np.meshgrid(range(300,360), range(50,75))
zz = yy*0 + T_hi
ax.plot_surface(xx, yy, zz, alpha=0.15)
ax.set_xlabel("Latitude [deg]")
ax.set_ylabel("Longitude [deg]")
ax.set_zlabel("Altitude [km]")
ax.add_collection3d(bm.drawcoastlines(linewidth=0.25))
plt.show()
The basemap IS working for the bm.drawcoastlines just nothing else.
IMAGELINK
I would greatly appreciate any ideas!
I made a PMF plot using seaborn:
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import matplotlib.patches as mpatches
n= 1000 #number of trials
p= 0.5 #probability
trial_2 = np.random.binomial(n,p,1000)
sns.displot(trial_2, stat = 'probability')
trial_2_mean= np.mean(trial_2)
plt.axvline(trial_2_mean,color='red')
plt.xlabel("Number of Successes")
red_patch = mpatches.Patch(color='red', label='Mean')
plt.legend(handles=[red_patch])
I want to add text to the plot like below (the n=60 and p=0.1):
Also how do I plot in a format similar to the one in the picture (straight lines)
You can do following:
from scipy.stats import binom
n = 50
p = 0.1
x = [x for x in range(15)]
trial_2 = binom.pmf(x, n, p)
sns.scatterplot(x, trial_2,label=('$n=50, p=0.1$'))
plt.vlines(x, 0, trial_2, colors='red', lw=3, alpha=0.4)
plt.xticks(x)
plt.ylabel('Probability')
plt.xlabel('Number of Successes')
plt.show()
Produces:
I'm making plots using matplotlib colormap "seismic" and would like to have the white color centered on 0. When I run my script with no changes, white falls from 0 to -10. I tried then setting vmin=-50, vmax=50 but I completely lose the white in that case. Any suggestions on how to accomplish that?
from netCDF4 import Dataset as NetCDFFile
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.basemap import Basemap
nc = NetCDFFile('myfile.nc')
lat = nc.variables['lat'][:]
lon = nc.variables['lon'][:]
time = nc.variables['time'][:]
hgt = nc.variables['hgt'][:]
map = Basemap(llcrnrlon=180.,llcrnrlat=0.,urcrnrlon=320.,urcrnrlat=80.)
lons,lats = np.meshgrid(lon,lat)
x,y = map(lons,lats)
cs = map.contourf(x,y,hgt[0],cmap='seismic')
cbar = plt.colorbar(cs, orientation='horizontal', shrink=0.5,
cmap='seismic')
cbar.set_label('500mb Geopotential Height Anomalies(m)')
map.drawcoastlines()
map.drawparallels(np.arange(20,80,20),labels=[1,1,0,0], linewidth=0.5)
map.drawmeridians(np.arange(200,320,20),labels=[0,0,0,1], linewidth=0.5)
plt.show()`
Plot with defaults
Plot with vmin, vmax set
You can set the levels you want to show manually. As long as you have the same spacing of intervals to the left and to the right of zero this works nicely.
levels = [-50,-40,-30,-20,-10,10,20,30,40,50]
ax.contourf(X,Y,Z, levels)
Example:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-6.3,6.3)
y = np.linspace(-3.1,3.1)
X,Y = np.meshgrid(x,y)
Z = -np.cos(X)*np.cos(Y)*45
levels = [-50,-40,-30,-20,-10,10,20,30,40,50]
fig, ax = plt.subplots(figsize=(4,2))
cont = ax.contourf(X,Y,Z,levels, cmap="seismic")
fig.colorbar(cont, orientation="horizontal")
plt.show()
Or, if you want the colorbar to be proportional to the data,
fig.colorbar(cont, orientation="horizontal", spacing="proportional")
If levels are unequal, you need to specify vmin and vmax.
levels = [-50,-40,-30,-20,-10,10,30,50,80,100]
cont = ax.contourf(X,Y,Z,levels, cmap="seismic", vmin=-50, vmax=50)
The disadvantage is that you loose resolution, hence you may use a BoundaryNorm to select equally spaced colors for unequally spaced labels.
import matplotlib.pyplot as plt
import matplotlib.colors
import numpy as np
x = np.linspace(-6.3,6.3)
y = np.linspace(-3.1,3.1)
X,Y = np.meshgrid(x,y)
Z = -np.cos(X)*np.cos(Y)*45
levels = [-50,-40,-30,-20,-10,10,30,50,80,100]
norm = matplotlib.colors.BoundaryNorm(levels, len(levels)-1)
fig, ax = plt.subplots(figsize=(4,2))
cont = ax.contourf(X,Y,Z,levels,cmap=plt.get_cmap("seismic",len(levels)-1), norm=norm)
fig.colorbar(cont, orientation="horizontal")
plt.show()
To change the ticklabels on the colorbar so something other than the levels or in case they are too dence you may use the ticks argument.
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-6.3,6.3)
y = np.linspace(-3.1,3.1)
X,Y = np.meshgrid(x,y)
Z = -np.cos(X)*np.cos(Y)*45
levels = np.arange(-45,50,5)
levels = levels[levels!=0]
ticks=np.arange(-40,50,10)
fig, ax = plt.subplots(figsize=(4,2))
cont = ax.contourf(X,Y,Z,levels,cmap="seismic", spacing="proportional")
fig.colorbar(cont, orientation="horizontal", ticks=ticks, spacing="proportional")
plt.show()
I have a dataset looking like this:
1 38.7114 -7.92482 16.4375 0.2
...
I'd like to make a 3D scatter plot. I've done it using cartesian coordinates. How I can do it using geographic coordinates? Any hint?
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import sys
from mpl_toolkits.basemap import Basemap
ID=[]
Latitude=[]
Longitude=[]
Depth=[]
cluster1='data1'
with open(cluster1) as f:
lines = f.readlines()
for line in lines:
items = line.strip().split()
lat = float(items[1])
lon = float(items[2])
dep = float(items[3])
mag = float(items[4])
Latitude.append(lat)
Longitude.append(lon)
Depth.append(dep)
ID.append(mag)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
p = ax.scatter(Longitude, Latitude, Depth, c=ID, marker='o')
ax.set_xlabel('Longitude')
ax.set_ylabel('Latitude')
ax.set_zlabel('Depth (km)')
ax.invert_zaxis()
cb = fig.colorbar(p,label='Magnitude')
plt.savefig('plot1.png')
Hi for the matplotlib plot below I want to set the axes titles such that they show that the x-axis values run from
2**-5, 2**-4, 2**-3,..., 2**14, 2**15
and the y-axis values run from
2**-15, 2**-14,...., 2**4, 2**5
The graph I want to display them on is:
The code for the graph is below:
from matplotlib import pyplot
import matplotlib as mpl
import numpy as np
zvals = 100*np.random.randn(21, 21)
fig = pyplot.figure(2)
cmap2 = mpl.colors.LinearSegmentedColormap.from_list('my_colormap',
['blue','green','brown'],
256)
img2 = pyplot.imshow(zvals,interpolation='nearest',
cmap = cmap2,
origin='lower')
pyplot.colorbar(img2,cmap=cmap2)
pyplot.show()
You can use a range with a stepsize to label every 5th cell:
locs = range(0, N, 5)
ax.set(xticks=locs, xlabels=...)
For example,
from matplotlib import pyplot as plt
from matplotlib import colors as mcolors
import numpy as np
N = 21
zvals = 100*np.random.randn(N, N)
fig = plt.figure(2)
ax = fig.add_subplot(111)
cmap2 = mcolors.LinearSegmentedColormap.from_list(
'my_colormap', ['blue','green','brown'], 256)
img2 = plt.imshow(zvals,interpolation='nearest',
cmap=cmap2, origin='lower')
plt.colorbar(img2, cmap=cmap2)
step = 5
locs = range(0, N, step)
ax.set(
xticks=locs,
xticklabels=['$2^{{{}}}$'.format(i-5) for i in locs],
yticks=locs,
yticklabels=['$2^{{{}}}$'.format(i-15) for i in locs])
plt.show()