Python Plotting Combine 2 Plots - python

I am trying to plot streamlines in matplotlib over a contour plot by combining these two plots shown below but showing my code first:
ax = plt.axes(projection=ccrs.PlateCarree())
ax.coastlines(lw=1)
clevs = np.linspace(-3., 3., 13)
cnplot = plt.contourf(lon,lat,anomspeed,clevs,add_labels=True,cmap='jet')
cbar = plt.colorbar(cnplot)
cbar.set_label('Standard Deviations')
plt.title('~50m Wind Speed Anomaly {} 2020'.format(calendar.month_name[currm-1]))
diffu = (uwndc - uwnd); diffv = (vwndc - vwnd)
lonn, latt = np.meshgrid(lon, lat)
plt.streamplot(lonn[0,:], latt[:,0], diffu, diffv, density=(3.5,3.5),
color='k',linewidth=0.4,arrowsize=0.6)#x,y 1D and u,v are 2D
I am getting this error (full traceback shown) when i try and run the code shown below but I do not understand 'ravel' error. I suppose it has something to do with matching coordinates or related between the two plots..? thank you for any help!
Traceback (most recent call last):
File "C:\Users\U321103\.spyder-
py3\MonthlyReport_mapsNCEP_contour_monthly_wspdv2.py", line 85, in <module>
plt.streamplot(lonn[0,:], latt[:,0], diffu, diffv, density=(3.5,3.5),
color='k',linewidth=0.4,arrowsize=0.6)
File "C:\Users\U321103\AppData\Local\Continuum\anaconda3\envs\Maps\lib\site-
packages\matplotlib\pyplot.py", line 2906, in streamplot
if data is not None else {}))
File "C:\Users\U321103\AppData\Local\Continuum\anaconda3\envs\Maps\lib\site-
packages\cartopy\mpl\geoaxes.py", line 1897, in streamplot
target_extent=target_extent)
File "C:\Users\U321103\AppData\Local\Continuum\anaconda3\envs\Maps\lib\site-
packages\cartopy\vector_transform.py", line 146, in vector_scalar_to_grid
return _interpolate_to_grid(nx, ny, x, y, u, v, *scalars, **kwargs)
File "C:\Users\U321103\AppData\Local\Continuum\anaconda3\envs\Maps\lib\site-
packages\cartopy\vector_transform.py", line 67, in _interpolate_to_grid
s_grid_tuple += (griddata(points, s.ravel(), (x_grid, y_grid),
AttributeError: 'Variable' object has no attribute 'ravel'

I'm looking to solving this same problem and I found an answer to a similar question that help me plotting streamlines and contour togheter. Take a look at here.
In a nutshell, instead of:
plt.streamplot(lonn[0,:], latt[:,0], diffu, diffv, density=(3.5,3.5), color='k',linewidth=0.4,arrowsize=0.6)
You'd use
plt.streamplot(lonn[0,:], latt[:,0], np.array(diffu), np.array(diffv), density=(3.5,3.5), color='k',linewidth=0.4,arrowsize=0.6)
The use of np.array() solves the problem for me.
Best regards,
Mateus

Related

Problem regarding axis shape in 3d surface plot in python

This is my first attempt at 3d surface plotting. Spent hours on trying to get a plot to show but no luck yet. Here is my script to do a surface plot of z_ax with respect to x_ax and y_ax. The z_ax variable is generated from some other script, but i thats irrelevant, so i just copy pasted the array just for the sake of reproduction.
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.axes3d import Axes3D
import numpy as np
z_ax = np.array([[98.0952381 , 98.37627192, 98.22459584, 97.96470716, 97.97332409,
98.55658199, 97.59356635, 97.72653459],
[98.78787879, 99.56700585, 99.26385681, 99.41539461, 99.43703447,
99.37211316, 99.28240025, 99.30172134],
[99.43722944, 99.35050877, 99.35046189, 99.3287864 , 99.50632254,
99.3432448 , 99.39993814, 99.38291653],
[99.13419913, 99.52370643, 99.52367206, 99.44787269, 99.49766153,
99.51645497, 99.55459326, 99.51824185],
[99.48051948, 99.45875731, 99.58140878, 99.58861102, 99.50632254,
99.4154157 , 99.44324157, 99.51282884],
[99.61038961, 99.41545789, 99.53810624, 99.51282884, 99.4630175 ,
99.54532333, 99.51128982, 99.55613294],
[99.43722944, 99.52370643, 99.4948037 , 99.58861102, 99.51498354,
99.48036952, 99.51747603, 99.5398939 ],
[99.48051948, 99.58865555, 99.50923788, 99.49117679, 99.41971245,
99.52367206, 99.55459326, 99.5398939 ],
[99.65367965, 99.48040701, 99.66801386, 99.577785 , 99.44569548,
99.55254042, 99.57315187, 99.59402403],
[99.39393939, 99.67525438, 99.48036952, 99.59943705, 99.5756106 ,
99.52367206, 99.52366223, 99.51282884]])
x_ax = np.linspace(0.1,0.8,8) # the test size
y_ax = np.linspace(0.01,1,10) # zero class weight
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_surface(x_ax, y_ax, z_ax)
plt.show()
However, when i run the script, i get:
Traceback (most recent call last):
File "tmp.py", line 30, in <module>
ax.plot_surface(x_ax, y_ax, z_ax)
File "C:\Python27\lib\site-packages\mpl_toolkits\mplot3d\axes3d.py", line 1567, in plot_surface
X, Y, Z = np.broadcast_arrays(X, Y, Z)
File "C:\Python27\lib\site-packages\numpy\lib\stride_tricks.py", line 249,
in broadcast_arrays
shape = _broadcast_shape(*args)
File "C:\Python27\lib\site-packages\numpy\lib\stride_tricks.py", line 184,
in _broadcast_shape
b = np.broadcast(*args[:32])
ValueError: shape mismatch: objects cannot be broadcast to a single shape
I checked the shapes of the co-ordinates, they seem to match for the surface plot. So, i dont understand what i am getting wrong. Any help is highly appreciated.
All the arrays have to have the same shape. See the documentation. Try to use np.meshgrid

Python Matplotlib Streamplot providing start points

I am trying to add start points to a streamline plot. I found an example code using start points here; at this link a different issue is discussed but the start_points argument works. From here I grabbed the streamline example code (images_contours_and_fields example code: streamplot_demo_features.py). I don't understand why I can define start points in one code and not the other. I get the following error when I try to define start points in the example code (streamplot_demo_features.py):
Traceback (most recent call last):
File "<ipython-input-79-981cad64cff6>", line 1, in <module>
runfile('C:/Users/Admin/.spyder/StreamlineExample.py', wdir='C:/Users/Admin/.spyder')
File "C:\ProgramData\Anaconda2\lib\site-packages\spyder\utils\site\sitecustomize.py", line 866, in runfile
execfile(filename, namespace)
File "C:\ProgramData\Anaconda2\lib\site-packages\spyder\utils\site\sitecustomize.py", line 87, in execfile
exec(compile(scripttext, filename, 'exec'), glob, loc)
File "C:/Users/Admin/.spyder/StreamlineExample.py", line 28, in <module>
ax1.streamplot(X, Y, U, V,start_points=start_points)
File "C:\ProgramData\Anaconda2\lib\site-packages\matplotlib\__init__.py", line 1891, in inner
return func(ax, *args, **kwargs)
File "C:\ProgramData\Anaconda2\lib\site-packages\matplotlib\axes\_axes.py", line 4620, in streamplot
zorder=zorder)
File "C:\ProgramData\Anaconda2\lib\site-packages\matplotlib\streamplot.py", line 144, in streamplot
sp2[:, 0] += np.abs(x[0])
ValueError: non-broadcastable output operand with shape (1,) doesn't match the broadcast shape (100,)
I've notice there isn't much on the web in way of using start_points, so any additional information would be helpful.
The main difference between the example that successfully uses start_points and the example from the matplotlib page is that the first uses 1D arrays as x and y grid, whereas the official example uses 2D arrays.
Since the documentation explicitely states
x, y : 1d arrays, an evenly spaced grid.
we might stick to 1D arrays. It's unclear why the example contradicts the docsting, but we can simply ignore that.
Now, using 1D arrays as grid, start_points works as expected in that it takes a 2-column array (first column x-coords, second y-coords).
A complete example:
import numpy as np
import matplotlib.pyplot as plt
x,y = np.linspace(-3,3,100),np.linspace(-3,3,100)
X,Y = np.meshgrid(x,y)
U = -1 - X**2 + Y
V = 1 + X - Y**2
speed = np.sqrt(U*U + V*V)
start = [[0,0], [1,2]]
fig0, ax0 = plt.subplots()
strm = ax0.streamplot(x,y, U, V, color=(.75,.90,.93))
strmS = ax0.streamplot(x,y, U, V, start_points=start, color="crimson", linewidth=2)
plt.show()

Python: Plotting errorbars in a loglog scale, in a loop and then saving the image

I have 58 files that I need to plot. Some of them are empty (not important, I already skipped them with the if condition). I need to plot the data in the files, using a loglog scale, with error bars. And I want to save the plots in the end.
I am using Python, spyder.
I have written the following code:
route='/......./'
L=np.arange (1,59, 1)
for i in range (L.shape[0]):
I=L[i]
name_sq= 'Spectra_without_quiescent_'+('{}'.format(I))+'.dat'
Q=np.loadtxt(route+name_sq)
if (len(Q) != 0):
x=Q[:,1]
y=Q[:,2]
z=Q[:,3]
fig=plt.errorbar(x,y,yerr=z, fmt = 'b')
fig.set_yscale('log')
fig.set_xscale('log')
xlabel='Frequency'
ylabel='Flux'
title='Spectrum_'+('{}'.format(I))+'.dat'
name='Spectrum_without_quiescent_'+('{}'.format(I))+'.pdf'
fig.savefig(route+name, fig)
however, when I run it, I get the following error:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.7/dist-packages/spyderlib/widgets/externalshell/sitecustomize.py", line 540, in runfile
execfile(filename, namespace)
File "/media/chidiac/My Passport/DOCUMENTS/My_Publications/2-3C273_radio_spectra/Maximum_flux_code.py", line 49, in <module>
fig.set_yscale('log')
AttributeError: 'ErrorbarContainer' object has no attribute 'set_yscale'
I am still a beginner in Python and I couldn't find the error, or how to fix it.
Any help is very appreciated.
This post may be a bit old, however I had the same problem and maybe this will help others in the future.
Your initial solution was actually almost correct. However, set_yscale is a method of the axes, not the figure. Thus your code in the if statement should look like:
import matplotlib.pyplot as plt
# other stuff you did ..
x=Q[:,1]
y=Q[:,2]
z=Q[:,3]
fig = plt.figure()
ax = plt.axes()
ax.set_xscale("log")
ax.set_yscale("log")
ax.errorbar(x,y,yerr=z, fmt = 'b')
ax.set_xlabel("Frequency")
ax.set_ylabel("Flux")
ax.set_title("Spectrum_{}.dat".format(I))
name="Spectrum_without_quiescent_{}.pdf".format(I)
plt.savefig(route+name)
Where I also adjusted your usage of the format function.
Note, that your second solution will not always work properly. If you have very small values and small errorbars the logarithm of these small values will get large (e.g. log(10^(-6)) = -6, as the logarithm to base 10 is used) and you will have huge errorbars though your actual error is small.
Long story short: Use ax.set_*scale. It's safe.
A friend of mine helped me with this issue and if someone is interested, here is the solution:
route='/....../'
L=np.arange (1,59, 1)
print L
for i in range (L.shape[0]):
I=L[i]
name_sq= 'Spectra_without_quiescent_'+('{}'.format(I))+'.dat'
Q=np.loadtxt(route+name_sq)
if (len(Q) != 0):
x=np.log(Q[:,1])
y=np.log(Q[:,2])
z=np.log(Q[:,3])
fig, ax = plt.subplots(facecolor='w', edgecolor='k')
plt.errorbar(x,y,yerr=z, fmt = 'b')
plt.ylabel('Flux', size='x-large')
plt.xlabel('Frequency', size='x-large')
title='Spectrum_'+('{}'.format(I))+'.dat'
name='Spectrum_without_quiescent_'+('{}'.format(I))+'.pdf'
pylab.savefig(route+name)
The first trick was, to first get the log values of the data and then plot them. Since I am not aware of any command that allows me to plot the errorbars in a logscale, I think this is the best solution.
The second trick was to use subplots. Otherwise, I got the 58 curves in one plot, 58 times.
I hope this solution is helpful.

(matpolotlib) ValueError: too many values to unpack

I am getting the following error when trying to display data values instead of markers:
Complete Traceback:
Traceback (most recent call last):
File "plotpoints.py", line 45, in <module>
plt.annotate(grid_x,grid_y)
File "/usr/lib/pymodules/python2.7/matplotlib/pyplot.py", line 3405, in annotate
ret = gca().annotate(*args, **kwargs)
File "/usr/lib/pymodules/python2.7/matplotlib/axes.py", line 3404, in annotate
a = mtext.Annotation(*args, **kwargs)
File "/usr/lib/pymodules/python2.7/matplotlib/text.py", line 1813, in __init__
annotation_clip=annotation_clip)
File "/usr/lib/pymodules/python2.7/matplotlib/text.py", line 1442, in __init__
x, y = self.xytext = xytext
ValueError: too many values to unpack
Code:
m = mapformat()
dx = 0.25
grid_x, grid_y = np.mgrid[-85:64:dx, 34:49:dx]
grid_z = griddata((data[:,1],data[:,0]), data[:,2], (grid_x,grid_y), method='linear')
x,y = m(data[:,1], data[:,0]) # flip lat/lon
grid_x,grid_y = m(grid_x,grid_y)
plt.annotate(grid_x,grid_y)
#m.plot(grid_x,grid_y, 'ko', markersize=2)
What am I doing wrong?
I don't think you are calling annotate correctly
plt.annotate(grid_x,grid_y)
That looks like 2 arrays or lists of points (I haven't fully deduced how you define those 2 variables).
But the documentation is:
ax.annotate('local max', xy=(3, 1), ...)
The 1st argument is the text and the second a tuple with the coordinates.
I'm guessing that the calling sequence converts your xgrid argument to mtext, and ygrid to its xytext
x, y = self.xytext = xytext
If there are more than 2 values in ygrid, this unpacking will produce your error.
annotate adds text at a specific point on the plot; it can't be used to label the coordinates of a bunch of data points (at least not in one call).
One of the functions that you're calling on the right is returning more values than there are variables to assign to on the left.
For example, if you do the following in a REPL:
a,b = [1,2,3]
You'll get the following error:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: too many values to unpack
It'll help to see which line the code is failing at - this way, you'll know which function is returning too many variables.

Trying to create a masked timeslice but returns AttributeError: 'numpy.ndarray' object has no attribute 'dim_coords' whent trying to do an iris plot

I am trying to create a contour plot showing annual dissolved iron concentrations for the years to 1860-1900 and am trying to exclude all values above a certain amount (0.000012) because these relate to a specific region which is throwing my data off.
Below is the script I am using, and each individual part works (before this I have of course imported all the relevant modules).
dissolved_iron = iris.load_cube('/home/em379/data/dis2/regriddedfiles/HadGEM2-ES_dfe_piControl_r1i1p1_regridded.nc')
dissolved_iron_timeslice = dissolved_iron.extract(iris.Constraint(time = lambda v: 1860 <= v <= 1900))
masked_dissolved_iron_timeslice = ma.masked_greater(dissolved_iron_timeslice.data, 0.000012)
qplt.contourf(masked_dissolved_iron_timeslice,25)
plt.show(block = False)
When I get to the step qplt.contourf(masked_dissolved_iron_timeslice,25), Python returns the error:
AttributeError: 'numpy.ndarray' object has no attribute 'dim_coords':
>>> qplt.contourf(masked_dissolved_iron_timeslice,25)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python2.7/dist-packages/Iris-1.7.0_dev-py2.7.egg/iris/quickplot.py", line 184, in contourf
result = iplt.contourf(cube, *args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/Iris-1.7.0_dev-py2.7.egg/iris/plot.py", line 579, in contourf
result = _draw_2d_from_points('contourf', None, cube, *args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/Iris-1.7.0_dev-py2.7.egg/iris/plot.py", line 275, in _draw_2d_from_points
plot_defn = _get_plot_defn(cube, mode, ndims=2)
File "/usr/local/lib/python2.7/dist-packages/Iris-1.7.0_dev-py2.7.egg/iris/plot.py", line 127, in _get_plot_defn
for dim_coord in cube.dim_coords:
AttributeError: 'MaskedArray' object has no attribute 'dim_coords'
The error gives us a clue as to what is going on:
AttributeError: 'MaskedArray' object has no attribute 'dim_coords'
This to me reads: "you're trying to do a cube thing with a MaskedArray".
So, looking at your code, that is indeed the case:
masked_dissolved_iron_timeslice = \
ma.masked_greater(dissolved_iron_timeslice.data, 0.000012)
masked_dissolved_iron_timeslice is now a numpy masked array not an iris cube. The solution, if you just want to look at your data, is to change from using iris' plotting functionality, to using matplotlib's:
# Use plt, not qplt:
plt.contourf(masked_dissolved_iron_timeslice, 25)
plt.show()
Of course, if you want a little more context (and to maintain a cube) you can update the existing cube's data with:
dissolved_iron_timeslice = ...
dissolved_iron_timeslice.data = \
ma.masked_greater(dissolved_iron_timeslice.data, 0.000012)
Or if you don't want to modify the existing cube:
dissolved_iron_timeslice = ...
ma_iron_t = dissolved_iron_timeslice.copy()
ma_iron_t.data = \
ma.masked_greater(dissolved_iron_timeslice.data, 0.000012)
With these cubes, you can continue to use qplt and get the automatic labelling/colorbar/colormap/title goodness that Iris provides.
HTH

Categories

Resources