9

I am trying to plot 3d Surface plots using code from this site using matplotlib:

X,Y and Z are obtained as below:

from math import pi
from numpy import cos, meshgrid
alpha = 0.7
phi_ext = 2 * pi * 0.5

def flux_qubit_potential(phi_m, phi_p):
    return 2 + alpha - 2 * cos(phi_p)*cos(phi_m) - alpha * cos(phi_ext - 2*phi_p)

phi_m = linspace(0, 2*pi, 100)
phi_p = linspace(0, 2*pi, 100)
X,Y = meshgrid(phi_p, phi_m)
Z = flux_qubit_potential(X, Y).T

And 3d plotting is done with following code:

from mpl_toolkits.mplot3d.axes3d import Axes3D

fig = plt.figure(figsize=(14,6))

# `ax` is a 3D-aware axis instance, because of the projection='3d' keyword argument to add_subplot
ax = fig.add_subplot(1, 2, 1, projection='3d')

p = ax.plot_surface(X, Y, Z, rstride=4, cstride=4, linewidth=0)

# surface_plot with color grading and color bar
ax = fig.add_subplot(1, 2, 2, projection='3d')
p = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.coolwarm, linewidth=0, antialiased=False)
cb = fig.colorbar(p, shrink=0.5)

However, if I replace X,Y and Z by my x,y,z 3d data (sample give below), there is an error that Z has to be 2 dimensional. How can I plot with usual x,y,z values, as following:

   x   y   z
0  12  0  0.1
1  13  1  0.8
2  14  3  1.0
3  16  4  1.2
4  18  4  0.7
Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
rnso
  • 23,686
  • 25
  • 112
  • 234
  • What do you mean by 'my x,y,z 3d data'? There is no reference to any such thing anywhere in your code. – Thierry Lathuille Nov 11 '18 at 08:24
  • I have added a sample of my data above. – rnso Nov 11 '18 at 09:03
  • Concerning the "why?", [Why does pyplot.contour() require Z to be a 2D array?](https://stackoverflow.com/questions/42045921/why-does-pyplot-contour-require-z-to-be-a-2d-array). I would be very much inclined to close this as duplicate of [Simplest way to plot 3d surface given 3d points](https://stackoverflow.com/questions/12423601/simplest-way-to-plot-3d-surface-given-3d-points) unless the question makes clear why it isn't. – ImportanceOfBeingErnest Nov 11 '18 at 12:08
  • @rnso The link in your question is dead. – Karlo Jun 25 '19 at 22:15
  • The site must have been removed. The code is already there in the question. – rnso Jun 26 '19 at 01:42

2 Answers2

6

This is because, in my understanding, to draw a surface you need to form a polygon mesh. To draw a 3d surface, you need to have small squares, for example, on the xy-plane and then have 1 corresponding z value for all the x-y points. The smaller the area of the square means finer mesh-grid and better resolution(smooth-looking surface.) Now if you have an arbitrary set of xyz points, how matplotlib can determine which surface to draw. That is why a mesh is required. You can of course plot 3d scatter or line plots with your data.

anotherone
  • 680
  • 1
  • 8
  • 23
  • 1
    Is there any way I can plot x,y,z values as a mesh, wireframe or surface? – rnso Nov 11 '18 at 11:19
  • 1
    Difficult because you can then, in theory, have 2 data points and could plot a surface which will have the same problem when you try to interpolate. This is essentially an interpolation in 3d. So you will then have a non-smooth surface with not a nice triangulation(or any tessellation) . Anyway you can do that https://stackoverflow.com/questions/12423601/simplest-way-to-plot-3d-surface-given-3d-points ( the 2nd answer) – anotherone Nov 11 '18 at 11:27
  • check this for the doc: https://matplotlib.org/api/_as_gen/mpl_toolkits.mplot3d.axes3d.Axes3D.html?highlight=trisurf#mpl_toolkits.mplot3d.axes3d.Axes3D.plot_trisurf – anotherone Nov 11 '18 at 11:29
2

In the documentation you will find that x, y and z need to a 2D array. For the coordinates x and y you will need to use numpy.meshgrid as you show in the first piece of code. This creates a 2D array for each coordinate where x and y are constant along the other direction and vary on its own direction.

With respect to z, this also needs to be a 2D array since Axes3D.surface_plot maps each element of the 2D array z with the 2D grid defined by x and y.

Hence, when you use your own x, y and z make sure that you use numpy.meshgrid for x and y and, then, define z = f(x,y) (e.g. the function flux_qubit_potential you show).

Edit:

After OP's comment, is clear that the desired output is a plot where the function g is g = f(x,y,z). This would mean that g is a 3D array in the end. To do this in terms of iso-surfaces have a look at these answers.

b-fg
  • 3,959
  • 2
  • 28
  • 44
  • By this approach, I will not be using my z values. How do I incorporate my z values? – rnso Nov 11 '18 at 11:13
  • So is `z` a coordinate? The code you show is to plot z = f(x,y). Not a function, say `g` to which is g = f(x,y,z). – b-fg Nov 11 '18 at 11:16
  • No, in my data, z is value along z-axis (just as x and y are values for corresponding axes). – rnso Nov 11 '18 at 11:17
  • Ok, then you need another function, not `Axes3D.surface_plot`. Give me a sec and I will point you on the right direction. – b-fg Nov 11 '18 at 11:18