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 theextent
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 sizegrid_size = 10
# Create a figure and axisfig, ax = plt.subplots()
# Set the x and y limits to the grid sizeax.set_xlim(0, grid_size)ax.set_ylim(0, grid_size)
# Draw grid linesax.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 markerax.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 gridplt.gca().set_aspect('equal', adjustable='box') # Keep the grid squares equal in sizeplt.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
: Theextent
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 npimport 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 extentplt.subplot(1, 2, 2)plt.imshow(image, cmap='gray', extent=[0, 5, 0, 2]) # Map image to data coordinatesplt.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
-
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.
- By default, in an image (like what
-
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.
- When you use
-
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 inextent
.
import numpy as npimport 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 extentplt.subplot(2, 2, 2)plt.imshow(image, cmap='gray', extent=[0, 5, 0, 2]) # Map image to data coordinatesplt.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 coordinatesplt.title("With extent (mapping reversed)")# Axis values will change
# Display image with extentplt.subplot(2, 2, 4)plt.imshow(image, cmap='gray', extent=[0, 5, 0, 2], origin='lower') # Map image to data coordinatesplt.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 npimport matplotlib.pyplot as plt
# Function to create a spheredef 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 environmentgrid_size = 10x = 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 modeplt.ion()fig = plt.figure(figsize=(10, 8))ax = fig.add_subplot(111, projection='3d')
# Plot the groundax.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 spheresfor 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 labelsax.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 angleax.view_init(elev=20, azim=30)
# Show the plotplt.show()
# Keep the plot open for interactionplt.pause(0.1) # Allows the plot to refresh and be interactive