Related
I am able to plot the stair-step like plot as attached using the below code
import numpy as np
from scipy.interpolate import interp1d
import matplotlib.pyplot as plt
x = np.array([3.45, 3.88, 3.99, 4.33])
y = np.array([14.0, 11.0, 14.0, 31.0])
y = np.cumsum(y)
y0 = np.array([0])
x0 = np.interp([0], y, x)
x = np.concatenate([x0, x])
y = np.concatenate([y0, y])
# Plot
fig, ax = plt.subplots()
ax.step(x, y, color='r', where='post')
ax.set_xlim(2, 5)
ax.set_ylim(0, y.max())
ax.invert_yaxis()
plt.show()
#####################################################
Now I need to generate more data points of x and y using interpolation function and want to generate same plot as above code produced(depicted above). I tried the below mentioned code but it produces different plot(depicted below), But definition says after interpolation, we should have the same plot, we just have more data points.
import numpy as np
from scipy.interpolate import interp1d
import matplotlib.pyplot as plt
x = np.array([3.45, 3.88, 3.99, 4.33])
y = np.array([14.0, 11.0, 14.0, 31.0])
y = np.cumsum(y)
y0 = np.array([0])
x0 = np.interp([0], y, x)
x = np.concatenate([x0, x])
y = np.concatenate([y0, y])
# I need to generate more data points
NUM = 100 # modify the number of points
funct = interp1d(x, y, kind='next')
x_cont = np.linspace(x[0], x[-1], NUM)
y_cont = funct(x_cont)
# Plot
fig, ax1 = plt.subplots()
ax1.step(x_cont, y_cont, color='r', where='post')
ax1.set_xlim(2, 5)
ax1.set_ylim(0, y.max())
ax1.invert_yaxis()
plt.show()
Update
IIUC, now you want the points where line changes direction. So you can use np.repeat
# Original data
x = np.array([3.45, 3.88, 3.99, 4.33])
y = np.array([14.0, 11.0, 14.0, 31.0])
y = np.cumsum(y)
# Find breakpoints
x_cont = np.hstack([x[0], np.repeat(x, 2)[1:]])
y_cont = np.hstack([0, np.repeat(y, 2)[:-1]])
# Plot
fig, ax = plt.subplots()
ax.scatter(x_cont, y_cont, marker='.', color='blue')
ax.plot(x_cont, y_cont, color='red')
ax.set_xlim(2, 5)
ax.set_ylim(0, y.max())
ax.invert_yaxis()
plt.show()
Output:
>>> x_cont
array([3.45, 3.45, 3.88, 3.88, 3.99, 3.99, 4.33, 4.33])
>>> y_cont
array([ 0., 14., 14., 25., 25., 39., 39., 70.])
Old answer
You want to increase the number of points for each step. You can use a custom function to interpolate values from (x1, y1) to (x2, y1) then from (x2, y1) to (x2, y2). It means you compute x points first then y. The function take 3 couple of parameters and the step size:
x, y: your intermediate step points (your two arrays x and y)
x0, y0: start coords (here you have to specify y=0 because it does not appear in your data)
xn, yn: end coords (here you can reuse the last value of x and y arrays)
step: the step size (we approximate the value to have points evenly spaced)
def interpolate(x, y, x0, y0, xn, yn, step):
# create arrays with all points
x = np.hstack([x0, x, xn])
y = np.hstack([y0, y, yn])
x_cont = []
y_cont = []
# get points pairwise
for x1, x2, y1, y2 in zip(x, x[1:], y, y[1:]):
# approximate the number of samples per segment
numx = int(np.abs(x2 - x1) / step)
numy = int(np.abs(y2 - y1) / step)
# x-first (left or right move)
a = np.linspace(x1, x2, numx, endpoint=False)
b = np.repeat(y1, numx)
# y-second (top or down move)
c = np.repeat(x2, numy)
d = np.linspace(y1, y2, numy, endpoint=False)
# save points
x_cont.append([*a, *c])
y_cont.append([*b, *d])
# flat all computed values
return np.hstack([*x_cont, xn]), np.hstack([*y_cont, yn])
# Original data
x = np.array([3.45, 3.88, 3.99, 4.33])
y = np.array([14.0, 11.0, 14.0, 31.0])
y = np.cumsum(y) # It seems you want the cumulative sum of y
x_cont, y_cont = interpolate(x, y, x[0], 0, x[-1], y[-1], step=0.1)
Plot the values:
fig, ax = plt.subplots()
ax.step(x_cont, y_cont, color='red', where='post')
ax.set_xlim(2, 5)
ax.set_ylim(0, y.max())
ax.invert_yaxis()
plt.show()
Output:
It seems like you are looking for a function that takes as input a number of pivots p and the number of points n to put in the horizontal and vertical straight lines connecting those pivots. I assume that you want the extra points to be evenly (linearly) spaced.
Essentially, you need to:
identify the pivot points
ensure the len(p) <= n
use repeated values for x and linearly spaced values for y when the lines are vertical
use repeated values for y and linearly spaced values for x when the lines are horizontal
A simple implementation using NumPy (and specifically np.linspace() and np.repeat()) could be:
import typing as typ
import numpy as np
def upscale_steps_equi(
p_x: typ.Sequence[float],
p_y: typ.Sequence[float],
n: int,
start_hor: typ.Optional[str] = None,
dtype: np.dtype = np.float_,
):
"""
The points are equi-spaced (except near the pivots).
The pivots are, in general, not included.
Args:
p_x: Must be strictly monotonic increasing.
p_y: Must be strictly monotonic increasing.
n: Must be larger than max(len(p_x), len(p_y))
start_hor: Must be True for horizontal, False for vertical.
Only used (and needed) if len(p_x) == len(p_y)
"""
p_x_n = len(p_x)
p_y_n = len(p_y)
is_same_len = p_x_n == p_y_n
p_n = max(p_x_n, p_y_n) + 1 # number of points
if p_x_n > p_y_n:
start_hor = True
elif p_x_n < p_y_n:
start_hor = False
elif start_hor is None or not isinstance(start_hor, bool):
raise ValueError("`start_hor` required if len(p_x) == len(p_y)")
p_x_ = np.repeat(p_x, 2) # x-coords of pivots
p_y_ = np.repeat(p_y, 2) # y-coords of pivots
if is_same_len:
if start_hor:
p_x_ = p_x_[1:]
p_y_ = p_y_[:-1]
else:
p_x_ = p_x_[:-1]
p_y_ = p_y_[1:]
else:
if start_hor:
p_x_ = p_x_[1:-1]
else:
p_y_ = p_y_[1:-1]
dx = max(p_x) - min(p_x) # distance covered along x
dy = max(p_y) - min(p_y) # distance covered along y
d = dx + dy
ll = np.linspace(0, d, n, endpoint=True)
x = min(p_x) + ll
y = min(p_y) + ll
last_x_ = last_y_ = last_d_ = None
d_ = d_x_ = d_y_ = 0
for x_, y_ in zip(p_x_, p_y_):
if x_ == last_x_:
dd_y_ = y_ - last_y_
d_y_ += dd_y_
d_ += dd_y_
mask = (ll >= last_d_) & (ll < d_)
x[mask] = x_
y[mask] -= d_x_
elif y_ == last_y_:
dd_x_ = x_ - last_x_
d_x_ += dd_x_
d_ += dd_x_
mask = (ll >= last_d_) & (ll < d_)
y[mask] = y_
x[mask] -= d_y_
last_x_ = x_
last_y_ = y_
last_d_ = d_
x[-1] = p_x[-1]
y[-1] = p_y[-1]
return x, y
to be used like:
import matplotlib.pyplot as plt
x, y = upscale_steps_equi([1, 4, 5], [2, 3, 7, 9], 20)
plt.scatter(x, y, marker='o')
plt.axis('scaled')
The function above does not, in general, include the pivots.
However, if the pivots must be included, one needs to forego the exact number of points and the same spacing for x and y.
Here is a possible solution where the points are equi-spaced within each segment:
import typing as typ
import numpy as np
def upscale_steps_with_pivots(
p_x: typ.Sequence[float],
p_y: typ.Sequence[float],
n: int,
start_hor: typ.Optional[bool] = None,
dtype: np.dtype = np.float_,
):
"""
The points are equi-spaced only within each segment.
The pivots are strictly included.
Args:
p_x: Must be strictly monotonic increasing.
p_y: Must be strictly monotonic increasing.
n: Must be larger than max(len(p_x), len(p_y))
start_hor: Must be `h` for horizontal, `v` for vertical.
Only used (and needed) if len(p_x) == len(p_y)
"""
p_x_n = len(p_x)
p_y_n = len(p_y)
is_same_len = p_x_n == p_y_n
p_n = max(p_x_n, p_y_n) + 1 # number of points
if p_x_n > p_y_n:
start_hor = True
elif p_x_n < p_y_n:
start_hor = False
elif start_hor is None or not isinstance(start_hor, bool):
raise ValueError("`start_hor` required if len(p_x) == len(p_y)")
p_x_ = np.repeat(p_x, 2) # x-coords of pivots
p_y_ = np.repeat(p_y, 2) # y-coords of pivots
if is_same_len:
if start_hor:
p_x_ = p_x_[1:]
p_y_ = p_y_[:-1]
else:
p_x_ = p_x_[:-1]
p_y_ = p_y_[1:]
else:
if start_hor:
p_x_ = p_x_[1:-1]
else:
p_y_ = p_y_[1:-1]
dx = max(p_x) - min(p_x) # distance covered along x
dy = max(p_y) - min(p_y) # distance covered along y
d = dx + dy
n_x = (np.diff(p_x) / d * (n - p_n)).astype(np.int_)
n_y = (np.diff(p_y) / d * (n - p_n)).astype(np.int_)
r = np.ones(len(n_x) + len(n_y) + 1, dtype=np.int_)
if start_hor:
r[:-1 if is_same_len else None:2] = n_x + 1
r[1:-1:2] = n_y + 1
else:
r[:-1 if is_same_len else None:2] = n_y + 1
r[1:-1:2] = n_x + 1
x = np.repeat(p_x_, r).astype(dtype)
y = np.repeat(p_y_, r).astype(dtype)
j = 0
for i, r_ in enumerate(r[:-1]):
if i % 2 != start_hor:
k = np.linspace(p_x_[i], p_x_[i + 1], r_, endpoint=False)
x[j : j + len(k)] = k
else:
k = np.linspace(p_y_[i], p_y_[i + 1], r_, endpoint=False)
y[j : j + len(k)] = k
j += r_
return x, y
to be used like:
import matplotlib.pyplot as plt
x, y = upscale_steps_with_pivots([1, 4, 5], [2, 3, 7, 9], 20)
plt.scatter(x, y, marker='o')
plt.axis('scaled')
(Note that until the computation of d, the two functions are identical, and it mostly contain the logic to deal with the different possible configurations of segments.)
This line
funct = interp1d(x, y, kind='next')
needs to be changed in
funct = interp1d(x, y, kind='previous')
This because you want values in [3.99, 4.33] (e.g.) to refer to the cumsum-value of 3.99, which is ~40 (previous) instead of values related to 4.33 which is ~70 (next).
I am working on a image unfolding assignment, in my program, I using glob to read multiple images from my pc, and after that after the program unfolded my image, I want to save it in another directory at once, but when I run the program, every new save image will overwrite or replace the previous image, I had try different way to solve it, but all of them failed. Please help me to solve, I will be very thankful for any assistance.
Here is my code:
import matplotlib.pyplot as plt
import numpy as np
import scipy as sp
import scipy.ndimage
from PIL import Image
#import cv2
import matplotlib
import glob
images = glob.glob(r'D:\Master of FOE\pythonProject\Program\Dataset\For New Training\NORMAL IMAGE\GOOD\*.png')
thumb_width = 200
Unfolded_image=[]
def main():
for im in images:
im = Image.open(im)
im = im.convert('RGB')
data = np.array(im)
print('Data',data.shape,im.size)
ch0=np.array(im.getchannel(0))
ch0 = np.where(ch0 > 0, 1, 0)
ch1=np.array(im.getchannel(1))
ch1 = np.where(ch1 > 0, 1, 0)
ch2=np.array(im.getchannel(2))
ch2 = np.where(ch2 > 0, 1, 0)
dt0 = np.where(((ch2+ch1+ch0) > 0), 1, 0).T
print('DTTT',dt0.shape)
tx=0
ty=0
for xx in range(im.width):
for yy in range(im.height):
tx+=xx*dt0[xx][yy]
ty+=yy*dt0[xx][yy]
ts = np.sum(dt0)
txc=tx/ts
tyc=ty/ts
rr=max(im.width,im.height)
for xx in range(im.width):
for yy in range(im.height):
if dt0[xx][yy]==0:
r=np.sqrt((xx -txc)** 2 + (yy-tyc) ** 2)
if r<rr:
rr=r
print('RSRS',rr)
rm=rr
print('RRR',rm)
print('Center',txc,tyc)
print('DT0',dt0)
print(11, data[0])
image = plot_polar_image(data, rm, origin=(txc, tyc))
Unfolded_image.append(image)
for i in enumerate(Unfolded_image):
plt.axis('off')
plt.savefig(r'D:\Master of FOE\pythonProject\Program\Dataset\For New Training\UNFOLLDED IMAGE\UNFOLDED_GOOD\UG{0}.png'.format(i), bbox_inches='tight', transparent=True, pad_inches=0)
def plot_polar_image(data, rm,origin=None):
polar_grid, r, theta = reproject_image_into_polar(data,rm, origin)
plt.imshow(polar_grid, extent=(theta.min(), theta.max(), r.max(), r.min()))
plt.axis('auto')
def index_coords(data, origin=None):
ny, nx = data.shape[:2]
if origin is None:
origin_x, origin_y = nx // 2, ny // 2
else:
origin_x, origin_y = origin
x, y = np.meshgrid(np.arange(nx), np.arange(ny))
x=x.astype('float64')
y=y.astype('float64')
x -= origin_x
y -= origin_y
print(999,x,y)
return x, y
def cart2polar(x, y):
r = np.sqrt(x**2 + y**2)
print('RR',r)
theta = np.arctan2(y, x)
print(33,r,theta)
return r, theta
def polar2cart(r, theta):
x = r * np.cos(theta)
y = r * np.sin(theta)
return x, y
def bin_by(x, y, nbins=30):
bins = np.linspace(y.min(), y.max(), nbins+1)
bins[-1] += 1
indicies = np.digitize(y, bins)
output = []
for i in range(1, len(bins)):
output.append(x[indicies==i])
bins = bins[:-1]
return output, bins
def reproject_image_into_polar(data,rm, origin=None):
print(22,data.shape)
nn=data.shape[:2]
ny=nx=min(nn)
if origin is None:
origin = (nx//2, ny//2)
rmin=min(nx-origin[0],origin[0],nx//2,ny-origin[1],origin[1],ny//2)
x, y = index_coords(data, origin=origin)
r, theta = cart2polar(x, y)
print(111,r.min(),r.max())
r_i = np.linspace(min(0,r.min(),rm), min(r.max(),rmin), nx)
print(222,theta.min(), theta.max())
theta_i = np.linspace(-np.pi,np.pi, ny)
theta_grid, r_grid = np.meshgrid(theta_i, r_i)
print(66,theta_grid,r_grid)
xi, yi = polar2cart(r_grid, theta_grid)
xi += origin[0]
yi += origin[1]
xi, yi = xi.flatten(), yi.flatten()
print(99,xi,yi)
coords = np.vstack((xi, yi))
print(55,coords)
bands = []
print(88,data.shape)
print(77,data.T.shape)
for band in data.T:
print(44,band)
zi = sp.ndimage.map_coordinates(band, coords, order=1)
bands.append(zi.reshape((nx, ny)))
output = np.dstack(bands)
return output, r_i, theta_i
if __name__ == '__main__':
main()
I am expecting a program that can successfully read, process and save my images, please fo me a favor, it will be very meaningful for me!
I was trying to an example of the book -"Dynamical Systems with Applications using Python" and I was asked to plot the phase portrait of Verhulst equation, then I came across this post: How to plot a phase portrait of Verhulst equation with SciPy (or SymPy) and Matplotlib?
I'm getting the same plot as the user on the previous post. Whenever, I try to use the accepted solution I get a "division by zero" error. Why doesn't the accepted solution in How to plot a phase portrait of Verhulst equation with SciPy (or SymPy) and Matplotlib? works?
Thank you very much for you help!
Edit:
Using the code from the previous post and the correction given by #Lutz Lehmann
beta, delta, gamma = 1, 2, 1
b,d,c = 1,2,1
C1 = gamma*c-delta*d
C2 = gamma*b-beta*d
C3 = beta*c-delta*b
def verhulst(X, t=0):
return np.array([beta*X[0] - delta*X[0]**2 -gamma*X[0]*X[1],
b*X[1] - d*X[1]**2 -c*X[0]*X[1]])
X_O = np.array([0., 0.])
X_R = np.array([C2/C1, C3/C1])
X_P = np.array([0, b/d])
X_Q = np.array([beta/delta, 0])
def jacobian(X, t=0):
return np.array([[beta-delta*2*X[0]-gamma*X[1], -gamma*x[0]],
[b-d*2*X[1]-c*X[0], -c*X[1]]])
values = np.linspace(0.3, 0.9, 5)
vcolors = plt.cm.autumn_r(np.linspace(0.3, 1., len(values)))
f2 = plt.figure(figsize=(4,4))
for v, col in zip(values, vcolors):
X0 = v * X_R
X = odeint(verhulst, X0, t)
plt.plot(X[:,0], X[:,1], color=col, label='X0=(%.f, %.f)' % ( X0[0], X0[1]) )
ymax = plt.ylim(ymin=0)[1]
xmax = plt.xlim(xmin=0)[1]
nb_points = 20
x = np.linspace(0, xmax, nb_points)
y = np.linspace(0, ymax, nb_points)
X1, Y1 = np.meshgrid(x, y)
DX1, DY1 = verhulst([X1, Y1]) # compute growth rate on the gridt
M = (np.hypot(DX1, DY1)) # Norm of the growth rate
M[M == 0] = 1. # Avoid zero division errors
DX1 /= M # Normalize each arrows
DY1 /= M
plt.quiver(X1, Y1, DX1, DY1, M, cmap=plt.cm.jet)
plt.xlabel('Number of Species 1')
plt.ylabel('Number of Species 2')
plt.legend()
plt.grid()
We have:
That is still different from:
What am I missing?
With the help of #Lutz Lehmann I could rewrite the code to get want I needed.
The solutions is something like this:
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(8, 4), dpi= 80, facecolor='whitesmoke', edgecolor='k')
beta, delta, gamma = 1, 2, 1
b,d,c = 1,2,1
t = np.linspace(0, 10, 100)
C1 = gamma*c-delta*d
C2 = gamma*b-beta*d
C3 = beta*c-delta*b
def verhulst(X, t=0):
return np.array([beta*X[0] - delta*X[0]**2 -gamma*X[0]*X[1],
b*X[1] - d*X[1]**2 -c*X[0]*X[1]])
X_O = np.array([0., 0.])
X_R = np.array([C2/C1, C3/C1])
X_P = np.array([0, b/d])
X_Q = np.array([beta/delta, 0])
def jacobian(X, t=0):
return np.array([[beta-delta*2*X[0]-gamma*X[1], -gamma*x[0]],
[b-d*2*X[1]-c*X[0], -c*X[1]]])
values = np.linspace(0.05, 0.15, 5)
vcolors = plt.cm.autumn_r(np.linspace(0.3, 1., len(values)))
for v, col in zip(values, vcolors):
X0 = [v,0.2-v]
X = odeint(verhulst, X0, t)
plt.plot(X[:,0], X[:,1], color=col, label='X0=(%.f, %.f)' % ( X0[0], X0[1]) )
for v, col in zip(values, vcolors):
X0 = [6 * v, 6 *(0.2-v)]
X = odeint(verhulst, X0, t)
plt.plot(X[:,0], X[:,1], color=col, label='X0=(%.f, %.f)' % ( X0[0], X0[1]) )
ymax = plt.ylim(ymin=0)[1]
xmax = plt.xlim(xmin=0)[1]
nb_points = 20
x = np.linspace(0, xmax, nb_points)
y = np.linspace(0, ymax, nb_points)
X1, Y1 = np.meshgrid(x, y)
DX1, DY1 = verhulst([X1, Y1]) # compute growth rate on the gridt
M = (np.hypot(DX1, DY1)) # Norm of the growth rate
M[M == 0] = 1. # Avoid zero division errors
DX1 /= M # Normalize each arrows
DY1 /= M
plt.quiver(X1, Y1, DX1, DY1, M, cmap=plt.cm.jet)
plt.xlabel('Number of Species 1')
plt.ylabel('Number of Species 2')
plt.grid()
We get what we were looking for:
Finally, I would like to thank again #Lutz Lehnmann for the help. I wouldn't have solved without it him.
Edit 1:
I forgot $t = np.linspace(0, 10, 100)$ and if you change figsize = (8,8), we get a nicer shape in the plot. (Thank you #Trenton McKinney for the remarks)
I don't know that how make the code the three graph in damping harmonic oscillation model,
[X - t(time)], [V(velocity) - t(time)], [a(acceleration) - t(time)] graph
i can make the [X - t(time)] graph
but i don`t know how to make another graphs..
import numpy as np
from matplotlib import pyplot as plt
# mx'' = - bx' - kx
x_0 = 3
v_0 = 0
y_0 = np.array([x_0,v_0]) # first array
def Euler_Method(f,a,b,y0,step):
t = np.linspace(a,b,step)
h = t[1] - t[0]
Y = [y0]
N = len(t)
n = 0
y = y0
for n in range(0,N-1) :
y = y + h*f(y,t[n])
Y.append(y)
n = n+1
Y = np.array(Y)
return Y, t
def harmonic(y,t) :
k = 50
m = 200
b = 20 # drag coefficient
a = (-1*k/m)*y[0] - (b/m)*y[1] # x'' = a, y[0] : first position
v = y[1] # v = first velocity : y[1]
f = np.array([v,a])
return f
a = Euler_Method(harmonic, 0, 100, y_0, 100000)
X = a[0][:,0]
t = a[1]
plt.plot(t,X)
plt.show()
Why can't you just take the derivative of X to get V and A?
V = np.diff(X)
A = np.diff(V)
fig, (ax1, ax2, ax3) = plt.subplots(3)
fig.suptitle('Vertically stacked subplots')
ax1.plot(t, X)
ax2.plot(t[1:], V)
ax3.plot(t[2:], A)
plt.show()
Gives,
Using a 2d matrix in python, how can I create a 3d surface plot, where columns=x, rows=y and the values are the heights in z?
I can't understand how to creat 3D surface plot using matplotlib.
Maybe it's different from MatLab.
example:
from pylab import *
from mpl_toolkits.mplot3d import Axes3D
def p(eps=0.9, lmd=1, err=10e-3, m=60, n=40):
delta_phi = 2 * np.pi / m
delta_lmd = 2 / n
k = 1
P0 = np.zeros([m + 1, n + 1])
P = np.zeros([m + 1, n + 1])
GAP = 1
while GAP >= err:
k = k + 1
for i in range(0, m):
for j in range(0, n):
if (i == 1) or (j == 1) or (i == m + 1) or (i == n + 1):
P[i,j] = 0
else:
A = (1+eps*np.cos((i+1/2)*delta_phi))**3
B = (1+eps*np.cos((i-1/2)*delta_phi))**3
C = (lmd*delta_phi/delta_lmd)**2 * (1+eps*np.cos((i)*delta_phi))**3
D = C
E = A + B + C + D
F = 3*delta_phi*((1+eps*np.cos((i+1/2)*delta_phi))-(1+eps*np.cos((i-1/2)*delta_phi)))
P[i,j] = (A*P[i+1,j] + B*P[i-1,j] + C*P[i,j+1] + D*P[i,j-1] - F)/E
if P[i,j] < 0:
P[i,j] = 0
S = P.sum() - P0.sum()
T = P.sum()
GAP = S / T
P0 = P.copy()
return P, k
def main():
start = time.time()
eps = 0.9
lmd = 1
err = 10e-8
m = 60
n = 40
P, k = p()
fig = figure()
ax = Axes3D(fig)
X = np.linspace(0, 2*np.pi, m+1)
Y = np.linspace(-1, 1, n+1)
X, Y = np.meshgrid(X, Y)
#Z = P[0:m, 0:n]
#Z = Z.reshape(X.shape)
ax.set_xticks([0, np.pi/2, np.pi, np.pi*1.5, 2*np.pi])
ax.set_yticks([-1, -0.5, 0, 0.5, 1])
ax.plot_surface(X, Y, P)
show()
if __name__ == '__main__':
main()
ValueError: shape mismatch: objects cannot be broadcast to a single
shape
And the pic
pic by matplotlic
And I also use MatLab to generate,the pic:
pic by MatLab
I should think this is a problem of getting the notaton straight. A m*n matrix is a matrix with m rows and n columns. Hence Y should be of length m and X of length n, such that after meshgridding X,Y and P all have shape (m,n).
At this point there would be no need to reshape of reindex and just plotting
ax.plot_surface(X, Y, P)
would give your the desired result.
Let's assume if you have a matrix mat.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits import mplot3d
h, w = mat.shape
plt.figure(figsize=(16, 8))
ax = plt.axes(projection='3d')
X, Y = np.meshgrid(np.arange(w), np.arange(h))
ax.plot_surface(X, Y, mat, rstride=1, cstride=1, cmap='viridis', edgecolor='none', antialiased=False)