<commit_before>---
title: Identifying Annual First Day of No Snow Cover
description: Using MODIS NDSI to map the annual first day of no snow cover.
author: aharmstrong
tags: snow-fraction, snow-cover, snow-melt, snow, modis-ndsi, ndsi
date_published: 2020-02-20
---
<!--
Copyright 2020 The Google Earth Engine Community Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->

This tutorial demonstrates how to produce annual maps depicting the first day
within a year where a given pixel reaches zero percent snow cover and provides
suggestions for summarizing and visualizing the results over time and space.

![arctic-first-doy-no-snow-polar-proj.jpg](arctic-first-doy-no-snow-polar-proj.jpg)<br>
_Patterns of snowmelt timing are represented here by the first day in 2018 where
each pixel no longer contained snow, as detected by the MODIS daily snow cover
product. The color grades from purple (earlier) to yellow (later) as the first
day of the year with zero percent snow per pixel increases
(Arctic Polar Stereographic projection)._

## Context

The timing of annual seasonal snowmelt and any potential change in that
timing has broad ecological implications and thus impacts human livelihoods,
particularly in and around high latitude and mountainous systems.

One of the most important phases of the hydrologic cycle within these
regions, the
annual melting of accumulated winter snowfall provides the dominant source of
water for streamflow and groundwater recharge for approximately one sixth of
the global population (Musselman et al., 2017; Barnhart et al., 2016;
Bengtsson, 1976).

The timing of snowmelt in the Arctic and Antarctic influences the length of
the growing season; and consistent snow cover
throughout the winter insulates vegetation from harsh temperatures and wind
(Duchesne et al., 2012; Kudo et al., 1999). In mountainous regions such as
the Himalayas, snowmelt is a major source of freshwater downstream (Barnhart
et al., 2016) and is essential in recharging groundwater.

This seasonal water resource is one of the fastest changing hydrologic
systems under Earth’s
warming climate, and will broadly impact regional economies, ecosystem
function and increase the potential for flood hazards (Musselman et al.,
2017; IPCC, 2007; Beniston, 2012; Allan and Casillo, 2007; Barnett and
Lettenmaier, 2005).

The anticipated warmer temperatures will alter the type
and onset of precipitation; multiple regions, including the Rocky Mountains
of North America have already measured a reduction in snowpack volume and
warmer temperatures have shifted precipitation from snowfall to rain, causing
snowmelt to occur earlier (Barnhart et al., 2016; Clow, 2010; Harpold et al.,
2012).

This tutorial calculates the first day of no snow annually at the pixel
level, providing the user with the ability to track the seasonal and interannual
variability in the timing of snowmelt toward a better understanding of how
the hydrological cycles of higher latitude and mountainous regions are
responding to climate change.

## Identify first day of zero percent snow cover

This section covers building an image collection where each image is a mosaic
of pixels that describe the first day in a given year that zero percent snow
cover is recorded. Snow cover is defined by the [MODIS NDSI Snow Cover
product](https://developers.google.com/earth-engine/datasets/catalog/MODIS_006_MOD10A1).
The general workflow is as follows:

1. Define the date ranges to consider for analysis.
2. Define a function that adds date information as bands to snow cover images.
3. Define an analysis mask.
4. For each year:
    1. Filter the image collection to observations from the given year.
    2. Add date bands to the filtered images.
    3. Identify the first day of the year without any snow per pixel.
    4. Apply an analysis mask to the image mosaic.
    5. Summarize the findings with a series of visualizations.

### 1\. Define date range

Define the day-of-year (DOY) to start the search for the first
day with zero percent snow cover. For applications in the northern
hemisphere, you will likely want to start with January 1st (DOY `1`).
However, if you are studying snowmelt timing in the southern hemisphere (e.g.,
the Andes), where snowmelt can occur on dates either side of the new year,
it is more appropriate to start the year on July 1st (DOY `183`), for
instance. In this calculation, a year is defined as the 365 days beginning
from the provided `startDay`.

```js
var startDoy = 1;
```

Define the year to start and end tracking snow cover fraction. All years in
the range will be included in the analysis.

```js
var startYear = 2000;
var endYear = 2019;
```

### 2\. Define date bands

Define a function to add several date bands to the images; they will be used
in a future step. Each image has a metadata timestamp property, but since we
will be creating annual image mosaics composed of pixels from many different
images, the date needs to be encoded per pixel as a value in an image band so
that it is retained in the final mosaics. The function encodes:

- Calendar DOY (`calDoy`): enumerated DOY from January 1st
- Relative DOY (`relDoy`): enumerated DOY from user-defined `startDoy`
- Milliseconds from Unix epoch (`millis`)
- Year (`year`) - Note that the year is tied to the `startDoy` e.g., if
`startDoy` is set at 183, the analysis will cross the new year, the year
given to all pixels will be the first year, even if a particular image was
collected on January 1 of the subsequent year.

Note that two global variables are initialized (`startDate` and `startYear`)
that will be redefined iteratively in a subsequent step.

```js
var startDate;
var startYear;

function addDateBands(img) {
  // Get image date.
  var date = img.date();
  // Get calendar day-of-year.
  var calDoy = date.getRelative('day', 'year');
  // Get relative day-of-year; enumerate from user-defined startDoy.
  var relDoy = date.difference(startDate, 'day');
  // Get the date as milliseconds from Unix epoch.
  var millis = date.millis();
  // Add all of the above date info as bands to the snow fraction image.
  var dateBands = ee.Image.constant([calDoy, relDoy, millis, startYear])
    .rename(['calDoy', 'relDoy', 'millis', 'year']);
  // Cast bands to correct data type before returning the image.
  return img.addBands(dateBands)
    .cast({'calDoy': 'int', 'relDoy': 'int', 'millis': 'long','year': 'int'})
    .set('millis', millis);
}
```

### 3\. Define an analysis mask

Here is the opportunity to define a mask for your analysis. This mask can be<commit_msg>Fix tutorial lint error<commit_after>---
title: Identifying Annual First Day of No Snow Cover
description: Using MODIS NDSI to map the annual first day of no snow cover.
author: aharmstrong
tags: snow-fraction, snow-cover, snow-melt, snow, modis-ndsi, ndsi
date_published: 2020-02-20
---
<!--
Copyright 2020 The Google Earth Engine Community Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->

This tutorial demonstrates how to produce annual maps depicting the first day
within a year where a given pixel reaches zero percent snow cover and provides
suggestions for summarizing and visualizing the results over time and space.

![arctic-first-doy-no-snow-polar-proj.jpg](arctic-first-doy-no-snow-polar-proj.jpg)<br>
_Patterns of snowmelt timing are represented here by the first day in 2018 where
each pixel no longer contained snow, as detected by the MODIS daily snow cover
product. The color grades from purple (earlier) to yellow (later) as the first
day of the year with zero percent snow per pixel increases
(Arctic Polar Stereographic projection)._

## Context

The timing of annual seasonal snowmelt and any potential change in that
timing has broad ecological implications and thus impacts human livelihoods,
particularly in and around high latitude and mountainous systems.

One of the most important phases of the hydrologic cycle within these
regions, the
annual melting of accumulated winter snowfall provides the dominant source of
water for streamflow and groundwater recharge for approximately one sixth of
the global population (Musselman et al., 2017; Barnhart et al., 2016;
Bengtsson, 1976).

The timing of snowmelt in the Arctic and Antarctic influences the length of
the growing season; and consistent snow cover
throughout the winter insulates vegetation from harsh temperatures and wind
(Duchesne et al., 2012; Kudo et al., 1999). In mountainous regions such as
the Himalayas, snowmelt is a major source of freshwater downstream (Barnhart
et al., 2016) and is essential in recharging groundwater.

This seasonal water resource is one of the fastest changing hydrologic
systems under Earth’s
warming climate, and will broadly impact regional economies, ecosystem
function and increase the potential for flood hazards (Musselman et al.,
2017; IPCC, 2007; Beniston, 2012; Allan and Casillo, 2007; Barnett and
Lettenmaier, 2005).

The anticipated warmer temperatures will alter the type
and onset of precipitation; multiple regions, including the Rocky Mountains
of North America have already measured a reduction in snowpack volume and
warmer temperatures have shifted precipitation from snowfall to rain, causing
snowmelt to occur earlier (Barnhart et al., 2016; Clow, 2010; Harpold et al.,
2012).

This tutorial calculates the first day of no snow annually at the pixel
level, providing the user with the ability to track the seasonal and interannual
variability in the timing of snowmelt toward a better understanding of how
the hydrological cycles of higher latitude and mountainous regions are
responding to climate change.

## Identify first day of zero percent snow cover

This section covers building an image collection where each image is a mosaic
of pixels that describe the first day in a given year that zero percent snow
cover is recorded. Snow cover is defined by the [MODIS NDSI Snow Cover
product](https://developers.google.com/earth-engine/datasets/catalog/MODIS_006_MOD10A1).
The general workflow is as follows:

1. Define the date ranges to consider for analysis.
2. Define a function that adds date information as bands to snow cover images.
3. Define an analysis mask.
4. For each year:
    1. Filter the image collection to observations from the given year.
    2. Add date bands to the filtered images.
    3. Identify the first day of the year without any snow per pixel.
    4. Apply an analysis mask to the image mosaic.
    5. Summarize the findings with a series of visualizations.

### 1\. Define date range

Define the day-of-year (DOY) to start the search for the first
day with zero percent snow cover. For applications in the northern
hemisphere, you will likely want to start with January 1st (DOY `1`).
However, if you are studying snowmelt timing in the southern hemisphere (e.g.,
the Andes), where snowmelt can occur on dates either side of the new year,
it is more appropriate to start the year on July 1st (DOY `183`), for
instance. In this calculation, a year is defined as the 365 days beginning
from the provided `startDay`.

```js
var startDoy = 1;
```

Define the year to start and end tracking snow cover fraction. All years in
the range will be included in the analysis.

```js
var startYear = 2000;
var endYear = 2019;
```

### 2\. Define date bands

Define a function to add several date bands to the images; they will be used
in a future step. Each image has a metadata timestamp property, but since we
will be creating annual image mosaics composed of pixels from many different
images, the date needs to be encoded per pixel as a value in an image band so
that it is retained in the final mosaics. The function encodes:

- Calendar DOY (`calDoy`): enumerated DOY from January 1st
- Relative DOY (`relDoy`): enumerated DOY from user-defined `startDoy`
- Milliseconds from Unix epoch (`millis`)
- Year (`year`) - Note that the year is tied to the `startDoy` e.g., if
`startDoy` is set at 183, the analysis will cross the new year, the year
given to all pixels will be the first year, even if a particular image was
collected on January 1 of the subsequent year.

Note that two global variables are initialized (`startDate` and `startYear`)
that will be redefined iteratively in a subsequent step.

```js
var startDate;
var startYear;

function addDateBands(img) {
  // Get image date.
  var date = img.date();
  // Get calendar day-of-year.
  var calDoy = date.getRelative('day', 'year');
  // Get relative day-of-year; enumerate from user-defined startDoy.
  var relDoy = date.difference(startDate, 'day');
  // Get the date as milliseconds from Unix epoch.
  var millis = date.millis();
  // Add all of the above date info as bands to the snow fraction image.
  var dateBands = ee.Image.constant([calDoy, relDoy, millis, startYear])
    .rename(['calDoy', 'relDoy', 'millis', 'year']);
  // Cast bands to correct data type before returning the image.
  return img.addBands(dateBands)
    .cast({'calDoy': 'int', 'relDoy': 'int', 'millis': 'long', 'year': 'int'})
    .set('millis', millis);
}
```

### 3\. Define an analysis mask

Here is the opportunity to define a mask for your analysis. This mask can be
{'fraction_non_alphanumeric': 0.06089357785173122, 'fraction_numerical': 0.01656871769454082, 'mean_word_length': 4.347974252177206, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 4, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2973220', 'n_tokens_mistral': 4018, 'n_tokens_neox': 3631, 'n_words': 2099}