4

I have a 3-D surface plot that shows x and y coordinates and depths. I also have a 2-D contourf plot with x and y coordinates and the filled contours at the different locations. If I know the depths at the coordinates in the contourf plot, is there a way I can show the contours on the 3-D surface plot?

I have created a 3-D surface plot using plotly with the code below:

import plotly.graph_objects as go
import oceansdb
import numpy as np 
import matplotlib.pyplot as plt

Xa = np.linspace(29.005,29.405,200)
Ya = np.linspace(-93.6683,-93.2683,200)

db = oceansdb.ETOPO()
dcont = db['topography'].extract(lat=Xa, lon=Ya)
depth = dcont['height']

fig = go.Figure(data=[go.Surface(z=depth, x=Xa, y=Ya)])
fig.show()

Say my contourf plot can be created with the code below:

X = np.array([29.1,29.15,29.2,29.25])
Y = np.array([-93.5,-93.45,-93.4,-93.35])
r = np.array([0,0,0,2,3,0,0,6,7,8,9,1,9,0,0,0])

plt.figure()
plt.contourf(X,Y,r.reshape(len(X),len(Y)))
plt.show()

Assuming that the depth at each location can be determined using the oceansdb module, can I overlay the contour plot on the surface plot at the correct depth?

MAJ
  • 437
  • 5
  • 17

1 Answers1

1

Using matplotlib the short answer is "yes", but there are two buts you have face:

  1. Visualizing 3d data is difficult, and overlapping multiple datasets is more often than not confusing beyond the simplest cases
  2. Matplotlib has a 2d renderer, so even though you can plot multiple objects in the same 3d figure, there will often be rendering artifacts (in particular, two objects can typically be either fully in front of or behind one another).

The key methods you need are Axes3D.contour or Axes3D.contourf. Here are these in action with your example data:

import numpy as np 
import matplotlib.pyplot as plt 
from mpl_toolkits.mplot3d import Axes3D  # this enables 3d axes

X = np.array([29.1,29.15,29.2,29.25]) 
Y = np.array([-93.5,-93.45,-93.4,-93.35]) 
r = np.array([0,0,0,2,3,0,0,6,7,8,9,1,9,0,0,0]).reshape(X.size, Y.size)

# plot your 2d contourf for reference 
fig,ax = plt.subplots() 
ax.contourf(X, Y, r) 

# plot in 3d using contourf
fig = plt.figure() 
ax = fig.add_subplot(111, projection='3d') 
ax.contourf(X, Y, r) 

# plot in 3d using contour
fig = plt.figure() 
ax = fig.add_subplot(111, projection='3d') 
ax.contour(X, Y, r) 

plt.show() 

Here's your 2d contourf plot: 2d contour plot according to OP's original code

Here's the 3d contourf version: 3d-embedded contour plot where each level is filled with horizontal planes

And here's the 3d contour version: 3d-embedded contour plot where only level lines are plotted

As you can see the difference between the latter two is that contourf also plots horizontal planes for each level (just like terraces), whereas contour only plots the level lines themselves.

Since repeated plots using the same axes will accumulate plots there's nothing stopping you from superimposing either of these 3d contour plots on your original surface. However, in line with my earlier warnings you'll have to watch if the contours are rendered correctly over the surface (under all view angles), and even if so the result might not be all that transparent for conveying information. I personally tend to find contourf much easier to comprehend than contour on a 3d plot, but I suspect that if we put these on top of full surface plots the latter will fare better.

  • I'm actually looking to plot the contourf in 4-D I guess. I want the z axis to be the same as the `depth` axis (assuming the depth is known at each X,Y) and the contour to show at that depth, rather than the z axis being the value for each contour. – MAJ Oct 25 '19 at 18:10
  • 1
    @MAJ sorry, in that case I don't understand what you're trying to plot. – Andras Deak -- Слава Україні Oct 25 '19 at 18:23