Repository: opendatacube/datacube-core

Issue:
Masking Tools could be a lot more user friendly
`datacube.storage.masking.describe_variable_flags()` should return an object with not only `__repr__()` but also `_repr_html_()` defined, so that the table of information is legible in a jupyter notebook (like how pandas works). 

Current output is about 50 lines illegibly formatted like this:
```
'Flag name          | Description                                      | Bit. No                                        | 
Value | Meaning        \n-------------------+--------------------------------------------------+-------------------------
-----------------------+-------+----------------\nga_good_pixel      | Best Quality Pixel                               |
[13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] | 16383 | True           \nblue_saturated     | Blue band is saturated 
| 0                                              | 0     | True           \n                   |       
| 0                                              | 1     | False          \n-------------------+-------------------------
-------------------------+------------------------------------------------+-------+----------------\ngreen_saturated    |
Green band is saturated                          | 1                                              | 0     | True  
\n                   |                                                  | 1  
```

This would also be an opportunity to simplify the masking api. For example, once you retrieve this pretty-displaying object, actually generating the mask could be as simple as reading an attribute/property from the same object. 


Discussion:

Resolving patch:
diff --git a/datacube/storage/masking.py b/datacube/storage/masking.py
--- a/datacube/storage/masking.py
+++ b/datacube/storage/masking.py
@@ -7,6 +7,7 @@
 
 import collections
 import warnings
+import pandas
 
 from datacube.utils import generate_table
 
@@ -26,12 +27,13 @@ def list_flag_names(variable):
     return sorted(list(flags_def.keys()))
 
 
-def describe_variable_flags(variable):
+def describe_variable_flags(variable, with_pandas=True):
     """
-    Returns a string describing the available flags for a masking variable
+    Returns either a Pandas Dataframe (with_pandas=True - default) or a string
+    (with_pandas=False) describing the available flags for a masking variable
 
-    Interprets the `flags_definition` attribute on the provided variable and returns
-    a string like::
+    Interprets the `flags_definition` attribute on the provided variable and
+    returns a Pandas Dataframe or string like::
 
         Bits are listed from the MSB (bit 13) to the LSB (bit 0)
         Bit     Value   Flag Name            Description
@@ -41,11 +43,14 @@ def describe_variable_flags(variable):
         10      0       cloud_acca           Cloud (ACCA)
 
     :param variable: Masking xarray.Dataset or xarray.DataArray
-    :return: str
+    :return: Pandas Dataframe or str
     """
     flags_def = get_flags_def(variable)
 
-    return describe_flags_def(flags_def)
+    if not with_pandas:
+        return describe_flags_def(flags_def)
+
+    return pandas.DataFrame.from_dict(flags_def, orient='index')
 
 
 def describe_flags_def(flags_def):
@@ -128,7 +133,7 @@ def mask_invalid_data(data, keep_attrs=True):
     """
     Sets all `nodata` values to ``nan``.
 
-    This will convert converts numeric data to type `float`.
+    This will convert numeric data to type `float`.
 
     :param Dataset or DataArray data:
     :param bool keep_attrs: If the attributes of the data should be included in the returned .


Test patch: