Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set/get 3d viewing direction for Matplotlib Axes3D

Tags:

matplotlib

3d

I'm just learning Matplotlib, so I'm going straight for stereo visualisation. I've already built the mirrors to view the screen, and have got left and right figures updating interactively the right distance apart.

What I need to do now is to interrogate the orientation of one axes, to set the orientation of the other. I have RFTM'd, and done help(Axes3D.function), and unfortunately the documentation seems a bit thin, and inconsistent.

The only Axes3D calls I've found so far that set/get the viewing orientation are view_init(azim=, elev=), and get_proj() which returns a 4x4 transformation matrix.

Now get_proj says - quoting from the pdf which is the same text as the docstring

get_proj()
Create the projection matrix from the current viewing position.
elev stores the elevation angle in the z plane 
azim stores the azimuth angle in the x,y plane
dist is the distance of the eye viewing point from the object point.

... which is not describing a 4x4 matrix.

I could try to reverse engineer the values in the matrix to give me azim and elev, but reverse engineering always feels wrong, especially for a widely used library. I've also not found any function to set the dist. I have written a short script based on one of the examples to set and interrogate viewing positions.

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

plt.ion()
fig = plt.figure()
ax = fig.gca(projection='3d')
theta = np.linspace(-4 * np.pi, 4 * np.pi, 100)
z = np.linspace(-2, 2, 100)
r = z**2 + 1
x = r * np.sin(theta)
y = r * np.cos(theta)
ax.plot(x, y, z, label='parametric curve')
fig.canvas.draw()

with open('dump_proj.txt','wt') as fout:
    for e in range(0, 61, 30):
        for a in range(0, 61, 30):
            fout.write('setting azimuth to {0}, elevation to {1}\n'.format(a, e))           
            ax.view_init(azim=a, elev=e)
            fig.canvas.draw()
            d=ax.get_proj()
            for row in d:
                fout.write('{0:8.4f}  {1:8.4f}  {2:8.4f}  {3:8.4f}  \n'.format(*row))
            fout.write('\n')

An example part of the saved file is shown here

setting azimuth to 60, elevation to 30

-0.1060 0.0604 0.0000 -0.0519
-0.0306 -0.0523 0.2165 0.0450
0.0000 0.0000 0.0000 -10.0000
-0.0530 -0.0906 -0.1250 10.0779

I would guess the 10 is something like the viewing distance. I was rather hoping for some 0.5 or 0.866 entries with 30 and 60 degree angles used, but it doesn't look like it's that simple.

Are there some functions I'm missing, to set distance, or to get elevation and azimuth? Or bits of documentation I'm missing, that tell me how the 4x4 proj matrix is constructed?

I have a workaround, which ultimately might give me better timing, and that's to use another control to set azimuth and elevation, and then use that to view_init() both left and right eye axes. But I'd prefer in the first instance to get the orientation from one of the axes.

Another question, how does the

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

work? I am only slowly getting to grips with OO methods, and this seems to work by magic. Does the import of Axes3D do something behind the scenes to alter the import of pyplot? I would have niavely expected to import the 3D stuff after the 2D stuff, if it was overriding methods. I guess if it all works it must be OK, but I don't get how.

like image 647
Neil_UK Avatar asked Jun 11 '13 13:06

Neil_UK


1 Answers

Doh, what I hadn't done was look at the dir() of an instance of the Axes3D class. And there they are, .azim, .elev and .dist properties.

like image 58
Neil_UK Avatar answered Sep 25 '22 07:09

Neil_UK