We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Remove date from NLCD glob/regex
### Description

We should remove the date from the NLCD glob/regex. NLCD products are regenerated every time a new release comes out, meaning the name (and unfortunately the hash) will change.

### Steps to reproduce

This came to me in a dream. 

### Version

0.5.0dev

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `torchgeo/datasets/nlcd.py`
Content:
```
1 # Copyright (c) Microsoft Corporation. All rights reserved.
2 # Licensed under the MIT License.
3 
4 """NLCD dataset."""
5 
6 import glob
7 import os
8 from typing import Any, Callable, Optional
9 
10 import matplotlib.pyplot as plt
11 import torch
12 from rasterio.crs import CRS
13 
14 from .geo import RasterDataset
15 from .utils import BoundingBox, download_url, extract_archive
16 
17 
18 class NLCD(RasterDataset):
19     """National Land Cover Database (NLCD) dataset.
20 
21     The `NLCD dataset
22     <https://www.usgs.gov/centers/eros/science/national-land-cover-database>`_
23     is a land cover product that covers the United States and Puerto Rico. The current
24     implementation supports maps for the continental United States only. The product is
25     a joint effort between the United States Geological Survey
26     (`USGS <https://www.usgs.gov/>`_) and the Multi-Resolution Land Characteristics
27     Consortium (`MRLC <https://www.mrlc.gov/>`_) which released the first product
28     in 2001 with new updates every five years since then.
29 
30     The dataset contains the following 17 classes:
31 
32     0. Background
33     #. Open Water
34     #. Perennial Ice/Snow
35     #. Developed, Open Space
36     #. Developed, Low Intensity
37     #. Developed, Medium Intensity
38     #. Developed, High Intensity
39     #. Barren Land (Rock/Sand/Clay)
40     #. Deciduous Forest
41     #. Evergreen Forest
42     #. Mixed Forest
43     #. Shrub/Scrub
44     #. Grassland/Herbaceous
45     #. Pasture/Hay
46     #. Cultivated Crops
47     #. Woody Wetlands
48     #. Emergent Herbaceous Wetlands
49 
50     Detailed descriptions of the classes can be found
51     `here <https://www.mrlc.gov/data/legends/national-land-cover-database-class-legend-and-description>`__.
52 
53     Dataset format:
54 
55     * single channel .img file with integer class labels
56 
57     If you use this dataset in your research, please use the corresponding citation:
58 
59     * 2001: https://doi.org/10.5066/P9MZGHLF
60     * 2006: https://doi.org/10.5066/P9HBR9V3
61     * 2011: https://doi.org/10.5066/P97S2IID
62     * 2016: https://doi.org/10.5066/P96HHBIE
63     * 2019: https://doi.org/10.5066/P9KZCM54
64 
65     .. versionadded:: 0.5
66     """  # noqa: E501
67 
68     filename_glob = "nlcd_*_land_cover_l48_20210604.img"
69     filename_regex = (
70         r"nlcd_(?P<date>\d{4})_land_cover_l48_(?P<publication_date>\d{8})\.img"
71     )
72     zipfile_glob = "nlcd_*_land_cover_l48_20210604.zip"
73     date_format = "%Y"
74     is_image = False
75 
76     url = "https://s3-us-west-2.amazonaws.com/mrlc/nlcd_{}_land_cover_l48_20210604.zip"
77 
78     md5s = {
79         2001: "538166a4d783204764e3df3b221fc4cd",
80         2006: "67454e7874a00294adb9442374d0c309",
81         2011: "ea524c835d173658eeb6fa3c8e6b917b",
82         2016: "452726f6e3bd3f70d8ca2476723d238a",
83         2019: "82851c3f8105763b01c83b4a9e6f3961",
84     }
85 
86     cmap = {
87         0: (0, 0, 0, 0),
88         11: (70, 107, 159, 255),
89         12: (209, 222, 248, 255),
90         21: (222, 197, 197, 255),
91         22: (217, 146, 130, 255),
92         23: (235, 0, 0, 255),
93         24: (171, 0, 0, 255),
94         31: (179, 172, 159, 255),
95         41: (104, 171, 95, 255),
96         42: (28, 95, 44, 255),
97         43: (181, 197, 143, 255),
98         52: (204, 184, 121, 255),
99         71: (223, 223, 194, 255),
100         81: (220, 217, 57, 255),
101         82: (171, 108, 40, 255),
102         90: (184, 217, 235, 255),
103         95: (108, 159, 184, 255),
104     }
105 
106     def __init__(
107         self,
108         root: str = "data",
109         crs: Optional[CRS] = None,
110         res: Optional[float] = None,
111         years: list[int] = [2019],
112         classes: list[int] = list(cmap.keys()),
113         transforms: Optional[Callable[[dict[str, Any]], dict[str, Any]]] = None,
114         cache: bool = True,
115         download: bool = False,
116         checksum: bool = False,
117     ) -> None:
118         """Initialize a new Dataset instance.
119 
120         Args:
121             root: root directory where dataset can be found
122             crs: :term:`coordinate reference system (CRS)` to warp to
123                 (defaults to the CRS of the first file found)
124             res: resolution of the dataset in units of CRS
125                 (defaults to the resolution of the first file found)
126             years: list of years for which to use nlcd layer
127             classes: list of classes to include, the rest will be mapped to 0
128                 (defaults to all classes)
129             transforms: a function/transform that takes an input sample
130                 and returns a transformed version
131             cache: if True, cache file handle to speed up repeated sampling
132             download: if True, download dataset and store it in the root directory
133             checksum: if True, check the MD5 after downloading files (may be slow)
134 
135         Raises:
136             AssertionError: if ``years`` or ``classes`` are invalid
137             FileNotFoundError: if no files are found in ``root``
138             RuntimeError: if ``download=False`` but dataset is missing or checksum fails
139         """
140         assert set(years) <= self.md5s.keys(), (
141             "NLCD data product only exists for the following years: "
142             f"{list(self.md5s.keys())}."
143         )
144         assert (
145             set(classes) <= self.cmap.keys()
146         ), f"Only the following classes are valid: {list(self.cmap.keys())}."
147         assert 0 in classes, "Classes must include the background class: 0"
148 
149         self.root = root
150         self.years = years
151         self.classes = classes
152         self.download = download
153         self.checksum = checksum
154         self.ordinal_map = torch.zeros(max(self.cmap.keys()) + 1, dtype=self.dtype)
155         self.ordinal_cmap = torch.zeros((len(self.classes), 4), dtype=torch.uint8)
156 
157         self._verify()
158 
159         super().__init__(root, crs, res, transforms=transforms, cache=cache)
160 
161         # Map chosen classes to ordinal numbers, all others mapped to background class
162         for v, k in enumerate(self.classes):
163             self.ordinal_map[k] = v
164             self.ordinal_cmap[v] = torch.tensor(self.cmap[k])
165 
166     def __getitem__(self, query: BoundingBox) -> dict[str, Any]:
167         """Retrieve mask and metadata indexed by query.
168 
169         Args:
170             query: (minx, maxx, miny, maxy, mint, maxt) coordinates to index
171 
172         Returns:
173             sample of mask and metadata at that index
174 
175         Raises:
176             IndexError: if query is not found in the index
177         """
178         sample = super().__getitem__(query)
179         sample["mask"] = self.ordinal_map[sample["mask"]]
180         return sample
181 
182     def _verify(self) -> None:
183         """Verify the integrity of the dataset.
184 
185         Raises:
186             RuntimeError: if ``download=False`` but dataset is missing or checksum fails
187         """
188         # Check if the extracted files already exist
189         exists = []
190         for year in self.years:
191             filename_year = self.filename_glob.replace("*", str(year))
192             pathname = os.path.join(self.root, "**", filename_year)
193             if glob.glob(pathname, recursive=True):
194                 exists.append(True)
195             else:
196                 exists.append(False)
197 
198         if all(exists):
199             return
200 
201         # Check if the zip files have already been downloaded
202         exists = []
203         for year in self.years:
204             zipfile_year = self.zipfile_glob.replace("*", str(year))
205             pathname = os.path.join(self.root, "**", zipfile_year)
206             if glob.glob(pathname, recursive=True):
207                 exists.append(True)
208                 self._extract()
209             else:
210                 exists.append(False)
211 
212         if all(exists):
213             return
214 
215         # Check if the user requested to download the dataset
216         if not self.download:
217             raise RuntimeError(
218                 f"Dataset not found in `root={self.root}` and `download=False`, "
219                 "either specify a different `root` directory or use `download=True` "
220                 "to automatically download the dataset."
221             )
222 
223         # Download the dataset
224         self._download()
225         self._extract()
226 
227     def _download(self) -> None:
228         """Download the dataset."""
229         for year in self.years:
230             download_url(
231                 self.url.format(year),
232                 self.root,
233                 md5=self.md5s[year] if self.checksum else None,
234             )
235 
236     def _extract(self) -> None:
237         """Extract the dataset."""
238         for year in self.years:
239             zipfile_name = self.zipfile_glob.replace("*", str(year))
240             pathname = os.path.join(self.root, "**", zipfile_name)
241             extract_archive(glob.glob(pathname, recursive=True)[0], self.root)
242 
243     def plot(
244         self,
245         sample: dict[str, Any],
246         show_titles: bool = True,
247         suptitle: Optional[str] = None,
248     ) -> plt.Figure:
249         """Plot a sample from the dataset.
250 
251         Args:
252             sample: a sample returned by :meth:`RasterDataset.__getitem__`
253             show_titles: flag indicating whether to show titles above each panel
254             suptitle: optional string to use as a suptitle
255 
256         Returns:
257             a matplotlib Figure with the rendered sample
258         """
259         mask = sample["mask"].squeeze()
260         ncols = 1
261 
262         showing_predictions = "prediction" in sample
263         if showing_predictions:
264             pred = sample["prediction"].squeeze()
265             ncols = 2
266 
267         fig, axs = plt.subplots(
268             nrows=1, ncols=ncols, figsize=(ncols * 4, 4), squeeze=False
269         )
270 
271         axs[0, 0].imshow(self.ordinal_cmap[mask], interpolation="none")
272         axs[0, 0].axis("off")
273 
274         if show_titles:
275             axs[0, 0].set_title("Mask")
276 
277         if showing_predictions:
278             axs[0, 1].imshow(self.ordinal_cmap[pred], interpolation="none")
279             axs[0, 1].axis("off")
280             if show_titles:
281                 axs[0, 1].set_title("Prediction")
282 
283         if suptitle is not None:
284             plt.suptitle(suptitle)
285 
286         return fig
287
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/torchgeo/datasets/nlcd.py b/torchgeo/datasets/nlcd.py
--- a/torchgeo/datasets/nlcd.py
+++ b/torchgeo/datasets/nlcd.py
@@ -65,11 +65,11 @@
     .. versionadded:: 0.5
     """  # noqa: E501
 
-    filename_glob = "nlcd_*_land_cover_l48_20210604.img"
+    filename_glob = "nlcd_*_land_cover_l48_*.img"
     filename_regex = (
         r"nlcd_(?P<date>\d{4})_land_cover_l48_(?P<publication_date>\d{8})\.img"
     )
-    zipfile_glob = "nlcd_*_land_cover_l48_20210604.zip"
+    zipfile_glob = "nlcd_*_land_cover_l48_*.zip"
     date_format = "%Y"
     is_image = False
 
@@ -188,7 +188,7 @@
         # Check if the extracted files already exist
         exists = []
         for year in self.years:
-            filename_year = self.filename_glob.replace("*", str(year))
+            filename_year = self.filename_glob.replace("*", str(year), 1)
             pathname = os.path.join(self.root, "**", filename_year)
             if glob.glob(pathname, recursive=True):
                 exists.append(True)
@@ -201,7 +201,7 @@
         # Check if the zip files have already been downloaded
         exists = []
         for year in self.years:
-            zipfile_year = self.zipfile_glob.replace("*", str(year))
+            zipfile_year = self.zipfile_glob.replace("*", str(year), 1)
             pathname = os.path.join(self.root, "**", zipfile_year)
             if glob.glob(pathname, recursive=True):
                 exists.append(True)
@@ -236,7 +236,7 @@
     def _extract(self) -> None:
         """Extract the dataset."""
         for year in self.years:
-            zipfile_name = self.zipfile_glob.replace("*", str(year))
+            zipfile_name = self.zipfile_glob.replace("*", str(year), 1)
             pathname = os.path.join(self.root, "**", zipfile_name)
             extract_archive(glob.glob(pathname, recursive=True)[0], self.root)

{"golden_diff": "diff --git a/torchgeo/datasets/nlcd.py b/torchgeo/datasets/nlcd.py\n--- a/torchgeo/datasets/nlcd.py\n+++ b/torchgeo/datasets/nlcd.py\n@@ -65,11 +65,11 @@\n     .. versionadded:: 0.5\n     \"\"\"  # noqa: E501\n \n-    filename_glob = \"nlcd_*_land_cover_l48_20210604.img\"\n+    filename_glob = \"nlcd_*_land_cover_l48_*.img\"\n     filename_regex = (\n         r\"nlcd_(?P<date>\\d{4})_land_cover_l48_(?P<publication_date>\\d{8})\\.img\"\n     )\n-    zipfile_glob = \"nlcd_*_land_cover_l48_20210604.zip\"\n+    zipfile_glob = \"nlcd_*_land_cover_l48_*.zip\"\n     date_format = \"%Y\"\n     is_image = False\n \n@@ -188,7 +188,7 @@\n         # Check if the extracted files already exist\n         exists = []\n         for year in self.years:\n-            filename_year = self.filename_glob.replace(\"*\", str(year))\n+            filename_year = self.filename_glob.replace(\"*\", str(year), 1)\n             pathname = os.path.join(self.root, \"**\", filename_year)\n             if glob.glob(pathname, recursive=True):\n                 exists.append(True)\n@@ -201,7 +201,7 @@\n         # Check if the zip files have already been downloaded\n         exists = []\n         for year in self.years:\n-            zipfile_year = self.zipfile_glob.replace(\"*\", str(year))\n+            zipfile_year = self.zipfile_glob.replace(\"*\", str(year), 1)\n             pathname = os.path.join(self.root, \"**\", zipfile_year)\n             if glob.glob(pathname, recursive=True):\n                 exists.append(True)\n@@ -236,7 +236,7 @@\n     def _extract(self) -> None:\n         \"\"\"Extract the dataset.\"\"\"\n         for year in self.years:\n-            zipfile_name = self.zipfile_glob.replace(\"*\", str(year))\n+            zipfile_name = self.zipfile_glob.replace(\"*\", str(year), 1)\n             pathname = os.path.join(self.root, \"**\", zipfile_name)\n             extract_archive(glob.glob(pathname, recursive=True)[0], self.root)\n", "issue": "Remove date from NLCD glob/regex\n### Description\n\nWe should remove the date from the NLCD glob/regex. NLCD products are regenerated every time a new release comes out, meaning the name (and unfortunately the hash) will change.\n\n### Steps to reproduce\n\nThis came to me in a dream. \n\n### Version\n\n0.5.0dev\n", "before_files": [{"content": "# Copyright (c) Microsoft Corporation. All rights reserved.\n# Licensed under the MIT License.\n\n\"\"\"NLCD dataset.\"\"\"\n\nimport glob\nimport os\nfrom typing import Any, Callable, Optional\n\nimport matplotlib.pyplot as plt\nimport torch\nfrom rasterio.crs import CRS\n\nfrom .geo import RasterDataset\nfrom .utils import BoundingBox, download_url, extract_archive\n\n\nclass NLCD(RasterDataset):\n    \"\"\"National Land Cover Database (NLCD) dataset.\n\n    The `NLCD dataset\n    <https://www.usgs.gov/centers/eros/science/national-land-cover-database>`_\n    is a land cover product that covers the United States and Puerto Rico. The current\n    implementation supports maps for the continental United States only. The product is\n    a joint effort between the United States Geological Survey\n    (`USGS <https://www.usgs.gov/>`_) and the Multi-Resolution Land Characteristics\n    Consortium (`MRLC <https://www.mrlc.gov/>`_) which released the first product\n    in 2001 with new updates every five years since then.\n\n    The dataset contains the following 17 classes:\n\n    0. Background\n    #. Open Water\n    #. Perennial Ice/Snow\n    #. Developed, Open Space\n    #. Developed, Low Intensity\n    #. Developed, Medium Intensity\n    #. Developed, High Intensity\n    #. Barren Land (Rock/Sand/Clay)\n    #. Deciduous Forest\n    #. Evergreen Forest\n    #. Mixed Forest\n    #. Shrub/Scrub\n    #. Grassland/Herbaceous\n    #. Pasture/Hay\n    #. Cultivated Crops\n    #. Woody Wetlands\n    #. Emergent Herbaceous Wetlands\n\n    Detailed descriptions of the classes can be found\n    `here <https://www.mrlc.gov/data/legends/national-land-cover-database-class-legend-and-description>`__.\n\n    Dataset format:\n\n    * single channel .img file with integer class labels\n\n    If you use this dataset in your research, please use the corresponding citation:\n\n    * 2001: https://doi.org/10.5066/P9MZGHLF\n    * 2006: https://doi.org/10.5066/P9HBR9V3\n    * 2011: https://doi.org/10.5066/P97S2IID\n    * 2016: https://doi.org/10.5066/P96HHBIE\n    * 2019: https://doi.org/10.5066/P9KZCM54\n\n    .. versionadded:: 0.5\n    \"\"\"  # noqa: E501\n\n    filename_glob = \"nlcd_*_land_cover_l48_20210604.img\"\n    filename_regex = (\n        r\"nlcd_(?P<date>\\d{4})_land_cover_l48_(?P<publication_date>\\d{8})\\.img\"\n    )\n    zipfile_glob = \"nlcd_*_land_cover_l48_20210604.zip\"\n    date_format = \"%Y\"\n    is_image = False\n\n    url = \"https://s3-us-west-2.amazonaws.com/mrlc/nlcd_{}_land_cover_l48_20210604.zip\"\n\n    md5s = {\n        2001: \"538166a4d783204764e3df3b221fc4cd\",\n        2006: \"67454e7874a00294adb9442374d0c309\",\n        2011: \"ea524c835d173658eeb6fa3c8e6b917b\",\n        2016: \"452726f6e3bd3f70d8ca2476723d238a\",\n        2019: \"82851c3f8105763b01c83b4a9e6f3961\",\n    }\n\n    cmap = {\n        0: (0, 0, 0, 0),\n        11: (70, 107, 159, 255),\n        12: (209, 222, 248, 255),\n        21: (222, 197, 197, 255),\n        22: (217, 146, 130, 255),\n        23: (235, 0, 0, 255),\n        24: (171, 0, 0, 255),\n        31: (179, 172, 159, 255),\n        41: (104, 171, 95, 255),\n        42: (28, 95, 44, 255),\n        43: (181, 197, 143, 255),\n        52: (204, 184, 121, 255),\n        71: (223, 223, 194, 255),\n        81: (220, 217, 57, 255),\n        82: (171, 108, 40, 255),\n        90: (184, 217, 235, 255),\n        95: (108, 159, 184, 255),\n    }\n\n    def __init__(\n        self,\n        root: str = \"data\",\n        crs: Optional[CRS] = None,\n        res: Optional[float] = None,\n        years: list[int] = [2019],\n        classes: list[int] = list(cmap.keys()),\n        transforms: Optional[Callable[[dict[str, Any]], dict[str, Any]]] = None,\n        cache: bool = True,\n        download: bool = False,\n        checksum: bool = False,\n    ) -> None:\n        \"\"\"Initialize a new Dataset instance.\n\n        Args:\n            root: root directory where dataset can be found\n            crs: :term:`coordinate reference system (CRS)` to warp to\n                (defaults to the CRS of the first file found)\n            res: resolution of the dataset in units of CRS\n                (defaults to the resolution of the first file found)\n            years: list of years for which to use nlcd layer\n            classes: list of classes to include, the rest will be mapped to 0\n                (defaults to all classes)\n            transforms: a function/transform that takes an input sample\n                and returns a transformed version\n            cache: if True, cache file handle to speed up repeated sampling\n            download: if True, download dataset and store it in the root directory\n            checksum: if True, check the MD5 after downloading files (may be slow)\n\n        Raises:\n            AssertionError: if ``years`` or ``classes`` are invalid\n            FileNotFoundError: if no files are found in ``root``\n            RuntimeError: if ``download=False`` but dataset is missing or checksum fails\n        \"\"\"\n        assert set(years) <= self.md5s.keys(), (\n            \"NLCD data product only exists for the following years: \"\n            f\"{list(self.md5s.keys())}.\"\n        )\n        assert (\n            set(classes) <= self.cmap.keys()\n        ), f\"Only the following classes are valid: {list(self.cmap.keys())}.\"\n        assert 0 in classes, \"Classes must include the background class: 0\"\n\n        self.root = root\n        self.years = years\n        self.classes = classes\n        self.download = download\n        self.checksum = checksum\n        self.ordinal_map = torch.zeros(max(self.cmap.keys()) + 1, dtype=self.dtype)\n        self.ordinal_cmap = torch.zeros((len(self.classes), 4), dtype=torch.uint8)\n\n        self._verify()\n\n        super().__init__(root, crs, res, transforms=transforms, cache=cache)\n\n        # Map chosen classes to ordinal numbers, all others mapped to background class\n        for v, k in enumerate(self.classes):\n            self.ordinal_map[k] = v\n            self.ordinal_cmap[v] = torch.tensor(self.cmap[k])\n\n    def __getitem__(self, query: BoundingBox) -> dict[str, Any]:\n        \"\"\"Retrieve mask and metadata indexed by query.\n\n        Args:\n            query: (minx, maxx, miny, maxy, mint, maxt) coordinates to index\n\n        Returns:\n            sample of mask and metadata at that index\n\n        Raises:\n            IndexError: if query is not found in the index\n        \"\"\"\n        sample = super().__getitem__(query)\n        sample[\"mask\"] = self.ordinal_map[sample[\"mask\"]]\n        return sample\n\n    def _verify(self) -> None:\n        \"\"\"Verify the integrity of the dataset.\n\n        Raises:\n            RuntimeError: if ``download=False`` but dataset is missing or checksum fails\n        \"\"\"\n        # Check if the extracted files already exist\n        exists = []\n        for year in self.years:\n            filename_year = self.filename_glob.replace(\"*\", str(year))\n            pathname = os.path.join(self.root, \"**\", filename_year)\n            if glob.glob(pathname, recursive=True):\n                exists.append(True)\n            else:\n                exists.append(False)\n\n        if all(exists):\n            return\n\n        # Check if the zip files have already been downloaded\n        exists = []\n        for year in self.years:\n            zipfile_year = self.zipfile_glob.replace(\"*\", str(year))\n            pathname = os.path.join(self.root, \"**\", zipfile_year)\n            if glob.glob(pathname, recursive=True):\n                exists.append(True)\n                self._extract()\n            else:\n                exists.append(False)\n\n        if all(exists):\n            return\n\n        # Check if the user requested to download the dataset\n        if not self.download:\n            raise RuntimeError(\n                f\"Dataset not found in `root={self.root}` and `download=False`, \"\n                \"either specify a different `root` directory or use `download=True` \"\n                \"to automatically download the dataset.\"\n            )\n\n        # Download the dataset\n        self._download()\n        self._extract()\n\n    def _download(self) -> None:\n        \"\"\"Download the dataset.\"\"\"\n        for year in self.years:\n            download_url(\n                self.url.format(year),\n                self.root,\n                md5=self.md5s[year] if self.checksum else None,\n            )\n\n    def _extract(self) -> None:\n        \"\"\"Extract the dataset.\"\"\"\n        for year in self.years:\n            zipfile_name = self.zipfile_glob.replace(\"*\", str(year))\n            pathname = os.path.join(self.root, \"**\", zipfile_name)\n            extract_archive(glob.glob(pathname, recursive=True)[0], self.root)\n\n    def plot(\n        self,\n        sample: dict[str, Any],\n        show_titles: bool = True,\n        suptitle: Optional[str] = None,\n    ) -> plt.Figure:\n        \"\"\"Plot a sample from the dataset.\n\n        Args:\n            sample: a sample returned by :meth:`RasterDataset.__getitem__`\n            show_titles: flag indicating whether to show titles above each panel\n            suptitle: optional string to use as a suptitle\n\n        Returns:\n            a matplotlib Figure with the rendered sample\n        \"\"\"\n        mask = sample[\"mask\"].squeeze()\n        ncols = 1\n\n        showing_predictions = \"prediction\" in sample\n        if showing_predictions:\n            pred = sample[\"prediction\"].squeeze()\n            ncols = 2\n\n        fig, axs = plt.subplots(\n            nrows=1, ncols=ncols, figsize=(ncols * 4, 4), squeeze=False\n        )\n\n        axs[0, 0].imshow(self.ordinal_cmap[mask], interpolation=\"none\")\n        axs[0, 0].axis(\"off\")\n\n        if show_titles:\n            axs[0, 0].set_title(\"Mask\")\n\n        if showing_predictions:\n            axs[0, 1].imshow(self.ordinal_cmap[pred], interpolation=\"none\")\n            axs[0, 1].axis(\"off\")\n            if show_titles:\n                axs[0, 1].set_title(\"Prediction\")\n\n        if suptitle is not None:\n            plt.suptitle(suptitle)\n\n        return fig\n", "path": "torchgeo/datasets/nlcd.py"}], "after_files": [{"content": "# Copyright (c) Microsoft Corporation. All rights reserved.\n# Licensed under the MIT License.\n\n\"\"\"NLCD dataset.\"\"\"\n\nimport glob\nimport os\nfrom typing import Any, Callable, Optional\n\nimport matplotlib.pyplot as plt\nimport torch\nfrom rasterio.crs import CRS\n\nfrom .geo import RasterDataset\nfrom .utils import BoundingBox, download_url, extract_archive\n\n\nclass NLCD(RasterDataset):\n    \"\"\"National Land Cover Database (NLCD) dataset.\n\n    The `NLCD dataset\n    <https://www.usgs.gov/centers/eros/science/national-land-cover-database>`_\n    is a land cover product that covers the United States and Puerto Rico. The current\n    implementation supports maps for the continental United States only. The product is\n    a joint effort between the United States Geological Survey\n    (`USGS <https://www.usgs.gov/>`_) and the Multi-Resolution Land Characteristics\n    Consortium (`MRLC <https://www.mrlc.gov/>`_) which released the first product\n    in 2001 with new updates every five years since then.\n\n    The dataset contains the following 17 classes:\n\n    0. Background\n    #. Open Water\n    #. Perennial Ice/Snow\n    #. Developed, Open Space\n    #. Developed, Low Intensity\n    #. Developed, Medium Intensity\n    #. Developed, High Intensity\n    #. Barren Land (Rock/Sand/Clay)\n    #. Deciduous Forest\n    #. Evergreen Forest\n    #. Mixed Forest\n    #. Shrub/Scrub\n    #. Grassland/Herbaceous\n    #. Pasture/Hay\n    #. Cultivated Crops\n    #. Woody Wetlands\n    #. Emergent Herbaceous Wetlands\n\n    Detailed descriptions of the classes can be found\n    `here <https://www.mrlc.gov/data/legends/national-land-cover-database-class-legend-and-description>`__.\n\n    Dataset format:\n\n    * single channel .img file with integer class labels\n\n    If you use this dataset in your research, please use the corresponding citation:\n\n    * 2001: https://doi.org/10.5066/P9MZGHLF\n    * 2006: https://doi.org/10.5066/P9HBR9V3\n    * 2011: https://doi.org/10.5066/P97S2IID\n    * 2016: https://doi.org/10.5066/P96HHBIE\n    * 2019: https://doi.org/10.5066/P9KZCM54\n\n    .. versionadded:: 0.5\n    \"\"\"  # noqa: E501\n\n    filename_glob = \"nlcd_*_land_cover_l48_*.img\"\n    filename_regex = (\n        r\"nlcd_(?P<date>\\d{4})_land_cover_l48_(?P<publication_date>\\d{8})\\.img\"\n    )\n    zipfile_glob = \"nlcd_*_land_cover_l48_*.zip\"\n    date_format = \"%Y\"\n    is_image = False\n\n    url = \"https://s3-us-west-2.amazonaws.com/mrlc/nlcd_{}_land_cover_l48_20210604.zip\"\n\n    md5s = {\n        2001: \"538166a4d783204764e3df3b221fc4cd\",\n        2006: \"67454e7874a00294adb9442374d0c309\",\n        2011: \"ea524c835d173658eeb6fa3c8e6b917b\",\n        2016: \"452726f6e3bd3f70d8ca2476723d238a\",\n        2019: \"82851c3f8105763b01c83b4a9e6f3961\",\n    }\n\n    cmap = {\n        0: (0, 0, 0, 0),\n        11: (70, 107, 159, 255),\n        12: (209, 222, 248, 255),\n        21: (222, 197, 197, 255),\n        22: (217, 146, 130, 255),\n        23: (235, 0, 0, 255),\n        24: (171, 0, 0, 255),\n        31: (179, 172, 159, 255),\n        41: (104, 171, 95, 255),\n        42: (28, 95, 44, 255),\n        43: (181, 197, 143, 255),\n        52: (204, 184, 121, 255),\n        71: (223, 223, 194, 255),\n        81: (220, 217, 57, 255),\n        82: (171, 108, 40, 255),\n        90: (184, 217, 235, 255),\n        95: (108, 159, 184, 255),\n    }\n\n    def __init__(\n        self,\n        root: str = \"data\",\n        crs: Optional[CRS] = None,\n        res: Optional[float] = None,\n        years: list[int] = [2019],\n        classes: list[int] = list(cmap.keys()),\n        transforms: Optional[Callable[[dict[str, Any]], dict[str, Any]]] = None,\n        cache: bool = True,\n        download: bool = False,\n        checksum: bool = False,\n    ) -> None:\n        \"\"\"Initialize a new Dataset instance.\n\n        Args:\n            root: root directory where dataset can be found\n            crs: :term:`coordinate reference system (CRS)` to warp to\n                (defaults to the CRS of the first file found)\n            res: resolution of the dataset in units of CRS\n                (defaults to the resolution of the first file found)\n            years: list of years for which to use nlcd layer\n            classes: list of classes to include, the rest will be mapped to 0\n                (defaults to all classes)\n            transforms: a function/transform that takes an input sample\n                and returns a transformed version\n            cache: if True, cache file handle to speed up repeated sampling\n            download: if True, download dataset and store it in the root directory\n            checksum: if True, check the MD5 after downloading files (may be slow)\n\n        Raises:\n            AssertionError: if ``years`` or ``classes`` are invalid\n            FileNotFoundError: if no files are found in ``root``\n            RuntimeError: if ``download=False`` but dataset is missing or checksum fails\n        \"\"\"\n        assert set(years) <= self.md5s.keys(), (\n            \"NLCD data product only exists for the following years: \"\n            f\"{list(self.md5s.keys())}.\"\n        )\n        assert (\n            set(classes) <= self.cmap.keys()\n        ), f\"Only the following classes are valid: {list(self.cmap.keys())}.\"\n        assert 0 in classes, \"Classes must include the background class: 0\"\n\n        self.root = root\n        self.years = years\n        self.classes = classes\n        self.download = download\n        self.checksum = checksum\n        self.ordinal_map = torch.zeros(max(self.cmap.keys()) + 1, dtype=self.dtype)\n        self.ordinal_cmap = torch.zeros((len(self.classes), 4), dtype=torch.uint8)\n\n        self._verify()\n\n        super().__init__(root, crs, res, transforms=transforms, cache=cache)\n\n        # Map chosen classes to ordinal numbers, all others mapped to background class\n        for v, k in enumerate(self.classes):\n            self.ordinal_map[k] = v\n            self.ordinal_cmap[v] = torch.tensor(self.cmap[k])\n\n    def __getitem__(self, query: BoundingBox) -> dict[str, Any]:\n        \"\"\"Retrieve mask and metadata indexed by query.\n\n        Args:\n            query: (minx, maxx, miny, maxy, mint, maxt) coordinates to index\n\n        Returns:\n            sample of mask and metadata at that index\n\n        Raises:\n            IndexError: if query is not found in the index\n        \"\"\"\n        sample = super().__getitem__(query)\n        sample[\"mask\"] = self.ordinal_map[sample[\"mask\"]]\n        return sample\n\n    def _verify(self) -> None:\n        \"\"\"Verify the integrity of the dataset.\n\n        Raises:\n            RuntimeError: if ``download=False`` but dataset is missing or checksum fails\n        \"\"\"\n        # Check if the extracted files already exist\n        exists = []\n        for year in self.years:\n            filename_year = self.filename_glob.replace(\"*\", str(year), 1)\n            pathname = os.path.join(self.root, \"**\", filename_year)\n            if glob.glob(pathname, recursive=True):\n                exists.append(True)\n            else:\n                exists.append(False)\n\n        if all(exists):\n            return\n\n        # Check if the zip files have already been downloaded\n        exists = []\n        for year in self.years:\n            zipfile_year = self.zipfile_glob.replace(\"*\", str(year), 1)\n            pathname = os.path.join(self.root, \"**\", zipfile_year)\n            if glob.glob(pathname, recursive=True):\n                exists.append(True)\n                self._extract()\n            else:\n                exists.append(False)\n\n        if all(exists):\n            return\n\n        # Check if the user requested to download the dataset\n        if not self.download:\n            raise RuntimeError(\n                f\"Dataset not found in `root={self.root}` and `download=False`, \"\n                \"either specify a different `root` directory or use `download=True` \"\n                \"to automatically download the dataset.\"\n            )\n\n        # Download the dataset\n        self._download()\n        self._extract()\n\n    def _download(self) -> None:\n        \"\"\"Download the dataset.\"\"\"\n        for year in self.years:\n            download_url(\n                self.url.format(year),\n                self.root,\n                md5=self.md5s[year] if self.checksum else None,\n            )\n\n    def _extract(self) -> None:\n        \"\"\"Extract the dataset.\"\"\"\n        for year in self.years:\n            zipfile_name = self.zipfile_glob.replace(\"*\", str(year), 1)\n            pathname = os.path.join(self.root, \"**\", zipfile_name)\n            extract_archive(glob.glob(pathname, recursive=True)[0], self.root)\n\n    def plot(\n        self,\n        sample: dict[str, Any],\n        show_titles: bool = True,\n        suptitle: Optional[str] = None,\n    ) -> plt.Figure:\n        \"\"\"Plot a sample from the dataset.\n\n        Args:\n            sample: a sample returned by :meth:`RasterDataset.__getitem__`\n            show_titles: flag indicating whether to show titles above each panel\n            suptitle: optional string to use as a suptitle\n\n        Returns:\n            a matplotlib Figure with the rendered sample\n        \"\"\"\n        mask = sample[\"mask\"].squeeze()\n        ncols = 1\n\n        showing_predictions = \"prediction\" in sample\n        if showing_predictions:\n            pred = sample[\"prediction\"].squeeze()\n            ncols = 2\n\n        fig, axs = plt.subplots(\n            nrows=1, ncols=ncols, figsize=(ncols * 4, 4), squeeze=False\n        )\n\n        axs[0, 0].imshow(self.ordinal_cmap[mask], interpolation=\"none\")\n        axs[0, 0].axis(\"off\")\n\n        if show_titles:\n            axs[0, 0].set_title(\"Mask\")\n\n        if showing_predictions:\n            axs[0, 1].imshow(self.ordinal_cmap[pred], interpolation=\"none\")\n            axs[0, 1].axis(\"off\")\n            if show_titles:\n                axs[0, 1].set_title(\"Prediction\")\n\n        if suptitle is not None:\n            plt.suptitle(suptitle)\n\n        return fig\n", "path": "torchgeo/datasets/nlcd.py"}]}