Python Forum
3-d surface plotting - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: 3-d surface plotting (/thread-42247.html)

Pages: 1 2


3-d surface plotting - Tuxedo - Jun-03-2024

Looking for a Python package for publication quality 3d surface plots. The surfaces I deal with have just a single peak but can have odd shapes near the base (e.g. banana shaped or triangular-ish shaped). I want to be able to "slice" the surface at a particular z value and highlight the resulting contour in some way. I'd also like to cut the base at a particular z value and discard everything below that value. I've fiddled with matplotlib quite a bit and can't really get the result I want. I'd also like to be able to easily rotate the plot to determine the best viewing angle. It appears plotly might have some promise, but most of the videos I find show everything but surface plots. Is there some clear winner for surface plotting? I'd even consider a ray tracing package (probably not Python based) but am wary about the learning curve.


RE: 3-d surface plotting - sawtooth500 - Jun-04-2024

Here is some sample code with plotly, it may not do exactly what you are looking for but perhaps it can give you a starting point:

import numpy as np
import plotly.graph_objects as go

# Generate example data
x = np.linspace(-10, 10, 100)
y = np.linspace(-10, 10, 100)
x, y = np.meshgrid(x, y)
z = np.sin(np.sqrt(x**2 + y**2))

# Specify the z-value for slicing and cutting the base
slice_z_value = 0.5
cut_base_z_value = -0.5

# Create a mask to discard values below the cut_base_z_value
z[z < cut_base_z_value] = np.nan

# Create the 3D surface plot
fig = go.Figure(data=[go.Surface(z=z, x=x, y=y)])

# Add contour at the slice_z_value
fig.add_trace(go.Surface(
    z=np.ones_like(z) * slice_z_value,
    x=x,
    y=y,
    showscale=False,
    opacity=0.5,
    surfacecolor=np.where(z >= slice_z_value, z, np.nan),
    contours={"z": {"show": True, "start": slice_z_value, "end": slice_z_value, "size": 0.1}}
))

# Update layout for better visualization
fig.update_layout(scene=dict(
    zaxis=dict(range=[cut_base_z_value, np.nanmax(z)])
))

# Show plot
fig.show()



RE: 3-d surface plotting - Tuxedo - Jun-21-2024

Thanks so much! I use spyder, so didn't get any plot. Using:

https://community.plotly.com/t/plotly-in-spyder/5414/3

I was able to get an interactive plot in my web browser by using

from plotly.offline import plot
plot(fig)

Next, I tried to save a static imaging based on:

https://plotly.com/python/static-image-export/

by installing kaleido:

conda install -c conda-forge python-kaleido

and writing the image with

fig.write_image('fig1.png')

For some reason, the program just hangs/stops and doesn't write the image file. I get no error messages, but the program doesn't complete. Nothing. What am I doing wrong?


RE: 3-d surface plotting - paul18fr - Jun-22-2024

I'm also a Spyder user. Here after my code works perfectly. The figure is plotted on Spyder and saved.

# -*- coding: utf-8 -*-

import matplotlib.pyplot as plt
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import numpy as np
import os

Path = os.getcwd()
fig = plt.figure(figsize=(18, 18))
ax = fig.add_subplot(projection='3d')
ax.set_xlabel('X axis')
ax.set_ylabel('Y axis')
ax.set_zlabel('Z axis')

# Make data.
x = np.linspace(-10, 10, 100)
y = np.linspace(-10, 10, 100)
x, y = np.meshgrid(x, y)
z = np.sin(np.sqrt(x**2 + y**2))

# Plot the surface.
surf = ax.plot_wireframe(x, y, z, color='black')
surf = ax.plot_surface(x, y, z, rstride=1, cstride=1, linewidth=1, antialiased=True, edgecolor='black')

# Customize the z axis.
ax.set_zlim(-1.01, 1.01)
ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))

plt.show()
fig.savefig(Path + '/fig.png', dpi=300)
[attachment=2920]


RE: 3-d surface plotting - paul18fr - Jun-22-2024

On my previous post, I forgot to add "elevation" and "azimut" features

import matplotlib.pyplot as plt
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import numpy as np
import os

elevation = 45;     # vertical
azimut = 30.;       # theta

Path = os.getcwd()
fig = plt.figure(figsize=(18, 18))
ax = fig.add_subplot(projection='3d')
ax.view_init(elevation, azimut)
ax.set_xlabel('X axis')
ax.set_ylabel('Y axis')
ax.set_zlabel('Z axis')

# Make data.
x = np.linspace(-10, 10, 100)
y = np.linspace(-10, 10, 100)
x, y = np.meshgrid(x, y)
z = np.sin(np.sqrt(x**2 + y**2))

# Plot the surface.
surf = ax.plot_wireframe(x, y, z, color='black')
surf = ax.plot_surface(x, y, z, rstride=1, cstride=1, linewidth=1, antialiased=True, edgecolor='black')

# Customize the z axis.
ax.set_zlim(-1.01, 1.01)
ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))

plt.show()
fig.savefig(Path + '/fig.png', dpi=100)



RE: 3-d surface plotting - Tuxedo - Jun-23-2024

Thanks, but I'm trying to use plotly instead of matplotlib.


RE: 3-d surface plotting - paul18fr - Jun-23-2024

I was not aware about plotly.

The following information partially answers (i guess) to your need:

1) From sawtooth500 code, the picture can be directly displayed in your browser with
fig.write_html(Path + '/figure.html', auto_open=True)
It also writes an html file.

2) you can record the file using an icon in the browser (see screenshot), but in my case, it's done in the Download repertory.

3) I tried to install imgkit on Anaconda, but i failed so far.
import imgkit
imgkit.from_file(Path + '/figure.html', Path + '/out.png')
Complete code:
# -*- coding: utf-8 -*-

import numpy as np
import plotly.graph_objects as go
import os

Path = os.getcwd()
# Generate example data
x = np.linspace(-10, 10, 100)
y = np.linspace(-10, 10, 100)
x, y = np.meshgrid(x, y)
z = np.sin(np.sqrt(x**2 + y**2))
 
# Specify the z-value for slicing and cutting the base
slice_z_value = 0.5
cut_base_z_value = -0.5
 
# Create a mask to discard values below the cut_base_z_value
z[z < cut_base_z_value] = np.nan
 
# Create the 3D surface plot
fig = go.Figure(data=[go.Surface(z=z, x=x, y=y)])
 
# Add contour at the slice_z_value
fig.add_trace(go.Surface(
    z=np.ones_like(z) * slice_z_value,
    x=x,
    y=y,
    showscale=False,
    opacity=0.5,
    surfacecolor=np.where(z >= slice_z_value, z, np.nan),
    contours={"z": {"show": True, "start": slice_z_value, "end": slice_z_value, "size": 0.1}}
))
 
# Update layout for better visualization
fig.update_layout(scene=dict(
    zaxis=dict(range=[cut_base_z_value, np.nanmax(z)])
))
 
# Show plot
fig.show()
fig.write_html(Path + '/figure.html', auto_open=True)

# import imgkit
# imgkit.from_file(Path + '/figure.html', Path + '/out.png')



RE: 3-d surface plotting - Tuxedo - Jun-23-2024

I'm trying to write png or jpg files to import into a Latex document, but my Python script hangs whenever it gets to the command:

fig.write_image('plotly_test.png')
I have to restart the Python kernel from Spyder to recover. I have no idea what's wrong.


RE: 3-d surface plotting - paul18fr - Jun-24-2024

I've had to install kaleido as well, but just typing conda install python-kaleido (see conda-forge) and it works fine for me. I would uninstall first your kaleido release and reinstall it, otherwise it may come from anaconda incompatibilities, broken links ...

Personnal feeling: In my opinion it's better to print the figure from the browser (after rotating, zooming, etc.)


RE: 3-d surface plotting - Tuxedo - Jun-24-2024

Sorry for the pivot, but it looks like I was too quick to abandon matplotlib. After implementing some tips in this thread (thanks!) I was able to get m-u-c-h closer to what I'm looking for. See attached. What I can't figure out how to do though, is restrict the face color to the area inside the axes. I want everything outside the axes to be white. How to do it? I've seen it done with 2d plots but not 3d. This is what I included:

ax.set_facecolor('Blue')