<jupyter_start><jupyter_text>Burn extent  validation against independent fire perimeter dataThis script shows the workflow to evaluate a burn extent map against independent fire perimeter polygon data. The workflow provides a visual comparison as well as False Positive and True Positive statistics that can be used to construct Receiver Pperating Characteristic (ROC) curves.  Import the required modules Import the `validationtoolbox`:<jupyter_code>import xarray as xr
import numpy as np
import validationtoolbox as val
import matplotlib.pyplot as plt
%matplotlib inline<jupyter_output><empty_output><jupyter_text>Load  burn severity mapLoad the saved NetCDF file containing the burn severity map that was produced.The example below assumes access to the indicated location in the NCI file system.If no burn severity map was produced yet, then first do so, for example, using the BurnCube Burn Mapping Example Notebook.<jupyter_code>sev = xr.open_dataset('/g/data/xc0/project/Burn_Mapping/TestSites/BurnMapping_SirIvan_2017.nc')<jupyter_output><empty_output><jupyter_text>Convert burn severity map to a burn extent mapThe `burnpixel_masking` function from  the validation toolbox converts the severity data into a binary map.<jupyter_code>Burnpixel = val.burnpixel_masking(sev,'Moderate') # mask the burnt area with "Medium" burnt area
cax=Burnpixel.plot.imshow(cmap='binary',add_colorbar=False)
cax.axes.set_title('Moderate and severe',fontsize=18)
cax.axes.get_xaxis().set_visible(False)
cax.axes.get_yaxis().set_visible(False)<jupyter_output><empty_output><jupyter_text>Filtering with datesThe start-date information for severe burnt area and moderate burnt area can be used to further filter out landcover change not related to the fire.The following example shows the use of StartDate to filter out the landcover change happened one-month before and one-month after the fire-date<jupyter_code>#use the date with maximum number of burnt area as the fire date
values, counts = np.unique(sev.StartDate, return_counts=True)
print('fire started at: ',values[counts==np.max(counts)].astype('datetime64[ns]')[0])
firedate=values[counts==np.max(counts)]
#filtered out any change happend one month before and one month after the fire
start = (firedate.astype('datetime64[ns]')-np.datetime64(1, 'M')).astype('datetime64[ns]')
end = (firedate.astype('datetime64[ns]')-np.datetime64(-1, 'M')).astype('datetime64[ns]')
row,col=np.where((sev.StartDate.data.astype('datetime64[ns]')<start)|(sev.StartDate.data.astype('datetime64[ns]')>end)) 

fig,axes=plt.subplots(ncols=2,figsize=[15,5])
cax1=Burnpixel.plot.imshow(ax=axes[0],cmap='binary',add_colorbar=False)
cax1.axes.set_title('unfiltered burnscar',fontsize=18)
cax1.axes.get_xaxis().set_visible(False)
cax1.axes.get_yaxis().set_visible(False)

Burnpixel.data[row,col]=0
cax2=Burnpixel.plot.imshow(cmap='binary',add_colorbar=False)
cax2.axes.set_title('filtered burnscar',fontsize=18)
cax2.axes.get_xaxis().set_visible(False)
cax2.axes.get_yaxis().set_visible(False)<jupyter_output>fire started at:  2017-02-15T23:55:36.000000000<jupyter_text>Separating the burned area into forest and non-forest componentsThis step uses the `treecover_masking` tool to combine the burn map with binary mapping of (pre-fire) forest and non-forest land cover.The forest cover mapping is derived from ANU's extended and resampled NCAS mapping available through www.ausenv.online.Required inputs:    "year" should be before the year before the fire event,     "data" the binary burn extent map with x,y    "prctg" the treecover fraction threshold used for forest mapping, default is 60Outputs:    forest mask, with 1 for forest and 0 for non-forest    non-forest mask, with 1 for non-forest and 0 for forestThe resulting maps show the burn forest and non-forest areas, respectively.<jupyter_code>#reminder: forest mask has to be derived from the tree cover data before fire occured
mask=val.treecover_masking(year=2016,data=Burnpixel,prctg=60) 
cax1=mask.ForestMask.plot.imshow(cmap='binary',add_colorbar=False)
cax1.axes.set_title('Forest mask',fontsize=18)
cax1.axes.get_xaxis().set_visible(False)
cax1.axes.get_yaxis().set_visible(False)
ForestBurned = Burnpixel*mask.ForestMask # burned pixel found in the forest area
NoneForestBurned = Burnpixel*mask.NoneForestMask # burned pixel found in the non-forest area
fig,axes=plt.subplots(ncols=2,figsize=[15,5])
cax1=ForestBurned.plot.imshow(ax=axes[0],cmap='binary',add_colorbar=False)
cax1.axes.set_title('burnscar for forest',fontsize=18)
cax1.axes.get_xaxis().set_visible(False)
cax1.axes.get_yaxis().set_visible(False)
cax2=NoneForestBurned.plot.imshow(ax=axes[1],cmap='binary',add_colorbar=False)
cax2.axes.set_title('burnscar for grassland',fontsize=18)
cax2.axes.get_xaxis().set_visible(False)
cax2.axes.get_yaxis().set_visible(False)<jupyter_output><empty_output><jupyter_text>Generate validation map from fire perimeter polygon dataUse the function `CreateValidatedBurnMask` to create a validation mask from the shapefile(s) of fire perimeters polygon data.Required inputs:    BurnPixel: burned pixel     State: abbreviation of state or territory name     Validation_period: start and end of corresponding burn occurence period    The output includes a binary grid for each time step, which can be summed up if a single mask is required:<jupyter_code>ValidationMask=val.CreateValidatedBurnMask(Burnpixel,State='NSW', Validation_period=("2017-01-01","2017-12-31"))
ValidationMask = ValidationMask.sum('time') #create one mask with all the burned area<jupyter_output><empty_output><jupyter_text>Validation mapThe validation map can be produced with forest and non-forest validation results combined or produced separately:When using `validationtoolbox.validate`, forest and non-forest land cover will not be separately considered.When using `validationtoolbox.validate_forest_grass`, forest and non-forest will be evaluated separately and shown in the same figure.The following example shows the validation result for burn mapping, with forest pixels in a darker shades and non-forest pixels in a lighter shade.<jupyter_code>a,b = val.validate_forest_grass(Test_Array = Burnpixel, Validated_Array = ValidationMask,Mask = mask, plot=True)
print('The false positive and truth positive rate for forest burnt area: %.3f, %.3f' %(a[0],a[1]))
print('The false positive and truth positive rate for non-forest burnt area: %.3f, %.3f' %(b[0],b[1]))<jupyter_output>The false positive and truth positive rate for forest burnt area: 0.001, 0.888
The false positive and truth positive rate for non-forest burnt area: 0.006, 0.749
{'fraction_non_alphanumeric': 0.09439393939393939, 'fraction_numerical': 0.02196969696969697, 'mean_word_length': 6.991525423728813, 'pattern_counts': {'":': 0, '<': 28, '<?xml version=': 0, '>': 28, 'https://': 0, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 1, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '7', 'dir': 'jupyter-structured-clean-dedup', 'id': '532883', 'license': 'Apache-2.0', 'n_tokens_mistral': 2171, 'n_tokens_neox': 1989, 'n_words': 619, 'path': 'BurnCube/Validation_example1.ipynb', 'repo_name': 'ANU-WALD/burn-mapping', 'size': '6600'}