Problem regarding axis shape in 3d surface plot in python - 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

Related

TypeError: unhashable type 'numpy.ndarray' followed by SympifyError

I am following the steps on https://www.sympy.org/scipy-2017-codegen-tutorial/notebooks/22-lambdify.html in order to produce a plot of a surface. The example shown on the link works perfectly to me.
Now, the problem appears to me when trying to produce a plot of my own: I define my functions also making use of lambdify and, as far as I am concerned, following the same steps as in the link mentioned before. Here is my code:
import numpy as np
import plotly.graph_objects as go # for the surface
import sympy as sym
sym.init_printing()
## definition of the surface and its normal unitary field
u,v = sym.symbols('u v') # we define the symbols
surface_expr = -sym.sqrt(1-u**2-v**2) # expresion for the surface
surface = sym.lambdify([u,v], surface_expr, modules = ['sympy']) # symbolic surface
## plot the surface
uplot = np.outer(np.linspace(-0.5, 0.5, 100), np.ones(100)) # plotting mesh
vplot = uplot.T
zplot = surface(uplot,vplot) # z value over the mesh
colorscale = 'oryel' # color scale for the surface plot
fig = go.Figure() # this creates the figure object
fig.add_surface(x=uplot, y=vplot, z=zplot, colorscale = colorscale) # we add a surfaceplot to it
fig.update_traces(showscale=False)
When running this code, I get the following error:
TypeError Traceback (most recent call last)
File ~/opt/anaconda3/lib/python3.9/site-packages/sympy/core/cache.py:70, in __cacheit.<locals>.func_wrapper.<locals>.wrapper(*args, **kwargs)
69 try:
---> 70 retval = cfunc(*args, **kwargs)
71 except TypeError as e:
TypeError: unhashable type: 'numpy.ndarray'
During handling of the above exception, another exception occurred:
SympifyError Traceback (most recent call last)
/Users/jzaragoza/PhD/Codes/offset_surface.ipynb Cell 4 in <cell line: 5>()
3 uplot = np.outer(np.linspace(-0.5, 0.5, 100), np.ones(100)) # plotting mesh
4 vplot = uplot.T
----> 5 zplot = surface(uplot,vplot) # z value over the mesh
7 colorscale = 'oryel' # color scale for the surface plot
10 fig = go.Figure() # this creates the figure object
File <lambdifygenerated-1>:2, in _lambdifygenerated(u, v)
1 def _lambdifygenerated(u, v):
----> 2 return -sqrt(-u**2 - v**2 + 1)
File ~/opt/anaconda3/lib/python3.9/site-packages/sympy/functions/elementary/miscellaneous.py:154, in sqrt(arg, evaluate)
70 """Returns the principal square root.
...
0.5197939 ],
[0.50999898, 0.51999796, 0.52979288, ..., 0.52979288, 0.51999796,
0.50999898],
[0.5 , 0.50999898, 0.5197939 , ..., 0.5197939 , 0.50999898,
0.5 ]])
You can finde an image of the error here
Anyone knows why this happens and/or how to fix it and make it work? Thank you in advance!!!
PS: number lines in the error message do not match with the lines of code posted here since my actual code has more lines but they are not relevant for the question.
The problem is this line:
surface = sym.lambdify([u,v], surface_expr, modules = ['sympy'])
here, you have created a lambda function that will be evaluated by SymPy. Then, with zplot = surface(uplot,vplot) you are passing in Numpy arrays, but SymPy doesn't know what to do with them.
Instead, you should create a lambda function that will be evaluated with Numpy/Scipy:
surface = sym.lambdify([u,v], surface_expr)
Now, everything will work as expected.
EDIT: if you want to create plots of symbolic expressions with Plotly, I suggest to take a look at this module, SymPy Plot Backends. Then, you can simply write:
from spb import *
plot3d(surface_expr, (u, -0.5, 0.5), (v, -0.5, 0.5), backend=PB, use_cm=True)

Python Plotting Combine 2 Plots

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

TypeError: Label image must be of integral type

I would like to detect some circles (circle like cells) in an image, and then measure the greenness (number of green pixel?) in each circle.
I am using this discussion with the following code:
from skimage import io, color, measure, draw, img_as_bool
import numpy as np
from scipy import optimize
import matplotlib.pyplot as plt
image = img_as_bool(color.rgb2gray(io.imread('0.06_3a.jpg')))
regions = measure.regionprops(image)
bubble = regions[0]
y0, x0 = bubble.centroid
r = bubble.major_axis_length / 2.
def cost(params):
x0, y0, r = params
coords = draw.circle(y0, x0, r, shape=image.shape)
template = np.zeros_like(image)
template[coords] = 1
return -np.sum(template == image)
x0, y0, r = optimize.fmin(cost, (x0, y0, r))
import matplotlib.pyplot as plt
f, ax = plt.subplots()
circle = plt.Circle((x0, y0), r)
ax.imshow(image, cmap='gray', interpolation='nearest')
ax.add_artist(circle)
plt.show()
I get the following error:
/home/mahsa/anaconda3/lib/python3.6/site-packages/skimage/util/dtype.py:118: UserWarning: Possible sign loss when converting negative image of type float64 to positive image of type bool.
.format(dtypeobj_in, dtypeobj_out))
/home/mahsa/anaconda3/lib/python3.6/site-packages/skimage/util/dtype.py:122: UserWarning: Possible precision loss when converting from float64 to bool
.format(dtypeobj_in, dtypeobj_out))
Traceback (most recent call last):
File "img.py", line 28, in <module>
regions = measure.regionprops(image)
File "/home/mahsa/anaconda3/lib/python3.6/site-packages/skimage/measure/_regionprops.py", line 539, in regionprops
raise TypeError('Label image must be of integral type.')
TypeError: Label image must be of integral type.
What does this error mean and what should i do to fix it?
After fixing this error, how do i loop through all the pixels in each region to count the green pixels?
Thank you very much for your help
The error occurs here:
regions = measure.regionprops(image)
Apparently regionprops() requires its argument to have an integer data type. You created image with
image = img_as_bool(color.rgb2gray(io.imread('0.06_3a.jpg')))
which means that the data type of image is bool. bool is not a subtype of np.integer, so regionprops complains.
A quick fix that you can try is:
regions = measure.regionprops(image.astype(int))
but you should probably rethink the way you created image. Why did you use img_as_bool()?

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()

Plotting asymmetric error bars for a single point using errorbar

Goal: To plot asymmetric x error bars for a single point using errorbar. I want to display the inter quartile range (IQR) for a data set.
Code:
import numpy as np
import matplotlib.pyplot as plt
y = 1.0
data = np.random.rand(100)
median = np.median(data)
upper_quartile = np.percentile(data, 75)
lower_quartile = np.percentile(data, 25)
IQR = upper_quartile - lower_quartile
plt.errorbar(median, y, xerr=[lower_quartile ,upper_quartile], fmt='k--')
plt.savefig('IQR.eps')
plt.show()
Error:
Traceback (most recent call last):
File "IQR.py", line 15, in <module>
plt.errorbar(median, y, xerr=[0.5,0.75], fmt='k--')
File "/usr/lib/pymodules/python2.7/matplotlib/pyplot.py", line 2251, in errorbar
ret = ax.errorbar(x, y, yerr, xerr, fmt, ecolor, elinewidth, capsize, barsabove, lolims, uplims, xlolims, xuplims, **kwargs)
File "/usr/lib/pymodules/python2.7/matplotlib/axes.py", line 5327, in errorbar
in cbook.safezip(x,xerr)]
File "/usr/lib/pymodules/python2.7/matplotlib/cbook.py", line 1294, in safezip
raise ValueError(_safezip_msg % (Nx, i+1, len(arg)))
ValueError: In safezip, len(args[0])=1 but len(args[1])=2
My issue is that I am unable to create asymmetric error bars for a single point, where the point will represent the mean and the upper and lower limits of the error bars will be the upper and lower quartile.
I typically use vlines or hlines for this (I think the caps are just distracting):
plt.hlines( y, median-lower_quartile, median+upper_quartile)
plt.plot(median, y, 'o')
If you still want to use errorbar, you can try
plt.errorbar(median, y, xerr=np.array([[lower_quartile ,upper_quartile]]).T,
fmt='ko')
Note that I don't really know how you define your quartiles here, so you may need to make sure you get the right numbers in!!!
Make sure xerr gets a list of lists. If it's only one list, it'll assume it contains symmetrical error bars for two Y's. But there's only one Y, which is why you get the error.
Also your errorbars are wrong. Change the errorbar call to
plt.errorbar(median, y, xerr=[[median-lower_quartile ,upper_quartile-median]], fmt='k--')
The two arguments you're passing to safezip are of different sizes. The stacktrace you posted says so right here:
ValueError: In safezip, len(args[0])=1 but len(args[1])=2
What that's saying is argument one's length is 1 but argument two's length is 2, so zip can't actually combine those two lists.

Categories

Resources