|
9 | 9 | from datetime import datetime, timedelta
|
10 | 10 | from typing import Any
|
11 | 11 |
|
| 12 | +import matplotlib.pyplot as plt |
12 | 13 | import numpy as np
|
13 | 14 | import pandas as pd
|
| 15 | +from matplotlib.figure import Figure |
| 16 | +from matplotlib.ticker import FuncFormatter |
14 | 17 | from rasterio.crs import CRS
|
15 | 18 |
|
16 | 19 | from .errors import DatasetNotFoundError
|
@@ -140,3 +143,61 @@ def __getitem__(self, query: BoundingBox) -> dict[str, Any]:
|
140 | 143 | sample = {'crs': self.crs, 'bounds': bboxes}
|
141 | 144 |
|
142 | 145 | return sample
|
| 146 | + |
| 147 | + def plot( |
| 148 | + self, |
| 149 | + sample: dict[str, Any], |
| 150 | + show_titles: bool = True, |
| 151 | + suptitle: str | None = None, |
| 152 | + ) -> Figure: |
| 153 | + """Plot a sample from the dataset. |
| 154 | +
|
| 155 | + Args: |
| 156 | + sample: a sample return by :meth:`__getitem__` |
| 157 | + show_titles: flag indicating whether to show titles above each panel |
| 158 | + suptitle: optional suptitle to use for Figure |
| 159 | + Returns: |
| 160 | + a matplotlib Figure with the rendered sample |
| 161 | +
|
| 162 | + .. versionadded:: 0.8 |
| 163 | + """ |
| 164 | + # Create figure and axis - using regular matplotlib axes |
| 165 | + fig, ax = plt.subplots(figsize=(10, 8)) |
| 166 | + ax.grid(ls='--') |
| 167 | + |
| 168 | + # Extract bounding boxes (coordinates) from the sample |
| 169 | + bboxes = sample['bounds'] |
| 170 | + |
| 171 | + # Extract coordinates and timestamps |
| 172 | + longitudes = [bbox[0] for bbox in bboxes] # minx |
| 173 | + latitudes = [bbox[1] for bbox in bboxes] # miny |
| 174 | + timestamps = [bbox[2] for bbox in bboxes] # mint |
| 175 | + |
| 176 | + # Plot the points with colors based on date |
| 177 | + scatter = ax.scatter(longitudes, latitudes, c=timestamps, edgecolors='black') |
| 178 | + |
| 179 | + # Create a formatter function |
| 180 | + def format_date(x: float, pos: int | None = None) -> str: |
| 181 | + # Convert timestamp to datetime |
| 182 | + return datetime.fromtimestamp(x).strftime('%Y-%m-%d') |
| 183 | + |
| 184 | + # Add a colorbar |
| 185 | + cbar = fig.colorbar(scatter, ax=ax, pad=0.04) |
| 186 | + cbar.set_label('Observed Timestamp', rotation=90, labelpad=-100, va='center') |
| 187 | + |
| 188 | + # Apply the formatter to the colorbar |
| 189 | + cbar.ax.yaxis.set_major_formatter(FuncFormatter(format_date)) |
| 190 | + |
| 191 | + # Set labels |
| 192 | + ax.set_xlabel('Longitude') |
| 193 | + ax.set_ylabel('Latitude') |
| 194 | + |
| 195 | + # Add titles if requested |
| 196 | + if show_titles: |
| 197 | + ax.set_title('GBIF Occurence Locations by Date') |
| 198 | + |
| 199 | + if suptitle is not None: |
| 200 | + fig.suptitle(suptitle) |
| 201 | + |
| 202 | + fig.tight_layout() |
| 203 | + return fig |
0 commit comments