Australian Geoscience Datacube

Feature Summary Examples

The Australian Geoscience Datacube provides an integrated gridded data analysis environment for decades of analysis ready earth observation satellite and related data from multiple satellite and other acquisition systems.

For instructions on using the Datacube on NCI, see: http://agdc-v2.readthedocs.io/en/develop/nci_usage.html

For instructions on setting up your own instance, see: http://agdc-v2.readthedocs.io/en/develop/install.html

This notebook touches briefly on some the implimented features of the Datacube module, and is only intended to deomstrat functionality rather than be a tutorial.


In [1]:
%matplotlib inline
import datacube

If you have set up your config correctly, or are using the module on NCI, you should be able to make Datacube object that can connects to the configured datacube system.


In [2]:
dc = datacube.Datacube(app='dc-example')
dc


Out[2]:
Datacube<index=Index<db=PostgresDb<engine=Engine(postgresql://adh547@130.56.244.227:5432/unification)>>>

Datacube products and measurements

The Datacube provides pandas.DataFrame representations of the available products and measurements:


In [3]:
dc.list_products()


Out[3]:
name description platform product_type instrument format crs resolution tile_size spatial_dimensions
id
1 dsm1sv10 DSM 1sec Version 1.0 SRTM DEM SIR ENVI EPSG:4326 [-0.00027777777778, 0.00027777777778] None (latitude, longitude)
2 ls5_satellite_telemetry_data Landsat 5 Satellite Telemetry Data LANDSAT_5 satellite_telemetry_data TM NaN NaN NaN NaN NaN
3 ls5_level1_scene Landsat 5 Level 1 - Ortho Rectified LANDSAT_5 level1 TM GeoTiff NaN NaN NaN NaN
4 ls5_nbar_scene Landsat 5 NBAR 25 metre LANDSAT_5 nbar TM GeoTiff NaN NaN NaN NaN
5 ls5_nbart_scene Landsat 5 NBART 25 metre LANDSAT_5 nbart TM GeoTiff NaN NaN NaN NaN
7 ls7_satellite_telemetry_data Landsat 7 Satellite Telemetry Data LANDSAT_7 satellite_telemetry_data ETM NaN NaN NaN NaN NaN
8 ls7_level1_scene Landsat 7 Level 1 - Ortho Rectified LANDSAT_7 level1 ETM GeoTiff NaN NaN NaN NaN
9 ls7_nbar_scene Landsat 7 NBAR 25 metre LANDSAT_7 nbar ETM GeoTiff NaN NaN NaN NaN
10 ls7_nbart_scene Landsat 7 NBART 25 metre LANDSAT_7 nbart ETM GeoTiff NaN NaN NaN NaN
12 ls8_satellite_telemetry_data Landsat 8 Satellite Telemetry Data LANDSAT_8 satellite_telemetry_data OLI NaN NaN NaN NaN NaN
13 ls8_level1_scene Landsat 8 Level 1 - Ortho Rectified LANDSAT_8 level1 OLI GeoTiff NaN NaN NaN NaN
6 ls5_pq_scene Landsat 5 PQ 25 metre LANDSAT_5 pqa TM GeoTiff NaN NaN NaN NaN
14 ls8_nbar_scene Landsat 8 NBAR 25 metre LANDSAT_8 nbar OLI GeoTiff NaN NaN NaN NaN
15 ls8_nbart_scene Landsat 8 NBART 25 metre LANDSAT_8 nbart OLI GeoTiff NaN NaN NaN NaN
17 ls5_nbar_albers Landsat 5 NBAR 25 metre, 100km tile, Australia... LANDSAT_5 nbar TM NetCDF EPSG:3577 [-25, 25] [100000.0, 100000.0] (y, x)
19 modis_mcd43a1_tile MODIS 500 metre MCD43A1 AQUA_TERRA MCD43A1 MODIS HDF4_EOS:EOS_GRID NaN NaN NaN NaN
20 modis_mcd43a2_tile MODIS 500 metre MCD43A2 AQUA_TERRA MCD43A2 MODIS HDF4_EOS:EOS_GRID NaN NaN NaN NaN
21 modis_mcd43a3_tile MODIS 500 metre MCD43A3 AQUA_TERRA MCD43A3 MODIS HDF4_EOS:EOS_GRID NaN NaN NaN NaN
22 modis_mcd43a4_tile MODIS 500 metre MCD43A4 AQUA_TERRA MCD43A4 MODIS HDF4_EOS:EOS_GRID NaN NaN NaN NaN
23 h8_ahi_brf_granule H8 BRF, 2km, 1km and 500m granules HIMAWARI_8 BRF AHI NETCDF NaN NaN NaN NaN
24 h8_ahi_obs_granule H8 OBS, 2km granules HIMAWARI_8 OBS AHI NETCDF NaN NaN NaN NaN
25 h8_ahi_solar_granule H8 SOLAR GEOMETRY, 2km, 1km and 500m granules HIMAWARI_8 GEOM_SOLAR AHI NETCDF NaN NaN NaN NaN
26 s2a_level1c_granule Sentinel-2 Level 1 - Ortho Rectified SENTINEL_2A S2MSI1C MSI JPEG2000 NaN NaN NaN NaN
29 ls5_ndvi_albers Landsat 5 NDVI LANDSAT_5 ndvi TM NetCDF EPSG:3577 [-25, 25] [100000.0, 100000.0] (y, x)
18 ls5_pq_albers Landsat 5 PQ 25 metre, 100km tile, Australian ... LANDSAT_5 pqa TM NetCDF EPSG:3577 [-25, 25] [100000.0, 100000.0] (y, x)

Datacube Measurements

The list of measurements stored in the datacube can also be listed.

Measurements are also known as bands in the imagery domain, and data variables when stored in NetCDF files or when working with xarray.Dataset objects.


In [4]:
dc.list_measurements()


Out[4]:
aliases dtype flags_definition name nodata spectral_definition units
product measurement
dsm1sv10 elevation NaN float32 NaN elevation NaN NaN metre
ls5_nbar_scene 1 [band_1, blue] int16 NaN 1 -999 {u'wavelength': [410, 411, 412, 413, 414, 415,... 1
2 [band_2, green] int16 NaN 2 -999 {u'wavelength': [500, 501, 502, 503, 504, 505,... 1
3 [band_3, red] int16 NaN 3 -999 {u'wavelength': [580, 590, 600, 605, 610, 611,... 1
4 [band_4, nir] int16 NaN 4 -999 {u'wavelength': [730, 735, 740, 745, 750, 751,... 1
5 [band_5, swir1] int16 NaN 5 -999 {u'wavelength': [1514, 1515, 1517, 1519, 1521,... 1
7 [band_7, swir2] int16 NaN 7 -999 {u'wavelength': [2000, 2001, 2003, 2005, 2007,... 1
ls5_nbart_scene 1 [band_1, blue] int16 NaN 1 -999 {u'wavelength': [410, 411, 412, 413, 414, 415,... 1
2 [band_2, green] int16 NaN 2 -999 {u'wavelength': [500, 501, 502, 503, 504, 505,... 1
3 [band_3, red] int16 NaN 3 -999 {u'wavelength': [580, 590, 600, 605, 610, 611,... 1
4 [band_4, nir] int16 NaN 4 -999 {u'wavelength': [730, 735, 740, 745, 750, 751,... 1
5 [band_5, swir1] int16 NaN 5 -999 {u'wavelength': [1514, 1515, 1517, 1519, 1521,... 1
7 [band_7, swir2] int16 NaN 7 -999 {u'wavelength': [2000, 2001, 2003, 2005, 2007,... 1
ls7_nbar_scene 1 [band_1, blue] int16 NaN 1 -999 {u'wavelength': [410, 411, 412, 413, 414, 415,... 1
2 [band_2, green] int16 NaN 2 -999 {u'wavelength': [500, 501, 502, 503, 504, 505,... 1
3 [band_3, red] int16 NaN 3 -999 {u'wavelength': [580, 590, 600, 605, 610, 611,... 1
4 [band_4, nir] int16 NaN 4 -999 {u'wavelength': [730, 735, 740, 745, 750, 751,... 1
5 [band_5, swir1] int16 NaN 5 -999 {u'wavelength': [1514, 1515, 1517, 1519, 1521,... 1
7 [band_7, swir2] int16 NaN 7 -999 {u'wavelength': [2000, 2001, 2003, 2005, 2007,... 1
ls7_nbart_scene 1 [band_1, blue] int16 NaN 1 -999 {u'wavelength': [410, 411, 412, 413, 414, 415,... 1
2 [band_2, green] int16 NaN 2 -999 {u'wavelength': [500, 501, 502, 503, 504, 505,... 1
3 [band_3, red] int16 NaN 3 -999 {u'wavelength': [580, 590, 600, 605, 610, 611,... 1
4 [band_4, nir] int16 NaN 4 -999 {u'wavelength': [730, 735, 740, 745, 750, 751,... 1
5 [band_5, swir1] int16 NaN 5 -999 {u'wavelength': [1514, 1515, 1517, 1519, 1521,... 1
7 [band_7, swir2] int16 NaN 7 -999 {u'wavelength': [2000, 2001, 2003, 2005, 2007,... 1
ls5_pq_scene pqa [qa_flags, quality] int16 {u'swir2_saturated': {u'values': {u'1': False,... pqa 0 NaN 1
ls8_nbar_scene 1 [band_1, coastal_aerosol] int16 NaN 1 -999 {u'wavelength': [427, 428, 429, 430, 431, 432,... 1
2 [band_2, blue] int16 NaN 2 -999 {u'wavelength': [436, 437, 438, 439, 440, 441,... 1
3 [band_3, green] int16 NaN 3 -999 {u'wavelength': [512, 513, 514, 515, 516, 517,... 1
4 [band_4, red] int16 NaN 4 -999 {u'wavelength': [625, 626, 627, 628, 629, 630,... 1
... ... ... ... ... ... ... ... ...
h8_ahi_obs_granule 05_2000 [band_5] float32 NaN 05_2000 10000000000 {u'wavelength': [1546.07, 1546.31, 1546.55, 15... 1
06_2000 [band_6] float32 NaN 06_2000 10000000000 {u'wavelength': [2188.18, 2188.66, 2189.14, 21... 1
07_2000 [band_7] float32 NaN 07_2000 10000000000 {u'wavelength': [3636.63, 3636.76, 3636.89, 36... 1
08_2000 [band_8] float32 NaN 08_2000 10000000000 {u'wavelength': [5432.13, 5432.42, 5432.72, 54... 1
09_2000 [band_9] float32 NaN 09_2000 10000000000 {u'wavelength': [6472.91, 6473.33, 6473.75, 64... 1
10_2000 [band_10] float32 NaN 10_2000 10000000000 {u'wavelength': [6999.37, 6999.86, 7000.35, 70... 1
11_2000 [band_11] float32 NaN 11_2000 10000000000 {u'wavelength': [8124.14, 8124.8, 8125.46, 812... 1
12_2000 [band_12] float32 NaN 12_2000 10000000000 {u'wavelength': [9183.58, 9184.42, 9185.27, 91... 1
13_2000 [band_13] float32 NaN 13_2000 10000000000 {u'wavelength': [9901.97, 9902.95, 9903.93, 99... 1
14_2000 [band_14] float32 NaN 14_2000 10000000000 {u'wavelength': [10310.34, 10311.4, 10312.47, ... 1
15_2000 [band_15] float32 NaN 15_2000 10000000000 {u'wavelength': [11174.43, 11175.68, 11176.93,... 1
16_2000 [band_16] float32 NaN 16_2000 10000000000 {u'wavelength': [12611.93, 12613.52, 12615.11,... 1
h8_ahi_solar_granule SOLAR_1000 NaN float32 NaN SOLAR_1000 10000000000 NaN 1
SOLAR_2000 NaN float32 NaN SOLAR_2000 10000000000 NaN 1
SOLAR_500 NaN float32 NaN SOLAR_500 10000000000 NaN 1
s2a_level1c_granule 01 [band_01, B01, Band1] int16 NaN 01 -999 {u'wavelength': [430, 431, 432, 433, 434, 435,... 1
02 [band_02, B02, Band2] int16 NaN 02 -999 {u'wavelength': [440, 441, 442, 443, 444, 445,... 1
03 [band_03, B03, Band3] int16 NaN 03 -999 {u'wavelength': [537, 538, 539, 540, 541, 542,... 1
04 [band_04, B04, Band4] int16 NaN 04 -999 {u'wavelength': [646, 647, 648, 649, 650, 651,... 1
05 [band_05, B05, Band5] int16 NaN 05 -999 {u'wavelength': [694, 695, 696, 697, 698, 699,... 1
06 [band_06, B06, Band6] int16 NaN 06 -999 {u'wavelength': [731, 732, 733, 734, 735, 736,... 1
07 [band_07, B07, Band7] int16 NaN 07 -999 {u'wavelength': [769, 770, 771, 772, 773, 774,... 1
08 [band_08, B08, Band8] int16 NaN 08 -999 {u'wavelength': [773, 774, 775, 776, 777, 778,... 1
8A [band_8A, B8A, Band8A] int16 NaN 8A -999 {u'wavelength': [848, 849, 850, 851, 852, 853,... 1
09 [band_09, B09, Band9] int16 NaN 09 -999 {u'wavelength': [932, 933, 934, 935, 936, 937,... 1
10 [band_10, B10, Band10] int16 NaN 10 -999 {u'wavelength': [1337, 1338, 1339, 1340, 1341,... 1
11 [band_11, B11, Band11] int16 NaN 11 -999 {u'wavelength': [1539, 1540, 1541, 1542, 1543,... 1
12 [band_12, B12, Band12] int16 NaN 12 -999 {u'wavelength': [2078, 2079, 2080, 2081, 2082,... 1
ls5_ndvi_albers ndvi NaN float32 NaN ndvi NaN NaN 1
ls5_pq_albers pixelquality [qa_flags, quality] int16 {u'swir2_saturated': {u'values': {u'1': False,... pixelquality 0 NaN 1

132 rows × 7 columns

Retrieving data


In [5]:
nbar = dc.load(product='ls5_nbar_albers', x=(149.25, 149.35), y=(-35.25, -35.35))

The returned data is an xarray.Dataset object, which is a labelled n-dimensional array wrapping a numpy array.

We can investigate the data to see the variables (measurement bands) and dimensions that were returned:


In [6]:
nbar


Out[6]:
<xarray.Dataset>
Dimensions:  (time: 179, x: 421, y: 490)
Coordinates:
  * time     (time) datetime64[ns] 1990-03-02T23:11:16 1990-03-02T23:11:39 ...
  * y        (y) float64 -3.956e+06 -3.956e+06 -3.956e+06 -3.956e+06 ...
  * x        (x) float64 1.56e+06 1.56e+06 1.56e+06 1.56e+06 1.56e+06 ...
Data variables:
    blue     (time, y, x) int16 3457 3247 3247 3438 3552 3324 2881 2997 2551 ...
    green    (time, y, x) int16 3924 3595 3554 3678 3842 3637 3223 3348 2891 ...
    red      (time, y, x) int16 4140 3766 3804 3954 4103 3916 3429 3504 3089 ...
    nir      (time, y, x) int16 5665 5331 5283 5426 5617 5427 4949 5140 4710 ...
    swir1    (time, y, x) int16 6626 6045 5840 5943 6080 6011 5704 5875 5362 ...
    swir2    (time, y, x) int16 5782 5286 5138 5187 5435 5386 4940 5088 4791 ...
Attributes:
    crs: EPSG:3577

We can look at the data by name directly, or through the data_vars dictionary:


In [7]:
nbar.data_vars


Out[7]:
Data variables:
    blue     (time, y, x) int16 3457 3247 3247 3438 3552 3324 2881 2997 2551 ...
    green    (time, y, x) int16 3924 3595 3554 3678 3842 3637 3223 3348 2891 ...
    red      (time, y, x) int16 4140 3766 3804 3954 4103 3916 3429 3504 3089 ...
    nir      (time, y, x) int16 5665 5331 5283 5426 5617 5427 4949 5140 4710 ...
    swir1    (time, y, x) int16 6626 6045 5840 5943 6080 6011 5704 5875 5362 ...
    swir2    (time, y, x) int16 5782 5286 5138 5187 5435 5386 4940 5088 4791 ...

In [8]:
nbar.green


Out[8]:
<xarray.DataArray 'green' (time: 179, y: 490, x: 421)>
array([[[3924, 3595, 3554, ...,  466,  509,  553],
        [4047, 3801, 3595, ...,  466,  509,  509],
        [4210, 4047, 4006, ...,  466,  466,  509],
        ..., 
        [-999, -999, -999, ...,  904,  991,  817],
        [-999, -999, -999, ...,  948, 1034,  991],
        [-999, -999, -999, ...,  861,  991, 1034]],

       [[3856, 3610, 3569, ...,  490,  534,  577],
        [4061, 3816, 3610, ...,  490,  534,  534],
        [4183, 4061, 4061, ...,  490,  490,  534],
        ..., 
        [ 663,  576,  533, ...,  971, 1014,  841],
        [ 619,  619,  489, ...,  971, 1057, 1057],
        [ 706,  706,  576, ...,  884, 1014, 1057]],

       [[3117, 3117, 3225, ..., 2522, 2248, 2082],
        [3171, 3171, 3117, ..., 2631, 2412, 2138],
        [3063, 3063, 3008, ..., 2467, 2522, 2193],
        ..., 
        [2857, 2966, 3129, ..., 1256, 1200, 1200],
        [2857, 3075, 3346, ..., 1368, 1312, 1480],
        [2911, 3129, 3292, ..., 1368, 1536, 1592]],

       ..., 
       [[ 741,  672,  672, ...,  466,  466,  466],
        [ 776,  706,  672, ...,  501,  431,  396],
        [ 741,  567,  497, ...,  501,  501,  466],
        ..., 
        [1300, 1300, 1438, ...,  855,  855,  820],
        [ 988, 1300, 1404, ...,  855,  890,  855],
        [ 814, 1473, 1542, ...,  820,  855,  890]],

       [[ 656,  656,  587, ...,  417,  382,  452],
        [ 552,  656,  621, ...,  452,  417,  417],
        [ 517,  656,  587, ...,  417,  417,  417],
        ..., 
        [ 520,  485,  485, ...,  558,  558,  454],
        [ 520,  450,  415, ...,  524,  558,  524],
        [ 554,  520,  415, ...,  489,  524,  558]],

       [[ 675,  641,  608, ...,  443,  443,  477],
        [ 641,  641,  608, ...,  477,  443,  443],
        [ 742,  608,  507, ...,  443,  443,  443],
        ..., 
        [ 577,  543,  509, ...,  582,  582,  514],
        [ 543,  509,  476, ...,  548,  582,  548],
        [ 543,  577,  476, ...,  514,  548,  548]]], dtype=int16)
Coordinates:
  * time     (time) datetime64[ns] 1990-03-02T23:11:16 1990-03-02T23:11:39 ...
  * y        (y) float64 -3.956e+06 -3.956e+06 -3.956e+06 -3.956e+06 ...
  * x        (x) float64 1.56e+06 1.56e+06 1.56e+06 1.56e+06 1.56e+06 ...
Attributes:
    units: 1
    spectral_definition: {u'wavelength': [500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, ...
    nodata: -999

Plotting data

We can select the data at a particular time and see what is there. We can use pandas-style labels to select a time period, inclusive of the end label:


In [9]:
autumn = nbar.green.loc['1991-3':'1991-5']
autumn.shape


Out[9]:
(9, 490, 421)

In [10]:
autumn.plot(col='time', col_wrap=3)


Out[10]:
<xarray.plot.facetgrid.FacetGrid at 0x69fcdd0>

Masking out NO_DATA values

When there is no data availaible, such as on the boundaries of a scene, it is filled in with a special value. We can use filter it out, although xarray will convert the data from int to float so that it can use NaN to indicate no data.

Now that bad values are no longer represented as -9999, the data fits on a much better colour ramp:


In [11]:
autumn_valid = autumn.where(autumn != autumn.attrs['nodata'])
autumn_valid.plot(col='time', col_wrap=3)


Out[11]:
<xarray.plot.facetgrid.FacetGrid at 0x79f4b90>

Masking out cloud

Some of the images are clearly clouds, we should remove them. There is a product with detected clouds called PQ (for Pixel Quality) we can use to mask out the clouds.


In [12]:
pq = dc.load(product='ls5_pq_albers', x=(149.25, 149.35), y=(-35.25, -35.35))
pq_autumn = pq.pixelquality.loc['1991-3':'1991-5']
pq_autumn.plot(col='time', col_wrap=3)


Out[12]:
<xarray.plot.facetgrid.FacetGrid at 0xa895790>

The PQ layer stores a bitmask of several values. We can list the information available:


In [13]:
from datacube.storage import masking
import pandas
pandas.DataFrame.from_dict(masking.get_flags_def(pq), orient='index')


Out[13]:
values bits description
blue_saturated {u'1': False, u'0': True} 0 Blue band is saturated
cloud_acca {u'1': u'no_cloud', u'0': u'cloud'} 10 Cloud Shadow (ACCA)
cloud_fmask {u'1': u'no_cloud', u'0': u'cloud'} 11 Cloud (Fmask)
cloud_shadow_acca {u'1': u'no_cloud_shadow', u'0': u'cloud_shadow'} 12 Cloud Shadow (ACCA)
cloud_shadow_fmask {u'1': u'no_cloud_shadow', u'0': u'cloud_shadow'} 13 Cloud Shadow (Fmask)
contiguous {u'1': True, u'0': False} 8 All bands for this pixel contain non-null values
ga_good_pixel {u'16383': True} [13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] Best Quality Pixel
green_saturated {u'1': False, u'0': True} 1 Green band is saturated
land_sea {u'1': u'land', u'0': u'sea'} 9 Land or Sea
nir_saturated {u'1': False, u'0': True} 3 NIR band is saturated
red_saturated {u'1': False, u'0': True} 2 Red band is saturated
swir1_saturated {u'1': False, u'0': True} 4 SWIR1 band is saturated
swir2_saturated {u'1': False, u'0': True} 7 SWIR2 band is saturated
tir_saturated {u'1': False, u'0': True} 5 Thermal Infrared band is saturated

In [14]:
good_data = masking.make_mask(pq, cloud_acca='no_cloud', cloud_fmask='no_cloud', contiguous=True)
autumn_good_data = good_data.pixelquality.loc['1991-3':'1991-5']
autumn_good_data.plot(col='time', col_wrap=3)


Out[14]:
<xarray.plot.facetgrid.FacetGrid at 0x10d1d450>

In [15]:
autumn_cloud_free = autumn_valid.where(autumn_good_data)
autumn_cloud_free.plot(col='time', col_wrap=3)


Out[15]:
<xarray.plot.facetgrid.FacetGrid at 0x11596990>

Group by time

You may have noticed that some of the days above are repeated, with times less than a minute apart. this is because of the overlap in LANDSAT scenes. If we group by solar day (a rough local time based on longitude), we can combine these slices:


In [16]:
nbar_by_solar_day = dc.load(product='ls5_nbar_albers', x=(149.25, 149.35), y=(-35.25, -35.35), group_by='solar_day')
len(nbar_by_solar_day.time)


Out[16]:
99

We have fewer times than we did previously.


In [17]:
autumn2 = nbar_by_solar_day.green.loc['1991-3':'1991-5']
autumn2.shape


Out[17]:
(5, 490, 421)

In [18]:
autumn2.plot(col='time', col_wrap=3)


Out[18]:
<xarray.plot.facetgrid.FacetGrid at 0x1d747490>

Some basic band maths

We can combine the red and nir (near-infrared) bands to calculate NDVI (normalised difference vegetation index).


In [19]:
two_bands = dc.load(product='ls5_nbar_albers', x=(149.07, 149.17), y=(-35.25, -35.35), 
                    time=('1991', '1992'), measurements=['red', 'nir'], group_by='solar_day')
red = two_bands.red.where(two_bands.red != two_bands.red.attrs['nodata'])
nir = two_bands.nir.where(two_bands.nir != two_bands.nir.attrs['nodata'])
pq = dc.load(product='ls5_pq_albers', x=(149.07, 149.17), y=(-35.25, -35.35), 
             time=('1991', '1992'), group_by='solar_day')
cloud_free = masking.make_mask(pq, cloud_acca='no_cloud', cloud_fmask='no_cloud', contiguous=True).pixelquality

ndvi = ((nir - red) / (nir + red)).where(cloud_free)

In [20]:
ndvi.shape


Out[20]:
(18, 490, 420)

In [21]:
ndvi.plot(col='time', col_wrap=5)


Out[21]:
<xarray.plot.facetgrid.FacetGrid at 0x2478e0d0>

In [22]:
mostly_cloud_free = cloud_free.sum(dim=('x','y')) > (0.75 * cloud_free.size / cloud_free.time.size)
mostly_good_ndvi = ndvi.where(mostly_cloud_free).dropna('time', how='all')
mostly_good_ndvi.plot(col='time', col_wrap=5)


Out[22]:
<xarray.plot.facetgrid.FacetGrid at 0x2e02ddd0>

Some stats


In [23]:
mostly_good_ndvi.median(dim='time').plot()


Out[23]:
<matplotlib.collections.QuadMesh at 0x39904450>

In [24]:
mostly_good_ndvi.std(dim='time').plot()


Out[24]:
<matplotlib.collections.QuadMesh at 0x2b639d90>

Pixel drill


In [25]:
mostly_good_ndvi.sel(y=-3955361, x=1549813, method='nearest').plot()


Out[25]:
[<matplotlib.lines.Line2D at 0x3f4ce350>]

In [26]:
mostly_good_ndvi.isel(x=[200], y=[200]).plot()


Out[26]:
[<matplotlib.lines.Line2D at 0x3f744fd0>]

In [27]:
mostly_good_ndvi.isel(y=250).plot()


Out[27]:
<matplotlib.collections.QuadMesh at 0x4021b950>

A line shapefile with pairs of coordinates (using sel_points instead of isel_points) would be able to be interpolated into something less blocky for the next plot.


In [28]:
mostly_good_ndvi.isel_points(x=[0, 100, 200, 300, 300, 400], 
                             y=[200, 200, 200, 250, 300, 400]).plot(x='points', y='time')


Out[28]:
<matplotlib.collections.QuadMesh at 0x40f42250>

Plotting a multi-band image


In [29]:
rgb = dc.load(product='ls5_nbar_albers', 
              x=(149.07, 149.17), y=(-35.25, -35.35), 
              time=('1991-3-1', '1991-6-30'), 
              measurements=['red', 'green', 'blue'], 
              group_by='solar_day', stack='color').transpose('time', 'y', 'x', 'color')
zip(rgb.dims, rgb.shape)


Out[29]:
[('time', 6), ('y', 490), ('x', 420), ('color', 3)]

In [30]:
fake_saturation = 3000
clipped_visible = rgb.where(rgb<fake_saturation).fillna(fake_saturation)
max_val = clipped_visible.max(['y', 'x'])
scaled = (clipped_visible / max_val)

In [31]:
from matplotlib import pyplot as plt
plt.imshow(scaled.isel(time=3))


Out[31]:
<matplotlib.image.AxesImage at 0x3f7220d0>

Elevation


In [32]:
grid = dc.load(product='dsm1sv10', x=(149.07, 149.17), y=(-35.25, -35.35))
grid.elevation.shape


Out[32]:
(1, 361, 361)

In [33]:
grid.elevation[0].plot()


Out[33]:
<matplotlib.collections.QuadMesh at 0x41466210>

Reprojection


In [34]:
albers_grid = dc.load(product='dsm1sv10', x=(149.07, 149.17), y=(-35.25, -35.35), 
                      output_crs='EPSG:3577', resolution=(-25,25))
albers_grid.elevation.shape


Out[34]:
(1, 490, 420)

In [35]:
albers_grid.elevation[0].plot()


Out[35]:
<matplotlib.collections.QuadMesh at 0x462f8890>