简体   繁体   中英

Smooth surface Plot with Pyplot

My question is almost similar to this on: smoothing surface plot from matrix

only that my toolset is matplotlib and numpy (so far).

I have sucessfully generated a X, Y and Z-grid to plot with

fig = plt.figure(figsize=(12,12))
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(X, Y, Z, cmap='summer', rstride=1, cstride=1, alpa=None)

However, as the values are quite jumpy, it looks terribly. Exampleplot - 非常前卫,丑陋......不可用和东西

I'd like to smoothen things up, make at least the vertices connected, or look like that.

My data is generated like that: I have a function

svOfMatrix(x, y)

which produces a matrix in dependence on x, calculates its y-th power, selects a subset of columns and rows, and calculates the maximum singular value. So, Z[x,y] is svOfMatrix(x, y)

As this calculation is quite expensive, I don't want to make the steps for x too small, and Y is bound to be integer
Further, even for very small steps, there might be quite some changes, I don't want see. So I'd like to interpolate it somehow. I found http://docs.scipy.org/doc/scipy-0.14.0/reference/tutorial/interpolate.html but I don't get it to work.

From the link you suggested, the example here is probably closest to what you want. You can use the example with your values,

import numpy as np
from scipy import interpolate
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d, Axes3D

X, Y = np.mgrid[-1:1:20j, -1:1:20j]
Z = (X+Y) * np.exp(-6.0*(X*X+Y*Y)) + np.random.rand(X.shape[0])

xnew, ynew = np.mgrid[-1:1:80j, -1:1:80j]
tck = interpolate.bisplrep(X, Y, Z, s=0)
znew = interpolate.bisplev(xnew[:,0], ynew[0,:], tck)

fig = plt.figure(figsize=(12,12))
ax = fig.gca(projection='3d')
ax.plot_surface(X, Y, Z, cmap='summer', rstride=1, cstride=1, alpha=None)
plt.show()

fig = plt.figure(figsize=(12,12))
ax = fig.gca(projection='3d')
ax.plot_surface(xnew, ynew, znew, cmap='summer', rstride=1, cstride=1, alpha=None, antialiased=True)
plt.show()

Also, antialiased=True may make it look better but I think is on by default. The first plot looks like this,

在此输入图像描述

and the smoothed plot like this,

在此输入图像描述

The problem with your the low frequency noise in your data is that it will be difficult to define a grid fine enough to resolve. You can adjust the level of smoothing with the s argument to interpolate.bisplrep or perhaps coarse grain/filter your data to leave only major trends (eg using scipy.ndimage.interpolation.zoom if you have regular gridded data). Alternatively, consider a different type of plot such as pcolormesh as the data is essentially 2D.

Simply put the data_frame into this function. You'll get a proper smoothen surface plot. Incase you face any error, just choose only those features from data_frame which are numerical.

'data_frame = data_frame.select_dtypes(include='number')'

    from scipy import interpolate
    from mpl_toolkits.mplot3d import axes3d, Axes3D

    def surface(data_frame, title=None, title_x=0.5, title_y=0.9):

        X, Y = np.mgrid[-10:10:complex(0,data_frame.shape[0]), 
    -10:10:complex(0,data_frame.shape[1])]
        Z = data_frame.values

        xnew, ynew = np.mgrid[-1:1:80j, -1:1:80j]
        tck = interpolate.bisplrep(X, Y, Z, s=0)
        znew = interpolate.bisplev(xnew[:,0], ynew[0,:], tck)

        fig = go.Figure(data=[go.Surface(z=znew)])
        fig.update_layout(template='plotly_dark', 
                          width=800, 
                          height=800,
                          title = title,
                          title_x = title_x, 
                          title_y = title_y
                         )
        return fig

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM