Repository: sunpy/sunpy

Issue:
`sunpy.map.sample_at_coords()` should check that passed coordinates are on the map
### Describe the bug

There's not a check whether the passed coordinates to `sunpy.map.pixelate_coord_path` are actually within the bounds of the map. Without this its returning values that are not correct


### To Reproduce

```python
aia_map = sunpy.map.Map(AIA_171_IMAGE)

line_coords = SkyCoord([-1324, -1300], [500, 1000], unit=(u.arcsec, u.arcsec),
                       frame=aia_map.coordinate_frame)

intensity_coords = sunpy.map.pixelate_coord_path(aia_map, line_coords)
intensity = sunpy.map.sample_at_coords(aia_map, intensity_coords)
fig = plt.figure(figsize=(10, 4))
ax1 = fig.add_subplot(121, projection=aia_map)
aia_map.plot(axes=ax1, clip_interval=[1, 99.9]*u.percent)
ax1.plot_coord(intensity_coords)
ax1.plot_coord(line_coords[0], marker="o", color="blue", label="start")
ax1.plot_coord(line_coords[1], marker="o", color="green", label="end")
ax1.legend()

ax2 = fig.add_subplot(122)
ax2.plot(angular_separation, intensity)
ax2.set_xlabel("Angular distance along slit [arcsec]")
ax2.set_ylabel(f"Intensity [{aia_map.unit}]")
```
![pixelate_coord_path_error](https://github.com/sunpy/sunpy/assets/4620298/874b827c-cdf3-4934-947a-11b790adda91)






Discussion:
`pixelate_coord_path()` being able to return pixels that are outside the map bounds may be uncommon, but it is perfectly legitimate and well defined.

The problem is in `sample_at_coords()`, which will blithely access data array using negative array indices.  Since negative indexing is parsed as indexing from the end, rather than out-of-bounds access, such data access can succeed and return pixel values that have no reasonable correspondence to the pixels that you thought you were requesting.
ah yes of course, thanks. Ok cool, I'll work on this and add a PR. 


I've got it, you can stand down =)

Resolving patch:
diff --git a/sunpy/map/maputils.py b/sunpy/map/maputils.py
--- a/sunpy/map/maputils.py
+++ b/sunpy/map/maputils.py
@@ -140,6 +140,8 @@ def sample_at_coords(smap, coordinates):
     Uses nearest-neighbor interpolation of coordinates in map, as
     it effectively uses array indexing.
 
+    An error is raised if any of the coordinates fall outside the map bounds.
+
     Parameters
     ----------
     smap : `~sunpy.map.GenericMap`
@@ -156,6 +158,9 @@ def sample_at_coords(smap, coordinates):
     --------
     .. minigallery:: sunpy.map.sample_at_coords
     """
+    if not all(contains_coordinate(smap, coordinates)):
+        raise ValueError('At least one coordinate is not within the bounds of the map.')
+
     return u.Quantity(smap.data[smap.wcs.world_to_array_index(coordinates)], smap.unit)
 
 
@@ -581,6 +586,12 @@ def pixelate_coord_path(smap, coord_path, *, bresenham=False):
     If a pixel intersects the coordinate path at only its corner, it may not be
     returned due to the limitations of floating-point comparisons.
 
+    If part of the coordinate path lies outside of the bounds of the map, this
+    function will still return pixel coordinates that are consistent with the WCS of
+    the map, but attempting to obtain the map data at these pixel coordinates
+    (e.g., using :func:`~sunpy.map.sample_at_coords`) will raise an error, as these
+    pixels are not "real" and have no corresponding data.
+
     Returns
     -------
     `~astropy.coordinates.SkyCoord`


Test patch:
diff --git a/sunpy/map/tests/test_maputils.py b/sunpy/map/tests/test_maputils.py
--- a/sunpy/map/tests/test_maputils.py
+++ b/sunpy/map/tests/test_maputils.py
@@ -219,6 +219,12 @@ def test_data_at_coordinates(aia171_test_map, aia_test_arc):
     assert_quantity_allclose(data[-1], intensity_along_arc[-1])
 
 
+def test_sample_out_of_bounds(aia171_test_map):
+    point = aia171_test_map.pixel_to_world([-1, 1]*u.pix, [-1, 1]*u.pix)
+    with pytest.raises(ValueError, match='At least one coordinate is not within the bounds of the map.'):
+        sample_at_coords(aia171_test_map, point)
+
+
 def test_contains_solar_center(aia171_test_map, all_off_disk_map, all_on_disk_map, straddles_limb_map, sub_smap):
     assert contains_solar_center(aia171_test_map)
     assert not contains_solar_center(all_off_disk_map)