Repository: sunpy/sunpy

Issue:
Confusing default choices of OpenJPEG binaries
I'm confused by the OpenJPEG binaries being called.  For some reason:
- `sunpy.io.jp2.get_data()` calls the binary that is specified as a keyword argument, which defaults to the binary `j2k_to_image`
- `sunpy.io.jp2.read()` calls `sunpy.io.jp2.get_data()`, and overrides the above keyword argument with its own keyword argument, which defaults to the binary `opj_decompress`

I understand very little about OpenJPEG, so I don't understand why there are two different binaries that apparently can do the same thing, but it really seems like these default choices should be consistent.  Perhaps they should not even be keyword arguments.

This was especially confusing on a student's laptop where `j2k_to_image` runs, but `opj_decompress` does not.



Discussion:
The whole openJEPG thing is stupid. I think we should move to glymur for 0.3. I can't actually use openJPEG on my machine.

@quintusdias, the developer of Glymur has already made a functioning version: https://github.com/quintusdias/sunpy/blob/glymur/sunpy/io/jp2.py he should be PR'ing it soon.

> The whole openJEPG thing is stupid.

Well, I won't argue with that!  However, if I understand Glymur correctly, it's just an interface, and you still need the OpenJPEG library.  Furthermore, you currently need to build the OpenJPEG library from source out of their development branch, which seems like a scary requirement to impose on SunPy users.

https://glymur.readthedocs.org/en/latest/introduction.html

yeah, I have just realised that, if you are on linux that's not too bad... prehaps we should have a feature branch with it in ;)

I merged the PR and pushed it back with one slight change.  Apologies for missing this PR, had an overly aggressive email filter in place, I feel badly :-(

@ayshih, with 0.2.x of glymur, one only needs the 1.5.x version of OpenJPEG to read JP2 images, so the usual package managers on linux or macports can take care of this without the need for compiling the library.  The development version is needed only for writing (but you get better read performance as well).

Another change since missing the origin PR was that glymur now works with Python 2.6 as well.

Sorry all for the poor OpenJPEG interfacing. It was never meant to actually be a permanent solution, but really just a hack so that it could be possible to work with JPEG 2000 images until something like Glymur came around.

Please feel free to completely change things around as you see fit.


Resolving patch:
diff --git a/sunpy/io/jp2.py b/sunpy/io/jp2.py
--- a/sunpy/io/jp2.py
+++ b/sunpy/io/jp2.py
@@ -15,7 +15,7 @@
 
 __all__ = ['read', 'get_header', 'write']
 
-def read(filepath, j2k_to_image='opj_decompress'):
+def read(filepath, j2k_to_image='j2k_to_image'):
     """
     Reads a JPEG2000 file
     
diff --git a/sunpy/map/compositemap.py b/sunpy/map/compositemap.py
--- a/sunpy/map/compositemap.py
+++ b/sunpy/map/compositemap.py
@@ -336,7 +336,7 @@ def plot(self, axes=None, gamma=None, annotate=True, # pylint: disable=W0613
             if m.levels is not False:
                 # Set data with values <= 0 to transparent
                 # contour_data = np.ma.masked_array(m, mask=(m <= 0))
-                ret.append(axes.contour(m, m.levels, **params))
+                ret.append(axes.contour(m.data, m.levels, **params))
                 #Set the label of the first line so a legend can be created
                 ret[-1].collections[0].set_label(m.name)
                                 
diff --git a/sunpy/map/map_factory.py b/sunpy/map/map_factory.py
--- a/sunpy/map/map_factory.py
+++ b/sunpy/map/map_factory.py
@@ -43,13 +43,13 @@ class Map(RegisteredFactoryBase):
     DefaultWidgetType = GenericMap
 
     @classmethod
-    def _read_file(cls, fname):
+    def _read_file(cls, fname, **kwargs):
         """ Read in a file name and return the list of (data, meta) pairs in
             that file. """
         
         # File gets read here.  This needs to be generic enough to seamlessly
         #call a fits file or a jpeg2k file, etc
-        pairs = read_file(fname)
+        pairs = read_file(fname, **kwargs)
         
         new_pairs = []
         for pair in pairs:
@@ -96,13 +96,13 @@ def _parse_args(cls, *args, **kwargs):
             # Data-header pair in a tuple
             if ((type(arg) in [tuple, list]) and 
                  len(arg) == 2 and
-                 isinstance(arg[0],np.ndarray) and # or NDData or something else?
-                 isinstance(arg[1],OrderedDict)): # FITSHeader, JP2kHeader, OrderedDict, dict?
+                 isinstance(arg[0],np.ndarray) and
+                 isinstance(arg[1],dict)):
                 data_header_pairs.append(arg)
             
             # Data-header pair not in a tuple
-            elif (isinstance(arg, np.ndarray) and # or NDData or something else?
-                  isinstance(args[i+1],OrderedDict)): # FITSHeader, JP2kHeader, OrderedDict, dict? 
+            elif (isinstance(arg, np.ndarray) and
+                  isinstance(args[i+1],dict)):
                 pair = (args[i], args[i+1])
                 data_header_pairs.append(pair)
                 i += 1 # an extra increment to account for the data-header pairing
@@ -111,7 +111,7 @@ def _parse_args(cls, *args, **kwargs):
             elif (isinstance(arg,basestring) and 
                   os.path.isfile(os.path.expanduser(arg))):
                 path = os.path.expanduser(arg)
-                pairs = cls._read_file(path)
+                pairs = cls._read_file(path, **kwargs)
                 data_header_pairs += pairs
             
             # Directory
@@ -120,13 +120,13 @@ def _parse_args(cls, *args, **kwargs):
                 path = os.path.expanduser(arg)
                 files = [os.path.join(path, elem) for elem in os.listdir(path)]
                 for afile in files:
-                    data_header_pairs += cls._read_file(afile)
+                    data_header_pairs += cls._read_file(afile, **kwargs)
             
             # Glob
             elif (isinstance(arg,basestring) and '*' in arg):
                 files = glob.glob( os.path.expanduser(arg) )
                 for afile in files:
-                    data_header_pairs += cls._read_file(afile)
+                    data_header_pairs += cls._read_file(afile, **kwargs)
             
             # Already a Map
             elif isinstance(arg, GenericMap):
@@ -138,7 +138,7 @@ def _parse_args(cls, *args, **kwargs):
                 default_dir = sunpy.config.get("downloads", "download_dir")
                 url = arg
                 path = download_file(url, default_dir)
-                pairs = cls._read_file(path)
+                pairs = cls._read_file(path, **kwargs)
                 data_header_pairs += pairs
             
             else:
@@ -193,9 +193,12 @@ def __new__(cls, *args, **kwargs):
                         break
                 else:
                     WidgetType = cls.DefaultWidgetType
-                    
+                
+                # Make sure the map header is a MapMeta, useful if the user
+                # passed in a dict
+                meta = MapMeta(header)
                 # Instantiate the new map.
-                new_maps.append(WidgetType(data, header, **kwargs))
+                new_maps.append(WidgetType(data, meta, **kwargs))
             
             new_maps += already_maps
             


Test patch:
diff --git a/sunpy/tests/map/test_map_factory.py b/sunpy/tests/map/test_map_factory.py
--- a/sunpy/tests/map/test_map_factory.py
+++ b/sunpy/tests/map/test_map_factory.py
@@ -6,6 +6,8 @@
 """
 import os
 import glob
+import numpy as np
+
 import sunpy
 import sunpy.map
 import sunpy.data.test
@@ -57,6 +59,11 @@ def test_patterns(self):
         # Data-header pair not in a tuple
         pair_map = sunpy.Map(amap.data, amap.meta)
         assert isinstance(pair_map, sunpy.map.GenericMap)
+        #Custom Map
+        data = np.arange(0,100).reshape(10,10)
+        header = {'cdelt1': 10, 'cdelt2': 10, 'telescop':'sunpy'}
+        pair_map = sunpy.Map(data, header)
+        assert isinstance(pair_map, sunpy.map.GenericMap)
          
     
     def test_save(self):