3

I wanted to plot images in a particular pattern as shown in the image below

enter image description here

I wanted to understand what would be the best way to plot images using python. I used the following method in which plots images in a grid pattern. output looks like this enter image description here

import numpy as np
import matplotlib.pyplot as plt
from datetime import datetime
import matplotlib as mpl
from matplotlib.dates import date2num
import matplotlib.dates as mdates
from mpl_toolkits.axes_grid1 import ImageGrid

img0 = f['B00'][i_ant, :, :]
img1 = f['B01'][i_ant, :, :]
img2 = f['B02'][i_ant, :, :]
img3 = f['B03'][i_ant, :, :]
    

img_arr = [img0,img1,img2,img3]
fig = plt.figure(figsize=(5., 5.))
grid = ImageGrid(fig, 111, 
                     nrows_ncols=(2, 2),  # creates 2x2 grid of axes
                     axes_pad=0,  # pad between axes
                     )

for ax, im in zip(grid, img_arr):
    ax.imshow(im)
        

plt.show()
Derek O
  • 16,770
  • 4
  • 24
  • 43
codehead
  • 33
  • 5
  • What does the plot produced by your code look like? – Derek O Jan 19 '22 at 01:42
  • Just added the plot it looks – codehead Jan 19 '22 at 01:57
  • do the images need to be added in the same order that they appear in your example image (diagonal counter clockwise starting from the center)? – Derek O Jan 19 '22 at 01:58
  • yes in the same order from the center – codehead Jan 19 '22 at 02:21
  • Are you interested in figuring out how to plot images in this particular pattern for any number of images or just for 4 images? – jylls Jan 19 '22 at 03:32
  • If it's only 4 images, you could use a 3×3 `GridSpec` (`GridSpec` doc [here](https://matplotlib.org/stable/api/_as_gen/matplotlib.gridspec.GridSpec.html)) and just place your plots where you want them to be. It sounds more complicated if it's for any number of images. – jylls Jan 19 '22 at 03:36
  • 2
    Ideally, it is for 36 images. – codehead Jan 19 '22 at 03:52

1 Answers1

3

For each additional level of the square spiral, two sides are added, except for the very last one where only one side is needed. The i,j positions increment or decrement with 1 at every step, and at each corner the direction is turned 90 degrees.

This is how it could work:

import matplotlib.pyplot as plt
import numpy as np

N = 6
fig = plt.figure(figsize=(16, 18), constrained_layout=True)
spec = fig.add_gridspec(ncols=N * 2 - 1, nrows=N * 2 - 1)
i, j = N - 2 + N % 2, N - 1
dir_i, dir_j = 1, - 1
plot_num = 0
for k in range(1, N + 1):
    for _ in range(2):  # add two strokes of k subplots (only 1 when k==N)
        for _ in range(k):
            ax = fig.add_subplot(spec[i, j])
            ax.imshow(np.random.rand(3, 3))
            ax.set_xlabel(f'{plot_num} [{k}]', fontsize=18)
            plot_num += 1
            i += dir_i
            j += dir_j
        if k == N:
            break
        dir_i, dir_j = -dir_j, dir_i
plt.show()

spiral of plots

To copy the original numbering exactly, some concentric squares can be drawn. For odd N, the last square is quite irregular, with only 2 sides, where the last line jumps to the opposite side and with one square less than the rest.

For the weird numbering of 2 and 3, some renumbering can be introced:


import matplotlib.pyplot as plt
import numpy as np

N = 6
fig = plt.figure(figsize=(16, 18), constrained_layout=True)
spec = fig.add_gridspec(ncols=2 * N - 1, nrows=2 * N - 1)
plot_num = 0
for k in range(2, N + 2, 2):
    # i, j = N - 2 + N % 2, N - 1
    i, j = N - k + N % 2, N - 1
    dir_i, dir_j = 1, - 1
    for side in range(4):  # add four strokes of k subplots (only 2 when k==N)
        for _ in range(k - 1):
            ax = fig.add_subplot(spec[i, j])
            modified_plot_num = 5 - plot_num if plot_num in (2, 3) else plot_num
            ax.imshow(np.random.rand(6, 6), cmap='inferno')
            ax.set_xlabel(f'{modified_plot_num} [{k}]', fontsize=18)
            plot_num += 1
            i += dir_i
            j += dir_j
            if plot_num == N * N:  # for odd N, the very last cell should be skipped
                break
        if k == N + 1:
            if side == 0:  # for last side of uneven square: jump to the other side
                dir_i, dir_j = -dir_i, -dir_j
                i, j = i - 1, 2 * N - 2
            elif side == 1:
                break
        dir_i, dir_j = -dir_j, dir_i
plt.show()

spiral of subplots, original numbering

JohanC
  • 71,591
  • 8
  • 33
  • 66
  • I think this could be the closest solution. Thank you so much. I might have to modify the positions to match the image numbers as shown on the map. Btw is it possible to tilt the images by 45 degrees? @JohanC – codehead Jan 19 '22 at 22:19
  • 1
    See [How to rotate a simple matplotlib Axes](https://stackoverflow.com/questions/21652631/how-to-rotate-a-simple-matplotlib-axes) about rotated subplots. It's not very flexible, so it doesn't make too much sense implementing it without knowing the exact usage. – JohanC Jan 19 '22 at 22:41
  • Thanks for the link on rotated plots. Yeah for some reason 2 and 3 have a different order than others. hope I can change image number 4 to sit on top of 0. – codehead Jan 19 '22 at 23:14
  • As I have to make a single image after combining all 36 images in this map. so the positioning of these images is very essential for me. – codehead Jan 19 '22 at 23:16
  • This solution works like a charm. Thank you so much! – codehead Jan 19 '22 at 23:49