Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
327 views
in Technique[技术] by (71.8m points)

python - Constructing 3D plot with 'negative' Z-axis below zero

We are working on a project in which we would like to construct 3D plots. Python is our main language, and therefore naturally chose to use matplotlib as our plotting library. Various tutorials (here, here and here) have teached us how to perform 3D plotting using the mplot3d functionality of matplotlib. Consequently, various StackOverflow answers helped us to move the origin of each of the axes to different locations (here and here).

After searching for a couple of hours we have a hard time finding an answer to our next question, however. We would like to have a positive and negative side for our Z-axis (see the picture below, orange part). This would mean that data points with Z>0 are above origin, and with Z<0 are below origin. We tried several things, but our Z-axis origin always ends up at the most negative value of our dataset.

Example

With great help of the community here, we've come to a minimal example showcasing what I want. The code I used is:

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure(figsize=(10, 10))
ax = fig.gca(projection='3d')

# Some settings
sn = 2   #limits in x,y,z
n = 50   #number of sample points
x1, x2 = 0, sn
y1, y2 = 0, sn
z1, z2 = -sn, sn

# Data for points
xs = (x2 - x1)*np.random.rand(n) + x1
ys = (y2 - y1)*np.random.rand(n) + y1
zs = (z2 - z1)*np.random.rand(n) + z1

# Points with z >= 0, plotted in green
ax.scatter(xs[zs>=0], ys[zs>=0], zs[zs>=0], color='green')
# Points with z < 0, plotted in red
ax.scatter(xs[zs<0], ys[zs<0], zs[zs<0], color='red')

# Data for plotting plane x|y|z=0 within the domain
tmp = np.linspace(0, sn, 8)
x, y = np.meshgrid(tmp, tmp)
z = 0*x

# Plot grid lines
ax.plot([0, sn], [0, 0], [0, 0], color='black')
ax.plot([0, 0], [0, sn], [0, 0], color='black')
ax.plot([0, 0], [0, 0], [-sn, sn], color='black')

# Maximum tick labels for X, Y, and Z (x3)
ax.plot([sn, sn], [0, 0], [-.05, .02], color='black')
ax.plot([0, 0], [sn, sn], [-.05, .02], color='black')
ax.plot([-.05, .02], [-.05, .02], [sn, sn], color='black')
ax.plot([-.05, .02], [-.05, .02], [-sn, -sn], color='black')
ax.plot([-.05, .02], [-.05, .02], [0, 0], color='black')

# Label texts
ax.text(sn/2, 0, -.2*sn, 'xlabel', 'x', ha='center')
ax.text(0, sn/2, -.2*sn, 'ylabel', 'y', ha='center')
ax.text(-.1*sn, 0, 0, 'zlabel', 'z', ha='center')

# Maximum limit text for X, Y and Z (x3)
ax.text(sn, 0, -.1*sn, f'{sn}', 'x', ha='center')
ax.text(0, sn, -.1*sn, f'{sn}', 'y', ha='center')
ax.text(-.05*sn, -.05*sn, 0, '0', 'x', ha='center')
ax.text(-.05*sn, -.05*sn, sn, f'{sn}', 'x', ha='right')
ax.text(-.05*sn, -.05*sn, -sn, f'{-sn}', 'x', ha='center')

# Set limits of the 3D display
ax.set_xlim3d([-sn, sn])
ax.set_ylim3d([-sn, sn])
ax.set_zlim3d([-sn, sn])

ax.set_axis_off()

plt.show()

This results in the graph below:

enter image description here

Although I am very happy with the outcome, this is still kind of 'hacky' solution with manually drawing the axis, ticks and labels. If anybody would have a solution in which we can re-design the axis from the mplot3d API that would be very helpful.

question from:https://stackoverflow.com/questions/65919351/constructing-3d-plot-with-negative-z-axis-below-zero

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

(Swatchai creates this as a community wiki):

Sometime, discussion without some runnable code to play/experiment with is not the best approach to get a solution. Here I propose this code to use for further discussion.

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure(figsize=(10, 10))
ax = fig.gca(projection='3d')

# Quivers for axes x,y,z from (0,0,0)
quiver1 = ax.quiver([0],[0],[0],[2],[0],[0], colors='r')
quiver2 = ax.quiver([0],[0],[0],[0],[2],[0], colors='g')
quiver3 = ax.quiver([0],[0],[0],[0],[0],[2], colors='b')

# Some settings
sn = 2   #limits in x,y,z
n = 50   #number of sample points
x1, x2 = -sn, sn
y1, y2 = -sn, sn    
z1, z2 = -sn, sn

# Data for points
xs = (x2 - x1)*np.random.rand(n) + x1
ys = (y2 - y1)*np.random.rand(n) + y1
zs = (z2 - z1)*np.random.rand(n) + z1

# Points with z >= 0, plotted in green
ax.scatter(xs[zs>=0], ys[zs>=0], zs[zs>=0], color='green')
# Points with z < 0, plotted in red
ax.scatter(xs[zs<0], ys[zs<0], zs[zs<0], color='red')

# Data for plotting plane x|y|z=0 within the domain
tmp = np.linspace(0, sn, 8)
x,y = np.meshgrid(tmp,tmp)
z = 0*x

ax.plot_surface(z,x,y, alpha=0.15, color='red')    # plot the plane x=0
ax.plot_surface(x,z,y, alpha=0.15, color='green')  # plot the plane y=0
ax.plot_surface(x,y,z, alpha=0.15, color='blue')   # plot the plane z=0

# Set limits of the 3D display
ax.set_xlim3d([-sn, sn])
ax.set_ylim3d([-sn, sn])
ax.set_zlim3d([-sn, sn])

# Set labels at the 3d box/frame
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')

plt.show()

Output plot:

quiverasaxes


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...