Skip to content

2. Ploting

1. Coordinate System

1.1 Overview

1. Image Coordinates

  • These refer to the internal coordinate system used by the image array (or the NumPy array) itself.
  • The image is represented as a matrix (2D array for grayscale or 3D array for RGB), where each element corresponds to a pixel.
  • The coordinates are based on row and column indices. For a 2D image of shape (height, width), the top-left corner is (0, 0), and the bottom-right corner is (height-1, width-1) in terms of the array’s row and column indices.
  • Example: A pixel at (2, 3) means the pixel is in the 3rd row and 4th column of the image array.

2. Pixel Coordinates

  • These refer to the physical pixel locations on the screen where the image will be displayed.
  • Pixel coordinates describe actual screen pixels where the image is rendered by imshow() or other plotting functions.
  • For example, on a screen with a resolution of 1920x1080, pixel coordinates would range from (0, 0) in the top-left to (1919, 1079) at the bottom-right.
  • The relationship between image coordinates and pixel coordinates depends on the figure size and resolution.

3. Data Coordinates

  • These refer to the coordinate system used in the plot. When you plot something with matplotlib, the axes have their own coordinate system, often unrelated to pixels or the image itself.
  • In imshow(), data coordinates define where the corners of the image will be placed on the plot. By default, data coordinates match the image coordinates (array indices), but you can modify this using the extent argument.
  • For example, if your data represents geographical information, the data coordinates could represent latitude and longitude.

Example

  • (0, 0) point corresponds to bottom left corner
  • (grid_size, grid_size) point corresponds to top right corner
import matplotlib.pyplot as plt
# Create a grid of given size
grid_size = 10
# Create a figure and axis
fig, ax = plt.subplots()
# Set the x and y limits to the grid size
ax.set_xlim(0, grid_size)
ax.set_ylim(0, grid_size)
# Draw grid lines
ax.set_xticks(range(grid_size + 1))
ax.set_yticks(range(grid_size + 1))
ax.grid(True)
# Place objects on the grid (e.g., a circle at (3, 4) and a star at (7, 2))
ax.plot(3, 4, 'o', label='Circle') # Circle marker
ax.plot(7, 2, '*', label='Star') # Star marker
# Add labels or objects (optional)
ax.text(3, 4.2, 'Object 1', fontsize=12)
ax.text(7, 2.2, 'Object 2', fontsize=12)
# Display the grid
plt.gca().set_aspect('equal', adjustable='box') # Keep the grid squares equal in size
plt.legend()
plt.show()

1.2 extent and How it Maps Coordinates

extent in imshow() allows you to control how the image coordinates (or pixel grid) are mapped onto the data coordinates of the plot axes.

  • Without extent: By default, imshow() assumes the image coordinates map to data coordinates directly. If you plot a 10x10 array, the plot’s data coordinates will range from 0 to 9 along both axes (matching the array indices).

  • With extent: The extent argument redefines the data coordinates to which the image is mapped. It takes four values: [x_min, x_max, y_min, y_max] that set the corners of the image in the plot’s coordinate system.

Example:

import numpy as np
import matplotlib.pyplot as plt
image = np.random.rand(10, 10)
# Display image without extent (default mapping)
plt.subplot(1, 2, 1)
plt.imshow(image, cmap='gray')
plt.title("Default")
# Display image with extent
plt.subplot(1, 2, 2)
plt.imshow(image, cmap='gray', extent=[0, 5, 0, 2]) # Map image to data coordinates
plt.title("With extent")
plt.show()

Explanation:

  • Without extent: The image coordinates (0, 0) to (9, 9) map to the plot axes exactly, so the image’s grid matches the data grid (image indices).
  • With extent=[0, 5, 0, 2]: The image is scaled so that the bottom-left corner is at (0, 0) and the top-right corner is at (5, 2) in data coordinates. This “stretches” the image horizontally and vertically in terms of the plot’s axes, but the image coordinates themselves remain unchanged.

Understanding extent and Y-Axis Orientation

  1. Image Coordinate System:

    • By default, in an image (like what plt.imshow() processes), the origin (0,0) is at the top-left corner.
    • The X-coordinates increase to the right, and the Y-coordinates increase as you move downwards. So, in standard image coordinates:
      • (0, 0) is the top-left corner.
      • (width, height) is the bottom-right corner.
  2. Data Coordinate System:

    • When you use extent, you are defining a custom coordinate mapping for the axes.
    • In the example you provided, extent=[0, 5, 0, 2], it means:
      • The left edge of the image corresponds to 0 on the X-axis, and the right edge corresponds to 5.
      • The bottom edge of the image corresponds to 0 on the Y-axis, and the top edge corresponds to 2.
  3. Effect on the Y-Axis:

    • This means that the Y-axis coordinates will start at 0 at the bottom and go up to 2 at the top.
    • Therefore, the typical image coordinate system is inverted vertically when using extent.

Visual Explanation

To clarify how this works, consider this simple representation:

  • Image Coordinate System (Default):

    Y
    |
    | (0, 0) -------------------> X
    |
    |
    |
    |
    | (height, width)
  • Data Coordinate System with extent=[0, 5, 0, 2]:

    Y
    |
    |
    | (0, 0) ---------------------> X
    |
    |
    |
    |
    | (2, 5)

How to Fix the Y-Axis Orientation

If you want the Y-axis to start at 0 at the top left (like the default image coordinates), you can use the origin parameter:

  • Set origin='lower' to align the top of the image with the maximum Y value defined in extent.
import numpy as np
import matplotlib.pyplot as plt
image = np.random.rand(10, 10)
plt.figure(figsize=(10, 10))
# Display image without extent (default mapping)
plt.subplot(2, 2, 1)
plt.imshow(image, cmap='gray')
plt.title("Default")
# Display image with extent
plt.subplot(2, 2, 2)
plt.imshow(image, cmap='gray', extent=[0, 5, 0, 2]) # Map image to data coordinates
plt.title("With extent")
# Display image with extent (mapping reversed)
plt.subplot(2, 2, 3)
plt.imshow(image, cmap='gray', extent=[0, 5, 2, 0]) # Map image to data coordinates
plt.title("With extent (mapping reversed)")
# Axis values will change
# Display image with extent
plt.subplot(2, 2, 4)
plt.imshow(image, cmap='gray', extent=[0, 5, 0, 2], origin='lower') # Map image to data coordinates
plt.title("With extent (origin=lower)")
# The image will be vertically flipped (top, left (0,0) origin will map to bottom left)
# Axis values will not change
plt.show()

2. 3D Map with Objects

import numpy as np
import matplotlib.pyplot as plt
# Function to create a sphere
def create_sphere(center, radius, num_points=100):
u = np.linspace(0, 2 * np.pi, num_points)
v = np.linspace(0, np.pi, num_points)
x = center[0] + radius * np.outer(np.cos(u), np.sin(v))
y = center[1] + radius * np.outer(np.sin(u), np.sin(v))
z = center[2] + radius * np.outer(np.ones(np.size(u)), np.cos(v))
return x, y, z
# Create a 3D grid for the environment
grid_size = 10
x = np.linspace(-grid_size, grid_size, 100)
y = np.linspace(-grid_size, grid_size, 100)
X, Y = np.meshgrid(x, y)
Z = np.zeros_like(X) # Flat ground
# Enable interactive mode
plt.ion()
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')
# Plot the ground
ax.plot_surface(X, Y, Z, alpha=0.3, color='lightgreen', zorder=1)
# Define animal positions and sizes (as spheres)
objects = [
{"center": (2, 3, 0), "radius": 0.3, "color": 'orange'}, # Animal 1
{"center": (-3, -1, 0), "radius": 0.5, "color": 'brown'}, # Animal 2
{"center": (1, -4, 0), "radius": 0.4, "color": 'red'}, # Animal 3
{"center": (-2, 2, 0), "radius": 0.2, "color": 'blue'} # Animal 4
]
# Plot animals as spheres
for object in objects:
x_sphere, y_sphere, z_sphere = create_sphere(object["center"], object["radius"])
ax.plot_surface(x_sphere, y_sphere, z_sphere, color=object["color"], alpha=0.7)
# Set limits and labels
ax.set_xlim([-grid_size, grid_size])
ax.set_ylim([-grid_size, grid_size])
ax.set_zlim([-grid_size, grid_size])
# ax.set_zlim([-1, 3])
ax.set_xlabel('X axis')
ax.set_ylabel('Y axis')
ax.set_zlabel('Z axis')
ax.set_title('3D Environment with Objects')
# Set the initial viewing angle
ax.view_init(elev=20, azim=30)
# Show the plot
plt.show()
# Keep the plot open for interaction
plt.pause(0.1) # Allows the plot to refresh and be interactive