Repository: sunpy/sunpy

Issue:
Map plotting does not work without WCSAxes
I have a data set 600x600 that represents electron densities and I'm trying to put it into a sunpy map like so: 
```python
header = {'cdelt1':20, 'cdelt2':20, 'telescop':'Electron Density Map'}
den_map = sunpy.map.Map(data, header)
den_map.peek()
```
`den_map.peek()` works fine but when I try to use `den_map.plot()` I get the following error that doesn't make much sense: 
```python
ValueError: Latitude angle(s) must be within -90 deg <= angle <= 90 deg, got -5990.0 deg
```
This was tested on an older version of sunpy and it works fine but doesn't work with 0.8.1. Any help would be much appreciated.



Discussion:
Hi @dianamorosan I can not replicate this on my local machine, I ran the following code:
```python
In [1]: import matplotlib.pyplot as plt
   ...: import numpy as np
   ...: import sunpy.map
   ...: 
   ...: data = np.random.random((600,600))
   ...: header = {'cdelt1':20, 'cdelt2':20, 'telescop':'Electron Density Map'}
   ...: den_map = sunpy.map.Map(data, header)
   ...: den_map.plot()
   ...: plt.show()
```
and I got a plot without any error (just a lot of warnings about default info).

Can you post the output of `sunpy.system_info()` to see if I can spot anything obviously wrong.
Hi, here is the output of sunpy.system_info():

==========================================================
 SunPy Installation Information

==========================================================

###########
 General
###########
Time : Wednesday, 25. October 2017 10:43AM UT
System : Darwin
Processor : i386
Arch : 64bit
SunPy : 0.8.1
SunPy_git : 69507e4df8f9280f4bada4b64015d556df768368
OS: Mac OS X 10.12.6 (i386)


###########
 Required Libraries 
###########
Python: 2.7.13
NumPy: 1.13.1
SciPy: 0.19.1
matplotlib: 2.0.2
Astropy: 2.0.2
Pandas: 0.20.3


###########
 Recommended Libraries 
###########
beautifulsoup: NOT INSTALLED
PyQt: NOT INSTALLED
SUDS: NOT INSTALLED
Sqlalchemy: NOT INSTALLED
Requests: NOT INSTALLED
I think I figured it out. @Cadair the code you sent above works fine for me. I got the error when I tried to plot the map as a subplot:

In [1]:  import matplotlib.pyplot as plt
   ...:  import numpy as np
   ...:  import sunpy.map 
   ...:  fig = plt.figure( 0, figsize = (14, 7))
   ...:  ax1 = plt.subplot2grid((1,2), (0,0))
   ...:  data = np.random.random((600,600))
   ...:  header = {'cdelt1':20, 'cdelt2':20, 'telescop':'Electron Density Map'}
   ...:  den_map = sunpy.map.Map(data, header)
   ...:  den_map.plot(axes = ax1)
   ...:  plt.show()

This worked fine in a previous sunpy version so I couldn't figure out what the mistake was. However I checked the new map documentation and modifying the code like so works:

In [1]:  import matplotlib.pyplot as plt
   ...:  import numpy as np
   ...:  import sunpy.map 
   ...:  data = np.random.random((600,600))
   ...:  header = {'cdelt1':20, 'cdelt2':20, 'telescop':'Electron Density Map'}
   ...:  den_map = sunpy.map.Map(data, header)
   ...:  fig = plt.figure( 0, figsize = (14, 7))
   ...:  ax1 = fig.add_subplot(1,2,1, projection =den_map)
   ...:  den_map.plot()
   ...:  plt.show()

Is the first version of that code incompatible withe the new sunpy? I don't know if this is still a possible bug or a mistake I've made, I can't spot anything wrong with the first version. 


You appear to have found a real, and rather serious, bug.

code:
```python
import matplotlib.pyplot as plt                                                 
import sunpy.map                                                                
from sunpy.data.sample import AIA_171_ROLL_IMAGE                                
                                                                                
a_map = sunpy.map.Map(AIA_171_ROLL_IMAGE)                                       
                                                                                
ax = plt.subplot()                                                              
a_map.plot(axes=ax)                                                             
plt.show()
```
result:
![figure_1](https://user-images.githubusercontent.com/1391051/32008642-a42119ac-b9a4-11e7-894d-0af9dba6f329.png)


alternative error:
```python
In [1]: import matplotlib.pyplot as plt
   ...: import numpy as np
   ...: import sunpy.map
   ...: 
   ...: data = np.random.random((600,600))
   ...: header = {'cdelt1':20, 'cdelt2':20}
   ...: den_map = sunpy.map.Map(data, header)
   ...: ax = plt.subplot()
   ...: den_map.plot(axes=ax)
   ...: plt.show()
   ...: 
```
```

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-1-831698fbd83c> in <module>()
      7 den_map = sunpy.map.Map(data, header)
      8 ax = plt.subplot()
----> 9 den_map.plot(axes=ax)
     10 plt.show()

/opt/miniconda/envs/sunpy-0.8/lib/python3.6/site-packages/sunpy/map/mapbase.py in plot(self, annotate, axes, title, **imshow_kwargs)
   1724 
   1725         if not wcsaxes_compat.is_wcsaxes(axes):
-> 1726             bl = self._get_lon_lat(self.bottom_left_coord)
   1727             tr = self._get_lon_lat(self.top_right_coord)
   1728             x_range = list(u.Quantity([bl[0], tr[0]]).to(self.spatial_units[0]).value)

/opt/miniconda/envs/sunpy-0.8/lib/python3.6/site-packages/sunpy/map/mapbase.py in bottom_left_coord(self)
    490         The physical coordinate for the bottom left [0,0] pixel.
    491         """
--> 492         return self.pixel_to_world(0*u.pix, 0*u.pix)
    493 
    494     @property

/opt/miniconda/envs/sunpy-0.8/lib/python3.6/site-packages/astropy/utils/decorators.py in pixel_to_world(self, x, y, origin)
    866             name = func.__name__
    867 
--> 868         func = make_function_with_signature(func, name=name, **wrapped_args)
    869         func = functools.update_wrapper(func, wrapped, assigned=assigned,
    870                                         updated=updated)

/opt/miniconda/envs/sunpy-0.8/lib/python3.6/site-packages/astropy/units/decorators.py in wrapper(*func_args, **func_kwargs)
    221             # Call the original function with any equivalencies in force.
    222             with add_enabled_equivalencies(self.equivalencies):
--> 223                 return_ = wrapped_function(*func_args, **func_kwargs)
    224             if wrapped_signature.return_annotation is not funcsigs.Signature.empty:
    225                 return return_.to(wrapped_signature.return_annotation)

/opt/miniconda/envs/sunpy-0.8/lib/python3.6/site-packages/sunpy/map/mapbase.py in pixel_to_world(self, x, y, origin)
    863             y = u.Quantity(y, self.spatial_units[1])
    864 
--> 865         return SkyCoord(x, y, frame=self.coordinate_frame)
    866 
    867     # Thought it would be easier to create a copy this way.

/opt/miniconda/envs/sunpy-0.8/lib/python3.6/site-packages/astropy/coordinates/sky_coordinate.py in __init__(self, *args, **kwargs)
    205         args = list(args)  # Make it mutable
    206         copy = kwargs.pop('copy', True)
--> 207         kwargs = self._parse_inputs(args, kwargs)
    208 
    209         frame = kwargs['frame']

/opt/miniconda/envs/sunpy-0.8/lib/python3.6/site-packages/astropy/coordinates/sky_coordinate.py in _parse_inputs(self, args, kwargs)
    376                                                                       repr_attr_names, units):
    377                     attr_class = frame.representation.attr_classes[repr_attr_name]
--> 378                     coord_kwargs[frame_attr_name] = attr_class(arg, unit=unit)
    379 
    380             else:

/opt/miniconda/envs/sunpy-0.8/lib/python3.6/site-packages/astropy/coordinates/angles.py in __new__(cls, angle, unit, **kwargs)
    509             raise TypeError("A Latitude angle cannot be created from a Longitude angle")
    510         self = super(Latitude, cls).__new__(cls, angle, unit=unit, **kwargs)
--> 511         self._validate_angles()
    512         return self
    513 

/opt/miniconda/envs/sunpy-0.8/lib/python3.6/site-packages/astropy/coordinates/angles.py in _validate_angles(self, angles)
    526         if np.any(angles.value < lower) or np.any(angles.value > upper):
    527             raise ValueError('Latitude angle(s) must be within -90 deg <= angle <= 90 deg, '
--> 528                              'got {0}'.format(angles.to(u.degree)))
    529 
    530     def __setitem__(self, item, value):

ValueError: Latitude angle(s) must be within -90 deg <= angle <= 90 deg, got -5990.0 deg
```
a_map.peek() works.
with a non-wcsaxes?
No - I was just a check of using the map plot method versus the map peek method.  That's all.
This issue seem to also effect certain map instance properties such as `top_right_coord` and `bottom_left_coord`

Resolving patch:
diff --git a/sunpy/map/mapbase.py b/sunpy/map/mapbase.py
--- a/sunpy/map/mapbase.py
+++ b/sunpy/map/mapbase.py
@@ -4,10 +4,10 @@
 from __future__ import absolute_import, division, print_function
 from sunpy.extern.six.moves import range
 
+import copy
 import warnings
 import inspect
 from abc import ABCMeta
-from copy import deepcopy
 from collections import OrderedDict, namedtuple
 
 import numpy as np
@@ -855,15 +855,17 @@ def pixel_to_world(self, x, y, origin=0):
             A coordinate object representing the output coordinate.
 
         """
-        x, y = self.wcs.wcs_pix2world(x, y, origin)
 
-        # If the wcs is celestial it is output in degress
-        if self.wcs.is_celestial:
-            x = u.Quantity(x, u.deg)
-            y = u.Quantity(y, u.deg)
-        else:
-            x = u.Quantity(x, self.spatial_units[0])
-            y = u.Quantity(y, self.spatial_units[1])
+        # Hold the WCS instance here so we can inspect the output units after
+        # the pix2world call
+        temp_wcs = self.wcs
+
+        x, y = temp_wcs.wcs_pix2world(x, y, origin)
+
+        out_units = list(map(u.Unit, temp_wcs.wcs.cunit))
+
+        x = u.Quantity(x, out_units[0])
+        y = u.Quantity(y, out_units[1])
 
         return SkyCoord(x, y, frame=self.coordinate_frame)
 
@@ -1703,7 +1705,7 @@ def plot(self, annotate=True, axes=None, title=True, **imshow_kwargs):
                               Warning)
 
         # Normal plot
-        imshow_args = deepcopy(self.plot_settings)
+        imshow_args = copy.deepcopy(self.plot_settings)
         if 'title' in imshow_args:
             plot_settings_title = imshow_args.pop('title')
         else:


Test patch:
diff --git a/sunpy/map/tests/test_mapbase.py b/sunpy/map/tests/test_mapbase.py
--- a/sunpy/map/tests/test_mapbase.py
+++ b/sunpy/map/tests/test_mapbase.py
@@ -266,9 +266,9 @@ def test_data_range(generic_map):
 
     # the weird unit-de-unit thing here is to work around and inconsistency in
     # the way np.average works with astropy 1.3 and 2.0dev
-    assert_quantity_allclose(np.average(u.Quantity(generic_map.xrange).value) * u.deg,
+    assert_quantity_allclose(np.average(u.Quantity(generic_map.xrange).value) * u.arcsec,
                              generic_map.center.Tx)
-    assert_quantity_allclose(np.average(u.Quantity(generic_map.yrange).value) * u.deg,
+    assert_quantity_allclose(np.average(u.Quantity(generic_map.yrange).value) * u.arcsec,
                              generic_map.center.Ty)
 
 
@@ -552,6 +552,12 @@ def test_as_mpl_axes_aia171(aia171_test_map):
     assert hasattr(ax.wcs, 'heliographic_observer')
 
 
+def test_pixel_to_world_no_projection(generic_map):
+    out = generic_map.pixel_to_world(*u.Quantity(generic_map.reference_pixel)+1*u.pix, origin=1)
+    assert_quantity_allclose(out.Tx, -10*u.arcsec)
+    assert_quantity_allclose(out.Ty, 10*u.arcsec)
+
+
 def test_validate_meta(generic_map):
     """Check to see if_validate_meta displays an appropriate error"""
     with warnings.catch_warnings(record=True) as w: