<jupyter_start><jupyter_text>Tropospheric corrections using GACOS**Author**: <NAME> - Jet Propulsion LaboratoryIn this notebook, we will walk through the steps in order to correct a geo-coded intergerogram with GACOS. We will apply the corrections to a topsApp geo-coded Sentinel-1 interferogram of the 12 November 2017 Mw7.3 earthquake that occurred in Iran.![title](support_docs/region.png)  0. Initial set-up for the notebook We will start with the initial set-up of the note-book. This step only needs to be ran at the very beginning and defines the processing locations as well as a few plotting routines that will be used throughout the tutorial.<jupyter_code>from shutil import copyfile
from osgeo import gdal            ## GDAL support for reading virtual files
import os                         ## To create and remove directories
import matplotlib.pyplot as plt   ## For plotting
import numpy as np                ## Matrix calculations
import glob                       ## Retrieving list of files
import isce 

## Defining the home and data directories at the processing location
home_dir = os.getenv("HOME")

## Defining the home directory as an absolute path
if 'tutorial_home_dir' in locals(): 
    pass
else:
    tutorial_home_dir = os.path.abspath(os.path.join(home_dir, "work/notebooks/Atmosphere/Troposphere"))
    ## Defining the gacos directory as an absolute path
    gacos_dir  =  os.path.join(tutorial_home_dir,'gacos_download')
    processing_dir = os.path.join(tutorial_home_dir,'insar','merged')
print("home directory: ", tutorial_home_dir)
os.chdir(tutorial_home_dir)

# generate all the folders in case they do not exist yet
if not os.path.isdir(gacos_dir):
    os.mkdir(gacos_dir)
if not os.path.isdir(processing_dir):
    os.mkdir(processing_dir)
    
# defining backup dirs in case of download issues on the local server
data_backup_dir = os.path.abspath(os.path.join(home_dir,"course-material/datasets/Atmosphere/Tropo"))
gacos_backup_dir = os.path.join(data_backup_dir,'gacos')
processing_backup_dir  =  os.path.join(data_backup_dir,'insar','merged')
    
# copy in the InSAR data 
cmd = "cp -r " + os.path.join(processing_backup_dir,'*') + " " + os.path.join(processing_dir,'.')
os.system(cmd)


def plotdata(GDALfilename,band=1,title=None,colormap='gray',aspect=1, datamin=None, datamax=None,draw_colorbar=True,colorbar_orientation="horizontal",background=None):
    ds = gdal.Open(GDALfilename, gdal.GA_ReadOnly)
    data = ds.GetRasterBand(band).ReadAsArray()
    transform = ds.GetGeoTransform()
    ds = None
    
    # getting the min max of the axes
    firstx = transform[0]
    firsty = transform[3]
    deltay = transform[5]
    deltax = transform[1]
    lastx = firstx+data.shape[1]*deltax
    lasty = firsty+data.shape[0]*deltay
    ymin = np.min([lasty,firsty])
    ymax = np.max([lasty,firsty])
    xmin = np.min([lastx,firstx])
    xmax = np.max([lastx,firstx])

    # put all zero values to nan and do not plot nan
    if background is None:
        try:
            data[data==0]=np.nan
        except:
            pass

    fig = plt.figure(figsize=(9, 8))
    ax = fig.add_subplot(111)
    cax = ax.imshow(data, vmin = datamin, vmax=datamax, cmap=colormap,extent=[xmin,xmax,ymin,ymax])
    ax.set_title(title)
    if draw_colorbar is not None:
        cbar = fig.colorbar(cax,orientation=colorbar_orientation)
    ax.set_aspect(aspect)    
    plt.show()
    data = None

def plotdata2(GDALfilename1,GDALfilename2,band=1,title=None,colormap='gray',aspect=1, datamin=None, datamax=None,draw_colorbar=True,background=None,plot_profile=None):
   
    # profiles to be drawn if requested
    profiles_x = [1100,600]
    profiles_y = [1600,600]


    # plotting a two pannel dataset
    counter=1
    GDALfilenames = [GDALfilename1,GDALfilename2]
    fig = plt.figure(figsize=(9, 8))
    for GDALfilename in GDALfilenames:
        ds = gdal.Open(GDALfilename, gdal.GA_ReadOnly)
        data = ds.GetRasterBand(band).ReadAsArray()
        transform = ds.GetGeoTransform()
        ds = None

        # getting the min max of the axes
        firstx = transform[0]
        firsty = transform[3]
        deltay = transform[5]
        deltax = transform[1]
        lastx = firstx+data.shape[1]*deltax
        lasty = firsty+data.shape[0]*deltay
        ymin = np.min([lasty,firsty])
        ymax = np.max([lasty,firsty])
        xmin = np.min([lastx,firstx])
        xmax = np.max([lastx,firstx])

        ax = fig.add_subplot(1,2,counter)
        
        # put all zero values to nan and do not plot nan
        if background is None:
            try:
                data[data==0]=np.nan
            except:
                pass

        cax = ax.imshow(data, vmin = datamin, vmax=datamax, cmap=colormap,extent=[xmin,xmax,ymin,ymax])
         

        # in case a profile is requested to be plotted, then show it on the overview figure and compute the profile
        if plot_profile is not None:
            if counter==1:
                data1=[]
                linetype='-'
                linecolor='magenta'
                for profile_x in profiles_x:
                    data1.append(data[0:-1,profile_x])  
                for profile_y in profiles_y:
                    data1.append(data[profile_y,0:-1])
            elif counter==2:
                data2=[]
                linetype='--'
                linecolor='k'
                for profile_x in profiles_x:
                    data2.append(data[0:-1,profile_x])  
                for profile_y in profiles_y:
                    data2.append(data[profile_y,0:-1])

            # plot the profiles on the figure
            count_profile_total=0
            for profile_y in profiles_y:
                profile_lat = firsty+profile_y*deltay
                ax.plot([xmin, xmax],[profile_lat, profile_lat],linestyle=linetype, color=linecolor)
                count_profile_total +=1
                ax.text(np.mean([xmin,xmax]),profile_lat,str(count_profile_total),fontsize=20)
            for profile_x in profiles_x:
                profile_lon = firstx+profile_x*deltax
                ax.plot([profile_lon, profile_lon],[ymin,ymax],linestyle=linetype, color=linecolor)
                count_profile_total +=1
                ax.text(profile_lon,np.mean([ymin,ymax]),str(count_profile_total),fontsize=20)

        
        ax.set_title(title[counter-1])
        if draw_colorbar is not None:
            cbar = fig.colorbar(cax,orientation="horizontal")
        ax.set_aspect(aspect)  
        counter +=1
    plt.show()
    
    # plotting the profile if requested
    if plot_profile is not None:
        fig2 = plt.figure(figsize=(15, 14))
        for i_profile in range(count_profile_total):
            ax = fig2.add_subplot(count_profile_total,1,i_profile+1)
            ax.plot(range(len(data2[i_profile])),data2[i_profile],'--',color='k')
            ax.plot(range(len(data1[i_profile])),data1[i_profile],'-',color='magenta')
            ax.set_title('profile number ' + str(i_profile+1))
        plt.show()
        
    data = None<jupyter_output><empty_output><jupyter_text>1. Overview of the tutorial input dataset The following steps require geo-coded itnerferogram products that are compatible with gdal and have correct geo-reference information stored in their meta-data. Gecoded **ISCE** product have a **.geo** suffix, while the addition of the **.vrt** suffix makes sure the products are also compatible with gdal. As part of this tutorial we use a Sentinel-1 dataset which has already been pre-processed with *topsApp.py*. You can find the unwrapped unwrapped interferogram (*filt_topophase.flat.geo*) and the line-of-sight angles (*los.rdr.geo*), containing incidence and heading, in the **insar/merged** data folder.<jupyter_code>ls insar/merged<jupyter_output><empty_output><jupyter_text>To verify if your *FILE* is gdal compatible try to run:```    gdalinfo FILE```Verify the coordinate information to ensure the parsing from the metadata is done correctly. This can be done by investigating the output from gdalinfo: - Coordinate System: typically reports an EPSG code, or spells out the coodinate system in its complete such as WGS84.- Origin: the origin of the coordinate system- Pixel Size: the sampling/resolution of the data- Corner Coordinates: longitude and latitude corners of the data<jupyter_code>!gdalinfo insar/merged/filt_topophase.unw.geo.vrt<jupyter_output><empty_output><jupyter_text>The names of the original input SLC's used in the processing are containted in the **SLC** folder. By exploring the slc folder you can see that these products files are zip archives. When unpacked the zip extension will be replaced by SAFE. The products are therefore also frequently called SAFE files. The SAFE filenames provide information on the product type, the polarization, the start and stop acquisition time. For example: S1A_IW_SLC__1SDV_20171111T150004_20171111T150032_019219_0208AF_EE89.zip - Type = slc- Polarization = Dual pole - Date = 20171111- UTC time of acquisition = ~15:00- Sensing start for the acquisition was 20171111 at 15:00:04  2. Overview of the GACOS dataset  2.1 Background on GACOS The Generic Atmospheric Correction Online Service for InSAR (GACOS) allows for the on-demand generation of zenith tropospheric delay maps given a user specified region of interest, date, and UTC time. Currently no command line API exist, but orders can be submitted using the online form at: http://ceg-research.ncl.ac.uk/v2/gacos/  2.2 GACOS download Let us first find all the required information needed to complete online GACOS fields   2.2.1 Dates and UTC  - **Dates** and **UTC**: For sentinel-1, the date and UTC information can be directly extracted from the original SAFE filename. For example: S1A_IW_SLC__1SDV_20171111T150004_20171111T150032_019219_0208AF_EE89 corresponds to an acquisition made on 20171111 at ~15:00 UTC. What are the other dates and do they roughly have the same acquisition time?<jupyter_code>ls slc<jupyter_output><empty_output><jupyter_text>2.2.2 Region - **Region**: You can extract the region information directly from the .geo.vrt file with gdalinfo. Look at the corner coordinates.<jupyter_code>!gdalinfo insar/merged/filt_topophase.unw.geo.vrt<jupyter_output><empty_output><jupyter_text>2.2.3 Summary of parameters - dates: 20171111 and 20171117- UTC: ~15:00 UTC (UTC does not vary much for SAR satellites due to their typical sun synchronous dawn-dusk orbit)- region: North=35.49, South=33.82, West=45.25, East=46.55NOTE on REGION: For ease we will select a region of integer degrees. **Region: North=36, South=33, West=45, East=47**  2.2.4 Placing GACOS order Now that we have all the required parameters at hand, initiate the GACOS request online at http://ceg-research.ncl.ac.uk/v2/gacos/. Once you submit the order, an email will be send to the provided email adress informing you about the job submission.![title](support_docs/gacos_order.png) A second email will be send to you once the processing has completed, depending on the number of requests this could take a few minutes or longer. The completion email contains an FTP URL where the product can be downloaded. For this tutorial we will download the GACOS product into a *gacos_download* processing folder. As we are processing this tutorial remotely, we will be using commandline **wget** for the download of the products. ```cd gacos_downloadwget GACOS_FILE.tar.gz```We will use the command line **tar** functionality to unzip the file```tar -xvf GACOS_FILE.tar.gz```GACOS NOTES: - The delays provided by GACOS are in meter units.- Suffix *.ztd* refers to the zenith (vertical column) tropospheric delay, and *.dztd* refers to the differential *.ztd*. - The GACOS ReadMe.pdf contains more information on the definition and references.**In case you are having issue with the download of the product proceed below, if not, proceed directly to section 2.2**  In case of unsuccessful download In case you are unable to download the product, we have already downloaded it for this tutorial in the gacos folder. You can copy this folder content into the *gacos_download* folder<jupyter_code># copy in the GACOS data 
cmd = "cp -r " + os.path.join(gacos_backup_dir,'*') + " " + os.path.join(gacos_dir,'.')
os.system(cmd)
!ls gacos_download/*<jupyter_output><empty_output><jupyter_text>3. SAR Tropospheric phase delay (slant) In this chapter we will convert the GACOS pseudo-range zenith tropospheric delays, into the projection reference as the geo-coded interferogram and project the zenith delay to the slant using the incidence angle information.$$\Phi_{\text{slant}}=\frac{-\lambda}{4 \pi* cos(\theta)}*d_{\text{zenith}}$$  3.1 Creating ENVI header files We will be using GDAL to interpolate the GACOS products on the same grid as our geocoded interferogram. Unfortunately, at this time the GACOS files are not GDAL compatible.<jupyter_code>!gdalinfo gacos_download/20171117.ztd<jupyter_output><empty_output><jupyter_text>This can be solved by making a new ENVI *.hdr* file. Below we include a function **loadrsc** which will open the GACOS *.rsc* file and load the relevant information. Another provided function will generate the *.hdr* file using a predefined template and the information extracted from the *.rsc* file. Execute the following cell to make these functions available for usage.<jupyter_code>def loadrsc(infile):
    '''A function to load the content of .rsc file and pass it back as a dictionary'''
    import numpy as np
    with open(infile + '.rsc') as f:
        text = f.read()
    lines = [e.split() for e in text.split("\n") if e != ""]
    headers = dict(lines)
    # add the filename such it can be called when making envi header
    headers['FILENAME'] = infile
    # take the abs of the y-spacing as upper left corner is to be specified
    headers['Y_STEP'] = str(np.abs(float(headers['Y_STEP'])))
    return headers

def writehdr(filename,headers):
    '''A function that writes a .hdr file from a template and a dictionarydescribing the fields'''
    print('Writing output HDR file...')
    print(headers)
    enviHDRFile = open(filename + '.hdr', 'w')
    enviHDR = '''ENVI
description = {{GACOS: {FILENAME} }}
samples = {WIDTH}
lines = {FILE_LENGTH}
bands = 1
header offset = 0
file type = ENVI Standard
data type = 4
interleave = bsq
sensor type = Unknown
byte order = 0
map info = {{Geographic Lat/Lon, 1, 1, {X_FIRST}, {Y_FIRST}, {X_STEP}, {Y_STEP}, WGS-84, units=Degrees}}
coordinate system string = {{GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.017453292519943295]]}}'''.format(**headers)

    enviHDRFile.write(enviHDR)
    enviHDRFile.close()
    print('Output HDR file =', filename)

def GACOS_rsc2hdr(inputfile):
    '''
    Wrapper code which calls .rsc reader and .hdr writer functionality 
    '''

    print('Generating hdr file for: ' + inputfile + '...')
    # make sure the user does not give a header file as input
    filename, file_extension = os.path.splitext(inputfile)
    if file_extension == '.hdr' or file_extension == '.rsc':
        raise Exception("Give path to the ENVI file not the .hdr or .rsc file")
    headers = loadrsc(inputfile)
    writehdr(inputfile,headers)
    print('hdr for ' + inputfile + ' generated')
    print(" ")<jupyter_output><empty_output><jupyter_text>We will generate the header files for all the SAR delays files:<jupyter_code>GACOS_rsc2hdr('gacos_download/20171111.ztd')
GACOS_rsc2hdr('gacos_download/20171117.ztd')<jupyter_output><empty_output><jupyter_text>Let us verify if the files are now GDAL compatible, and if the geo-reference information is correctly represented.<jupyter_code>!gdalinfo gacos_download/20171117.ztd<jupyter_output><empty_output><jupyter_text>3.2 Geo-coodinate mapping In the next step, we will interpolate GACOS data to the grid of the geo-coded interferogram. Below we include a function **file_transform** which will allow us to do this using GDAL. It takes three inputs, namely the unwrapped ISCE file, the GACOS APS file, and an output filename. Execute the following cell to make this function available for usage.<jupyter_code>def file_transform(unwfile,apsfile,apsfile_out):
    '''
    convert the aps file into the same geo frame as the unw file
    Unwfile is an envi file and has a corresponding vrt file
    aps file is gdal compatible
    '''
    import isceobj
    from osgeo import gdal, gdalconst
    #from gdal2isce_xml import gdalisce2XML

    # convert all to absolute paths
    apsfile = os.path.abspath(apsfile)
    apsfile_out = os.path.abspath(apsfile_out)

    # Source
    src = gdal.Open(apsfile, gdalconst.GA_ReadOnly)
    src_proj = src.GetProjection()
    src_geotrans = src.GetGeoTransform()
    print("Working on " + apsfile )
    # We want a section of source that matches this:
    match_ds = gdal.Open(unwfile + '.vrt', gdalconst.GA_ReadOnly)
    match_proj = match_ds.GetProjection()
    match_geotrans = match_ds.GetGeoTransform()
    print("Getting target reference information")
    wide = match_ds.RasterXSize
    high = match_ds.RasterYSize
    
    # Output / destination
    dst = gdal.GetDriverByName('envi').Create(apsfile_out, wide, high, 1, gdalconst.GDT_Float32)
    dst.SetGeoTransform( match_geotrans )
    dst.SetProjection( match_proj)

    # Do the work
    gdal.ReprojectImage(src, dst, src_proj, match_proj, gdalconst.GRA_Bilinear)
    print("Done")
    print("")


    # closing the images
    dst = None
    src = None

    ## run gdal 2 isce on this file so we can use ISCE functionality latter on
    #gdalisce2XML(apsfile_out)<jupyter_output><empty_output><jupyter_text>We will interpolate all the SAR delays:<jupyter_code>os.chdir(processing_dir)
file_transform('filt_topophase.unw.geo',os.path.join(gacos_dir,'20171117.ztd'),'20171117.ztd.geo')
file_transform('filt_topophase.unw.geo',os.path.join(gacos_dir,'20171111.ztd'),'20171111.ztd.geo')<jupyter_output><empty_output><jupyter_text>Let us visualize the zenith delays for both the master and slave acquisition. Typical tropospheric delays reach magnitudes up to 2.5 m. Are you expecting to see a lot of difference between both days?<jupyter_code>plotdata2('20171111.ztd.geo','20171117.ztd.geo',1,title=['Slave zenith delay [m]: 20171111','Master zenithdelay [m]: 20171117'],colormap='jet',datamin=1.7, datamax=2.4)<jupyter_output><empty_output><jupyter_text>3.3 Converting zenith tropopsheric delay to slant phase delay Next, we will project the zenith delay into the radar slant (radar look direction) by using a simple cosine mapping function of the incidence angle, and at the same time apply the scaling to convert from pseudo-range to phase $$\Phi_{\text{slant}}=\frac{-\lambda}{4 \pi* cos(\theta)}*d_{\text{zenith}}$$The **zenith2slant** function included below takes the geocoded zenith APS file as well as the LOS file as inputs and outputs an ENVI geo-coded slant delay file<jupyter_code>def zenith2slant(losfile,aps_zenith,aps_slant):
    
    # convert all to absolute paths
    aps_zenith = os.path.abspath(aps_zenith)
    aps_slant = os.path.abspath(aps_slant)
    losfile = os.path.abspath(losfile)
    
    # loading the zenith APS file
    ds = gdal.Open(aps_zenith, gdal.GA_ReadOnly)
    zenith = ds.GetRasterBand(1).ReadAsArray()
    proj = ds.GetProjection()
    geotrans = ds.GetGeoTransform()
    ds = None
    
    # loading the incidence angle file
    ds = gdal.Open(losfile, gdal.GA_ReadOnly)
    inc = ds.GetRasterBand(1).ReadAsArray()
    ds = None
    # convert the inc from deg to rad
    inc = inc*np.pi/180
    
    # scaling factor to convert pseudo-range [m] increase to phase delay [rad]
    scaling = -4*np.pi/5.6*100
    
    # projecting the zenith into the slant
    slant = scaling*zenith/np.cos(inc)
    
    # making sure the no-date is propagated
    slant[zenith==0]=0
    slant[inc==0]=0
        
    
    # writing out the file   
    drv = gdal.GetDriverByName('envi').Create(aps_slant, slant.shape[1], slant.shape[0], 1,gdal.GDT_Float32)
    drv.SetGeoTransform(geotrans)
    drv.SetProjection(proj)
    drv.GetRasterBand(1).WriteArray(slant)
    drv = None<jupyter_output><empty_output><jupyter_text>We will run this function for both SAR acquisitions and plot the results.<jupyter_code>zenith2slant('los.rdr.geo.vrt','20171117.ztd.geo','20171117.aps.geo')
zenith2slant('los.rdr.geo.vrt','20171111.ztd.geo','20171111.aps.geo')
plotdata2('20171111.aps.geo','20171117.aps.geo',1,title=['Slave slant phase delay [rad]: 20171111','Master slant phase delay [rad]: 20171117'],colormap='jet',datamin=-725, datamax=-525)<jupyter_output><empty_output><jupyter_text>4. InSAR Tropospheric phase delay (slant) Now that we have a tropospheric phase delay estimated for both SAR acquisitions, we can compute the differential delay. Note it is important to apply the same convention as you did when making the interferogram. Below we include the **differential_delay** function which takes a master and slave APS files as input as well as an output name.By investigating the orignal *topsApp.xml* file you can see that the master was selected as 20171117 and the slave as 20171111. $$\Delta \Phi_{\text{slant}}=\Phi_{\text{slant}}^{\text{master}}- \Phi_{\text{slant}}^{\text{slave}} $$<jupyter_code>def differential_delay(master_aps,slave_aps,outname):
    
    # convert all to absolute paths
    master_aps = os.path.abspath(master_aps)
    slave_aps = os.path.abspath(slave_aps)
    outname = os.path.abspath(outname)
    
    # loading the master APS file
    ds = gdal.Open(master_aps, gdal.GA_ReadOnly)
    master = ds.GetRasterBand(1).ReadAsArray()
    proj = ds.GetProjection()
    geotrans = ds.GetGeoTransform()
    ds = None
    
    # loading the slave APS file
    ds = gdal.Open(slave_aps, gdal.GA_ReadOnly)
    slave = ds.GetRasterBand(1).ReadAsArray()
    ds = None
    
    
    # computing the differential APS
    diffAPS = master-slave
    
    # writing out the file 
    drv = gdal.GetDriverByName('envi').Create(outname, diffAPS.shape[1], diffAPS.shape[0], 1,gdal.GDT_Float32)
    drv.SetGeoTransform(geotrans)
    drv.SetProjection(proj)
    drv.GetRasterBand(1).WriteArray(diffAPS)
    drv = None<jupyter_output><empty_output><jupyter_text>Below we will execute the **differential_delay** function, and plot the results. From the results you can see that even though the SAR delays looked quite similar there is spatial variation of up to 14 rad. Keeping in mind that 6.28 rad is equivalent to 2.8 cm, we find about 6.2 cm of delay for our intergerogram<jupyter_code>differential_delay('20171117.aps.geo','20171111.aps.geo','20171117_20171111.aps.geo')
plotdata('20171117_20171111.aps.geo',1,title="Differential phase delay (20171117-20171111) [rad] ",colormap='jet',colorbar_orientation="vertical",datamin=-6, datamax=8)<jupyter_output><empty_output><jupyter_text>5. Applying InSAR Tropospheric correction As last step we will correct our original interferogram for the estimated tropospheric phase delay. Below we provide the function to do the correction.<jupyter_code>def IFG_correction(unw,aps,outname):
    
    # convert all to absolute paths
    unw = os.path.abspath(unw)
    aps = os.path.abspath(aps)
    outname = os.path.abspath(outname)
    
    # loading the UNW file
    ds = gdal.Open(unw, gdal.GA_ReadOnly)
    unwdata_phase = ds.GetRasterBand(2).ReadAsArray()
    unwdata_amplitude = ds.GetRasterBand(1).ReadAsArray()
    proj = ds.GetProjection()
    geotrans = ds.GetGeoTransform()
    ds = None
    
    # loading the APS file
    ds = gdal.Open(aps, gdal.GA_ReadOnly)
    apsdata = ds.GetRasterBand(1).ReadAsArray()
    ds = None
    
    # Correcting the IFG
    unwdata_phase = unwdata_phase-apsdata
    # making sure the no-date is propagated
    unwdata_phase[unwdata_phase==0]=0
    unwdata_phase[apsdata==0]=0 
    
    
    # writing out the file 
    drv = gdal.GetDriverByName('envi').Create(outname, unwdata_phase.shape[1], unwdata_phase.shape[0], 2,gdal.GDT_Float32)
    drv.SetGeoTransform(geotrans)
    drv.SetProjection(proj)
    drv.GetRasterBand(1).WriteArray(unwdata_amplitude)
    drv.GetRasterBand(2).WriteArray(unwdata_phase)
    drv = None<jupyter_output><empty_output><jupyter_text>Using this function, we will now compute the correction and make a comparison plot before and after correction.<jupyter_code>IFG_correction('filt_topophase.unw.geo.vrt','20171117_20171111.aps.geo','filt_topophase_aps.unw.geo')
plotdata2('filt_topophase.unw.geo','filt_topophase_aps.unw.geo',2,title=["UNW before [rad]",'UNW after APS correction [rad]'],colormap='jet',datamin=-50, datamax=50,plot_profile='True')<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.09674414837612376, 'fraction_numerical': 0.02858994087632623, 'mean_word_length': 3.9095427435387675, 'pattern_counts': {'":': 0, '<': 78, '<?xml version=': 0, '>': 78, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 18, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '19', 'dir': 'jupyter-structured-clean-dedup', 'id': '413997', 'license': 'ECL-2.0', 'n_tokens_mistral': 8442, 'n_tokens_neox': 7778, 'n_words': 2351, 'path': 'docs/Notebooks/Atmosphere/Troposphere/Tropo.ipynb', 'repo_name': 'mohseniaref-InSAR/isce2', 'size': '24701'}