Repository: sunpy/sunpy

Issue:
A home for functions which operate on Map
We seem to have a couple of things waiting in the wings ([#2972](https://github.com/sunpy/sunpy/pull/2972/files#diff-e5b590f063aafc6198499904a424fc22R547) and #2278) which are a set of functions which provide utilities based on taking a `GenericMap` object (or subclass) as input (or output) and performing some check, or to help people construct a map etc.

 @wafels added a bunch of functions which operate on a map in #2972 the ones relevant for this discussion are:

* `map_edges`
* `contains_full_disk`
* `is_all_off_disk`
* `is_all_on_disk`
* `contains_limb`
* `coordinate_is_on_disk`
* `on_disk_bounding_coordinates`

The other one is a header generation utility as described in #2278, which is a little different in that it doesn't operate on a map but I feel still generally in the same bin as these helpers.

This was discussed at the community meeting (2019-03-27) and it was agreed that we need somewhere in core to put these kind of functions but that we also need to come up with **a strong definition of what the scope of the namespace is so we limit the type of helpers that are in it**.


Discussion:
There are two other helpers for getting all the world coordinates in a map in #2972 for which API already exists in [`NDCube`](https://github.com/sunpy/ndcube/blob/master/ndcube/ndcube.py#L300) as `axis_world_coords` so we should probably just adopt that as a method on `GenericMap`.
Something like `sunpy.map.util` but `util` is used too often.
NDCube is not in SunPy yet, right?
Not yet! but it will be (maybe in 2.0?). See my PR to the [roadmap](https://github.com/sunpy/roadmap/pull/1).
> NDCube is not in SunPy yet, right?

No, I was suggesting we copy the API for now.
# Proposals for Namespaces

Given the general agreement on the need for this to exist I propose the following options for how to actually do it (in order of my preference):


## 1. Put everything in `sunpy.map`

This would mean that we have the following as our recommended imports and usage:

```python
import sunpy.map

aia = sunpy.map.Map(AIA_171_IMAGE)

assert sunpy.map.contains_full_disk(aia) is True
```


*Note, these functions would actually live in a file named something like `helpers` or `utils` but we wouldn't expose this to the user*

## 2. Have the users directly use a sub-namespace

To my mind this gets a little long.

```python
import sunpy.map

aia = sunpy.map.Map(AIA_171_IMAGE)

assert sunpy.map.util.contains_full_disk(aia) is True
```

## 3. Separately import the sub-namespace

I don't really like this because whatever we call the sub-namespace (util in the example) is ambiguous.

```python
import sunpy.map
from sunpy.map import util

aia = sunpy.map.Map(AIA_171_IMAGE)

assert util.contains_full_disk(aia) is True
```
I want to say this has broader implications for how we organize our namespace. 
Agreed. Do you have specific suggestions of other things we should change?
Regarding this direct issue, I am leaning towards solution number 1. 

With that in mind, I think we should make sure that  in the main namespace for each package you can import all user facing functions (we seem to for most modules but not all). Anything that needs to be imported for registration or the like should be done in a way to hide it. 

This probably means making some functions "private" ones but leaving them there or moving them to `util`. 

So there are some places where the main level ``__init__`` file (like image) have no imports. 
I think `instr` can be left alone, it makes more sense to have the instr name in the import. 

I think main one that might need some flattening and looking after is `net`. Adding `HEKClient` and the like to the namespace above. Also  I think that maybe for `viz` adding the animators to the main namespace too. (This could be controversial) 
I think to some extent it depends on the submodule, some like `map` are a one thing kind of namespace whereas some others like `instr` are a more a collection of related sub-submodules.

I think we should probably take them one at a time and decide if we are pulling everything into a flat top namespace or having a collection of sub namespaces?
How about we go with flat namespace as default unless we have many many submodules per package?

Again, for `map`, I would prefer a flat namespace. 
Sounds good as a general rule to me, I would want to take it on a case-by-case basis to see if it translates into reality well.
@sunpy/sunpy-developers If anyone has any opinions on how we organise our namespaces in SunPy (specifically map) now is the time to shout, if nobody objects on here within a week I will be implementing this for 1.0.
Yeah, we should try it and see what it does to the namespace before we adopt it formally.
So if we went with 1. where would all of the code live?
A helper or util file that we can just import into the namespace directly. 
I vote for 1.
I vote 1 🌞 
I think for users' discoverability, option 1 is best.  Although it will confuse users when trying to find the source code if it is not in the map.py file.  I acknowledge that actually putting everything in map.py is untenable, however.
I vote for 1 in the sense that I feel that functions should not be *required* to be only in a sub-namespace such as `util`.  That said, I think it is still reasonable for a set of highly specialized functions to be accessible only through a sub-namespace if that is desired for organization purposes.
I agree with the crowd and think number 1 is the best. I think an instrument specific namespace would make sense for highly specialized code that operate on maps. 
Also in favor of option 1

> On Apr 10, 2019, at 12:23, Michael Kirk <notifications@github.com> wrote:
> 
> I agree with the crowd and think number 1 is the best. I think an instrument specific namespace would make sense for highly specialized code that operate on maps.
> 
> —
> You are receiving this because you are on a team that was mentioned.
> Reply to this email directly, view it on GitHub, or mute the thread.


Resolving patch:
diff --git a/sunpy/map/__init__.py b/sunpy/map/__init__.py
--- a/sunpy/map/__init__.py
+++ b/sunpy/map/__init__.py
@@ -8,5 +8,6 @@
 from . mapsequence import MapSequence
 from . compositemap import CompositeMap
 
+from sunpy.map.maputils import *
 from sunpy.map.map_factory import Map
 from sunpy.map import sources
diff --git a/sunpy/map/maputils.py b/sunpy/map/maputils.py
new file mode 100644
--- /dev/null
+++ b/sunpy/map/maputils.py
@@ -0,0 +1,7 @@
+"""
+This submodule provides utility functions to act on `sunpy.map.Map` instances.
+"""
+
+
+__all__ = []
+


Test patch: