Creating overlapping images in matplotlib using imshow or another function

I have two three-dimensional arrays of ground-based radar data. Each array is basically a collection of two-dimensional images with a time resolution, where time increases in the third dimension. I want to create a three-dimensional graph that intersects a two-dimensional image from each array.

I am essentially trying to create a fence. Some examples of this type of plot are on these sites: http://www.geogiga.com/images/products/seismapper_3d_seismic_color.gif http://www.usna.edu/Users/oceano/pguth/website/so461web/seismic_refl/fence .png

Usually I use imshow to individually display two-dimensional images for analysis. However, my research on imshow functionality suggests that it does not work with 3D axes. Is there any way around this? Or is there another plotting function that can copy imshow functionality, but can be combined with 3D axes?

+3
source share
3 answers

If you are happy to contemplate using another graph library (i.e. not matplotlib), then you should consider Mayavi / tvtk (although the learning curve is a little steep). The closest I saw what you want is scalar cut planes at http://wiki.scipy.org/Cookbook/MayaVi/Examples

Most documentation: http://docs.enthought.com/mayavi/mayavi/index.html

+1
source

There may be better ways, but at least you can always make a flat grid and color it:

import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D import numpy as np # create a 21 x 21 vertex mesh xx, yy = np.meshgrid(np.linspace(0,1,21), np.linspace(0,1,21)) # create some dummy data (20 x 20) for the image data = np.random.random((20, 20)) # create vertices for a rotated mesh (3D rotation matrix) X = np.sqrt(1./3) * xx + np.sqrt(1./3) * yy Y = -np.sqrt(1./3) * xx + np.sqrt(1./3) * yy Z = np.sqrt(1./3) * xx - np.sqrt(1./3) * yy # create the figure fig = plt.figure() # show the reference image ax1 = fig.add_subplot(121) ax1.imshow(data, cmap=plt.cm.BrBG, interpolation='nearest', origin='lower', extent=[0,1,0,1]) # show the 3D rotated projection ax2 = fig.add_subplot(122, projection='3d') ax2.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors=plt.cm.BrBG(data), shade=False) 

This creates:

enter image description here

(Please note that I was not very careful about the rotation matrix, you will need to create your own projection. It may actually be a good idea to use a real rotation matrix.)

Please note that there is a slight problem with fence poles and fences, i.e. the grid has one more vertex compared to the number of patches.


The above approach is not very effective if you have high resolution images. It may not even be useful with them. Then another option is to use a backend that supports affine image transformations. Unfortunately, you will have to calculate the conversions yourself. It's not terribly complicated, but still a little awkward, and then you won't get a real 3D image that could be rotated, etc.

For this approach, see http://matplotlib.org/examples/api/demo_affine_image.html

Alternatively, you can use OpenCV and its cv2.warpAffine function to warp the image before showing it with imshow . If you fill the environment with transparent color, you can then fold the images to get a result that looks like your iamge example.


To give you an idea of ​​the plot_surface capabilities, I tried to flip Lena around the half cylinder:

 import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D import numpy as np # create a 513 x 513 vertex mesh xx, yy = np.meshgrid(np.linspace(0,1,513), np.linspace(0,1,513)) # create vertices for a rotated mesh (3D rotation matrix) theta = np.pi*xx X = np.cos(theta) Y = np.sin(theta) Z = yy # create the figure fig = plt.figure() # show the 3D rotated projection ax = fig.add_subplot(111, projection='3d') ax.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors=plt.imread('/tmp/lena.jpg')/255., shade=False) 

It bends really well, but all operations on the image are rather slow:

enter image description here

+8
source

There is no way to do this with matplotlib. @DrV answer is an estimate. Matplotlib actually shows not every single pixel of the original image, but some scaled image. rstride and cstride allow you to specify how the image is scaled, however, the output will not be an exact image.

0
source

Source: https://habr.com/ru/post/1272046/


All Articles