Module gplately.download
Functions for downloading assorted plate reconstruction data to use with GPlately's main objects. Files are stored in the user's cache and can be reused after being downloaded once.
These data have been created and used in plate reconstruction models and studies, and are available from public web servers (like EarthByte's webDAV server, or the GPlates 2.3 sample dataset library).
Expand source code
""" Functions for downloading assorted plate reconstruction data to use with GPlately's
main objects. Files are stored in the user's cache and can be reused after being
downloaded once. 
These data have been created and used in plate reconstruction models and studies, and
are available from public web servers (like EarthByte's webDAV server, or the GPlates 
2.3 sample dataset library).
"""
import pooch as _pooch
from pooch import os_cache as _os_cache
from pooch import retrieve as _retrieve
from pooch import utils as _utils
from pooch import HTTPDownloader as _HTTPDownloader
from pooch import Unzip as _Unzip
from pooch import Decompress as _Decompress
from matplotlib import image as _image
from .pygplates import RotationModel as _RotationModel
from .pygplates import FeatureCollection as _FeatureCollection
from gplately.data import DataCollection
import gplately as _gplately
import pygplates as _pygplates
import re as _re
import os as _os
import numpy as _np
import urllib.request as _request
import hashlib as _hashlib
import pathlib as _pathlib
import shutil as _shutil
import requests as _requests
def _test_internet_connection(url):
    """Test whether a connection to the required web server
    can be made given a `url`.
    
    Returns `False` the `url` is incorrect, and/or if there
    is no internet connection."""
    try:
        _request.urlopen(url) 
        return True
    except:
        return False
    
def _determine_processor(url):
    """Set instructions for how to process/unpack a file depending on
    its filetype. The unpacked file paths will have an .unzip, or 
    .decomp, or no file extension in their processed form."""
    archive_formats = tuple([".gz", ".xz", ".bz2"])
    if url.endswith(".zip"):
        processor=_Unzip()
        ext = ".unzip"
    elif url.endswith(archive_formats):
        processor=_Decompress()
        ext = ".decomp"
    else:
        processor = None
        ext = ""
    return processor, ext
def path_of_cached_file(url, model_name=None):
    """Determine the absolute path where the file(s) from `url` 
    will be downloaded to.
    Parameters
    ----------
    url : str
        The full download URL for the file passed as a string.
    model_name : str, default None
        An optional substring that ideally describes/labels the file.
        This will help name the file(s) when it is downloaded to the 
        gplately cache (this directory can be
        found using `gplately.download.path_to_cache()`). 
        """
    cached_filename = _pooch.utils.unique_file_name(url)
    cached_filename = _remove_hash(cached_filename)
    path = path_to_cache()
    processor_to_use, processor_extension = _determine_processor(url)
    # If the requested files need processing (i.e. zip, gz folders)
    if processor_extension:
        # Are they from plate models? These typically are the .zip folders for plate models
        if model_name:
            cached_filename  = str(path) + '/' + model_name + processor_extension+'/'
            unprocessed_path = str(path) + '/' + model_name
            #cached_filename = cached_filename = str(path) + '/' + model_name
        # If not from plate models but need processing, i.e. ETOPO1
        else:
            cached_filename = str(path) + '/' + "gplately_"+_parse_url_for_filenames(url) + processor_extension+'/'
            unprocessed_path = str(path) + '/' + "gplately_"+_parse_url_for_filenames(url)
            #cached_filename = "gplately_"+_parse_url_for_filenames(url) 
    # If the requested files do not need processing, like standalone .nc files:
    else:
        if model_name:
            cached_filename = str(path) + '/' + model_name + "_" + _parse_url_for_filenames(url)
            unprocessed_path = None
        else:
            cached_filename = str(path) + '/' + "gplately_"+_parse_url_for_filenames(url)
            unprocessed_path = None
      
    _pooch.utils.make_local_storage(path)
    full_path = path.resolve() / cached_filename
    return full_path, unprocessed_path
def _extract_processed_files(processed_directory):
    """Return a list of all full filenames from a given directory 
    in the GPlately cache.
    """
    if _os.path.isdir(processed_directory):
        fnames = []
        for root, dirs, files in _os.walk(processed_directory):
            for file in files:
                fnames.append(_os.path.join(root,file))
        return(fnames)
    elif _os.path.isfile(str(processed_directory)):
        return(processed_directory)
def path_to_cache():
    """Determine the absolute path to the system gplately cache. 
    """
    path = _pooch.utils.cache_location(
        _os_cache('gplately'), 
        env=None, 
        version=None
    )
    return path
def clear_cache():
    """Clear the `gplately` cache directory. 
    The absolute path of this directory can be found by running
    [gplately.download.path_to_cache()](file:///Users/laurenilano/gplately/api/gplately/download.html#gplately.download.path_to_cache).
    Caution - when called, all files in /path/to/caches/gplately will
    be deleted. This action cannot be undone.
    """
    cache_path = path_to_cache()
    _shutil.rmtree(str(cache_path))
    _pooch.utils.make_local_storage(str(cache_path))
    return
    
def _parse_url_for_filenames(url, return_hash=False):
    # Determine the filename of an E-Tag txt file
    md5 = _hashlib.md5(url.encode()).hexdigest()
    fname = _os.path.basename(_pooch.utils.parse_url(url)["path"])
    fname = fname[-(255 - len(md5) - 1) :]
    if return_hash:
        return str(fname), str(md5)
    else:
        return str(fname)
def _get_url_etag(url):
    """Obtain the E-Tag of a web server URL. 
    
    The E-Tag identifies a resource under a URL. If the resource
    is modified, a new E-Tag is generated. DataServer uses the
    E-Tag to determine whether local copies of plate model files
    available from a web server need to be updated to match the
    version on the web server.
    """
    # Determine E-Tag of the URL
    etag = str(_requests.head(url).headers.get("ETag"))
    # Determine the filename of an E-Tag txt file
    parsed_fname, filehash = _parse_url_for_filenames(url, return_hash=True)
    unique_name = filehash + "-ETAG.txt"
    cachepath = str(
        _pathlib.Path(
            _os.path.expanduser(str(_os_cache('gplately'))))
    )
    text_path = _os.path.join(cachepath, unique_name)
    return(etag, text_path)
    
    
def _save_url_etag_to_txt(etag, text_path):
    """Write an E-Tag to a text file.
    """       
    # Write E-Tag to a text file on the GPlately cache. 
    text_file = open(text_path, "w")
    text_file.write(etag)
    text_file.close()
    
def _match_url_to_extension(url):
    url = str(url)
    if url.endswith(".nc"):
        return ".nc"
    elif url.endswith(".jpg"):
        return ".jpg"
    elif url.endswith(".png"):
        return ".png"
    elif url.endswith(".tif"):
        return ".tif"
def _first_time_download_from_web(url, model_name=None, verbose=True):
    """
    # Provided a web connection to a server can be established,
    download the files from the URL into the GPlately cache.
    """
    
    if _test_internet_connection(url):
        if not verbose:
            logger = _pooch.get_logger()
            log_level = logger.level
            logger.setLevel("WARNING")
        # The filename pooch saves the requested file is derived from
        # one of four permutations:
        # 1. File is from a plate model and needs processing (i.e. zip --> unzip)
        # 2. File is from a plate model and does not need processing (i.e. .nc age grids)
        # 3. File is not from a plate model but needs processing (i.e. ETOPO, .grd.gz --> .decomp)
        # 4. File is not from a plate model and does not need processing
        processor_to_use, processor_extension = _determine_processor(url)
        # If the requested files need processing (i.e. zip, gz folders)
        if processor_extension:
            # Are they from plate models? These typically are the .zip folders for plate models
            if model_name:
                # Download the files with a naming structure like:
                # /path/to/cache/gplately/model_name+processor_extension
                used_fname = model_name
                fnames = _retrieve(
                        url=url,
                        known_hash=None,  
                        downloader=_HTTPDownloader(progressbar=verbose),
                        fname=used_fname,
                        path=_os_cache('gplately'),
                        processor=processor_to_use
                )
            # If not from plate models but need processing, i.e. ETOPO1
            else:
                # Download the files with a naming structure like:
                # /path/to/cache/gplately/file_name-as_inteded_in_url+processor_extension
                used_fname = "gplately_"+_parse_url_for_filenames(url)
                fnames = _retrieve(
                    url=url,
                    known_hash=None,  
                    downloader=_HTTPDownloader(progressbar=verbose),
                    fname=used_fname,
                    path=_os_cache('gplately'),
                    processor=processor_to_use
                )
        # If the requested files do not need processing, like standalone .nc files:
        else:
            # Are they from plate models? These typically are age or spreading rate grids
            if model_name:
                # Download the files with a naming structure like:
                # /path/to/cache/gplately/file_name-as_inteded_in_url+processor_extension
                used_fname = model_name+"_"+_parse_url_for_filenames(url)
                fnames = _retrieve(
                        url=url,
                        known_hash=None,  
                        downloader=_HTTPDownloader(progressbar=verbose),
                        fname=used_fname,
                        path=_os_cache('gplately'),
                        processor=processor_to_use
                )
            # If not from plate models and do not need processing,
            else:
                used_fname = "gplately_"+_parse_url_for_filenames(url)
                fnames = _retrieve(
                        url=url,
                        known_hash=None,  
                        downloader=_HTTPDownloader(progressbar=verbose),
                        fname=used_fname,
                        path=_os_cache('gplately'),
                        processor=processor_to_use
                )
        
        if not verbose:
            logger.setLevel(log_level)
        # Get the URL's E-Tag for the first time
        etag, textfilename = _get_url_etag(url)
        _save_url_etag_to_txt(etag, textfilename)
        return(fnames, etag, textfilename, used_fname)
    
def download_from_web(url, verbose=True, download_changes=True, model_name=None):
    """Download a file from a `url` into the `gplately` cache.
    
    Notes
    -----
    After the file belonging to the given `url` is downloaded 
    to the `gplately` cache once, subsequent runs of 
    `download_from_web` with this `url` will not redownload 
    the file as long as:
    
    * The file has not been updated on the web server,
    * The file has not been removed from the `gplately` cache.
    
    Instead, the file will be re-accessed from the `gplately` 
    cache it was downloaded to. 
    
    However, if the file has been updated on the web server,
    `download_from_web` overwrites the cached file with the 
    updated version. The following messages will be displayed 
    to the user:
    
        "Checking whether the requested files need to be updated..."
        "Yes - updating requested files..."
        "Requested files downloaded to the GPlately cache folder!"
    
    If ever a connection to the web server (and the file(s)) in 
    `url` is unsuccessful, this is likely because:
    * An internet connection could not be established; or
    * The `url` passed to `download_from_web` is incorrect
    In either case, `download_from_web` attempts to find a version 
    of the requested file(s) in `url` already stored in the 
    `gplately` cache (assuming it has been downloaded from the same 
    `url` once before). This version may not match the one on the web
    server. If a copy of the file(s) cannot be found in the `gplately`
    cache, a `ConnectionError` is raised.
    
    Parameters
    ----------
    url : str
        The full URL used to download a file from a public web server
        like webDAV.
    verbose : bool
        Choose whether to print user alerts regarding file availability,
        data server/internet connection status etc. 
    download_changes : bool, default=True
        Permit the re-downloading/update of the file from `url` if 
        it has been updated on the web server since the last download.
        
    Returns
    -------
    fnames : list of str
        A list of strings representing the full paths to all cached data
        downloaded from the given `url`.
    Raises
    ------
    ConnectionError
        If a connection to the web server and file(s) in the given `url` is
        unsuccessful (because there is no internet access, and/or the `url`
        is incorrect) and no version of the requested file(s) have been
        cached before. In this case, nothing is returned. 
    """
    #   NOTE: We need a way to verify the existence of requested file(s) in the gplately
    #   cache to determine whether a file needs to be installed, updated, or re-accessed 
    #   from the cache. Every time a file is installed for the first time,
    #   DataServer creates a directory called `full_path`. Its existence verifies the 
    #   existence
    #
    #   The nature of `full_path` is dependent on the file-type:
    #
    #   .zip files will be downloaded and expanded in an inside folder:
    #   
    #   /path/to/cache/gplately/fname.zip.unzip/
    #
    #   Thus, for zips, `full_path` is a directory that ends in ".zip.unzip":
    #
    #   For example: /Users/laurenilano/Library/Caches/gplately/Muller2019.zip.unzip/
    #   Other types of files that need processing, like .gz --> .decomp, aren't
    #   expanded in an internal folder. This is also the case for files that do not 
    #   need processing, e.g. ".nc" files. In these cases, `full_path` is the exact
    #   directory that the cached file is saved to.
    # 
    #
    #   For example: /Users/laurenilano/Library/Caches/gplately/Muller_etal_2019_Tectonics_v2.0_AgeGrid-100.nc
    #
    #   `full_path` is an empty directory for non-zips, and is the parent directory of
    #   unzipped contents in ".zip" URLs. 
    #
    #   Why do we need `full_path`?
    #   We search the top-level gplately cache directory for the `full_path` directory as it is
    #   installed with the requested files. Its existence verifies the
    #   existence of the requested file(s), and thus to decide whether to install the
    #   files or re-access existing cached versions. This also helps with E-Tag versioning
    #   in instances where the download URL remains the same but its contents may have changed
    #   since the file(s) were last cached. 
    
    full_path, unprocessed_path = path_of_cached_file(url, model_name)
    # If the file required processing (zips make a directory to unzip in, and .gz for example
    # makes a file just saved to the top-level directory), and the directory or file is not 
    # yet on the cache,
    if _determine_processor(url)[1] and not (
        _os.path.isdir(str(full_path)) or _os.path.isfile(str(full_path))
        ):
        # ...and if a connection to the web server can be established,
        # download files from the URL and create a textfile for this URL's E-Tag
        if _test_internet_connection(url):
            fnames, etag, textfilename, used_fname = _first_time_download_from_web(
                url, 
                model_name=model_name,
                verbose=verbose
            )
            if verbose:
                print("Requested files downloaded to the GPlately cache folder!")
            return(fnames)
    
        # ... if a connection to the web server cannot be established
        else:
            raise ConnectionError(
                    "A connection to {} could not be made. Please check your internet connection and/or ensure the URL is correct. No file from the given URL has been cached to {} yet - nothing has been returned.".format(url, full_path.parent))
    # If the file does not require processing, it did not open up a directory, so check isfile,
    # and if the file is not yet on the cache,
    elif not _determine_processor(url)[1] and not _os.path.isfile(str(full_path)):
        # ...and if a connection to the web server can be established,
        # download files from the URL and create a textfile for this URL's E-Tag
        if _test_internet_connection(url):
            fnames, etag, textfilename, used_fname = _first_time_download_from_web(
                url, 
                model_name=model_name,
                verbose=verbose
            )
            if verbose:
                print("Requested files downloaded to the GPlately cache folder!")
            return(fnames)
    
        # ... if a connection to the web server cannot be established
        else:
            raise ConnectionError(
                    "A connection to {} could not be made. Please check your internet connection and/or ensure the URL is correct. No file from the given URL has been cached to {} yet - nothing has been returned.".format(url, full_path.parent))
    # If the files have been downloaded before...
    else:
        #... and if a connection to the web server can be made...
        if _test_internet_connection(url):
            
            _, local_etag_txtfile = _get_url_etag(url)
            # If the newest version of the files in `url` must be cached 
            # at all times, perform E-Tag comparisons:
            if download_changes:
                # Walk through the top-level cache directory to find an E-Tag textfile unique to the URL
                etag_exists = False
                cache_path = str(path_to_cache())
                if _os.path.isfile(local_etag_txtfile):
                    etag_exists = True
                # If an e-tag text file does not exist, erase the cached files
                # and download the latest version from the web server. This, in turn,
                # creates an e-tag textfile for this version.
                if not etag_exists:
                    if _os.path.isdir(full_path):
                        _shutil.rmtree(str(full_path))
                    elif _os.path.isfile(full_path):
                        _os.remove(full_path)
                    if unprocessed_path:
                        if _os.path.isdir(unprocessed_path):
                            _shutil.rmtree(str(unprocessed_path))
                        elif _os.path.isfile(unprocessed_path):
                            _os.remove(unprocessed_path)
                    fnames, etag, local_etag_txtfile, used_fname = _first_time_download_from_web(
                        url, 
                        model_name=model_name,
                        verbose=verbose
                    )
                    return(fnames)
                # If the e-tag textfile exists for the local files,
                else: 
                    if verbose:
                        print("Checking whether the requested files need to be updated...")
                    # Determine the local file's URL e-tag from the textfile
                    with open(local_etag_txtfile) as f:
                        local_etag = str(f.readlines()[0])
                    # Get the e-tag of the web server URL at current time
                    remote_etag, remote_etag_textfile = _get_url_etag(url)
                    # If the local and remote e-tags are unequal, the web-server URL 
                    # contains an updated version of the cached files.
                    if str(remote_etag) != str(local_etag):
                        if verbose:
                            print("Yes - updating requested files...")
                        # Update the e-tag textfile with this newly-identified URL e-tag
                        _save_url_etag_to_txt(remote_etag, local_etag_txtfile)
                        # Delete existing version of the files...
                        # If it didn't need processing, i.e. 'unzipping', just delete as-is
                        if _os.path.isdir(full_path):
                            _shutil.rmtree(str(full_path))
                        elif _os.path.isfile(full_path):
                            _os.remove(full_path)
                            
                        # If it's the kind of file that needs processing, delete the 
                        # unprocessed version so we can re-download it
                        if unprocessed_path:
                            if _os.path.isdir(unprocessed_path):
                                _shutil.rmtree(str(unprocessed_path))
                            elif _os.path.isfile(unprocessed_path):
                                _os.remove(unprocessed_path)
                        # Treat as if downloading the file(s) from the URL for the first time
                        fnames, etag, local_etag_txtfile, used_fname = _first_time_download_from_web(
                            url, 
                            model_name=model_name,
                            verbose=verbose
                        )
                        if verbose:
                            print("Updated requested files downloaded to the GPlately cache folder!")
                        return(fnames)
                    # If the e-tags are equal, the local and remote files are the same.
                    # Just return the file(s) as-is.
                    else:
                        if verbose:
                            print("Requested files are up-to-date!")
                        # If files were processed once, return the processed files.
                        if _determine_processor(url):
                            if str(full_path).endswith(_determine_processor(url)[1]):
                                return(_extract_processed_files((str(full_path))))
                            else:
                                return(_extract_processed_files(
                                    str(full_path)+_determine_processor(url)[1]))
                        # If not, return as-is.
                        else:
                            return(_extract_processed_files(
                                str(full_path)+_match_url_to_extension(url)))
            # If file versioning doesn't matter, just keep returning the cached files.
            else:
                fnames, etag, local_etag_txtfile = _first_time_download_from_web(url, model_name)
                return(fnames)
                
        # If a connection to the web server could not be made, and the files exist in
        # the GPlately cache, just return the files as-is.
        else:
            print("No connection to {} established. The requested file(s) (potentially older versions) exist in the GPlately cache ({}) and have been returned.".format(url, full_path.parent))
            #print(str(full_path)+_determine_processor(url)[1])
            return(_extract_processed_files(
                    str(full_path)))
            # This created zip.unzip.unzip, so i deleted it but not sure if this will affect other files. 
            # return(_extract_processed_files(str(full_path)+_determine_processor(url)[1]))
def _collect_file_extension(fnames, file_extension):
    """Searches cached directory for filenames with a specified extension(s)."""
    sorted_fnames = []
    file_extension=tuple(file_extension)
    for file in fnames:
        if file.endswith(file_extension):
            sorted_fnames.append(file)
    return sorted_fnames
def _str_in_folder(fnames, strings_to_include=None, strings_to_ignore=None):
    fnames_to_ignore = []
    fnames_to_include = []
    sorted_fnames = []
    for i, fname in enumerate(fnames):
        parent_directory = _os.path.dirname(fname)
        if strings_to_ignore is not None:
            for s in strings_to_ignore:
                if s in parent_directory:
                    fnames_to_ignore.append(fname)
            sorted_fnames = list(set(fnames) - set(fnames_to_ignore))
    if strings_to_include is not None:
        for fname in sorted_fnames:
            parent_directory = _os.path.dirname(fname)
            for s in strings_to_include:
                if s in parent_directory:
                    fnames_to_include.append(fname)
        sorted_fnames = list(set(sorted_fnames).intersection(set(fnames_to_include)))
    return sorted_fnames
def _str_in_filename(fnames, strings_to_include=None, strings_to_ignore=None, file_collection=None, file_collection_sensitive=False):
    out = []
    def filter_func(fname):
        basename = _os.path.basename(fname)
        keep = False
        if strings_to_include is None:
            keep = True
        else:
            # If a file collection was passed to the string to include, there is at least one file specific to
            # this model that must be included. Such a file should be presented in the respective
            # strings_to_include list in data.py with format:
            
            #    "file_collection string_to_include"
            # That is, a whitespace must be placed between the file collection and the string to include.
            # The file collection must be identical to the string allocated to the key. 
            # For example, strings_to_include = ["Muller2022 1000_0_rotfile_Merdith_et_al_optimised.rot"]
            # In this example, "Muller2022" and the strings_to_include list from data.py are passed to this function
            # when sorting through rotation files. 
            # The list is looped through - if the current string has "Muller2022" (case insensitive) in it, 
            # we will only pass through the filename following "Muller2022", i.e. the optmised plate model.
            # All other rotation files bundled in the webDAV zip (including the published Merdith et al. 2021 rot files) 
            # are excluded from the filter. 
            # If no strings in the list include the passed file collection, we have one of two options, depending on whether
            # file_collection_sensitive is True or False. 
            # If it is set to True, that means that we should only treat strings_to_include as True if and only if the
            #  passed file collection was found in the strings_to_include list. Otherwise, we have to treat strings_to_include
            # as if it was NoneType, and therefore place no filter for the files we accept through (that is, accept all files).
            # If it is set to False, that means that we should treat strings_to_include as True always, irrespective of
            # whether the passed file collection was found in the strings_to_include list. An example is the static polygon
            # filetype - this relies on strings_to_include being True no matter what.
            # For example, Merdith2021, Muller2019 would have file_collection_sensitive = False because these
            # models currently don't have any files that MUST be excluded for their own instance, but MUST 
            # be included for other model instances. 
            # Conversely, Muller2022 would have file_collection_sensitive = True because it requires all published Merdith2021
            # rot models to be ignored (in favour of the optimised model). However, we do not want to ignore Merdith2021 rot
            # models when we are using DataServer to collect Merdith2021 files.
            if file_collection is not None:
                # If the file collection is in the provided list of strings to include...
                strings_with_file_collection = [s for s in strings_to_include if file_collection.lower() in s.lower()]
                if strings_with_file_collection:
                    # Include the string, and break out.
                    for s in strings_with_file_collection:
                        if s.split(" ")[-1].lower() in basename.lower():
                            keep = True
                            break
                
                # If there is a file collection passed, but none of the strings to include include the file collection,
                else:
                    # If we no longer require strings_to_include, treat as if strings_to_include is False, and just pass
                    # all files through.
                    if file_collection_sensitive is True:
                        keep = True
                    # If we still need strings_to_include, treat as if strings_to_include is True, and pass only required
                    # files through.
                    else:
                        for s in strings_to_include:
                            if s.lower() in basename.lower():
                                keep = True
                                break
                    
             
            # If a file collection is not passed, but strings_to_include exists, only pass through those requested.       
            else:
                for s in strings_to_include:
                    if s.lower() in basename.lower():
                        keep = True
                        break
        if strings_to_ignore is not None:
            for s in strings_to_ignore:
                if s.lower() in basename.lower():
                    keep = False
                    break
        return keep
    return list(filter(filter_func, fnames))
def _check_gpml_or_shp(fnames):
    """For topology features, returns GPML by default. Searches for ESRI Shapefiles 
    instead if GPML files not found."""
    sorted_fnames = []
    for file in fnames:
        if file.endswith(".gpml") or file.endswith(".gpmlz"):
            sorted_fnames.append(file)
        elif file.endswith(".shp"):
            sorted_fnames.append(file)
    return sorted_fnames
def _remove_hash(fname):
    """Removes hashes (32 character file IDs) from cached filenames."""
    split_paths = fname.split("-")
    cache_path = split_paths[0][:-32]
    new_path = cache_path + "-".join(split_paths[1:])
    return new_path
def _order_filenames_by_time(fnames):
    """Orders filenames in a list from present day to deeper geological time if they
    are labelled by time."""
    # Collect all digits in each filename.
    filepath_digits=[]
    for i, file in enumerate(fnames):
        digits = []
        for element in _re.split('([0-9]+)', _remove_hash(file)):
            if element.isdigit():
                digits.append(int(str(element)))
        filepath_digits.append(digits)
    # Ignore digits common to all full file paths. This leaves behind the files' 
    # geological time label.
    geological_times = []
    filepath_digits = _np.array(filepath_digits).T
    for digit_array in filepath_digits:
        if not all(digit == digit_array[0] for digit in digit_array):
            geological_times.append(digit_array)
    # If files have geological time labels, allocate indices to the current filename order, 
    # and sort files from recent to deep geological time.
    if geological_times:
        sorted_geological_times = sorted(
            enumerate(geological_times[0]), 
            key=lambda x: x[1]
        )
        sorted_geological_time_indices = [geo_time[0] for geo_time in sorted_geological_times]
        filenames_sorted = [fnames[index] for index in sorted_geological_time_indices]
    else:
        # If given filenames do not have a time label, return them as is.
        filenames_sorted = fnames
    return filenames_sorted
def _collection_sorter(fnames, string_identifier):
    """If multiple file collections or plate reconstruction models are downloaded from
    a single zip folder, only return the needed model. 
    The plate models that need separating are listed."""
    needs_sorting = [
        "merdith2021",
        "scotese2008",
        "golonka2007",
        "clennett2020",
        "johansson2018",
        "whittaker2015"
    ]
    if string_identifier.lower() in needs_sorting:
        studyname = _re.findall(r'[A-Za-z]+|\d+', string_identifier)[0]
        newfnames = []
        for files in fnames:
            if studyname not in files:
                continue
            newfnames.append(files)
        return newfnames
    else:
        return fnames
def _match_filetype_to_extension(filetype):
    extensions = []
    if filetype == "netCDF":
        extensions.append(".nc")
    elif filetype == "jpeg":
        extensions.append(".jpg")
    elif filetype == "png":
        extensions.append(".png")
    elif filetype == "TIFF":
        extensions.append(".tif")
    return extensions
def get_raster(raster_id_string=None, verbose=True):
    """Downloads assorted raster data that are not associated with the plate 
    reconstruction models supported by GPlately's `DataServer`. Stores rasters in the 
    "gplately" cache.
    Currently, gplately supports the following rasters and images:
    * __[ETOPO1](https://www.ngdc.noaa.gov/mgg/global/)__: 
        * Filetypes available : TIF, netCDF (GRD)
        * `raster_id_string` = `"ETOPO1_grd"`, `"ETOPO1_tif"` (depending on the requested format)
        * A 1-arc minute global relief model combining lang topography and ocean bathymetry.
        * Citation: doi:10.7289/V5C8276M
    Parameters
    ----------
    raster_id_string : str, default=None
        A string to identify which raster to download.
    Returns
    -------
    a gplately.Raster object
        A gplately.Raster object containing the raster data. The gridded data can be extracted 
        into a numpy ndarray or MaskedArray by appending `.data` to the variable assigned to `get_raster()`.
        For example:
            graster = gplately.download.get_raster(raster_id_string, verbose)
            graster_data = graster.data
        where `graster_data` is a numpy ndarray. This array can be visualised using 
        `matplotlib.pyplot.imshow` on a `cartopy.mpl.GeoAxis` GeoAxesSubplot 
        (see example below).
    Raises
    ------
    ValueError
        * if a `raster_id_string` is not supplied.
    Notes
    -----
    Rasters obtained by this method are (so far) only reconstructed to present-day. 
    Examples
    --------
    To download ETOPO1 and plot it on a Mollweide projection:
        import gplately
        import numpy as np
        import matplotlib.pyplot as plt
        import cartopy.crs as ccrs
        etopo1 = gplately.download.get_raster("ETOPO1_tif")
        etopo1_data = etopo1.data
        fig = plt.figure(figsize=(18,14), dpi=300)
        ax = fig.add_subplot(111, projection=ccrs.Mollweide(central_longitude = -150))
        etopo1.imshow(ax)
    """
    from matplotlib import image
    if raster_id_string is None:
        raise ValueError(
            "Please specify which raster to download."
        )
    #filetype = "."+"_".split(raster_id_string)[-1]
    archive_formats = tuple([".gz", ".xz", ".bz2"])
    grid_extensions = tuple([".grd", ".nc"])
    # Set to true if we find the given collection in database
    found_collection = False
    raster_filenames = []
    database = _gplately.data._rasters()
    for collection, zip_url in database.items():
        # Isolate the raster name and the file type
        #raster_name = collection.split("_")[0]
        #raster_type = "."+collection.split("_")[-1]
        if (raster_id_string.lower() == collection.lower()):
            raster_filenames = download_from_web(zip_url[0], verbose)
            found_collection = True
            break
    if found_collection is False:
        raise ValueError("{} not in collection database.".format(raster_id_string))
    else:
        # If the downloaded raster is a grid, process it with the gplately.Raster object
        if any(grid_extension in raster_filenames for grid_extension in grid_extensions):
            raster = _gplately.grids.Raster(data=raster_filenames)
        # Otherwise, the raster is an image; use imread to process
        else:
            raster_matrix = image.imread(raster_filenames)
            raster = _gplately.grids.Raster(data=raster_matrix)
        if raster_id_string.lower() == "etopo1_tif":
            raster.lats = raster.lats[::-1]
        if raster_id_string.lower() == "etopo1_grd":
            raster._data = raster._data.astype(float)
    return raster
def get_feature_data(feature_data_id_string=None, verbose=True):
    """Downloads assorted geological feature data from web servers (i.e. 
    [GPlates 2.3 sample data](https://www.earthbyte.org/gplates-2-3-software-and-data-sets/))
    into the "gplately" cache.
    Currently, gplately supports the following feature data:
    --------------
    | **Feature data string identifier** | **Description**                                                                                                                                                                              |
    |------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
    | Johansson2018                      | Large igneous provinces from  Johansson et al. (2018)                                                                                                                                        |
    | Whittaker2015                      | Large igneous province products  interpreted as plume products  from Whittaker et al. (2015).                                                                                                |
    | SeafloorFabric                     | Seafloor tectonic fabric  (fracture zones, discordant zones,  V-shaped structures, unclassified  V-anomalies, propagating ridge  lineations and extinct ridges)  from Matthews et al. (2011) |
    | Hotspots                           | Present day surface hotspot/plume  locations from Whittaker et al. (2013)                                                                                                                    |
   
    ---------------
    Detailed descriptions can be found below:
    * __Large igneous provinces from Johansson et al. (2018)__
        Information
        -----------
        * Formats: .gpmlz
        * `feature_data_id_string` = `Johansson2018`
        Citations
        ---------
        * Johansson, L., Zahirovic, S., and Müller, R. D., In Prep, The 
        interplay between the eruption and weathering of Large Igneous Provinces and 
        the deep-time carbon cycle: Geophysical Research Letters.
    - __Large igneous province products interpreted as plume products from Whittaker 
    et al. (2015)__.
        Information
        -----------
        * Formats: .gpmlz, .shp
        * `feature_data_id_string` = `Whittaker2015`
        
        Citations
        ---------
        * Whittaker, J. M., Afonso, J. C., Masterton, S., Müller, R. D., 
        Wessel, P., Williams, S. E., & Seton, M. (2015). Long-term interaction between 
        mid-ocean ridges and mantle plumes. Nature Geoscience, 8(6), 479-483. 
        doi:10.1038/ngeo2437.
    - __Seafloor tectonic fabric (fracture zones, discordant zones, V-shaped structures, 
    unclassified V-anomalies, propagating ridge lineations and extinct ridges) from 
    Matthews et al. (2011)__
        Information
        -----------
        * Formats: .gpml
        * `feature_data_id_string` = `SeafloorFabric`
        Citations
        ---------
        * Matthews, K.J., Müller, R.D., Wessel, P. and Whittaker, J.M., 2011. The 
        tectonic fabric of the ocean basins. Journal of Geophysical Research, 116(B12): 
        B12109, DOI: 10.1029/2011JB008413. 
    - __Present day surface hotspot/plume locations from Whittaker et al. (2013)__
        Information
        -----------
        * Formats: .gpmlz
        * `feature_data_id_string` = `Hotspots`
        Citation
        --------
        * Whittaker, J., Afonso, J., Masterton, S., Müller, R., Wessel, P., 
        Williams, S., and Seton, M., 2015, Long-term interaction between mid-ocean ridges and 
        mantle plumes: Nature Geoscience, v. 8, no. 6, p. 479-483, doi:10.1038/ngeo2437.
    
    Parameters
    ----------
    feature_data_id_string : str, default=None
        A string to identify which feature data to download to the cache (see list of supported
        feature data above).
    Returns
    -------
    feature_data_filenames : instance of <pygplates.FeatureCollection>, or list of instance <pygplates.FeatureCollection>
        If a single set of feature data is downloaded, a single pyGPlates `FeatureCollection` 
        object is returned. Otherwise, a list containing multiple pyGPlates `FeatureCollection` 
        objects is returned (like for `SeafloorFabric`). In the latter case, feature reconstruction 
        and plotting may have to be done iteratively.
    Raises
    ------
    ValueError
        If a `feature_data_id_string` is not provided.
    Examples
    --------
    For examples of plotting data downloaded with `get_feature_data`, see GPlately's sample 
    notebook 05 - Working With Feature Geometries [here](https://github.com/GPlates/gplately/blob/master/Notebooks/05-WorkingWithFeatureGeometries.ipynb).
    """
    if feature_data_id_string is None:
        raise ValueError(
            "Please specify which feature data to fetch."
        )
    database = _gplately.data._feature_data()
    found_collection = False
    for collection, zip_url in database.items():
        if feature_data_id_string.lower() == collection.lower():
            found_collection = True
            feature_data_filenames = _collection_sorter(
                _collect_file_extension(
                download_from_web(zip_url[0], verbose), [".gpml", ".gpmlz"]
                ),
                collection
            )
            break
    if found_collection is False:
        raise ValueError("{} are not in GPlately's DataServer.".format(feature_data_id_string))
    feat_data = _FeatureCollection()
    if len(feature_data_filenames) == 1:
            feat_data.add(_FeatureCollection(feature_data_filenames[0]))
            return feat_data
    else:    
        feat_data=[]
        for file in feature_data_filenames:
            feat_data.append(_FeatureCollection(file))
        return feat_data
class DataServer(object):
    """Uses [Pooch](https://www.fatiando.org/pooch/latest/) to download plate reconstruction 
    feature data from plate models and other studies that are stored on web servers 
    (e.g. EarthByte's [webDAV server](https://www.earthbyte.org/webdav/ftp/Data_Collections/)). 
    
    If the `DataServer` object and its methods are called for the first time, i.e. by:
        # string identifier to access the Muller et al. 2019 model
        gDownload = gplately.download.DataServer("Muller2019")
    all requested files are downloaded into the user's 'gplately' cache folder only _once_. If the same
    object and method(s) are re-run, the files will be re-accessed from the cache provided they have not been 
    moved or deleted. 
    Currently, `DataServer` supports a number of plate reconstruction models. 
    ------------------
    | **Model name string Identifier** | **Rot. files** | **Topology features** | **Static polygons** | **Coast-lines** | **Cont-inents** | **COB-** | **Age grids** | **SR grids** |
    |:--------------------------------:|:--------------:|:---------------------:|:-------------------:|:---------------:|:---------------:|:--------:|:-------------:|:------------:|
    |            Muller2019            |        ✅       |           ✅           |          ✅          |        ✅        |        ✅        |     ✅    |       ✅       |       ❌      |
    |            Muller2016            |        ✅       |           ✅           |          ✅          |        ✅        |        ❌        |     ❌    |       ✅       |       ❌      |
    |            Merdith2021           |        ✅       |           ✅           |          ✅          |        ✅        |        ✅        |     ❌    |       ❌       |       ❌      |
    |              Cao2020             |        ✅       |           ✅           |          ✅          |        ✅        |        ✅        |     ❌    |       ❌       |       ❌      |
    |           Clennett2020           |        ✅       |           ✅           |          ✅          |        ✅        |        ✅        |     ❌    |       ✅       |       ✅      |
    |             Seton2012            |        ✅       |           ✅           |          ❌          |        ✅        |        ❌        |     ✅    |       ✅       |       ❌      |
    |           Matthews2016           |        ✅       |           ✅           |          ✅          |        ✅        |        ✅        |     ❌    |       ❌       |       ❌      |
    |            Merdith2017           |        ✅       |           ✅           |          ❌          |        ❌        |        ❌        |     ❌    |       ❌       |       ❌      |
    |              Li2008              |        ✅       |           ✅           |          ❌          |        ❌        |        ❌        |     ❌    |       ❌       |       ❌      |
    |           Pehrsson2015           |        ✅       |           ✅           |          ❌          |        ❌        |        ❌        |     ❌    |       ❌       |       ❌      |
    |         TorsvikCocks2017         |        ✅       |           ❌           |          ❌          |        ✅        |        ❌        |     ❌    |       ❌       |       ❌      |
    |             Young2019            |        ✅       |           ✅           |          ✅          |        ✅        |        ✅        |     ❌    |       ❌       |       ❌      |
    |            Scotese2008           |        ✅       |           ✅           |          ❌          |        ❌        |        ✅        |     ❌    |       ❌       |       ❌      |
    |         Clennett2020_M19         |        ✅       |           ✅           |          ❌          |        ✅        |        ✅        |     ❌    |       ❌       |       ❌      |
    |         Clennett2020_S13         |        ✅       |           ✅           |          ❌          |        ✅        |        ✅        |     ❌    |       ❌       |       ❌      |
    |            Muller2008            |        ✅       |           ❌           |          ✅          |        ❌        |        ❌        |     ❌    |       ❌       |       ❌      |
    |            Muller2022            |        ✅       |           ✅           |          ✅          |        ✅        |        ✅        |     ✅    |       ❌       |       ❌      |
    |            Scotese2016           |        ✅       |           ❌           |          ✅          |        ✅        |        ❌        |     ❌    |       ❌       |       ❌      |
    |           Shephard2013           |        ✅       |           ✅           |          ✅          |        ✅        |        ❌        |     ❌    |       ❌       |       ❌      |
    ------------------
    To call the object, supply a model name string Identifier, `file_collection`, from one of the following models:
    * __[Müller et al. 2019](https://www.earthbyte.org/muller-et-al-2019-deforming-plate-reconstruction-and-seafloor-age-grids-tectonics/):__ 
        file_collection = `Muller2019`
    
        Information
        -----------
        * Downloadable files: a `rotation_model`, `topology_features`, `static_polygons`, `coastlines`, `continents`, `COBs`, and
        seafloor `age_grids` from 0 to 250 Ma. 
        * Maximum reconstruction time: 250 Ma
        Citations
        ---------
        Müller, R. D., Zahirovic, S., Williams, S. E., Cannon, J., Seton, M., 
        Bower, D. J., Tetley, M. G., Heine, C., Le Breton, E., Liu, S., Russell, S. H. J., 
        Yang, T., Leonard, J., and Gurnis, M. (2019), A global plate model including 
        lithospheric deformation along major rifts and orogens since the Triassic. 
        Tectonics, vol. 38, https://doi.org/10.1029/2018TC005462.
            
    * __Müller et al. 2016__:
        file_collection = `Muller2016`
        Information
        -----------
        * Downloadable files: a `rotation_model`, `topology_features`, `static_polygons`, `coastlines`, and
        seafloor `age_grids` from 0-230 Ma. 
        * Maximum reconstruction time: 230 Ma
        Citations
        ---------
        * Müller R.D., Seton, M., Zahirovic, S., Williams, S.E., Matthews, K.J.,
        Wright, N.M., Shephard, G.E., Maloney, K.T., Barnett-Moore, N., Hosseinpour, M., 
        Bower, D.J., Cannon, J., InPress. Ocean basin evolution and global-scale plate 
        reorganization events since Pangea breakup, Annual Review of Earth and Planetary 
        Sciences, Vol 44, 107-138. DOI: 10.1146/annurev-earth-060115-012211.
    * __[Merdith et al. 2021](https://zenodo.org/record/4485738#.Yhrm8hNBzA0)__: 
        file_collection = `Merdith2021`
        Information
        -----------
        * Downloadable files: a `rotation_model`, `topology_features`, `static_polygons`, `coastlines`
        and `continents`.
        * Maximum reconstruction time: 1 Ga (however, `PlotTopologies` correctly visualises up to 410 Ma) 
        Citations: 
        ----------
        * Merdith et al. (in review), 'A continuous, kinematic full-plate motion model
        from 1 Ga to present'. 
        * Andrew Merdith. (2020). Plate model for 'Extending Full-Plate Tectonic Models 
        into Deep Time: Linking the Neoproterozoic and the Phanerozoic ' (1.1b) [Data set]. 
        Zenodo. https://doi.org/10.5281/zenodo.4485738
    * __Cao et al. 2020__: 
        file_collection = `Cao2020`
        Information
        -----------
        * Downloadable files: `rotation_model`, `topology_features`, `static_polygons`, `coastlines`
        and `continents`.
        * Maximum reconstruction time: 1 Ga
        Citations
        ---------
        * Toy Billion-year reconstructions from Cao et al (2020). 
        Coupled Evolution of Plate Tectonics and Basal Mantle Structure Tectonics, 
        doi: 10.1029/2020GC009244
    - __Clennett et al. 2020__ : 
        file_collection = `Clennett2020`
        
        Information
        -----------
        * Downloadable files: `rotation_model`, `topology_features`, `static_polygons`, `coastlines`
        and `continents`
        * Maximum reconstruction time: 170 Ma
        Citations
        ---------
        * Mather, B., Müller, R.D.,; Alfonso, C.P., Seton, M., 2021, Kimberlite eruption 
        driven by slab flux and subduction angle. DOI: 10.5281/zenodo.5769002
    - __Seton et al. 2012__:
        file_collection = `Seton2012`
        Information
        -----------
        * Downloadable files: `rotation_model`, `topology_features`, `coastlines`,
        `COBs`, and paleo-age grids (0-200 Ma)
        * Maximum reconstruction time: 200 Ma
        Citations
        ---------
        * M. Seton, R.D. Müller, S. Zahirovic, C. Gaina, T.H. Torsvik, G. Shephard, A. Talsma, 
        M. Gurnis, M. Turner, S. Maus, M. Chandler, Global continental and ocean basin reconstructions 
        since 200 Ma, Earth-Science Reviews, Volume 113, Issues 3-4, July 2012, Pages 212-270, 
        ISSN 0012-8252, 10.1016/j.earscirev.2012.03.002.
    - __Matthews et al. 2016__: 
        file_collection = `Matthews2016`
        Information
        -----------
        * Downloadable files: `rotation_model`, `topology_features`, `static_polygons`, `coastlines`,
        and `continents`
        * Maximum reconstruction time(s): 410-250 Ma, 250-0 Ma
        Citations
        ---------
        * Matthews, K.J., Maloney, K.T., Zahirovic, S., Williams, S.E., Seton, M.,
        and Müller, R.D. (2016). Global plate boundary evolution and kinematics since the 
        late Paleozoic, Global and Planetary Change, 146, 226-250. 
        DOI: 10.1016/j.gloplacha.2016.10.002
    - __Merdith et al. 2017__: 
        file_collection = `Merdith2017`
        Information
        -----------
        * Downloadable files: `rotation_files` and `topology_features`
        * Maximum reconstruction time: 410 Ma
        Citations
        ---------
        * Merdith, A., Collins, A., Williams, S., Pisarevskiy, S., Foden, J., Archibald, D. 
        and Blades, M. et al. 2016. A full-plate global reconstruction of the Neoproterozoic. 
        Gondwana Research. 50: pp. 84-134. DOI: 10.1016/j.gr.2017.04.001
    - __Li et al. 2008__: 
        file_collection = `Li2008`
        Information
        -----------
        * Downloadable files: `rotation_model` and `static_polygons`
        * Maximum reconstruction time: 410 Ma
        Citations
        ---------
        * Rodinia reconstruction from Li et al (2008), Assembly, configuration, and break-up 
        history of Rodinia: A synthesis. Precambrian Research. 160. 179-210. 
        DOI: 10.1016/j.precamres.2007.04.021.
    - __Pehrsson et al. 2015__: 
        file_collection = `Pehrsson2015`
        Information
        -----------
        * Downloadable files: `rotation_model` and `static_polygons`
        * Maximum reconstruction time: N/A
        Citations
        ---------
        * Pehrsson, S.J., Eglington, B.M., Evans, D.A.D., Huston, D., and Reddy, S.M., (2015),
        Metallogeny and its link to orogenic style during the Nuna supercontinent cycle. Geological 
        Society, London, Special Publications, 424, 83-94. DOI: https://doi.org/10.1144/SP424.5
    - __Torsvik and Cocks et al. 2017__: 
        file_collection = `TorsvikCocks2017`
        Information
        -----------
        * Downloadable files: `rotation_model`, and `coastlines`
        * Maximum reconstruction time: 410 Ma
        Citations
        ---------
        * Torsvik, T., & Cocks, L. (2016). Earth History and Palaeogeography. Cambridge: 
        Cambridge University Press. doi:10.1017/9781316225523
    - __Young et al. 2019__: 
        file_collection = `Young2019`
        Information
        -----------
        * Downloadable files: `rotation_model`, `topology_features`, `static_polygons`, `coastlines`
        and `continents`.
        * Maximum reconstruction time: 410-250 Ma, 250-0 Ma
        
        Citations
        ---------
        * Young, A., Flament, N., Maloney, K., Williams, S., Matthews, K., Zahirovic, S.,
        Müller, R.D., (2019), Global kinematics of tectonic plates and subduction zones since the late 
        Paleozoic Era, Geoscience Frontiers, Volume 10, Issue 3, pp. 989-1013, ISSN 1674-9871,
        DOI: https://doi.org/10.1016/j.gsf.2018.05.011.
    - __Scotese et al. 2008__: 
        file_collection = `Scotese2008`
        Information
        -----------
        * Downloadable files: `rotation_model`, `static_polygons`, and `continents`
        * Maximum reconstruction time: 
        
        Citations
        ---------
        * Scotese, C.R. 2008. The PALEOMAP Project PaleoAtlas for ArcGIS, Volume 2, Cretaceous 
        paleogeographic and plate tectonic reconstructions. PALEOMAP Project, Arlington, Texas.
    - __Golonka et al. 2007__: 
        file_collection = `Golonka2007`
        Information
        -----------
        * Downloadable files: `rotation_model`, `static_polygons`, and `continents`
        * Maximum reconstruction time: 410 Ma
        
        Citations
        ---------
        * Golonka, J. 2007. Late Triassic and Early Jurassic palaeogeography of the world. 
        Palaeogeography, Palaeoclimatology, Palaeoecology 244(1–4), 297–307.
    - __Clennett et al. 2020 (based on Müller et al. 2019)__: 
        file_collection = `Clennett2020_M2019`
        Information
        -----------
        * Downloadable files: `rotation_model`, `topology_features`, `continents` and `coastlines`
        * Maximum reconstruction time: 170 Ma
        
        Citations
        ---------
        * Clennett, E.J., Sigloch, K., Mihalynuk, M.G., Seton, M., Henderson, M.A., Hosseini, K.,
        Mohammadzaheri, A., Johnston, S.T., Müller, R.D., (2020), A Quantitative Tomotectonic Plate 
        Reconstruction of Western North America and the Eastern Pacific Basin. Geochemistry, Geophysics, 
        Geosystems, 21, e2020GC009117. DOI: https://doi.org/10.1029/2020GC009117
    - __Clennett et al. 2020 (rigid topological model based on Shephard et al, 2013)__: 
        file_collection = `Clennett2020_S2013`
        Information
        -----------
        * Downloadable files: `rotation_model`, `topology_features`, `continents` and `coastlines`
        * Maximum reconstruction time: 170
        
        Citations
        ---------
        * Clennett, E.J., Sigloch, K., Mihalynuk, M.G., Seton, M., Henderson, M.A., Hosseini, K.,
        Mohammadzaheri, A., Johnston, S.T., Müller, R.D., (2020), A Quantitative Tomotectonic Plate 
        Reconstruction of Western North America and the Eastern Pacific Basin. Geochemistry, Geophysics, 
        Geosystems, 21, e2020GC009117. DOI: https://doi.org/10.1029/2020GC009117
    - __Müller et al. 2008__:
        file_collection = `Muller2008`
        Information
        -----------
        * Downloadable files:  `rotation_model`, `static_polygons`
        * Maximum reconstruction time: 141 Ma
        Citations
        ---------
        * Müller, R. D., Sdrolias, M., Gaina, C., & Roest, W. R. (2008). Age, spreading rates, and 
        spreading asymmetry of the world's ocean crust. Geochemistry, Geophysics, Geosystems, 9(4).
    - __Müller et al. 2022__:
        file_collection = `Muller2022`
        Information
        -----------
        * Downloadable files:  `rotation_model`, `topology_features`, `static_polygons`, `continents`, `coastlines` and `COBs`
        * Maximum reconstruction time: 1000 Ma
        Citations
        ---------
        *  Müller, R. D., Flament, N., Cannon, J., Tetley, M. G., Williams, S. E., Cao, X., Bodur, Ö. F., Zahirovic, S., 
        and Merdith, A.: A tectonic-rules-based mantle reference frame since 1 billion years ago – implications for 
        supercontinent cycles and plate–mantle system evolution, Solid Earth, 13, 1127–1159, 
        https://doi.org/10.5194/se-13-1127-2022, 2022.
    - __Scotese 2016__:
        file_collection = `Scotese2016`
        Information
        -----------
        * Downloadable files:  `rotation_model`, `static_polygons`, `coastlines` 
        * Maximum reconstruction time: 410 Ma
        Citations
        ---------
        * Scotese, C.R., 2016. PALEOMAP PaleoAtlas for GPlates and the PaleoData 
        Plotter Program, PALEOMAP Project, 
        http://www.earthbyte.org/paleomappaleoatlas-for-gplates/
    - __Shephard et al. 2013__:
        file_collection = `Shephard2013`
        Information
        -----------
        * Downloadable files:  `rotation_model`, `topology_features`, `static_polygons`, `coastlines`
        * Maximum reconstruction time: 200 Ma
        Citations
        ---------
        * Shephard, G.E., Müller, R.D., and Seton, M., 2013. The tectonic evolution of the Arctic since 
        Pangea breakup: Integrating constraints from surface geology and geophysics with mantle structure. 
        Earth-Science Reviews, Volume 124 p.148-183. doi:10.1016/j.earscirev.2013.05.012 
        (http://www.sciencedirect.com/science/article/pii/S0012825213001104)
        * M. Seton, R.D. Müller, S. Zahirovic, C. Gaina, T.H. Torsvik, G. Shephard, A. Talsma, M. Gurnis, 
        M. Turner, S. Maus, M. Chandler, Global continental and ocean basin reconstructions since 200 Ma, 
        Earth-Science Reviews, Volume 113, p.212-270 doi:10.1016/j.earscirev.2012.03.002.
        (http://www.sciencedirect.com/science/article/pii/S0012825212000311)
        Parameters
        ----------
        file_collection : str
            name of file collection to use
        verbose : bool, default True
            Toggle print messages regarding server/internet connection status, file availability etc.
    """
    def __init__(self, file_collection, verbose=True):
        self.file_collection = file_collection.capitalize()
        self.data_collection = DataCollection(self.file_collection)
        if str(type(verbose)) == "<class 'bool'>":
            self.verbose = verbose
        else:
            raise ValueError("The verbose toggle must be of Boolean type, not {}".format(type(verbose)))
    def get_plate_reconstruction_files(self):
        """Downloads and constructs a `rotation model`, a set of `topology_features` and
        and a set of `static_polygons` needed to call the `PlateReconstruction` object.
        Returns
        -------
        rotation_model : instance of <pygplates.RotationModel>
            A rotation model to query equivalent and/or relative topological plate rotations
            from a time in the past relative to another time in the past or to present day.
        topology_features : instance of <pygplates.FeatureCollection>
            Point, polyline and/or polygon feature data that are reconstructable through 
            geological time.
        static_polygons : instance of <pygplates.FeatureCollection>
            Present-day polygons whose shapes do not change through geological time. They are
            used to cookie-cut dynamic polygons into identifiable topological plates (assigned 
            an ID) according to their present-day locations.
        Notes
        -----
        This method accesses the plate reconstruction model ascribed to the `file_collection` string passed 
        into the `DataServer` object. For example, if the object was called with `"Muller2019"`:
            gDownload = gplately.download.DataServer("Muller2019")
            rotation_model, topology_features, static_polygons = gDownload.get_plate_reconstruction_files()
        the method will download a `rotation_model`, `topology_features` and `static_polygons` from the 
        Müller et al. (2019) plate reconstruction model. Once the reconstruction objects are returned, 
        they can be passed into:
            model = gplately.reconstruction.PlateReconstruction(rotation_model, topology_features, static_polygons)
        * Note: If the requested plate model does not have a certain file(s), a message will be printed 
        to alert the user. For example, using `get_plate_reconstruction_files()`
        for the Torsvik and Cocks (2017) plate reconstruction model yields the printed message:
                No topology features in TorsvikCocks2017. No FeatureCollection created - unable to 
                plot trenches, ridges and transforms.
                No continent-ocean boundaries in TorsvikCocks2017.
        """
        verbose = self.verbose
        rotation_filenames = []
        rotation_model = []
        topology_filenames = []
        topology_features = _FeatureCollection()
        static_polygons= _FeatureCollection()
        static_polygon_filenames = []
        # Locate all plate reconstruction files from GPlately's DataCollection
        database = DataCollection.plate_reconstruction_files(self)
        # Set to true if we find the given collection in our database
        found_collection = False
        for collection, url in database.items():
            # Only continue if the user's chosen collection exists in our database
            if self.file_collection.lower() == collection.lower():
                found_collection = True
                if len(url) == 1:
                    fnames = _collection_sorter(
                        download_from_web(url[0], verbose, model_name=self.file_collection), self.file_collection
                    )
                    rotation_filenames = _collect_file_extension(
                        _str_in_folder(
                            _str_in_filename(fnames,
                                strings_to_include=DataCollection.rotation_strings_to_include(self),
                                strings_to_ignore=DataCollection.rotation_strings_to_ignore(self),
                                file_collection=self.file_collection,
                                file_collection_sensitive=True
                            ),
                        strings_to_ignore=DataCollection.rotation_strings_to_ignore(self)
                        ),
                        [".rot"]
                    )
                    #print(rotation_filenames)
                    rotation_model = _RotationModel(rotation_filenames)
                    topology_filenames = _collect_file_extension(
                        _str_in_folder(
                            _str_in_filename(fnames, 
                                strings_to_include=DataCollection.dynamic_polygon_strings_to_include(self),
                                strings_to_ignore=DataCollection.dynamic_polygon_strings_to_ignore(self),
                                file_collection=self.file_collection,
                                file_collection_sensitive=False,
                            ), 
                            strings_to_ignore=DataCollection.dynamic_polygon_strings_to_ignore(self)
                        ),
                        [".gpml", ".gpmlz"]
                    )
                    #print(topology_filenames)
                    for file in topology_filenames:
                        topology_features.add(_FeatureCollection(file))
                    static_polygon_filenames = _check_gpml_or_shp(
                        _str_in_folder(
                            _str_in_filename(fnames, 
                                strings_to_include=DataCollection.static_polygon_strings_to_include(self),
                                strings_to_ignore=DataCollection.static_polygon_strings_to_ignore(self),
                                file_collection=self.file_collection,
                                file_collection_sensitive=False
                            ),
                            strings_to_ignore=DataCollection.static_polygon_strings_to_ignore(self)
                        )
                    )
                    #print(static_polygon_filenames)
                    for stat in static_polygon_filenames:
                        static_polygons.add(_FeatureCollection(stat))
                else:
                    for file in url[0]:
                        rotation_filenames.append(_collect_file_extension(download_from_web(file, verbose, model_name=self.file_collection), [".rot"]))
                        rotation_model = _RotationModel(rotation_filenames)
                    for file in url[1]:
                        topology_filenames.append(_collect_file_extension(download_from_web(file, verbose, model_name=self.file_collection), [".gpml"]))
                        for file in topology_filenames:
                            topology_features.add(_FeatureCollection(file))
                    for file in url[2]:
                        static_polygon_filenames.append(
                            _check_gpml_or_shp(
                                _str_in_folder(
                                    _str_in_filename(download_from_web(url[0], verbose, model_name=self.file_collection), 
                                        strings_to_include=DataCollection.static_polygon_strings_to_include(self)
                                    ),    
                                        strings_to_ignore=DataCollection.static_polygon_strings_to_ignore(self)
                                )
                            )   
                        )
                        for stat in static_polygon_filenames:
                            static_polygons.add(_FeatureCollection(stat))
                break
        if found_collection is False:
            raise ValueError("{} is not in GPlately's DataServer.".format(self.file_collection))
        if not rotation_filenames:
            print("No .rot files in {}. No rotation model created.".format(self.file_collection))
            rotation_model = []
        if not topology_filenames:
            print("No topology features in {}. No FeatureCollection created - unable to plot trenches, ridges and transforms.".format(self.file_collection))
            topology_features = []
        if not static_polygons:
            print("No static polygons in {}.".format(self.file_collection))
            static_polygons = []
        # add identifier for setting up DownloadServer independently
        rotation_model.reconstruction_identifier = self.file_collection
        return rotation_model, topology_features, static_polygons
    def get_topology_geometries(self):
        """Uses Pooch to download coastline, continent and COB (continent-ocean boundary)
        Shapely geometries from the requested plate model. These are needed to call the `PlotTopologies`
        object and visualise topological plates through time.
        Parameters
        ----------
        verbose : bool, default True
            Toggle print messages regarding server/internet connection status, file availability etc.
        Returns
        -------
        coastlines : instance of <pygplates.FeatureCollection>
            Present-day global coastline Shapely polylines cookie-cut using static polygons. Ready for
            reconstruction to a particular geological time and for plotting.
        continents : instance of <pygplates.FeatureCollection>
            Cookie-cutting Shapely polygons for non-oceanic regions (continents, inta-oceanic arcs, etc.)
            ready for reconstruction to a particular geological time and for plotting.
        COBs : instance of <pygplates.FeatureCollection>
            Shapely polylines resolved from .shp and/or .gpml topology files that represent the 
            locations of the boundaries between oceanic and continental crust.
            Ready for reconstruction to a particular geological time and for plotting.
        Notes
        -----
        This method accesses the plate reconstruction model ascribed to the `file_collection` 
        string passed into the `DataServer` object. For example, if the object was called with
        `"Muller2019"`:
            gDownload = gplately.download.DataServer("Muller2019")
            coastlines, continents, COBs = gDownload.get_topology_geometries()
        the method will attempt to download `coastlines`, `continents` and `COBs` from the Müller
        et al. (2019) plate reconstruction model. If found, these files are returned as individual 
        pyGPlates Feature Collections. They can be passed into:
            gPlot = gplately.plot.PlotTopologies(gplately.reconstruction.PlateReconstruction, time, continents, coastlines, COBs)
        to reconstruct features to a certain geological time. The `PlotTopologies`
        object provides simple methods to plot these geometries along with trenches, ridges and 
        transforms (see documentation for more info). Note that the `PlateReconstruction` object 
        is a parameter.
        * Note: If the requested plate model does not have a certain geometry, a
        message will be printed to alert the user. For example, if `get_topology_geometries()` 
        is used with the `"Matthews2016"` plate model, the workflow will print the following 
        message: 
                No continent-ocean boundaries in Matthews2016.
        """
        verbose = self.verbose
        # Locate all topology geometries from GPlately's DataCollection
        database = DataCollection.topology_geometries(self)
        coastlines = []
        continents = []
        COBs = []
        
        # Find the requested plate model data collection
        found_collection = False
        for collection, url in database.items():
            if self.file_collection.lower() == collection.lower():
                found_collection = True
                if len(url) == 1:
                    # Some plate models do not have reconstructable geometries i.e. Li et al. 2008
                    if url[0] is None:
                        break
                    else:
                        fnames = _collection_sorter(
                            download_from_web(url[0], verbose, model_name=self.file_collection), self.file_collection
                        )
                        coastlines = _check_gpml_or_shp(
                            _str_in_folder(
                                _str_in_filename(
                                    fnames,
                                    strings_to_include=DataCollection.coastline_strings_to_include(self),
                                    strings_to_ignore=DataCollection.coastline_strings_to_ignore(self),
                                    file_collection=self.file_collection,
                                    file_collection_sensitive=False
                                ), 
                                strings_to_ignore=DataCollection.coastline_strings_to_ignore(self)
                            )
                        )
                        continents = _check_gpml_or_shp(
                            _str_in_folder(
                                _str_in_filename(
                                    fnames, 
                                    strings_to_include=DataCollection.continent_strings_to_include(self),
                                    strings_to_ignore=DataCollection.continent_strings_to_ignore(self),
                                    file_collection=self.file_collection,
                                    file_collection_sensitive=False
                                ), 
                                strings_to_ignore=DataCollection.continent_strings_to_ignore(self)
                            )
                        )
                        COBs = _check_gpml_or_shp(
                            _str_in_folder(
                                _str_in_filename(
                                    fnames,
                                    strings_to_include=DataCollection.COB_strings_to_include(self),
                                    strings_to_ignore=DataCollection.COB_strings_to_ignore(self),
                                    file_collection=self.file_collection,
                                    file_collection_sensitive=False
                                ), 
                                strings_to_ignore=DataCollection.COB_strings_to_ignore(self)
                            )
                        )
                else:
                    for file in url[0]:
                        if url[0] is not None:
                            coastlines.append(_str_in_filename(
                                download_from_web(file, verbose, model_name=self.file_collection), 
                                strings_to_include=["coastline"])
                            )
                            coastlines = _check_gpml_or_shp(coastlines)
                        else:
                            coastlines = []
                    for file in url[1]:
                        if url[1] is not None:
                            continents.append(_str_in_filename(
                                download_from_web(file, verbose, model_name=self.file_collection), 
                                strings_to_include=["continent"])
                            )
                            continents = _check_gpml_or_shp(continents)
                        else:
                            continents = []
                    for file in url[2]:
                        if url[2] is not None:
                            COBs.append(_str_in_filename(
                                download_from_web(file, verbose, model_name=self.file_collection), 
                                strings_to_include=["cob"])
                            )
                            COBs = _check_gpml_or_shp(COBs)
                        else:
                            COBs = []
                break
        if found_collection is False:
            raise ValueError("{} is not in GPlately's DataServer.".format(self.file_collection))
        if not coastlines:
            print("No coastlines in {}.".format(self.file_collection))
            coastlines_featurecollection = []
        else:
            #print(coastlines)
            coastlines_featurecollection = _FeatureCollection()
            for coastline in coastlines:
                coastlines_featurecollection.add(_FeatureCollection(coastline))
        
        if not continents:
            print("No continents in {}.".format(self.file_collection))
            continents_featurecollection = []
        else:
            #print(continents)
            continents_featurecollection = _FeatureCollection()
            for continent in continents:
                continents_featurecollection.add(_FeatureCollection(continent))
        
        if not COBs:
            print("No continent-ocean boundaries in {}.".format(self.file_collection))
            COBs_featurecollection = []
        else:
            #print(COBs)
            COBs_featurecollection = _FeatureCollection()
            for COB in COBs:
                COBs_featurecollection.add(_FeatureCollection(COB))
        
        geometries = coastlines_featurecollection, continents_featurecollection, COBs_featurecollection
        return geometries
    def get_age_grid(self, time):
        """Downloads seafloor and paleo-age grids from the plate reconstruction model (`file_collection`)
        passed into the `DataServer` object. Stores grids in the "gplately" cache.
        Currently, `DataServer` supports the following age grids:
        * __Muller et al. 2019__
            * `file_collection` = `Muller2019`
            * Time range: 0-250 Ma
            * Seafloor age grid rasters in netCDF format.
        * __Muller et al. 2016__
            
            * `file_collection` = `Muller2016`
            * Time range: 0-240 Ma
            * Seafloor age grid rasters in netCDF format. 
        * __Seton et al. 2012__
            * `file_collection` = `Seton2012`
            * Time range: 0-200 Ma
            * Paleo-age grid rasters in netCDF format.
        
        Parameters
        ----------
        time : int, or list of int, default=None
            Request an age grid from one (an integer) or multiple reconstruction times (a
            list of integers).
        Returns
        -------
        a gplately.Raster object
            A gplately.Raster object containing the age grid. The age grid data can be extracted 
            into a numpy ndarray or MaskedArray by appending `.data` to the variable assigned to 
            `get_age_grid()`.
            For example:
                gdownload = gplately.DataServer("Muller2019")
                graster = gdownload.get_age_grid(time=100)
                graster_data = graster.data
            where `graster_data` is a numpy ndarray.
        Raises
        -----
        ValueError
            If `time` (a single integer, or a list of integers representing reconstruction
            times to extract the age grids from) is not passed.
        Notes
        -----
        The first time that `get_age_grid` is called for a specific time(s), the age grid(s) 
        will be downloaded into the GPlately cache once. Upon successive calls of `get_age_grid`
        for the same reconstruction time(s), the age grids will not be re-downloaded; rather, 
        they are re-accessed from the same cache provided the age grid(s) have not been moved or deleted. 
        Examples
        --------
        if the `DataServer` object was called with the `Muller2019` `file_collection` string:
            gDownload = gplately.download.DataServer("Muller2019")
        `get_age_grid` will download seafloor age grids from the Müller et al. (2019) plate 
        reconstruction model for the geological time(s) requested in the `time` parameter. 
        If found, these age grids are returned as masked arrays. 
        For example, to download  Müller et al. (2019) seafloor age grids for 0Ma, 1Ma and
        100 Ma:
            age_grids = gDownload.get_age_grid([0, 1, 100])
            
        """
        age_grids = []
        age_grid_links = DataCollection.netcdf4_age_grids(self, time)
        if not isinstance(time, list):
            time = [time]
        # For a single time passed that isn't in the valid time range, 
        if not age_grid_links:
            raise ValueError(
                "{} {}Ma age grids are not on GPlately's DataServer.".format(
                    self.file_collection, 
                    time[0]
                )
            )
        # For a list of times passed...
        for i, link in enumerate(age_grid_links):
            if not link:
                raise ValueError(
                    "{} {}Ma age grids are not on GPlately's DataServer.".format(
                        self.file_collection,
                        time[i]
                    )
                )
            age_grid_file = download_from_web(
                link, 
                verbose=self.verbose, 
                model_name=self.file_collection
            )
            age_grid = _gplately.grids.Raster(data=age_grid_file)
            age_grids.append(age_grid)
        # One last check to alert user if the masked array grids were not processed properly
        if not age_grids:
            raise ValueError("{} netCDF4 age grids not found.".format(self.file_collection))
        if len(age_grids) == 1:
            return age_grids[0]
        else: 
            return age_grids
    def get_spreading_rate_grid(self, time):
        """Downloads seafloor spreading rate grids from the plate reconstruction 
        model (`file_collection`) passed into the `DataServer` object. Stores 
        grids in the "gplately" cache.
        Currently, `DataServer` supports spreading rate grids from the following plate
        models:
        * __Clennett et al. 2020__
            * `file_collection` = `Clennett2020`
            * Time range: 0-250 Ma
            * Seafloor spreading rate grids in netCDF format.
        
        Parameters
        ----------
        time : int, or list of int, default=None
            Request a spreading grid from one (an integer) or multiple reconstruction 
            times (a list of integers).
        Returns
        -------
        a gplately.Raster object
            A gplately.Raster object containing the spreading rate grid. The spreading 
            rate grid data can be extracted into a numpy ndarray or MaskedArray by 
            appending `.data` to the variable assigned to `get_spreading_rate_grid()`.
            For example:
                gdownload = gplately.DataServer("Clennett2020")
                graster = gdownload.get_spreading_rate_grid(time=100)
                graster_data = graster.data
            where `graster_data` is a numpy ndarray.
        Raises
        -----
        ValueError
            If `time` (a single integer, or a list of integers representing reconstruction
            times to extract the spreading rate grids from) is not passed.
        Notes
        -----
        The first time that `get_spreading_rate_grid` is called for a specific time(s), 
        the spreading rate grid(s) will be downloaded into the GPlately cache once. 
        Upon successive calls of `get_spreading_rate_grid` for the same reconstruction 
        time(s), the grids will not be re-downloaded; rather, they are re-accessed from 
        the same cache location provided they have not been moved or deleted. 
        Examples
        --------
        if the `DataServer` object was called with the `Clennett2020` `file_collection` string:
            gDownload = gplately.download.DataServer("Clennett2020")
        `get_spreading_rate_grid` will download seafloor spreading rate grids from the 
        Clennett et al. (2020) plate reconstruction model for the geological time(s) 
        requested in the `time` parameter. When found, these spreading rate grids are 
        returned as masked arrays. 
        For example, to download Clennett et al. (2020) seafloor spreading rate grids for 
        0Ma, 1Ma and 100 Ma as MaskedArray objects:
            spreading_rate_grids = gDownload.get_spreading_rate_grid([0, 1, 100])
            
        """
        spreading_rate_grids = []
        spreading_rate_grid_links = DataCollection.netcdf4_spreading_rate_grids(self, time)
        if not isinstance(time, list):
            time = [time]
        # For a single time passed that isn't in the valid time range, 
        if not spreading_rate_grid_links:
            raise ValueError(
                "{} {}Ma spreading rate grids are not on GPlately's DataServer.".format(
                    self.file_collection,
                    time[0]
                )
            )
        # For a list of times passed...
        for i, link in enumerate(spreading_rate_grid_links):
            if not link:
                raise ValueError(
                    "{} {}Ma spreading rate grids are not on GPlately's DataServer.".format(
                        self.file_collection,
                        time[i]
                    )
                )
            spreading_rate_grid_file = download_from_web(
                link, 
                verbose=self.verbose, 
                model_name=self.file_collection
            )
            spreading_rate_grid = _gplately.grids.Raster(data=spreading_rate_grid_file)
            spreading_rate_grids.append(spreading_rate_grid)
        # One last check to alert user if the masked array grids were not processed properly
        if not spreading_rate_grids:
            raise ValueError("{} netCDF4 seafloor spreading rate grids not found.".format(self.file_collection))
        if len(spreading_rate_grids) == 1:
            return spreading_rate_grids[0]
        else: 
            return spreading_rate_grids
    def get_valid_times(self):
        """Returns a tuple of the valid plate model time range, (min_time, max_time).
        """
        all_model_valid_times = DataCollection.plate_model_valid_reconstruction_times(self)
        min_time = None
        max_time = None
        for plate_model_name, valid_times in list(all_model_valid_times.items()):
            if plate_model_name.lower() == self.file_collection.lower():
                min_time = valid_times[0]
                max_time = valid_times[1]
        if not min_time and not max_time:
            raise ValueError("Could not find the valid reconstruction time of {}".format(self.file_collection))
        return (min_time, max_time)
    def get_raster(self, raster_id_string=None):
        """Downloads assorted raster data that are not associated with the plate 
        reconstruction models supported by GPlately's `DataServer`. Stores rasters in the 
        "gplately" cache.
        Currently, `DataServer` supports the following rasters and images:
        * __[ETOPO1](https://www.ngdc.noaa.gov/mgg/global/)__: 
            * Filetypes available : TIF, netCDF (GRD)
            * `raster_id_string` = `"ETOPO1_grd"`, `"ETOPO1_tif"` (depending on the requested format)
            * A 1-arc minute global relief model combining lang topography and ocean bathymetry.
            * Citation: doi:10.7289/V5C8276M
        Parameters
        ----------
        raster_id_string : str, default=None
            A string to identify which raster to download.
        Returns
        -------
        a gplately.Raster object
            A gplately.Raster object containing the raster data. The gridded data can be extracted 
            into a numpy ndarray or MaskedArray by appending `.data` to the variable assigned to `get_raster()`.
            For example:
                gdownload = gplately.DataServer("Muller2019")
                graster = gdownload.get_raster(raster_id_string, verbose)
                graster_data = graster.data
            where `graster_data` is a numpy ndarray. This array can be visualised using 
            `matplotlib.pyplot.imshow` on a `cartopy.mpl.GeoAxis` GeoAxesSubplot 
            (see example below).
        Raises
        ------
        ValueError
            * if a `raster_id_string` is not supplied.
        Notes
        -----
        Rasters obtained by this method are (so far) only reconstructed to present-day. 
        Examples
        --------
        To download ETOPO1 and plot it on a Mollweide projection:
            import gplately
            import numpy as np
            import matplotlib.pyplot as plt
            import cartopy.crs as ccrs
            gdownload = gplately.DataServer("Muller2019")
            etopo1 = gdownload.get_raster("ETOPO1_tif")
            fig = plt.figure(figsize=(18,14), dpi=300)
            ax = fig.add_subplot(111, projection=ccrs.Mollweide(central_longitude = -150))
            ax2.imshow(etopo1, extent=[-180,180,-90,90], transform=ccrs.PlateCarree()) 
        """
        return get_raster(raster_id_string, self.verbose)
    def get_feature_data(self, feature_data_id_string=None):
        """Downloads assorted geological feature data from web servers (i.e. 
        [GPlates 2.3 sample data](https://www.earthbyte.org/gplates-2-3-software-and-data-sets/))
        into the "gplately" cache.
        Currently, `DataServer` supports the following feature data:
        * __Large igneous provinces from Johansson et al. (2018)__
            Information
            -----------
            * Formats: .gpmlz
            * `feature_data_id_string` = `Johansson2018`
            Citations
            ---------
            * Johansson, L., Zahirovic, S., and Müller, R. D., In Prep, The 
            interplay between the eruption and weathering of Large Igneous Provinces and 
            the deep-time carbon cycle: Geophysical Research Letters.
        - __Large igneous province products interpreted as plume products from Whittaker 
        et al. (2015)__.
            Information
            -----------
            * Formats: .gpmlz, .shp
            * `feature_data_id_string` = `Whittaker2015`
            
            Citations
            ---------
            * Whittaker, J. M., Afonso, J. C., Masterton, S., Müller, R. D., 
            Wessel, P., Williams, S. E., & Seton, M. (2015). Long-term interaction between 
            mid-ocean ridges and mantle plumes. Nature Geoscience, 8(6), 479-483. 
            doi:10.1038/ngeo2437.
        - __Seafloor tectonic fabric (fracture zones, discordant zones, V-shaped structures, 
        unclassified V-anomalies, propagating ridge lineations and extinct ridges) from 
        Matthews et al. (2011)__
            Information
            -----------
            * Formats: .gpml
            * `feature_data_id_string` = `SeafloorFabric`
            Citations
            ---------
            * Matthews, K.J., Müller, R.D., Wessel, P. and Whittaker, J.M., 2011. The 
            tectonic fabric of the ocean basins. Journal of Geophysical Research, 116(B12): 
            B12109, DOI: 10.1029/2011JB008413. 
        - __Present day surface hotspot/plume locations from Whittaker et al. (2013)__
            Information
            -----------
            * Formats: .gpmlz
            * `feature_data_id_string` = `Hotspots`
            Citation
            --------
            * Whittaker, J., Afonso, J., Masterton, S., Müller, R., Wessel, P., 
            Williams, S., and Seton, M., 2015, Long-term interaction between mid-ocean ridges and 
            mantle plumes: Nature Geoscience, v. 8, no. 6, p. 479-483, doi:10.1038/ngeo2437.
        
        Parameters
        ----------
        feature_data_id_string : str, default=None
            A string to identify which feature data to download to the cache (see list of supported
            feature data above).
        Returns
        -------
        feature_data_filenames : instance of <pygplates.FeatureCollection>, or list of instance <pygplates.FeatureCollection>
            If a single set of feature data is downloaded, a single pyGPlates `FeatureCollection` 
            object is returned. Otherwise, a list containing multiple pyGPlates `FeatureCollection` 
            objects is returned (like for `SeafloorFabric`). In the latter case, feature reconstruction 
            and plotting may have to be done iteratively.
        Raises
        ------
        ValueError
            If a `feature_data_id_string` is not provided.
        Examples
        --------
        For examples of plotting data downloaded with `get_feature_data`, see GPlately's sample 
        notebook 05 - Working With Feature Geometries [here](https://github.com/GPlates/gplately/blob/master/Notebooks/05-WorkingWithFeatureGeometries.ipynb).
        """
        if feature_data_id_string is None:
            raise ValueError(
                "Please specify which feature data to fetch."
            )
        database = _gplately.data._feature_data()
        found_collection = False
        for collection, zip_url in database.items():
            if feature_data_id_string.lower() == collection.lower():
                found_collection = True
                feature_data_filenames = _collection_sorter(
                    _collect_file_extension(
                    download_from_web(zip_url[0], self.verbose), [".gpml", ".gpmlz"]
                    ),
                    collection
                )
                break
        if found_collection is False:
            raise ValueError("{} are not in GPlately's DataServer.".format(feature_data_id_string))
        feat_data = _FeatureCollection()
        if len(feature_data_filenames) == 1:
                feat_data.add(_FeatureCollection(feature_data_filenames[0]))
                return feat_data
        else:    
            feat_data=[]
            for file in feature_data_filenames:
                feat_data.append(_FeatureCollection(file))
            return feat_data
    Functions
- def clear_cache()
- 
Clear the gplatelycache directory.The absolute path of this directory can be found by running gplately.download.path_to_cache(). Caution - when called, all files in /path/to/caches/gplately will be deleted. This action cannot be undone. Expand source codedef clear_cache(): """Clear the `gplately` cache directory. The absolute path of this directory can be found by running [gplately.download.path_to_cache()](file:///Users/laurenilano/gplately/api/gplately/download.html#gplately.download.path_to_cache). Caution - when called, all files in /path/to/caches/gplately will be deleted. This action cannot be undone. """ cache_path = path_to_cache() _shutil.rmtree(str(cache_path)) _pooch.utils.make_local_storage(str(cache_path)) return
- def download_from_web(url, verbose=True, download_changes=True, model_name=None)
- 
Download a file from a urlinto thegplatelycache.NotesAfter the file belonging to the given urlis downloaded to thegplatelycache once, subsequent runs ofdownload_from_web()with thisurlwill not redownload the file as long as:- The file has not been updated on the web server,
- The file has not been removed from the gplatelycache.
 Instead, the file will be re-accessed from the gplatelycache it was downloaded to.However, if the file has been updated on the web server, download_from_web()overwrites the cached file with the updated version. The following messages will be displayed to the user:"Checking whether the requested files need to be updated..." "Yes - updating requested files..." "Requested files downloaded to the GPlately cache folder!"If ever a connection to the web server (and the file(s)) in urlis unsuccessful, this is likely because:- An internet connection could not be established; or
- The urlpassed todownload_from_web()is incorrect
 In either case, download_from_web()attempts to find a version of the requested file(s) inurlalready stored in thegplatelycache (assuming it has been downloaded from the sameurlonce before). This version may not match the one on the web server. If a copy of the file(s) cannot be found in thegplatelycache, aConnectionErroris raised.Parameters- url:- str
- The full URL used to download a file from a public web server like webDAV.
- verbose:- bool
- Choose whether to print user alerts regarding file availability, data server/internet connection status etc.
- download_changes:- bool, default=- True
- Permit the re-downloading/update of the file from urlif it has been updated on the web server since the last download.
 Returns- fnames:- listof- str
- A list of strings representing the full paths to all cached data
downloaded from the given url.
 Raises- ConnectionError
- If a connection to the web server and file(s) in the given urlis unsuccessful (because there is no internet access, and/or theurlis incorrect) and no version of the requested file(s) have been cached before. In this case, nothing is returned.
 Expand source codedef download_from_web(url, verbose=True, download_changes=True, model_name=None): """Download a file from a `url` into the `gplately` cache. Notes ----- After the file belonging to the given `url` is downloaded to the `gplately` cache once, subsequent runs of `download_from_web` with this `url` will not redownload the file as long as: * The file has not been updated on the web server, * The file has not been removed from the `gplately` cache. Instead, the file will be re-accessed from the `gplately` cache it was downloaded to. However, if the file has been updated on the web server, `download_from_web` overwrites the cached file with the updated version. The following messages will be displayed to the user: "Checking whether the requested files need to be updated..." "Yes - updating requested files..." "Requested files downloaded to the GPlately cache folder!" If ever a connection to the web server (and the file(s)) in `url` is unsuccessful, this is likely because: * An internet connection could not be established; or * The `url` passed to `download_from_web` is incorrect In either case, `download_from_web` attempts to find a version of the requested file(s) in `url` already stored in the `gplately` cache (assuming it has been downloaded from the same `url` once before). This version may not match the one on the web server. If a copy of the file(s) cannot be found in the `gplately` cache, a `ConnectionError` is raised. Parameters ---------- url : str The full URL used to download a file from a public web server like webDAV. verbose : bool Choose whether to print user alerts regarding file availability, data server/internet connection status etc. download_changes : bool, default=True Permit the re-downloading/update of the file from `url` if it has been updated on the web server since the last download. Returns ------- fnames : list of str A list of strings representing the full paths to all cached data downloaded from the given `url`. Raises ------ ConnectionError If a connection to the web server and file(s) in the given `url` is unsuccessful (because there is no internet access, and/or the `url` is incorrect) and no version of the requested file(s) have been cached before. In this case, nothing is returned. """ # NOTE: We need a way to verify the existence of requested file(s) in the gplately # cache to determine whether a file needs to be installed, updated, or re-accessed # from the cache. Every time a file is installed for the first time, # DataServer creates a directory called `full_path`. Its existence verifies the # existence # # The nature of `full_path` is dependent on the file-type: # # .zip files will be downloaded and expanded in an inside folder: # # /path/to/cache/gplately/fname.zip.unzip/ # # Thus, for zips, `full_path` is a directory that ends in ".zip.unzip": # # For example: /Users/laurenilano/Library/Caches/gplately/Muller2019.zip.unzip/ # Other types of files that need processing, like .gz --> .decomp, aren't # expanded in an internal folder. This is also the case for files that do not # need processing, e.g. ".nc" files. In these cases, `full_path` is the exact # directory that the cached file is saved to. # # # For example: /Users/laurenilano/Library/Caches/gplately/Muller_etal_2019_Tectonics_v2.0_AgeGrid-100.nc # # `full_path` is an empty directory for non-zips, and is the parent directory of # unzipped contents in ".zip" URLs. # # Why do we need `full_path`? # We search the top-level gplately cache directory for the `full_path` directory as it is # installed with the requested files. Its existence verifies the # existence of the requested file(s), and thus to decide whether to install the # files or re-access existing cached versions. This also helps with E-Tag versioning # in instances where the download URL remains the same but its contents may have changed # since the file(s) were last cached. full_path, unprocessed_path = path_of_cached_file(url, model_name) # If the file required processing (zips make a directory to unzip in, and .gz for example # makes a file just saved to the top-level directory), and the directory or file is not # yet on the cache, if _determine_processor(url)[1] and not ( _os.path.isdir(str(full_path)) or _os.path.isfile(str(full_path)) ): # ...and if a connection to the web server can be established, # download files from the URL and create a textfile for this URL's E-Tag if _test_internet_connection(url): fnames, etag, textfilename, used_fname = _first_time_download_from_web( url, model_name=model_name, verbose=verbose ) if verbose: print("Requested files downloaded to the GPlately cache folder!") return(fnames) # ... if a connection to the web server cannot be established else: raise ConnectionError( "A connection to {} could not be made. Please check your internet connection and/or ensure the URL is correct. No file from the given URL has been cached to {} yet - nothing has been returned.".format(url, full_path.parent)) # If the file does not require processing, it did not open up a directory, so check isfile, # and if the file is not yet on the cache, elif not _determine_processor(url)[1] and not _os.path.isfile(str(full_path)): # ...and if a connection to the web server can be established, # download files from the URL and create a textfile for this URL's E-Tag if _test_internet_connection(url): fnames, etag, textfilename, used_fname = _first_time_download_from_web( url, model_name=model_name, verbose=verbose ) if verbose: print("Requested files downloaded to the GPlately cache folder!") return(fnames) # ... if a connection to the web server cannot be established else: raise ConnectionError( "A connection to {} could not be made. Please check your internet connection and/or ensure the URL is correct. No file from the given URL has been cached to {} yet - nothing has been returned.".format(url, full_path.parent)) # If the files have been downloaded before... else: #... and if a connection to the web server can be made... if _test_internet_connection(url): _, local_etag_txtfile = _get_url_etag(url) # If the newest version of the files in `url` must be cached # at all times, perform E-Tag comparisons: if download_changes: # Walk through the top-level cache directory to find an E-Tag textfile unique to the URL etag_exists = False cache_path = str(path_to_cache()) if _os.path.isfile(local_etag_txtfile): etag_exists = True # If an e-tag text file does not exist, erase the cached files # and download the latest version from the web server. This, in turn, # creates an e-tag textfile for this version. if not etag_exists: if _os.path.isdir(full_path): _shutil.rmtree(str(full_path)) elif _os.path.isfile(full_path): _os.remove(full_path) if unprocessed_path: if _os.path.isdir(unprocessed_path): _shutil.rmtree(str(unprocessed_path)) elif _os.path.isfile(unprocessed_path): _os.remove(unprocessed_path) fnames, etag, local_etag_txtfile, used_fname = _first_time_download_from_web( url, model_name=model_name, verbose=verbose ) return(fnames) # If the e-tag textfile exists for the local files, else: if verbose: print("Checking whether the requested files need to be updated...") # Determine the local file's URL e-tag from the textfile with open(local_etag_txtfile) as f: local_etag = str(f.readlines()[0]) # Get the e-tag of the web server URL at current time remote_etag, remote_etag_textfile = _get_url_etag(url) # If the local and remote e-tags are unequal, the web-server URL # contains an updated version of the cached files. if str(remote_etag) != str(local_etag): if verbose: print("Yes - updating requested files...") # Update the e-tag textfile with this newly-identified URL e-tag _save_url_etag_to_txt(remote_etag, local_etag_txtfile) # Delete existing version of the files... # If it didn't need processing, i.e. 'unzipping', just delete as-is if _os.path.isdir(full_path): _shutil.rmtree(str(full_path)) elif _os.path.isfile(full_path): _os.remove(full_path) # If it's the kind of file that needs processing, delete the # unprocessed version so we can re-download it if unprocessed_path: if _os.path.isdir(unprocessed_path): _shutil.rmtree(str(unprocessed_path)) elif _os.path.isfile(unprocessed_path): _os.remove(unprocessed_path) # Treat as if downloading the file(s) from the URL for the first time fnames, etag, local_etag_txtfile, used_fname = _first_time_download_from_web( url, model_name=model_name, verbose=verbose ) if verbose: print("Updated requested files downloaded to the GPlately cache folder!") return(fnames) # If the e-tags are equal, the local and remote files are the same. # Just return the file(s) as-is. else: if verbose: print("Requested files are up-to-date!") # If files were processed once, return the processed files. if _determine_processor(url): if str(full_path).endswith(_determine_processor(url)[1]): return(_extract_processed_files((str(full_path)))) else: return(_extract_processed_files( str(full_path)+_determine_processor(url)[1])) # If not, return as-is. else: return(_extract_processed_files( str(full_path)+_match_url_to_extension(url))) # If file versioning doesn't matter, just keep returning the cached files. else: fnames, etag, local_etag_txtfile = _first_time_download_from_web(url, model_name) return(fnames) # If a connection to the web server could not be made, and the files exist in # the GPlately cache, just return the files as-is. else: print("No connection to {} established. The requested file(s) (potentially older versions) exist in the GPlately cache ({}) and have been returned.".format(url, full_path.parent)) #print(str(full_path)+_determine_processor(url)[1]) return(_extract_processed_files( str(full_path))) # This created zip.unzip.unzip, so i deleted it but not sure if this will affect other files. # return(_extract_processed_files(str(full_path)+_determine_processor(url)[1]))
- def get_feature_data(feature_data_id_string=None, verbose=True)
- 
Downloads assorted geological feature data from web servers (i.e. GPlates 2.3 sample data) into the "gplately" cache. Currently, gplately supports the following feature data: 
 Feature data string identifier Description Johansson2018 Large igneous provinces from Johansson et al. (2018) Whittaker2015 Large igneous province products interpreted as plume products from Whittaker et al. (2015). SeafloorFabric Seafloor tectonic fabric (fracture zones, discordant zones, V-shaped structures, unclassified V-anomalies, propagating ridge lineations and extinct ridges) from Matthews et al. (2011) Hotspots Present day surface hotspot/plume locations from Whittaker et al. (2013) 
 Detailed descriptions can be found below: - 
Large igneous provinces from Johansson et al. (2018) Information- Formats: .gpmlz
- feature_data_id_string=- Johansson2018
 Citations- Johansson, L., Zahirovic, S., and Müller, R. D., In Prep, The interplay between the eruption and weathering of Large Igneous Provinces and the deep-time carbon cycle: Geophysical Research Letters.
 
- 
Large igneous province products interpreted as plume products from Whittaker et al. (2015). Information- Formats: .gpmlz, .shp
- feature_data_id_string=- Whittaker2015
 Citations- Whittaker, J. M., Afonso, J. C., Masterton, S., Müller, R. D., Wessel, P., Williams, S. E., & Seton, M. (2015). Long-term interaction between mid-ocean ridges and mantle plumes. Nature Geoscience, 8(6), 479-483. doi:10.1038/ngeo2437.
 
- 
Seafloor tectonic fabric (fracture zones, discordant zones, V-shaped structures, unclassified V-anomalies, propagating ridge lineations and extinct ridges) from Matthews et al. (2011) Information- Formats: .gpml
- feature_data_id_string=- SeafloorFabric
 Citations- Matthews, K.J., Müller, R.D., Wessel, P. and Whittaker, J.M., 2011. The tectonic fabric of the ocean basins. Journal of Geophysical Research, 116(B12): B12109, DOI: 10.1029/2011JB008413.
 
- 
Present day surface hotspot/plume locations from Whittaker et al. (2013) Information- Formats: .gpmlz
- feature_data_id_string=- Hotspots
 Citation- Whittaker, J., Afonso, J., Masterton, S., Müller, R., Wessel, P., Williams, S., and Seton, M., 2015, Long-term interaction between mid-ocean ridges and mantle plumes: Nature Geoscience, v. 8, no. 6, p. 479-483, doi:10.1038/ngeo2437.
 
 Parameters- feature_data_id_string:- str, default=- None
- A string to identify which feature data to download to the cache (see list of supported feature data above).
 Returns- feature_data_filenames:- instanceof- <pygplates.FeatureCollection>,or- listof- instance <pygplates.FeatureCollection>
- If a single set of feature data is downloaded, a single pyGPlates FeatureCollectionobject is returned. Otherwise, a list containing multiple pyGPlatesFeatureCollectionobjects is returned (like forSeafloorFabric). In the latter case, feature reconstruction and plotting may have to be done iteratively.
 Raises- ValueError
- If a feature_data_id_stringis not provided.
 ExamplesFor examples of plotting data downloaded with get_feature_data(), see GPlately's sample notebook 05 - Working With Feature Geometries here.Expand source codedef get_feature_data(feature_data_id_string=None, verbose=True): """Downloads assorted geological feature data from web servers (i.e. [GPlates 2.3 sample data](https://www.earthbyte.org/gplates-2-3-software-and-data-sets/)) into the "gplately" cache. Currently, gplately supports the following feature data: -------------- | **Feature data string identifier** | **Description** | |------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Johansson2018 | Large igneous provinces from Johansson et al. (2018) | | Whittaker2015 | Large igneous province products interpreted as plume products from Whittaker et al. (2015). | | SeafloorFabric | Seafloor tectonic fabric (fracture zones, discordant zones, V-shaped structures, unclassified V-anomalies, propagating ridge lineations and extinct ridges) from Matthews et al. (2011) | | Hotspots | Present day surface hotspot/plume locations from Whittaker et al. (2013) | --------------- Detailed descriptions can be found below: * __Large igneous provinces from Johansson et al. (2018)__ Information ----------- * Formats: .gpmlz * `feature_data_id_string` = `Johansson2018` Citations --------- * Johansson, L., Zahirovic, S., and Müller, R. D., In Prep, The interplay between the eruption and weathering of Large Igneous Provinces and the deep-time carbon cycle: Geophysical Research Letters. - __Large igneous province products interpreted as plume products from Whittaker et al. (2015)__. Information ----------- * Formats: .gpmlz, .shp * `feature_data_id_string` = `Whittaker2015` Citations --------- * Whittaker, J. M., Afonso, J. C., Masterton, S., Müller, R. D., Wessel, P., Williams, S. E., & Seton, M. (2015). Long-term interaction between mid-ocean ridges and mantle plumes. Nature Geoscience, 8(6), 479-483. doi:10.1038/ngeo2437. - __Seafloor tectonic fabric (fracture zones, discordant zones, V-shaped structures, unclassified V-anomalies, propagating ridge lineations and extinct ridges) from Matthews et al. (2011)__ Information ----------- * Formats: .gpml * `feature_data_id_string` = `SeafloorFabric` Citations --------- * Matthews, K.J., Müller, R.D., Wessel, P. and Whittaker, J.M., 2011. The tectonic fabric of the ocean basins. Journal of Geophysical Research, 116(B12): B12109, DOI: 10.1029/2011JB008413. - __Present day surface hotspot/plume locations from Whittaker et al. (2013)__ Information ----------- * Formats: .gpmlz * `feature_data_id_string` = `Hotspots` Citation -------- * Whittaker, J., Afonso, J., Masterton, S., Müller, R., Wessel, P., Williams, S., and Seton, M., 2015, Long-term interaction between mid-ocean ridges and mantle plumes: Nature Geoscience, v. 8, no. 6, p. 479-483, doi:10.1038/ngeo2437. Parameters ---------- feature_data_id_string : str, default=None A string to identify which feature data to download to the cache (see list of supported feature data above). Returns ------- feature_data_filenames : instance of <pygplates.FeatureCollection>, or list of instance <pygplates.FeatureCollection> If a single set of feature data is downloaded, a single pyGPlates `FeatureCollection` object is returned. Otherwise, a list containing multiple pyGPlates `FeatureCollection` objects is returned (like for `SeafloorFabric`). In the latter case, feature reconstruction and plotting may have to be done iteratively. Raises ------ ValueError If a `feature_data_id_string` is not provided. Examples -------- For examples of plotting data downloaded with `get_feature_data`, see GPlately's sample notebook 05 - Working With Feature Geometries [here](https://github.com/GPlates/gplately/blob/master/Notebooks/05-WorkingWithFeatureGeometries.ipynb). """ if feature_data_id_string is None: raise ValueError( "Please specify which feature data to fetch." ) database = _gplately.data._feature_data() found_collection = False for collection, zip_url in database.items(): if feature_data_id_string.lower() == collection.lower(): found_collection = True feature_data_filenames = _collection_sorter( _collect_file_extension( download_from_web(zip_url[0], verbose), [".gpml", ".gpmlz"] ), collection ) break if found_collection is False: raise ValueError("{} are not in GPlately's DataServer.".format(feature_data_id_string)) feat_data = _FeatureCollection() if len(feature_data_filenames) == 1: feat_data.add(_FeatureCollection(feature_data_filenames[0])) return feat_data else: feat_data=[] for file in feature_data_filenames: feat_data.append(_FeatureCollection(file)) return feat_data
- 
- def get_raster(raster_id_string=None, verbose=True)
- 
Downloads assorted raster data that are not associated with the plate reconstruction models supported by GPlately's DataServer. Stores rasters in the "gplately" cache.Currently, gplately supports the following rasters and images: - ETOPO1: - Filetypes available : TIF, netCDF (GRD)
- raster_id_string=- "ETOPO1_grd",- "ETOPO1_tif"(depending on the requested format)
- A 1-arc minute global relief model combining lang topography and ocean bathymetry.
- Citation: doi:10.7289/V5C8276M
 
 Parameters- raster_id_string:- str, default=- None
- A string to identify which raster to download.
 Returns- a Raster object
- 
A gplately.Raster object containing the raster data. The gridded data can be extracted into a numpy ndarray or MaskedArray by appending .datato the variable assigned toget_raster().For example: graster = gplately.download.get_raster(raster_id_string, verbose) graster_data = graster.datawhere graster_datais a numpy ndarray. This array can be visualised usingmatplotlib.pyplot.imshowon acartopy.mpl.GeoAxisGeoAxesSubplot (see example below).
 Raises- ValueError
- 
- if a raster_id_stringis not supplied.
 
- if a 
 NotesRasters obtained by this method are (so far) only reconstructed to present-day. ExamplesTo download ETOPO1 and plot it on a Mollweide projection: import gplately import numpy as np import matplotlib.pyplot as plt import cartopy.crs as ccrs etopo1 = gplately.download.get_raster("ETOPO1_tif") etopo1_data = etopo1.data fig = plt.figure(figsize=(18,14), dpi=300) ax = fig.add_subplot(111, projection=ccrs.Mollweide(central_longitude = -150)) etopo1.imshow(ax)Expand source codedef get_raster(raster_id_string=None, verbose=True): """Downloads assorted raster data that are not associated with the plate reconstruction models supported by GPlately's `DataServer`. Stores rasters in the "gplately" cache. Currently, gplately supports the following rasters and images: * __[ETOPO1](https://www.ngdc.noaa.gov/mgg/global/)__: * Filetypes available : TIF, netCDF (GRD) * `raster_id_string` = `"ETOPO1_grd"`, `"ETOPO1_tif"` (depending on the requested format) * A 1-arc minute global relief model combining lang topography and ocean bathymetry. * Citation: doi:10.7289/V5C8276M Parameters ---------- raster_id_string : str, default=None A string to identify which raster to download. Returns ------- a gplately.Raster object A gplately.Raster object containing the raster data. The gridded data can be extracted into a numpy ndarray or MaskedArray by appending `.data` to the variable assigned to `get_raster()`. For example: graster = gplately.download.get_raster(raster_id_string, verbose) graster_data = graster.data where `graster_data` is a numpy ndarray. This array can be visualised using `matplotlib.pyplot.imshow` on a `cartopy.mpl.GeoAxis` GeoAxesSubplot (see example below). Raises ------ ValueError * if a `raster_id_string` is not supplied. Notes ----- Rasters obtained by this method are (so far) only reconstructed to present-day. Examples -------- To download ETOPO1 and plot it on a Mollweide projection: import gplately import numpy as np import matplotlib.pyplot as plt import cartopy.crs as ccrs etopo1 = gplately.download.get_raster("ETOPO1_tif") etopo1_data = etopo1.data fig = plt.figure(figsize=(18,14), dpi=300) ax = fig.add_subplot(111, projection=ccrs.Mollweide(central_longitude = -150)) etopo1.imshow(ax) """ from matplotlib import image if raster_id_string is None: raise ValueError( "Please specify which raster to download." ) #filetype = "."+"_".split(raster_id_string)[-1] archive_formats = tuple([".gz", ".xz", ".bz2"]) grid_extensions = tuple([".grd", ".nc"]) # Set to true if we find the given collection in database found_collection = False raster_filenames = [] database = _gplately.data._rasters() for collection, zip_url in database.items(): # Isolate the raster name and the file type #raster_name = collection.split("_")[0] #raster_type = "."+collection.split("_")[-1] if (raster_id_string.lower() == collection.lower()): raster_filenames = download_from_web(zip_url[0], verbose) found_collection = True break if found_collection is False: raise ValueError("{} not in collection database.".format(raster_id_string)) else: # If the downloaded raster is a grid, process it with the gplately.Raster object if any(grid_extension in raster_filenames for grid_extension in grid_extensions): raster = _gplately.grids.Raster(data=raster_filenames) # Otherwise, the raster is an image; use imread to process else: raster_matrix = image.imread(raster_filenames) raster = _gplately.grids.Raster(data=raster_matrix) if raster_id_string.lower() == "etopo1_tif": raster.lats = raster.lats[::-1] if raster_id_string.lower() == "etopo1_grd": raster._data = raster._data.astype(float) return raster
- ETOPO1: 
- def path_of_cached_file(url, model_name=None)
- 
Determine the absolute path where the file(s) from urlwill be downloaded to.Parameters- url:- str
- The full download URL for the file passed as a string.
- model_name:- str, default- None
- An optional substring that ideally describes/labels the file.
This will help name the file(s) when it is downloaded to the
gplately cache (this directory can be
found using path_to_cache()).
 Expand source codedef path_of_cached_file(url, model_name=None): """Determine the absolute path where the file(s) from `url` will be downloaded to. Parameters ---------- url : str The full download URL for the file passed as a string. model_name : str, default None An optional substring that ideally describes/labels the file. This will help name the file(s) when it is downloaded to the gplately cache (this directory can be found using `gplately.download.path_to_cache()`). """ cached_filename = _pooch.utils.unique_file_name(url) cached_filename = _remove_hash(cached_filename) path = path_to_cache() processor_to_use, processor_extension = _determine_processor(url) # If the requested files need processing (i.e. zip, gz folders) if processor_extension: # Are they from plate models? These typically are the .zip folders for plate models if model_name: cached_filename = str(path) + '/' + model_name + processor_extension+'/' unprocessed_path = str(path) + '/' + model_name #cached_filename = cached_filename = str(path) + '/' + model_name # If not from plate models but need processing, i.e. ETOPO1 else: cached_filename = str(path) + '/' + "gplately_"+_parse_url_for_filenames(url) + processor_extension+'/' unprocessed_path = str(path) + '/' + "gplately_"+_parse_url_for_filenames(url) #cached_filename = "gplately_"+_parse_url_for_filenames(url) # If the requested files do not need processing, like standalone .nc files: else: if model_name: cached_filename = str(path) + '/' + model_name + "_" + _parse_url_for_filenames(url) unprocessed_path = None else: cached_filename = str(path) + '/' + "gplately_"+_parse_url_for_filenames(url) unprocessed_path = None _pooch.utils.make_local_storage(path) full_path = path.resolve() / cached_filename return full_path, unprocessed_path
- def path_to_cache()
- 
Determine the absolute path to the system gplately cache. Expand source codedef path_to_cache(): """Determine the absolute path to the system gplately cache. """ path = _pooch.utils.cache_location( _os_cache('gplately'), env=None, version=None ) return path
Classes
- class DataServer (file_collection, verbose=True)
- 
Uses Pooch to download plate reconstruction feature data from plate models and other studies that are stored on web servers (e.g. EarthByte's webDAV server). If the DataServerobject and its methods are called for the first time, i.e. by:# string identifier to access the Muller et al. 2019 model gDownload = gplately.download.DataServer("Muller2019")all requested files are downloaded into the user's 'gplately' cache folder only once. If the same object and method(s) are re-run, the files will be re-accessed from the cache provided they have not been moved or deleted. Currently, DataServersupports a number of plate reconstruction models.
 Model name string Identifier Rot. files Topology features Static polygons Coast-lines Cont-inents COB- Age grids SR grids Muller2019 ✅ ✅ ✅ ✅ ✅ ✅ ✅ ❌ Muller2016 ✅ ✅ ✅ ✅ ❌ ❌ ✅ ❌ Merdith2021 ✅ ✅ ✅ ✅ ✅ ❌ ❌ ❌ Cao2020 ✅ ✅ ✅ ✅ ✅ ❌ ❌ ❌ Clennett2020 ✅ ✅ ✅ ✅ ✅ ❌ ✅ ✅ Seton2012 ✅ ✅ ❌ ✅ ❌ ✅ ✅ ❌ Matthews2016 ✅ ✅ ✅ ✅ ✅ ❌ ❌ ❌ Merdith2017 ✅ ✅ ❌ ❌ ❌ ❌ ❌ ❌ Li2008 ✅ ✅ ❌ ❌ ❌ ❌ ❌ ❌ Pehrsson2015 ✅ ✅ ❌ ❌ ❌ ❌ ❌ ❌ TorsvikCocks2017 ✅ ❌ ❌ ✅ ❌ ❌ ❌ ❌ Young2019 ✅ ✅ ✅ ✅ ✅ ❌ ❌ ❌ Scotese2008 ✅ ✅ ❌ ❌ ✅ ❌ ❌ ❌ Clennett2020_M19 ✅ ✅ ❌ ✅ ✅ ❌ ❌ ❌ Clennett2020_S13 ✅ ✅ ❌ ✅ ✅ ❌ ❌ ❌ Muller2008 ✅ ❌ ✅ ❌ ❌ ❌ ❌ ❌ Muller2022 ✅ ✅ ✅ ✅ ✅ ✅ ❌ ❌ Scotese2016 ✅ ❌ ✅ ✅ ❌ ❌ ❌ ❌ Shephard2013 ✅ ✅ ✅ ✅ ❌ ❌ ❌ ❌ 
 To call the object, supply a model name string Identifier, file_collection, from one of the following models:- 
file_collection = Muller2019Information- Downloadable files: a rotation_model,topology_features,static_polygons,coastlines,continents,COBs, and seafloorage_gridsfrom 0 to 250 Ma.
- Maximum reconstruction time: 250 Ma
 CitationsMüller, R. D., Zahirovic, S., Williams, S. E., Cannon, J., Seton, M., Bower, D. J., Tetley, M. G., Heine, C., Le Breton, E., Liu, S., Russell, S. H. J., Yang, T., Leonard, J., and Gurnis, M. (2019), A global plate model including lithospheric deformation along major rifts and orogens since the Triassic. Tectonics, vol. 38, https://doi.org/10.1029/2018TC005462. 
- Downloadable files: a 
- 
Müller et al. 2016: file_collection = Muller2016Information- Downloadable files: a rotation_model,topology_features,static_polygons,coastlines, and seafloorage_gridsfrom 0-230 Ma.
- Maximum reconstruction time: 230 Ma
 Citations- Müller R.D., Seton, M., Zahirovic, S., Williams, S.E., Matthews, K.J., Wright, N.M., Shephard, G.E., Maloney, K.T., Barnett-Moore, N., Hosseinpour, M., Bower, D.J., Cannon, J., InPress. Ocean basin evolution and global-scale plate reorganization events since Pangea breakup, Annual Review of Earth and Planetary Sciences, Vol 44, 107-138. DOI: 10.1146/annurev-earth-060115-012211.
 
- Downloadable files: a 
- 
file_collection = Merdith2021Information- Downloadable files: a rotation_model,topology_features,static_polygons,coastlinesandcontinents.
- Maximum reconstruction time: 1 Ga (however, PlotTopologiescorrectly visualises up to 410 Ma)
 Citations:- Merdith et al. (in review), 'A continuous, kinematic full-plate motion model from 1 Ga to present'.
- Andrew Merdith. (2020). Plate model for 'Extending Full-Plate Tectonic Models into Deep Time: Linking the Neoproterozoic and the Phanerozoic ' (1.1b) [Data set]. Zenodo. https://doi.org/10.5281/zenodo.4485738
 
- Downloadable files: a 
- 
Cao et al. 2020: file_collection = Cao2020Information- Downloadable files: rotation_model,topology_features,static_polygons,coastlinesandcontinents.
- Maximum reconstruction time: 1 Ga
 Citations- Toy Billion-year reconstructions from Cao et al (2020). Coupled Evolution of Plate Tectonics and Basal Mantle Structure Tectonics, doi: 10.1029/2020GC009244
 
- Downloadable files: 
- 
Clennett et al. 2020 : file_collection = Clennett2020Information- Downloadable files: rotation_model,topology_features,static_polygons,coastlinesandcontinents
- Maximum reconstruction time: 170 Ma
 Citations- Mather, B., Müller, R.D.,; Alfonso, C.P., Seton, M., 2021, Kimberlite eruption driven by slab flux and subduction angle. DOI: 10.5281/zenodo.5769002
 
- Downloadable files: 
- 
Seton et al. 2012: file_collection = Seton2012Information- Downloadable files: rotation_model,topology_features,coastlines,COBs, and paleo-age grids (0-200 Ma)
- Maximum reconstruction time: 200 Ma
 Citations- M. Seton, R.D. Müller, S. Zahirovic, C. Gaina, T.H. Torsvik, G. Shephard, A. Talsma, M. Gurnis, M. Turner, S. Maus, M. Chandler, Global continental and ocean basin reconstructions since 200 Ma, Earth-Science Reviews, Volume 113, Issues 3-4, July 2012, Pages 212-270, ISSN 0012-8252, 10.1016/j.earscirev.2012.03.002.
 
- Downloadable files: 
- 
Matthews et al. 2016: file_collection = Matthews2016Information- Downloadable files: rotation_model,topology_features,static_polygons,coastlines, andcontinents
- Maximum reconstruction time(s): 410-250 Ma, 250-0 Ma
 Citations- Matthews, K.J., Maloney, K.T., Zahirovic, S., Williams, S.E., Seton, M., and Müller, R.D. (2016). Global plate boundary evolution and kinematics since the late Paleozoic, Global and Planetary Change, 146, 226-250. DOI: 10.1016/j.gloplacha.2016.10.002
 
- Downloadable files: 
- 
Merdith et al. 2017: file_collection = Merdith2017Information- Downloadable files: rotation_filesandtopology_features
- Maximum reconstruction time: 410 Ma
 Citations- Merdith, A., Collins, A., Williams, S., Pisarevskiy, S., Foden, J., Archibald, D. and Blades, M. et al. 2016. A full-plate global reconstruction of the Neoproterozoic. Gondwana Research. 50: pp. 84-134. DOI: 10.1016/j.gr.2017.04.001
 
- Downloadable files: 
- 
Li et al. 2008: file_collection = Li2008Information- Downloadable files: rotation_modelandstatic_polygons
- Maximum reconstruction time: 410 Ma
 Citations- Rodinia reconstruction from Li et al (2008), Assembly, configuration, and break-up history of Rodinia: A synthesis. Precambrian Research. 160. 179-210. DOI: 10.1016/j.precamres.2007.04.021.
 
- Downloadable files: 
- 
Pehrsson et al. 2015: file_collection = Pehrsson2015Information- Downloadable files: rotation_modelandstatic_polygons
- Maximum reconstruction time: N/A
 Citations- Pehrsson, S.J., Eglington, B.M., Evans, D.A.D., Huston, D., and Reddy, S.M., (2015), Metallogeny and its link to orogenic style during the Nuna supercontinent cycle. Geological Society, London, Special Publications, 424, 83-94. DOI: https://doi.org/10.1144/SP424.5
 
- Downloadable files: 
- 
Torsvik and Cocks et al. 2017: file_collection = TorsvikCocks2017Information- Downloadable files: rotation_model, andcoastlines
- Maximum reconstruction time: 410 Ma
 Citations- Torsvik, T., & Cocks, L. (2016). Earth History and Palaeogeography. Cambridge: Cambridge University Press. doi:10.1017/9781316225523
 
- Downloadable files: 
- 
Young et al. 2019: file_collection = Young2019Information- Downloadable files: rotation_model,topology_features,static_polygons,coastlinesandcontinents.
- Maximum reconstruction time: 410-250 Ma, 250-0 Ma
 Citations- Young, A., Flament, N., Maloney, K., Williams, S., Matthews, K., Zahirovic, S., Müller, R.D., (2019), Global kinematics of tectonic plates and subduction zones since the late Paleozoic Era, Geoscience Frontiers, Volume 10, Issue 3, pp. 989-1013, ISSN 1674-9871, DOI: https://doi.org/10.1016/j.gsf.2018.05.011.
 
- Downloadable files: 
- 
Scotese et al. 2008: file_collection = Scotese2008Information- Downloadable files: rotation_model,static_polygons, andcontinents
- Maximum reconstruction time:
 Citations- Scotese, C.R. 2008. The PALEOMAP Project PaleoAtlas for ArcGIS, Volume 2, Cretaceous paleogeographic and plate tectonic reconstructions. PALEOMAP Project, Arlington, Texas.
 
- Downloadable files: 
- 
Golonka et al. 2007: file_collection = Golonka2007Information- Downloadable files: rotation_model,static_polygons, andcontinents
- Maximum reconstruction time: 410 Ma
 Citations- Golonka, J. 2007. Late Triassic and Early Jurassic palaeogeography of the world. Palaeogeography, Palaeoclimatology, Palaeoecology 244(1–4), 297–307.
 
- Downloadable files: 
- 
Clennett et al. 2020 (based on Müller et al. 2019): file_collection = Clennett2020_M2019Information- Downloadable files: rotation_model,topology_features,continentsandcoastlines
- Maximum reconstruction time: 170 Ma
 Citations- Clennett, E.J., Sigloch, K., Mihalynuk, M.G., Seton, M., Henderson, M.A., Hosseini, K., Mohammadzaheri, A., Johnston, S.T., Müller, R.D., (2020), A Quantitative Tomotectonic Plate Reconstruction of Western North America and the Eastern Pacific Basin. Geochemistry, Geophysics, Geosystems, 21, e2020GC009117. DOI: https://doi.org/10.1029/2020GC009117
 
- Downloadable files: 
- 
Clennett et al. 2020 (rigid topological model based on Shephard et al, 2013): file_collection = Clennett2020_S2013Information- Downloadable files: rotation_model,topology_features,continentsandcoastlines
- Maximum reconstruction time: 170
 Citations- Clennett, E.J., Sigloch, K., Mihalynuk, M.G., Seton, M., Henderson, M.A., Hosseini, K., Mohammadzaheri, A., Johnston, S.T., Müller, R.D., (2020), A Quantitative Tomotectonic Plate Reconstruction of Western North America and the Eastern Pacific Basin. Geochemistry, Geophysics, Geosystems, 21, e2020GC009117. DOI: https://doi.org/10.1029/2020GC009117
 
- Downloadable files: 
- 
Müller et al. 2008: file_collection = Muller2008Information- Downloadable files:
rotation_model,static_polygons
- Maximum reconstruction time: 141 Ma
 Citations- Müller, R. D., Sdrolias, M., Gaina, C., & Roest, W. R. (2008). Age, spreading rates, and spreading asymmetry of the world's ocean crust. Geochemistry, Geophysics, Geosystems, 9(4).
 
- Downloadable files:
- 
Müller et al. 2022: file_collection = Muller2022Information- Downloadable files:
rotation_model,topology_features,static_polygons,continents,coastlinesandCOBs
- Maximum reconstruction time: 1000 Ma
 Citations- Müller, R. D., Flament, N., Cannon, J., Tetley, M. G., Williams, S. E., Cao, X., Bodur, Ö. F., Zahirovic, S., and Merdith, A.: A tectonic-rules-based mantle reference frame since 1 billion years ago – implications for supercontinent cycles and plate–mantle system evolution, Solid Earth, 13, 1127–1159, https://doi.org/10.5194/se-13-1127-2022, 2022.
 
- Downloadable files:
- 
Scotese 2016: file_collection = Scotese2016Information- Downloadable files:
rotation_model,static_polygons,coastlines
- Maximum reconstruction time: 410 Ma
 Citations- Scotese, C.R., 2016. PALEOMAP PaleoAtlas for GPlates and the PaleoData Plotter Program, PALEOMAP Project, http://www.earthbyte.org/paleomappaleoatlas-for-gplates/
 
- Downloadable files:
- 
Shephard et al. 2013: file_collection = Shephard2013Information- Downloadable files:
rotation_model,topology_features,static_polygons,coastlines
- Maximum reconstruction time: 200 Ma
 Citations- 
Shephard, G.E., Müller, R.D., and Seton, M., 2013. The tectonic evolution of the Arctic since Pangea breakup: Integrating constraints from surface geology and geophysics with mantle structure. Earth-Science Reviews, Volume 124 p.148-183. doi:10.1016/j.earscirev.2013.05.012 (http://www.sciencedirect.com/science/article/pii/S0012825213001104) 
- 
M. Seton, R.D. Müller, S. Zahirovic, C. Gaina, T.H. Torsvik, G. Shephard, A. Talsma, M. Gurnis, M. Turner, S. Maus, M. Chandler, Global continental and ocean basin reconstructions since 200 Ma, Earth-Science Reviews, Volume 113, p.212-270 doi:10.1016/j.earscirev.2012.03.002. (http://www.sciencedirect.com/science/article/pii/S0012825212000311) 
 Parametersfile_collection : str name of file collection to use verbose : bool, default True Toggle print messages regarding server/internet connection status, file availability etc. 
- Downloadable files:
 Expand source codeclass DataServer(object): """Uses [Pooch](https://www.fatiando.org/pooch/latest/) to download plate reconstruction feature data from plate models and other studies that are stored on web servers (e.g. EarthByte's [webDAV server](https://www.earthbyte.org/webdav/ftp/Data_Collections/)). If the `DataServer` object and its methods are called for the first time, i.e. by: # string identifier to access the Muller et al. 2019 model gDownload = gplately.download.DataServer("Muller2019") all requested files are downloaded into the user's 'gplately' cache folder only _once_. If the same object and method(s) are re-run, the files will be re-accessed from the cache provided they have not been moved or deleted. Currently, `DataServer` supports a number of plate reconstruction models. ------------------ | **Model name string Identifier** | **Rot. files** | **Topology features** | **Static polygons** | **Coast-lines** | **Cont-inents** | **COB-** | **Age grids** | **SR grids** | |:--------------------------------:|:--------------:|:---------------------:|:-------------------:|:---------------:|:---------------:|:--------:|:-------------:|:------------:| | Muller2019 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | | Muller2016 | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | | Merdith2021 | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | | Cao2020 | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | | Clennett2020 | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | | Seton2012 | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | | Matthews2016 | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | | Merdith2017 | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | Li2008 | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | Pehrsson2015 | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | TorsvikCocks2017 | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | | Young2019 | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | | Scotese2008 | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | | Clennett2020_M19 | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | | Clennett2020_S13 | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | | Muller2008 | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | | Muller2022 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | | Scotese2016 | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | | Shephard2013 | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ------------------ To call the object, supply a model name string Identifier, `file_collection`, from one of the following models: * __[Müller et al. 2019](https://www.earthbyte.org/muller-et-al-2019-deforming-plate-reconstruction-and-seafloor-age-grids-tectonics/):__ file_collection = `Muller2019` Information ----------- * Downloadable files: a `rotation_model`, `topology_features`, `static_polygons`, `coastlines`, `continents`, `COBs`, and seafloor `age_grids` from 0 to 250 Ma. * Maximum reconstruction time: 250 Ma Citations --------- Müller, R. D., Zahirovic, S., Williams, S. E., Cannon, J., Seton, M., Bower, D. J., Tetley, M. G., Heine, C., Le Breton, E., Liu, S., Russell, S. H. J., Yang, T., Leonard, J., and Gurnis, M. (2019), A global plate model including lithospheric deformation along major rifts and orogens since the Triassic. Tectonics, vol. 38, https://doi.org/10.1029/2018TC005462. * __Müller et al. 2016__: file_collection = `Muller2016` Information ----------- * Downloadable files: a `rotation_model`, `topology_features`, `static_polygons`, `coastlines`, and seafloor `age_grids` from 0-230 Ma. * Maximum reconstruction time: 230 Ma Citations --------- * Müller R.D., Seton, M., Zahirovic, S., Williams, S.E., Matthews, K.J., Wright, N.M., Shephard, G.E., Maloney, K.T., Barnett-Moore, N., Hosseinpour, M., Bower, D.J., Cannon, J., InPress. Ocean basin evolution and global-scale plate reorganization events since Pangea breakup, Annual Review of Earth and Planetary Sciences, Vol 44, 107-138. DOI: 10.1146/annurev-earth-060115-012211. * __[Merdith et al. 2021](https://zenodo.org/record/4485738#.Yhrm8hNBzA0)__: file_collection = `Merdith2021` Information ----------- * Downloadable files: a `rotation_model`, `topology_features`, `static_polygons`, `coastlines` and `continents`. * Maximum reconstruction time: 1 Ga (however, `PlotTopologies` correctly visualises up to 410 Ma) Citations: ---------- * Merdith et al. (in review), 'A continuous, kinematic full-plate motion model from 1 Ga to present'. * Andrew Merdith. (2020). Plate model for 'Extending Full-Plate Tectonic Models into Deep Time: Linking the Neoproterozoic and the Phanerozoic ' (1.1b) [Data set]. Zenodo. https://doi.org/10.5281/zenodo.4485738 * __Cao et al. 2020__: file_collection = `Cao2020` Information ----------- * Downloadable files: `rotation_model`, `topology_features`, `static_polygons`, `coastlines` and `continents`. * Maximum reconstruction time: 1 Ga Citations --------- * Toy Billion-year reconstructions from Cao et al (2020). Coupled Evolution of Plate Tectonics and Basal Mantle Structure Tectonics, doi: 10.1029/2020GC009244 - __Clennett et al. 2020__ : file_collection = `Clennett2020` Information ----------- * Downloadable files: `rotation_model`, `topology_features`, `static_polygons`, `coastlines` and `continents` * Maximum reconstruction time: 170 Ma Citations --------- * Mather, B., Müller, R.D.,; Alfonso, C.P., Seton, M., 2021, Kimberlite eruption driven by slab flux and subduction angle. DOI: 10.5281/zenodo.5769002 - __Seton et al. 2012__: file_collection = `Seton2012` Information ----------- * Downloadable files: `rotation_model`, `topology_features`, `coastlines`, `COBs`, and paleo-age grids (0-200 Ma) * Maximum reconstruction time: 200 Ma Citations --------- * M. Seton, R.D. Müller, S. Zahirovic, C. Gaina, T.H. Torsvik, G. Shephard, A. Talsma, M. Gurnis, M. Turner, S. Maus, M. Chandler, Global continental and ocean basin reconstructions since 200 Ma, Earth-Science Reviews, Volume 113, Issues 3-4, July 2012, Pages 212-270, ISSN 0012-8252, 10.1016/j.earscirev.2012.03.002. - __Matthews et al. 2016__: file_collection = `Matthews2016` Information ----------- * Downloadable files: `rotation_model`, `topology_features`, `static_polygons`, `coastlines`, and `continents` * Maximum reconstruction time(s): 410-250 Ma, 250-0 Ma Citations --------- * Matthews, K.J., Maloney, K.T., Zahirovic, S., Williams, S.E., Seton, M., and Müller, R.D. (2016). Global plate boundary evolution and kinematics since the late Paleozoic, Global and Planetary Change, 146, 226-250. DOI: 10.1016/j.gloplacha.2016.10.002 - __Merdith et al. 2017__: file_collection = `Merdith2017` Information ----------- * Downloadable files: `rotation_files` and `topology_features` * Maximum reconstruction time: 410 Ma Citations --------- * Merdith, A., Collins, A., Williams, S., Pisarevskiy, S., Foden, J., Archibald, D. and Blades, M. et al. 2016. A full-plate global reconstruction of the Neoproterozoic. Gondwana Research. 50: pp. 84-134. DOI: 10.1016/j.gr.2017.04.001 - __Li et al. 2008__: file_collection = `Li2008` Information ----------- * Downloadable files: `rotation_model` and `static_polygons` * Maximum reconstruction time: 410 Ma Citations --------- * Rodinia reconstruction from Li et al (2008), Assembly, configuration, and break-up history of Rodinia: A synthesis. Precambrian Research. 160. 179-210. DOI: 10.1016/j.precamres.2007.04.021. - __Pehrsson et al. 2015__: file_collection = `Pehrsson2015` Information ----------- * Downloadable files: `rotation_model` and `static_polygons` * Maximum reconstruction time: N/A Citations --------- * Pehrsson, S.J., Eglington, B.M., Evans, D.A.D., Huston, D., and Reddy, S.M., (2015), Metallogeny and its link to orogenic style during the Nuna supercontinent cycle. Geological Society, London, Special Publications, 424, 83-94. DOI: https://doi.org/10.1144/SP424.5 - __Torsvik and Cocks et al. 2017__: file_collection = `TorsvikCocks2017` Information ----------- * Downloadable files: `rotation_model`, and `coastlines` * Maximum reconstruction time: 410 Ma Citations --------- * Torsvik, T., & Cocks, L. (2016). Earth History and Palaeogeography. Cambridge: Cambridge University Press. doi:10.1017/9781316225523 - __Young et al. 2019__: file_collection = `Young2019` Information ----------- * Downloadable files: `rotation_model`, `topology_features`, `static_polygons`, `coastlines` and `continents`. * Maximum reconstruction time: 410-250 Ma, 250-0 Ma Citations --------- * Young, A., Flament, N., Maloney, K., Williams, S., Matthews, K., Zahirovic, S., Müller, R.D., (2019), Global kinematics of tectonic plates and subduction zones since the late Paleozoic Era, Geoscience Frontiers, Volume 10, Issue 3, pp. 989-1013, ISSN 1674-9871, DOI: https://doi.org/10.1016/j.gsf.2018.05.011. - __Scotese et al. 2008__: file_collection = `Scotese2008` Information ----------- * Downloadable files: `rotation_model`, `static_polygons`, and `continents` * Maximum reconstruction time: Citations --------- * Scotese, C.R. 2008. The PALEOMAP Project PaleoAtlas for ArcGIS, Volume 2, Cretaceous paleogeographic and plate tectonic reconstructions. PALEOMAP Project, Arlington, Texas. - __Golonka et al. 2007__: file_collection = `Golonka2007` Information ----------- * Downloadable files: `rotation_model`, `static_polygons`, and `continents` * Maximum reconstruction time: 410 Ma Citations --------- * Golonka, J. 2007. Late Triassic and Early Jurassic palaeogeography of the world. Palaeogeography, Palaeoclimatology, Palaeoecology 244(1–4), 297–307. - __Clennett et al. 2020 (based on Müller et al. 2019)__: file_collection = `Clennett2020_M2019` Information ----------- * Downloadable files: `rotation_model`, `topology_features`, `continents` and `coastlines` * Maximum reconstruction time: 170 Ma Citations --------- * Clennett, E.J., Sigloch, K., Mihalynuk, M.G., Seton, M., Henderson, M.A., Hosseini, K., Mohammadzaheri, A., Johnston, S.T., Müller, R.D., (2020), A Quantitative Tomotectonic Plate Reconstruction of Western North America and the Eastern Pacific Basin. Geochemistry, Geophysics, Geosystems, 21, e2020GC009117. DOI: https://doi.org/10.1029/2020GC009117 - __Clennett et al. 2020 (rigid topological model based on Shephard et al, 2013)__: file_collection = `Clennett2020_S2013` Information ----------- * Downloadable files: `rotation_model`, `topology_features`, `continents` and `coastlines` * Maximum reconstruction time: 170 Citations --------- * Clennett, E.J., Sigloch, K., Mihalynuk, M.G., Seton, M., Henderson, M.A., Hosseini, K., Mohammadzaheri, A., Johnston, S.T., Müller, R.D., (2020), A Quantitative Tomotectonic Plate Reconstruction of Western North America and the Eastern Pacific Basin. Geochemistry, Geophysics, Geosystems, 21, e2020GC009117. DOI: https://doi.org/10.1029/2020GC009117 - __Müller et al. 2008__: file_collection = `Muller2008` Information ----------- * Downloadable files: `rotation_model`, `static_polygons` * Maximum reconstruction time: 141 Ma Citations --------- * Müller, R. D., Sdrolias, M., Gaina, C., & Roest, W. R. (2008). Age, spreading rates, and spreading asymmetry of the world's ocean crust. Geochemistry, Geophysics, Geosystems, 9(4). - __Müller et al. 2022__: file_collection = `Muller2022` Information ----------- * Downloadable files: `rotation_model`, `topology_features`, `static_polygons`, `continents`, `coastlines` and `COBs` * Maximum reconstruction time: 1000 Ma Citations --------- * Müller, R. D., Flament, N., Cannon, J., Tetley, M. G., Williams, S. E., Cao, X., Bodur, Ö. F., Zahirovic, S., and Merdith, A.: A tectonic-rules-based mantle reference frame since 1 billion years ago – implications for supercontinent cycles and plate–mantle system evolution, Solid Earth, 13, 1127–1159, https://doi.org/10.5194/se-13-1127-2022, 2022. - __Scotese 2016__: file_collection = `Scotese2016` Information ----------- * Downloadable files: `rotation_model`, `static_polygons`, `coastlines` * Maximum reconstruction time: 410 Ma Citations --------- * Scotese, C.R., 2016. PALEOMAP PaleoAtlas for GPlates and the PaleoData Plotter Program, PALEOMAP Project, http://www.earthbyte.org/paleomappaleoatlas-for-gplates/ - __Shephard et al. 2013__: file_collection = `Shephard2013` Information ----------- * Downloadable files: `rotation_model`, `topology_features`, `static_polygons`, `coastlines` * Maximum reconstruction time: 200 Ma Citations --------- * Shephard, G.E., Müller, R.D., and Seton, M., 2013. The tectonic evolution of the Arctic since Pangea breakup: Integrating constraints from surface geology and geophysics with mantle structure. Earth-Science Reviews, Volume 124 p.148-183. doi:10.1016/j.earscirev.2013.05.012 (http://www.sciencedirect.com/science/article/pii/S0012825213001104) * M. Seton, R.D. Müller, S. Zahirovic, C. Gaina, T.H. Torsvik, G. Shephard, A. Talsma, M. Gurnis, M. Turner, S. Maus, M. Chandler, Global continental and ocean basin reconstructions since 200 Ma, Earth-Science Reviews, Volume 113, p.212-270 doi:10.1016/j.earscirev.2012.03.002. (http://www.sciencedirect.com/science/article/pii/S0012825212000311) Parameters ---------- file_collection : str name of file collection to use verbose : bool, default True Toggle print messages regarding server/internet connection status, file availability etc. """ def __init__(self, file_collection, verbose=True): self.file_collection = file_collection.capitalize() self.data_collection = DataCollection(self.file_collection) if str(type(verbose)) == "<class 'bool'>": self.verbose = verbose else: raise ValueError("The verbose toggle must be of Boolean type, not {}".format(type(verbose))) def get_plate_reconstruction_files(self): """Downloads and constructs a `rotation model`, a set of `topology_features` and and a set of `static_polygons` needed to call the `PlateReconstruction` object. Returns ------- rotation_model : instance of <pygplates.RotationModel> A rotation model to query equivalent and/or relative topological plate rotations from a time in the past relative to another time in the past or to present day. topology_features : instance of <pygplates.FeatureCollection> Point, polyline and/or polygon feature data that are reconstructable through geological time. static_polygons : instance of <pygplates.FeatureCollection> Present-day polygons whose shapes do not change through geological time. They are used to cookie-cut dynamic polygons into identifiable topological plates (assigned an ID) according to their present-day locations. Notes ----- This method accesses the plate reconstruction model ascribed to the `file_collection` string passed into the `DataServer` object. For example, if the object was called with `"Muller2019"`: gDownload = gplately.download.DataServer("Muller2019") rotation_model, topology_features, static_polygons = gDownload.get_plate_reconstruction_files() the method will download a `rotation_model`, `topology_features` and `static_polygons` from the Müller et al. (2019) plate reconstruction model. Once the reconstruction objects are returned, they can be passed into: model = gplately.reconstruction.PlateReconstruction(rotation_model, topology_features, static_polygons) * Note: If the requested plate model does not have a certain file(s), a message will be printed to alert the user. For example, using `get_plate_reconstruction_files()` for the Torsvik and Cocks (2017) plate reconstruction model yields the printed message: No topology features in TorsvikCocks2017. No FeatureCollection created - unable to plot trenches, ridges and transforms. No continent-ocean boundaries in TorsvikCocks2017. """ verbose = self.verbose rotation_filenames = [] rotation_model = [] topology_filenames = [] topology_features = _FeatureCollection() static_polygons= _FeatureCollection() static_polygon_filenames = [] # Locate all plate reconstruction files from GPlately's DataCollection database = DataCollection.plate_reconstruction_files(self) # Set to true if we find the given collection in our database found_collection = False for collection, url in database.items(): # Only continue if the user's chosen collection exists in our database if self.file_collection.lower() == collection.lower(): found_collection = True if len(url) == 1: fnames = _collection_sorter( download_from_web(url[0], verbose, model_name=self.file_collection), self.file_collection ) rotation_filenames = _collect_file_extension( _str_in_folder( _str_in_filename(fnames, strings_to_include=DataCollection.rotation_strings_to_include(self), strings_to_ignore=DataCollection.rotation_strings_to_ignore(self), file_collection=self.file_collection, file_collection_sensitive=True ), strings_to_ignore=DataCollection.rotation_strings_to_ignore(self) ), [".rot"] ) #print(rotation_filenames) rotation_model = _RotationModel(rotation_filenames) topology_filenames = _collect_file_extension( _str_in_folder( _str_in_filename(fnames, strings_to_include=DataCollection.dynamic_polygon_strings_to_include(self), strings_to_ignore=DataCollection.dynamic_polygon_strings_to_ignore(self), file_collection=self.file_collection, file_collection_sensitive=False, ), strings_to_ignore=DataCollection.dynamic_polygon_strings_to_ignore(self) ), [".gpml", ".gpmlz"] ) #print(topology_filenames) for file in topology_filenames: topology_features.add(_FeatureCollection(file)) static_polygon_filenames = _check_gpml_or_shp( _str_in_folder( _str_in_filename(fnames, strings_to_include=DataCollection.static_polygon_strings_to_include(self), strings_to_ignore=DataCollection.static_polygon_strings_to_ignore(self), file_collection=self.file_collection, file_collection_sensitive=False ), strings_to_ignore=DataCollection.static_polygon_strings_to_ignore(self) ) ) #print(static_polygon_filenames) for stat in static_polygon_filenames: static_polygons.add(_FeatureCollection(stat)) else: for file in url[0]: rotation_filenames.append(_collect_file_extension(download_from_web(file, verbose, model_name=self.file_collection), [".rot"])) rotation_model = _RotationModel(rotation_filenames) for file in url[1]: topology_filenames.append(_collect_file_extension(download_from_web(file, verbose, model_name=self.file_collection), [".gpml"])) for file in topology_filenames: topology_features.add(_FeatureCollection(file)) for file in url[2]: static_polygon_filenames.append( _check_gpml_or_shp( _str_in_folder( _str_in_filename(download_from_web(url[0], verbose, model_name=self.file_collection), strings_to_include=DataCollection.static_polygon_strings_to_include(self) ), strings_to_ignore=DataCollection.static_polygon_strings_to_ignore(self) ) ) ) for stat in static_polygon_filenames: static_polygons.add(_FeatureCollection(stat)) break if found_collection is False: raise ValueError("{} is not in GPlately's DataServer.".format(self.file_collection)) if not rotation_filenames: print("No .rot files in {}. No rotation model created.".format(self.file_collection)) rotation_model = [] if not topology_filenames: print("No topology features in {}. No FeatureCollection created - unable to plot trenches, ridges and transforms.".format(self.file_collection)) topology_features = [] if not static_polygons: print("No static polygons in {}.".format(self.file_collection)) static_polygons = [] # add identifier for setting up DownloadServer independently rotation_model.reconstruction_identifier = self.file_collection return rotation_model, topology_features, static_polygons def get_topology_geometries(self): """Uses Pooch to download coastline, continent and COB (continent-ocean boundary) Shapely geometries from the requested plate model. These are needed to call the `PlotTopologies` object and visualise topological plates through time. Parameters ---------- verbose : bool, default True Toggle print messages regarding server/internet connection status, file availability etc. Returns ------- coastlines : instance of <pygplates.FeatureCollection> Present-day global coastline Shapely polylines cookie-cut using static polygons. Ready for reconstruction to a particular geological time and for plotting. continents : instance of <pygplates.FeatureCollection> Cookie-cutting Shapely polygons for non-oceanic regions (continents, inta-oceanic arcs, etc.) ready for reconstruction to a particular geological time and for plotting. COBs : instance of <pygplates.FeatureCollection> Shapely polylines resolved from .shp and/or .gpml topology files that represent the locations of the boundaries between oceanic and continental crust. Ready for reconstruction to a particular geological time and for plotting. Notes ----- This method accesses the plate reconstruction model ascribed to the `file_collection` string passed into the `DataServer` object. For example, if the object was called with `"Muller2019"`: gDownload = gplately.download.DataServer("Muller2019") coastlines, continents, COBs = gDownload.get_topology_geometries() the method will attempt to download `coastlines`, `continents` and `COBs` from the Müller et al. (2019) plate reconstruction model. If found, these files are returned as individual pyGPlates Feature Collections. They can be passed into: gPlot = gplately.plot.PlotTopologies(gplately.reconstruction.PlateReconstruction, time, continents, coastlines, COBs) to reconstruct features to a certain geological time. The `PlotTopologies` object provides simple methods to plot these geometries along with trenches, ridges and transforms (see documentation for more info). Note that the `PlateReconstruction` object is a parameter. * Note: If the requested plate model does not have a certain geometry, a message will be printed to alert the user. For example, if `get_topology_geometries()` is used with the `"Matthews2016"` plate model, the workflow will print the following message: No continent-ocean boundaries in Matthews2016. """ verbose = self.verbose # Locate all topology geometries from GPlately's DataCollection database = DataCollection.topology_geometries(self) coastlines = [] continents = [] COBs = [] # Find the requested plate model data collection found_collection = False for collection, url in database.items(): if self.file_collection.lower() == collection.lower(): found_collection = True if len(url) == 1: # Some plate models do not have reconstructable geometries i.e. Li et al. 2008 if url[0] is None: break else: fnames = _collection_sorter( download_from_web(url[0], verbose, model_name=self.file_collection), self.file_collection ) coastlines = _check_gpml_or_shp( _str_in_folder( _str_in_filename( fnames, strings_to_include=DataCollection.coastline_strings_to_include(self), strings_to_ignore=DataCollection.coastline_strings_to_ignore(self), file_collection=self.file_collection, file_collection_sensitive=False ), strings_to_ignore=DataCollection.coastline_strings_to_ignore(self) ) ) continents = _check_gpml_or_shp( _str_in_folder( _str_in_filename( fnames, strings_to_include=DataCollection.continent_strings_to_include(self), strings_to_ignore=DataCollection.continent_strings_to_ignore(self), file_collection=self.file_collection, file_collection_sensitive=False ), strings_to_ignore=DataCollection.continent_strings_to_ignore(self) ) ) COBs = _check_gpml_or_shp( _str_in_folder( _str_in_filename( fnames, strings_to_include=DataCollection.COB_strings_to_include(self), strings_to_ignore=DataCollection.COB_strings_to_ignore(self), file_collection=self.file_collection, file_collection_sensitive=False ), strings_to_ignore=DataCollection.COB_strings_to_ignore(self) ) ) else: for file in url[0]: if url[0] is not None: coastlines.append(_str_in_filename( download_from_web(file, verbose, model_name=self.file_collection), strings_to_include=["coastline"]) ) coastlines = _check_gpml_or_shp(coastlines) else: coastlines = [] for file in url[1]: if url[1] is not None: continents.append(_str_in_filename( download_from_web(file, verbose, model_name=self.file_collection), strings_to_include=["continent"]) ) continents = _check_gpml_or_shp(continents) else: continents = [] for file in url[2]: if url[2] is not None: COBs.append(_str_in_filename( download_from_web(file, verbose, model_name=self.file_collection), strings_to_include=["cob"]) ) COBs = _check_gpml_or_shp(COBs) else: COBs = [] break if found_collection is False: raise ValueError("{} is not in GPlately's DataServer.".format(self.file_collection)) if not coastlines: print("No coastlines in {}.".format(self.file_collection)) coastlines_featurecollection = [] else: #print(coastlines) coastlines_featurecollection = _FeatureCollection() for coastline in coastlines: coastlines_featurecollection.add(_FeatureCollection(coastline)) if not continents: print("No continents in {}.".format(self.file_collection)) continents_featurecollection = [] else: #print(continents) continents_featurecollection = _FeatureCollection() for continent in continents: continents_featurecollection.add(_FeatureCollection(continent)) if not COBs: print("No continent-ocean boundaries in {}.".format(self.file_collection)) COBs_featurecollection = [] else: #print(COBs) COBs_featurecollection = _FeatureCollection() for COB in COBs: COBs_featurecollection.add(_FeatureCollection(COB)) geometries = coastlines_featurecollection, continents_featurecollection, COBs_featurecollection return geometries def get_age_grid(self, time): """Downloads seafloor and paleo-age grids from the plate reconstruction model (`file_collection`) passed into the `DataServer` object. Stores grids in the "gplately" cache. Currently, `DataServer` supports the following age grids: * __Muller et al. 2019__ * `file_collection` = `Muller2019` * Time range: 0-250 Ma * Seafloor age grid rasters in netCDF format. * __Muller et al. 2016__ * `file_collection` = `Muller2016` * Time range: 0-240 Ma * Seafloor age grid rasters in netCDF format. * __Seton et al. 2012__ * `file_collection` = `Seton2012` * Time range: 0-200 Ma * Paleo-age grid rasters in netCDF format. Parameters ---------- time : int, or list of int, default=None Request an age grid from one (an integer) or multiple reconstruction times (a list of integers). Returns ------- a gplately.Raster object A gplately.Raster object containing the age grid. The age grid data can be extracted into a numpy ndarray or MaskedArray by appending `.data` to the variable assigned to `get_age_grid()`. For example: gdownload = gplately.DataServer("Muller2019") graster = gdownload.get_age_grid(time=100) graster_data = graster.data where `graster_data` is a numpy ndarray. Raises ----- ValueError If `time` (a single integer, or a list of integers representing reconstruction times to extract the age grids from) is not passed. Notes ----- The first time that `get_age_grid` is called for a specific time(s), the age grid(s) will be downloaded into the GPlately cache once. Upon successive calls of `get_age_grid` for the same reconstruction time(s), the age grids will not be re-downloaded; rather, they are re-accessed from the same cache provided the age grid(s) have not been moved or deleted. Examples -------- if the `DataServer` object was called with the `Muller2019` `file_collection` string: gDownload = gplately.download.DataServer("Muller2019") `get_age_grid` will download seafloor age grids from the Müller et al. (2019) plate reconstruction model for the geological time(s) requested in the `time` parameter. If found, these age grids are returned as masked arrays. For example, to download Müller et al. (2019) seafloor age grids for 0Ma, 1Ma and 100 Ma: age_grids = gDownload.get_age_grid([0, 1, 100]) """ age_grids = [] age_grid_links = DataCollection.netcdf4_age_grids(self, time) if not isinstance(time, list): time = [time] # For a single time passed that isn't in the valid time range, if not age_grid_links: raise ValueError( "{} {}Ma age grids are not on GPlately's DataServer.".format( self.file_collection, time[0] ) ) # For a list of times passed... for i, link in enumerate(age_grid_links): if not link: raise ValueError( "{} {}Ma age grids are not on GPlately's DataServer.".format( self.file_collection, time[i] ) ) age_grid_file = download_from_web( link, verbose=self.verbose, model_name=self.file_collection ) age_grid = _gplately.grids.Raster(data=age_grid_file) age_grids.append(age_grid) # One last check to alert user if the masked array grids were not processed properly if not age_grids: raise ValueError("{} netCDF4 age grids not found.".format(self.file_collection)) if len(age_grids) == 1: return age_grids[0] else: return age_grids def get_spreading_rate_grid(self, time): """Downloads seafloor spreading rate grids from the plate reconstruction model (`file_collection`) passed into the `DataServer` object. Stores grids in the "gplately" cache. Currently, `DataServer` supports spreading rate grids from the following plate models: * __Clennett et al. 2020__ * `file_collection` = `Clennett2020` * Time range: 0-250 Ma * Seafloor spreading rate grids in netCDF format. Parameters ---------- time : int, or list of int, default=None Request a spreading grid from one (an integer) or multiple reconstruction times (a list of integers). Returns ------- a gplately.Raster object A gplately.Raster object containing the spreading rate grid. The spreading rate grid data can be extracted into a numpy ndarray or MaskedArray by appending `.data` to the variable assigned to `get_spreading_rate_grid()`. For example: gdownload = gplately.DataServer("Clennett2020") graster = gdownload.get_spreading_rate_grid(time=100) graster_data = graster.data where `graster_data` is a numpy ndarray. Raises ----- ValueError If `time` (a single integer, or a list of integers representing reconstruction times to extract the spreading rate grids from) is not passed. Notes ----- The first time that `get_spreading_rate_grid` is called for a specific time(s), the spreading rate grid(s) will be downloaded into the GPlately cache once. Upon successive calls of `get_spreading_rate_grid` for the same reconstruction time(s), the grids will not be re-downloaded; rather, they are re-accessed from the same cache location provided they have not been moved or deleted. Examples -------- if the `DataServer` object was called with the `Clennett2020` `file_collection` string: gDownload = gplately.download.DataServer("Clennett2020") `get_spreading_rate_grid` will download seafloor spreading rate grids from the Clennett et al. (2020) plate reconstruction model for the geological time(s) requested in the `time` parameter. When found, these spreading rate grids are returned as masked arrays. For example, to download Clennett et al. (2020) seafloor spreading rate grids for 0Ma, 1Ma and 100 Ma as MaskedArray objects: spreading_rate_grids = gDownload.get_spreading_rate_grid([0, 1, 100]) """ spreading_rate_grids = [] spreading_rate_grid_links = DataCollection.netcdf4_spreading_rate_grids(self, time) if not isinstance(time, list): time = [time] # For a single time passed that isn't in the valid time range, if not spreading_rate_grid_links: raise ValueError( "{} {}Ma spreading rate grids are not on GPlately's DataServer.".format( self.file_collection, time[0] ) ) # For a list of times passed... for i, link in enumerate(spreading_rate_grid_links): if not link: raise ValueError( "{} {}Ma spreading rate grids are not on GPlately's DataServer.".format( self.file_collection, time[i] ) ) spreading_rate_grid_file = download_from_web( link, verbose=self.verbose, model_name=self.file_collection ) spreading_rate_grid = _gplately.grids.Raster(data=spreading_rate_grid_file) spreading_rate_grids.append(spreading_rate_grid) # One last check to alert user if the masked array grids were not processed properly if not spreading_rate_grids: raise ValueError("{} netCDF4 seafloor spreading rate grids not found.".format(self.file_collection)) if len(spreading_rate_grids) == 1: return spreading_rate_grids[0] else: return spreading_rate_grids def get_valid_times(self): """Returns a tuple of the valid plate model time range, (min_time, max_time). """ all_model_valid_times = DataCollection.plate_model_valid_reconstruction_times(self) min_time = None max_time = None for plate_model_name, valid_times in list(all_model_valid_times.items()): if plate_model_name.lower() == self.file_collection.lower(): min_time = valid_times[0] max_time = valid_times[1] if not min_time and not max_time: raise ValueError("Could not find the valid reconstruction time of {}".format(self.file_collection)) return (min_time, max_time) def get_raster(self, raster_id_string=None): """Downloads assorted raster data that are not associated with the plate reconstruction models supported by GPlately's `DataServer`. Stores rasters in the "gplately" cache. Currently, `DataServer` supports the following rasters and images: * __[ETOPO1](https://www.ngdc.noaa.gov/mgg/global/)__: * Filetypes available : TIF, netCDF (GRD) * `raster_id_string` = `"ETOPO1_grd"`, `"ETOPO1_tif"` (depending on the requested format) * A 1-arc minute global relief model combining lang topography and ocean bathymetry. * Citation: doi:10.7289/V5C8276M Parameters ---------- raster_id_string : str, default=None A string to identify which raster to download. Returns ------- a gplately.Raster object A gplately.Raster object containing the raster data. The gridded data can be extracted into a numpy ndarray or MaskedArray by appending `.data` to the variable assigned to `get_raster()`. For example: gdownload = gplately.DataServer("Muller2019") graster = gdownload.get_raster(raster_id_string, verbose) graster_data = graster.data where `graster_data` is a numpy ndarray. This array can be visualised using `matplotlib.pyplot.imshow` on a `cartopy.mpl.GeoAxis` GeoAxesSubplot (see example below). Raises ------ ValueError * if a `raster_id_string` is not supplied. Notes ----- Rasters obtained by this method are (so far) only reconstructed to present-day. Examples -------- To download ETOPO1 and plot it on a Mollweide projection: import gplately import numpy as np import matplotlib.pyplot as plt import cartopy.crs as ccrs gdownload = gplately.DataServer("Muller2019") etopo1 = gdownload.get_raster("ETOPO1_tif") fig = plt.figure(figsize=(18,14), dpi=300) ax = fig.add_subplot(111, projection=ccrs.Mollweide(central_longitude = -150)) ax2.imshow(etopo1, extent=[-180,180,-90,90], transform=ccrs.PlateCarree()) """ return get_raster(raster_id_string, self.verbose) def get_feature_data(self, feature_data_id_string=None): """Downloads assorted geological feature data from web servers (i.e. [GPlates 2.3 sample data](https://www.earthbyte.org/gplates-2-3-software-and-data-sets/)) into the "gplately" cache. Currently, `DataServer` supports the following feature data: * __Large igneous provinces from Johansson et al. (2018)__ Information ----------- * Formats: .gpmlz * `feature_data_id_string` = `Johansson2018` Citations --------- * Johansson, L., Zahirovic, S., and Müller, R. D., In Prep, The interplay between the eruption and weathering of Large Igneous Provinces and the deep-time carbon cycle: Geophysical Research Letters. - __Large igneous province products interpreted as plume products from Whittaker et al. (2015)__. Information ----------- * Formats: .gpmlz, .shp * `feature_data_id_string` = `Whittaker2015` Citations --------- * Whittaker, J. M., Afonso, J. C., Masterton, S., Müller, R. D., Wessel, P., Williams, S. E., & Seton, M. (2015). Long-term interaction between mid-ocean ridges and mantle plumes. Nature Geoscience, 8(6), 479-483. doi:10.1038/ngeo2437. - __Seafloor tectonic fabric (fracture zones, discordant zones, V-shaped structures, unclassified V-anomalies, propagating ridge lineations and extinct ridges) from Matthews et al. (2011)__ Information ----------- * Formats: .gpml * `feature_data_id_string` = `SeafloorFabric` Citations --------- * Matthews, K.J., Müller, R.D., Wessel, P. and Whittaker, J.M., 2011. The tectonic fabric of the ocean basins. Journal of Geophysical Research, 116(B12): B12109, DOI: 10.1029/2011JB008413. - __Present day surface hotspot/plume locations from Whittaker et al. (2013)__ Information ----------- * Formats: .gpmlz * `feature_data_id_string` = `Hotspots` Citation -------- * Whittaker, J., Afonso, J., Masterton, S., Müller, R., Wessel, P., Williams, S., and Seton, M., 2015, Long-term interaction between mid-ocean ridges and mantle plumes: Nature Geoscience, v. 8, no. 6, p. 479-483, doi:10.1038/ngeo2437. Parameters ---------- feature_data_id_string : str, default=None A string to identify which feature data to download to the cache (see list of supported feature data above). Returns ------- feature_data_filenames : instance of <pygplates.FeatureCollection>, or list of instance <pygplates.FeatureCollection> If a single set of feature data is downloaded, a single pyGPlates `FeatureCollection` object is returned. Otherwise, a list containing multiple pyGPlates `FeatureCollection` objects is returned (like for `SeafloorFabric`). In the latter case, feature reconstruction and plotting may have to be done iteratively. Raises ------ ValueError If a `feature_data_id_string` is not provided. Examples -------- For examples of plotting data downloaded with `get_feature_data`, see GPlately's sample notebook 05 - Working With Feature Geometries [here](https://github.com/GPlates/gplately/blob/master/Notebooks/05-WorkingWithFeatureGeometries.ipynb). """ if feature_data_id_string is None: raise ValueError( "Please specify which feature data to fetch." ) database = _gplately.data._feature_data() found_collection = False for collection, zip_url in database.items(): if feature_data_id_string.lower() == collection.lower(): found_collection = True feature_data_filenames = _collection_sorter( _collect_file_extension( download_from_web(zip_url[0], self.verbose), [".gpml", ".gpmlz"] ), collection ) break if found_collection is False: raise ValueError("{} are not in GPlately's DataServer.".format(feature_data_id_string)) feat_data = _FeatureCollection() if len(feature_data_filenames) == 1: feat_data.add(_FeatureCollection(feature_data_filenames[0])) return feat_data else: feat_data=[] for file in feature_data_filenames: feat_data.append(_FeatureCollection(file)) return feat_dataMethods- def get_age_grid(self, time)
- 
Downloads seafloor and paleo-age grids from the plate reconstruction model ( file_collection) passed into theDataServerobject. Stores grids in the "gplately" cache.Currently, DataServersupports the following age grids:- 
Muller et al. 2019 - file_collection=- Muller2019
- Time range: 0-250 Ma
- Seafloor age grid rasters in netCDF format.
 
- 
Muller et al. 2016 - file_collection=- Muller2016
- Time range: 0-240 Ma
- Seafloor age grid rasters in netCDF format.
 
- 
Seton et al. 2012 - file_collection=- Seton2012
- Time range: 0-200 Ma
- Paleo-age grid rasters in netCDF format.
 
 Parameters- time:- int,or- listof- int, default=- None
- Request an age grid from one (an integer) or multiple reconstruction times (a list of integers).
 Returns- a Raster object
- 
A gplately.Raster object containing the age grid. The age grid data can be extracted into a numpy ndarray or MaskedArray by appending .datato the variable assigned toget_age_grid().For example: gdownload = gplately.DataServer("Muller2019") graster = gdownload.get_age_grid(time=100) graster_data = graster.datawhere graster_datais a numpy ndarray.
 Raises- ValueError
- If time(a single integer, or a list of integers representing reconstruction times to extract the age grids from) is not passed.
 NotesThe first time that get_age_gridis called for a specific time(s), the age grid(s) will be downloaded into the GPlately cache once. Upon successive calls ofget_age_gridfor the same reconstruction time(s), the age grids will not be re-downloaded; rather, they are re-accessed from the same cache provided the age grid(s) have not been moved or deleted.Examplesif the DataServerobject was called with theMuller2019file_collectionstring:gDownload = gplately.download.DataServer("Muller2019")get_age_gridwill download seafloor age grids from the Müller et al. (2019) plate reconstruction model for the geological time(s) requested in thetimeparameter. If found, these age grids are returned as masked arrays.For example, to download Müller et al. (2019) seafloor age grids for 0Ma, 1Ma and 100 Ma: age_grids = gDownload.get_age_grid([0, 1, 100])Expand source codedef get_age_grid(self, time): """Downloads seafloor and paleo-age grids from the plate reconstruction model (`file_collection`) passed into the `DataServer` object. Stores grids in the "gplately" cache. Currently, `DataServer` supports the following age grids: * __Muller et al. 2019__ * `file_collection` = `Muller2019` * Time range: 0-250 Ma * Seafloor age grid rasters in netCDF format. * __Muller et al. 2016__ * `file_collection` = `Muller2016` * Time range: 0-240 Ma * Seafloor age grid rasters in netCDF format. * __Seton et al. 2012__ * `file_collection` = `Seton2012` * Time range: 0-200 Ma * Paleo-age grid rasters in netCDF format. Parameters ---------- time : int, or list of int, default=None Request an age grid from one (an integer) or multiple reconstruction times (a list of integers). Returns ------- a gplately.Raster object A gplately.Raster object containing the age grid. The age grid data can be extracted into a numpy ndarray or MaskedArray by appending `.data` to the variable assigned to `get_age_grid()`. For example: gdownload = gplately.DataServer("Muller2019") graster = gdownload.get_age_grid(time=100) graster_data = graster.data where `graster_data` is a numpy ndarray. Raises ----- ValueError If `time` (a single integer, or a list of integers representing reconstruction times to extract the age grids from) is not passed. Notes ----- The first time that `get_age_grid` is called for a specific time(s), the age grid(s) will be downloaded into the GPlately cache once. Upon successive calls of `get_age_grid` for the same reconstruction time(s), the age grids will not be re-downloaded; rather, they are re-accessed from the same cache provided the age grid(s) have not been moved or deleted. Examples -------- if the `DataServer` object was called with the `Muller2019` `file_collection` string: gDownload = gplately.download.DataServer("Muller2019") `get_age_grid` will download seafloor age grids from the Müller et al. (2019) plate reconstruction model for the geological time(s) requested in the `time` parameter. If found, these age grids are returned as masked arrays. For example, to download Müller et al. (2019) seafloor age grids for 0Ma, 1Ma and 100 Ma: age_grids = gDownload.get_age_grid([0, 1, 100]) """ age_grids = [] age_grid_links = DataCollection.netcdf4_age_grids(self, time) if not isinstance(time, list): time = [time] # For a single time passed that isn't in the valid time range, if not age_grid_links: raise ValueError( "{} {}Ma age grids are not on GPlately's DataServer.".format( self.file_collection, time[0] ) ) # For a list of times passed... for i, link in enumerate(age_grid_links): if not link: raise ValueError( "{} {}Ma age grids are not on GPlately's DataServer.".format( self.file_collection, time[i] ) ) age_grid_file = download_from_web( link, verbose=self.verbose, model_name=self.file_collection ) age_grid = _gplately.grids.Raster(data=age_grid_file) age_grids.append(age_grid) # One last check to alert user if the masked array grids were not processed properly if not age_grids: raise ValueError("{} netCDF4 age grids not found.".format(self.file_collection)) if len(age_grids) == 1: return age_grids[0] else: return age_grids
- 
- def get_feature_data(self, feature_data_id_string=None)
- 
Downloads assorted geological feature data from web servers (i.e. GPlates 2.3 sample data) into the "gplately" cache. Currently, DataServersupports the following feature data:- 
Large igneous provinces from Johansson et al. (2018) Information- Formats: .gpmlz
- feature_data_id_string=- Johansson2018
 Citations- Johansson, L., Zahirovic, S., and Müller, R. D., In Prep, The interplay between the eruption and weathering of Large Igneous Provinces and the deep-time carbon cycle: Geophysical Research Letters.
 
- 
Large igneous province products interpreted as plume products from Whittaker et al. (2015). Information- Formats: .gpmlz, .shp
- feature_data_id_string=- Whittaker2015
 Citations- Whittaker, J. M., Afonso, J. C., Masterton, S., Müller, R. D., Wessel, P., Williams, S. E., & Seton, M. (2015). Long-term interaction between mid-ocean ridges and mantle plumes. Nature Geoscience, 8(6), 479-483. doi:10.1038/ngeo2437.
 
- 
Seafloor tectonic fabric (fracture zones, discordant zones, V-shaped structures, unclassified V-anomalies, propagating ridge lineations and extinct ridges) from Matthews et al. (2011) Information- Formats: .gpml
- feature_data_id_string=- SeafloorFabric
 Citations- Matthews, K.J., Müller, R.D., Wessel, P. and Whittaker, J.M., 2011. The tectonic fabric of the ocean basins. Journal of Geophysical Research, 116(B12): B12109, DOI: 10.1029/2011JB008413.
 
- 
Present day surface hotspot/plume locations from Whittaker et al. (2013) Information- Formats: .gpmlz
- feature_data_id_string=- Hotspots
 Citation- Whittaker, J., Afonso, J., Masterton, S., Müller, R., Wessel, P., Williams, S., and Seton, M., 2015, Long-term interaction between mid-ocean ridges and mantle plumes: Nature Geoscience, v. 8, no. 6, p. 479-483, doi:10.1038/ngeo2437.
 
 Parameters- feature_data_id_string:- str, default=- None
- A string to identify which feature data to download to the cache (see list of supported feature data above).
 Returns- feature_data_filenames:- instanceof- <pygplates.FeatureCollection>,or- listof- instance <pygplates.FeatureCollection>
- If a single set of feature data is downloaded, a single pyGPlates FeatureCollectionobject is returned. Otherwise, a list containing multiple pyGPlatesFeatureCollectionobjects is returned (like forSeafloorFabric). In the latter case, feature reconstruction and plotting may have to be done iteratively.
 Raises- ValueError
- If a feature_data_id_stringis not provided.
 ExamplesFor examples of plotting data downloaded with get_feature_data(), see GPlately's sample notebook 05 - Working With Feature Geometries here.Expand source codedef get_feature_data(self, feature_data_id_string=None): """Downloads assorted geological feature data from web servers (i.e. [GPlates 2.3 sample data](https://www.earthbyte.org/gplates-2-3-software-and-data-sets/)) into the "gplately" cache. Currently, `DataServer` supports the following feature data: * __Large igneous provinces from Johansson et al. (2018)__ Information ----------- * Formats: .gpmlz * `feature_data_id_string` = `Johansson2018` Citations --------- * Johansson, L., Zahirovic, S., and Müller, R. D., In Prep, The interplay between the eruption and weathering of Large Igneous Provinces and the deep-time carbon cycle: Geophysical Research Letters. - __Large igneous province products interpreted as plume products from Whittaker et al. (2015)__. Information ----------- * Formats: .gpmlz, .shp * `feature_data_id_string` = `Whittaker2015` Citations --------- * Whittaker, J. M., Afonso, J. C., Masterton, S., Müller, R. D., Wessel, P., Williams, S. E., & Seton, M. (2015). Long-term interaction between mid-ocean ridges and mantle plumes. Nature Geoscience, 8(6), 479-483. doi:10.1038/ngeo2437. - __Seafloor tectonic fabric (fracture zones, discordant zones, V-shaped structures, unclassified V-anomalies, propagating ridge lineations and extinct ridges) from Matthews et al. (2011)__ Information ----------- * Formats: .gpml * `feature_data_id_string` = `SeafloorFabric` Citations --------- * Matthews, K.J., Müller, R.D., Wessel, P. and Whittaker, J.M., 2011. The tectonic fabric of the ocean basins. Journal of Geophysical Research, 116(B12): B12109, DOI: 10.1029/2011JB008413. - __Present day surface hotspot/plume locations from Whittaker et al. (2013)__ Information ----------- * Formats: .gpmlz * `feature_data_id_string` = `Hotspots` Citation -------- * Whittaker, J., Afonso, J., Masterton, S., Müller, R., Wessel, P., Williams, S., and Seton, M., 2015, Long-term interaction between mid-ocean ridges and mantle plumes: Nature Geoscience, v. 8, no. 6, p. 479-483, doi:10.1038/ngeo2437. Parameters ---------- feature_data_id_string : str, default=None A string to identify which feature data to download to the cache (see list of supported feature data above). Returns ------- feature_data_filenames : instance of <pygplates.FeatureCollection>, or list of instance <pygplates.FeatureCollection> If a single set of feature data is downloaded, a single pyGPlates `FeatureCollection` object is returned. Otherwise, a list containing multiple pyGPlates `FeatureCollection` objects is returned (like for `SeafloorFabric`). In the latter case, feature reconstruction and plotting may have to be done iteratively. Raises ------ ValueError If a `feature_data_id_string` is not provided. Examples -------- For examples of plotting data downloaded with `get_feature_data`, see GPlately's sample notebook 05 - Working With Feature Geometries [here](https://github.com/GPlates/gplately/blob/master/Notebooks/05-WorkingWithFeatureGeometries.ipynb). """ if feature_data_id_string is None: raise ValueError( "Please specify which feature data to fetch." ) database = _gplately.data._feature_data() found_collection = False for collection, zip_url in database.items(): if feature_data_id_string.lower() == collection.lower(): found_collection = True feature_data_filenames = _collection_sorter( _collect_file_extension( download_from_web(zip_url[0], self.verbose), [".gpml", ".gpmlz"] ), collection ) break if found_collection is False: raise ValueError("{} are not in GPlately's DataServer.".format(feature_data_id_string)) feat_data = _FeatureCollection() if len(feature_data_filenames) == 1: feat_data.add(_FeatureCollection(feature_data_filenames[0])) return feat_data else: feat_data=[] for file in feature_data_filenames: feat_data.append(_FeatureCollection(file)) return feat_data
- 
- def get_plate_reconstruction_files(self)
- 
Downloads and constructs a rotation model, a set oftopology_featuresand and a set ofstatic_polygonsneeded to call thePlateReconstructionobject.Returns- rotation_model:- instanceof- <pygplates.RotationModel>
- A rotation model to query equivalent and/or relative topological plate rotations from a time in the past relative to another time in the past or to present day.
- topology_features:- instanceof- <pygplates.FeatureCollection>
- Point, polyline and/or polygon feature data that are reconstructable through geological time.
- static_polygons:- instanceof- <pygplates.FeatureCollection>
- Present-day polygons whose shapes do not change through geological time. They are used to cookie-cut dynamic polygons into identifiable topological plates (assigned an ID) according to their present-day locations.
 NotesThis method accesses the plate reconstruction model ascribed to the file_collectionstring passed into theDataServerobject. For example, if the object was called with"Muller2019":gDownload = gplately.download.DataServer("Muller2019") rotation_model, topology_features, static_polygons = gDownload.get_plate_reconstruction_files()the method will download a rotation_model,topology_featuresandstatic_polygonsfrom the Müller et al. (2019) plate reconstruction model. Once the reconstruction objects are returned, they can be passed into:model = gplately.reconstruction.PlateReconstruction(rotation_model, topology_features, static_polygons)- Note: If the requested plate model does not have a certain file(s), a message will be printed
to alert the user. For example, using get_plate_reconstruction_files()for the Torsvik and Cocks (2017) plate reconstruction model yields the printed message:No topology features in TorsvikCocks2017. No FeatureCollection created - unable to plot trenches, ridges and transforms. No continent-ocean boundaries in TorsvikCocks2017.
 Expand source codedef get_plate_reconstruction_files(self): """Downloads and constructs a `rotation model`, a set of `topology_features` and and a set of `static_polygons` needed to call the `PlateReconstruction` object. Returns ------- rotation_model : instance of <pygplates.RotationModel> A rotation model to query equivalent and/or relative topological plate rotations from a time in the past relative to another time in the past or to present day. topology_features : instance of <pygplates.FeatureCollection> Point, polyline and/or polygon feature data that are reconstructable through geological time. static_polygons : instance of <pygplates.FeatureCollection> Present-day polygons whose shapes do not change through geological time. They are used to cookie-cut dynamic polygons into identifiable topological plates (assigned an ID) according to their present-day locations. Notes ----- This method accesses the plate reconstruction model ascribed to the `file_collection` string passed into the `DataServer` object. For example, if the object was called with `"Muller2019"`: gDownload = gplately.download.DataServer("Muller2019") rotation_model, topology_features, static_polygons = gDownload.get_plate_reconstruction_files() the method will download a `rotation_model`, `topology_features` and `static_polygons` from the Müller et al. (2019) plate reconstruction model. Once the reconstruction objects are returned, they can be passed into: model = gplately.reconstruction.PlateReconstruction(rotation_model, topology_features, static_polygons) * Note: If the requested plate model does not have a certain file(s), a message will be printed to alert the user. For example, using `get_plate_reconstruction_files()` for the Torsvik and Cocks (2017) plate reconstruction model yields the printed message: No topology features in TorsvikCocks2017. No FeatureCollection created - unable to plot trenches, ridges and transforms. No continent-ocean boundaries in TorsvikCocks2017. """ verbose = self.verbose rotation_filenames = [] rotation_model = [] topology_filenames = [] topology_features = _FeatureCollection() static_polygons= _FeatureCollection() static_polygon_filenames = [] # Locate all plate reconstruction files from GPlately's DataCollection database = DataCollection.plate_reconstruction_files(self) # Set to true if we find the given collection in our database found_collection = False for collection, url in database.items(): # Only continue if the user's chosen collection exists in our database if self.file_collection.lower() == collection.lower(): found_collection = True if len(url) == 1: fnames = _collection_sorter( download_from_web(url[0], verbose, model_name=self.file_collection), self.file_collection ) rotation_filenames = _collect_file_extension( _str_in_folder( _str_in_filename(fnames, strings_to_include=DataCollection.rotation_strings_to_include(self), strings_to_ignore=DataCollection.rotation_strings_to_ignore(self), file_collection=self.file_collection, file_collection_sensitive=True ), strings_to_ignore=DataCollection.rotation_strings_to_ignore(self) ), [".rot"] ) #print(rotation_filenames) rotation_model = _RotationModel(rotation_filenames) topology_filenames = _collect_file_extension( _str_in_folder( _str_in_filename(fnames, strings_to_include=DataCollection.dynamic_polygon_strings_to_include(self), strings_to_ignore=DataCollection.dynamic_polygon_strings_to_ignore(self), file_collection=self.file_collection, file_collection_sensitive=False, ), strings_to_ignore=DataCollection.dynamic_polygon_strings_to_ignore(self) ), [".gpml", ".gpmlz"] ) #print(topology_filenames) for file in topology_filenames: topology_features.add(_FeatureCollection(file)) static_polygon_filenames = _check_gpml_or_shp( _str_in_folder( _str_in_filename(fnames, strings_to_include=DataCollection.static_polygon_strings_to_include(self), strings_to_ignore=DataCollection.static_polygon_strings_to_ignore(self), file_collection=self.file_collection, file_collection_sensitive=False ), strings_to_ignore=DataCollection.static_polygon_strings_to_ignore(self) ) ) #print(static_polygon_filenames) for stat in static_polygon_filenames: static_polygons.add(_FeatureCollection(stat)) else: for file in url[0]: rotation_filenames.append(_collect_file_extension(download_from_web(file, verbose, model_name=self.file_collection), [".rot"])) rotation_model = _RotationModel(rotation_filenames) for file in url[1]: topology_filenames.append(_collect_file_extension(download_from_web(file, verbose, model_name=self.file_collection), [".gpml"])) for file in topology_filenames: topology_features.add(_FeatureCollection(file)) for file in url[2]: static_polygon_filenames.append( _check_gpml_or_shp( _str_in_folder( _str_in_filename(download_from_web(url[0], verbose, model_name=self.file_collection), strings_to_include=DataCollection.static_polygon_strings_to_include(self) ), strings_to_ignore=DataCollection.static_polygon_strings_to_ignore(self) ) ) ) for stat in static_polygon_filenames: static_polygons.add(_FeatureCollection(stat)) break if found_collection is False: raise ValueError("{} is not in GPlately's DataServer.".format(self.file_collection)) if not rotation_filenames: print("No .rot files in {}. No rotation model created.".format(self.file_collection)) rotation_model = [] if not topology_filenames: print("No topology features in {}. No FeatureCollection created - unable to plot trenches, ridges and transforms.".format(self.file_collection)) topology_features = [] if not static_polygons: print("No static polygons in {}.".format(self.file_collection)) static_polygons = [] # add identifier for setting up DownloadServer independently rotation_model.reconstruction_identifier = self.file_collection return rotation_model, topology_features, static_polygons
- def get_raster(self, raster_id_string=None)
- 
Downloads assorted raster data that are not associated with the plate reconstruction models supported by GPlately's DataServer. Stores rasters in the "gplately" cache.Currently, DataServersupports the following rasters and images:- ETOPO1: - Filetypes available : TIF, netCDF (GRD)
- raster_id_string=- "ETOPO1_grd",- "ETOPO1_tif"(depending on the requested format)
- A 1-arc minute global relief model combining lang topography and ocean bathymetry.
- Citation: doi:10.7289/V5C8276M
 
 Parameters- raster_id_string:- str, default=- None
- A string to identify which raster to download.
 Returns- a Raster object
- 
A gplately.Raster object containing the raster data. The gridded data can be extracted into a numpy ndarray or MaskedArray by appending .datato the variable assigned toget_raster().For example: gdownload = gplately.DataServer("Muller2019") graster = gdownload.get_raster(raster_id_string, verbose) graster_data = graster.datawhere graster_datais a numpy ndarray. This array can be visualised usingmatplotlib.pyplot.imshowon acartopy.mpl.GeoAxisGeoAxesSubplot (see example below).
 Raises- ValueError
- 
- if a raster_id_stringis not supplied.
 
- if a 
 NotesRasters obtained by this method are (so far) only reconstructed to present-day. ExamplesTo download ETOPO1 and plot it on a Mollweide projection: import gplately import numpy as np import matplotlib.pyplot as plt import cartopy.crs as ccrs gdownload = gplately.DataServer("Muller2019") etopo1 = gdownload.get_raster("ETOPO1_tif") fig = plt.figure(figsize=(18,14), dpi=300) ax = fig.add_subplot(111, projection=ccrs.Mollweide(central_longitude = -150)) ax2.imshow(etopo1, extent=[-180,180,-90,90], transform=ccrs.PlateCarree())Expand source codedef get_raster(self, raster_id_string=None): """Downloads assorted raster data that are not associated with the plate reconstruction models supported by GPlately's `DataServer`. Stores rasters in the "gplately" cache. Currently, `DataServer` supports the following rasters and images: * __[ETOPO1](https://www.ngdc.noaa.gov/mgg/global/)__: * Filetypes available : TIF, netCDF (GRD) * `raster_id_string` = `"ETOPO1_grd"`, `"ETOPO1_tif"` (depending on the requested format) * A 1-arc minute global relief model combining lang topography and ocean bathymetry. * Citation: doi:10.7289/V5C8276M Parameters ---------- raster_id_string : str, default=None A string to identify which raster to download. Returns ------- a gplately.Raster object A gplately.Raster object containing the raster data. The gridded data can be extracted into a numpy ndarray or MaskedArray by appending `.data` to the variable assigned to `get_raster()`. For example: gdownload = gplately.DataServer("Muller2019") graster = gdownload.get_raster(raster_id_string, verbose) graster_data = graster.data where `graster_data` is a numpy ndarray. This array can be visualised using `matplotlib.pyplot.imshow` on a `cartopy.mpl.GeoAxis` GeoAxesSubplot (see example below). Raises ------ ValueError * if a `raster_id_string` is not supplied. Notes ----- Rasters obtained by this method are (so far) only reconstructed to present-day. Examples -------- To download ETOPO1 and plot it on a Mollweide projection: import gplately import numpy as np import matplotlib.pyplot as plt import cartopy.crs as ccrs gdownload = gplately.DataServer("Muller2019") etopo1 = gdownload.get_raster("ETOPO1_tif") fig = plt.figure(figsize=(18,14), dpi=300) ax = fig.add_subplot(111, projection=ccrs.Mollweide(central_longitude = -150)) ax2.imshow(etopo1, extent=[-180,180,-90,90], transform=ccrs.PlateCarree()) """ return get_raster(raster_id_string, self.verbose)
- ETOPO1: 
- def get_spreading_rate_grid(self, time)
- 
Downloads seafloor spreading rate grids from the plate reconstruction model ( file_collection) passed into theDataServerobject. Stores grids in the "gplately" cache.Currently, DataServersupports spreading rate grids from the following plate models:- 
Clennett et al. 2020 - file_collection=- Clennett2020
- Time range: 0-250 Ma
- Seafloor spreading rate grids in netCDF format.
 
 Parameters- time:- int,or- listof- int, default=- None
- Request a spreading grid from one (an integer) or multiple reconstruction times (a list of integers).
 Returns- a Raster object
- 
A gplately.Raster object containing the spreading rate grid. The spreading rate grid data can be extracted into a numpy ndarray or MaskedArray by appending .datato the variable assigned toget_spreading_rate_grid().For example: gdownload = gplately.DataServer("Clennett2020") graster = gdownload.get_spreading_rate_grid(time=100) graster_data = graster.datawhere graster_datais a numpy ndarray.
 Raises- ValueError
- If time(a single integer, or a list of integers representing reconstruction times to extract the spreading rate grids from) is not passed.
 NotesThe first time that get_spreading_rate_gridis called for a specific time(s), the spreading rate grid(s) will be downloaded into the GPlately cache once. Upon successive calls ofget_spreading_rate_gridfor the same reconstruction time(s), the grids will not be re-downloaded; rather, they are re-accessed from the same cache location provided they have not been moved or deleted.Examplesif the DataServerobject was called with theClennett2020file_collectionstring:gDownload = gplately.download.DataServer("Clennett2020")get_spreading_rate_gridwill download seafloor spreading rate grids from the Clennett et al. (2020) plate reconstruction model for the geological time(s) requested in thetimeparameter. When found, these spreading rate grids are returned as masked arrays.For example, to download Clennett et al. (2020) seafloor spreading rate grids for 0Ma, 1Ma and 100 Ma as MaskedArray objects: spreading_rate_grids = gDownload.get_spreading_rate_grid([0, 1, 100])Expand source codedef get_spreading_rate_grid(self, time): """Downloads seafloor spreading rate grids from the plate reconstruction model (`file_collection`) passed into the `DataServer` object. Stores grids in the "gplately" cache. Currently, `DataServer` supports spreading rate grids from the following plate models: * __Clennett et al. 2020__ * `file_collection` = `Clennett2020` * Time range: 0-250 Ma * Seafloor spreading rate grids in netCDF format. Parameters ---------- time : int, or list of int, default=None Request a spreading grid from one (an integer) or multiple reconstruction times (a list of integers). Returns ------- a gplately.Raster object A gplately.Raster object containing the spreading rate grid. The spreading rate grid data can be extracted into a numpy ndarray or MaskedArray by appending `.data` to the variable assigned to `get_spreading_rate_grid()`. For example: gdownload = gplately.DataServer("Clennett2020") graster = gdownload.get_spreading_rate_grid(time=100) graster_data = graster.data where `graster_data` is a numpy ndarray. Raises ----- ValueError If `time` (a single integer, or a list of integers representing reconstruction times to extract the spreading rate grids from) is not passed. Notes ----- The first time that `get_spreading_rate_grid` is called for a specific time(s), the spreading rate grid(s) will be downloaded into the GPlately cache once. Upon successive calls of `get_spreading_rate_grid` for the same reconstruction time(s), the grids will not be re-downloaded; rather, they are re-accessed from the same cache location provided they have not been moved or deleted. Examples -------- if the `DataServer` object was called with the `Clennett2020` `file_collection` string: gDownload = gplately.download.DataServer("Clennett2020") `get_spreading_rate_grid` will download seafloor spreading rate grids from the Clennett et al. (2020) plate reconstruction model for the geological time(s) requested in the `time` parameter. When found, these spreading rate grids are returned as masked arrays. For example, to download Clennett et al. (2020) seafloor spreading rate grids for 0Ma, 1Ma and 100 Ma as MaskedArray objects: spreading_rate_grids = gDownload.get_spreading_rate_grid([0, 1, 100]) """ spreading_rate_grids = [] spreading_rate_grid_links = DataCollection.netcdf4_spreading_rate_grids(self, time) if not isinstance(time, list): time = [time] # For a single time passed that isn't in the valid time range, if not spreading_rate_grid_links: raise ValueError( "{} {}Ma spreading rate grids are not on GPlately's DataServer.".format( self.file_collection, time[0] ) ) # For a list of times passed... for i, link in enumerate(spreading_rate_grid_links): if not link: raise ValueError( "{} {}Ma spreading rate grids are not on GPlately's DataServer.".format( self.file_collection, time[i] ) ) spreading_rate_grid_file = download_from_web( link, verbose=self.verbose, model_name=self.file_collection ) spreading_rate_grid = _gplately.grids.Raster(data=spreading_rate_grid_file) spreading_rate_grids.append(spreading_rate_grid) # One last check to alert user if the masked array grids were not processed properly if not spreading_rate_grids: raise ValueError("{} netCDF4 seafloor spreading rate grids not found.".format(self.file_collection)) if len(spreading_rate_grids) == 1: return spreading_rate_grids[0] else: return spreading_rate_grids
- 
- def get_topology_geometries(self)
- 
Uses Pooch to download coastline, continent and COB (continent-ocean boundary) Shapely geometries from the requested plate model. These are needed to call the PlotTopologiesobject and visualise topological plates through time.Parameters- verbose:- bool, default- True
- Toggle print messages regarding server/internet connection status, file availability etc.
 Returns- coastlines:- instanceof- <pygplates.FeatureCollection>
- Present-day global coastline Shapely polylines cookie-cut using static polygons. Ready for reconstruction to a particular geological time and for plotting.
- continents:- instanceof- <pygplates.FeatureCollection>
- Cookie-cutting Shapely polygons for non-oceanic regions (continents, inta-oceanic arcs, etc.) ready for reconstruction to a particular geological time and for plotting.
- COBs:- instanceof- <pygplates.FeatureCollection>
- Shapely polylines resolved from .shp and/or .gpml topology files that represent the locations of the boundaries between oceanic and continental crust. Ready for reconstruction to a particular geological time and for plotting.
 NotesThis method accesses the plate reconstruction model ascribed to the file_collectionstring passed into theDataServerobject. For example, if the object was called with"Muller2019":gDownload = gplately.download.DataServer("Muller2019") coastlines, continents, COBs = gDownload.get_topology_geometries()the method will attempt to download coastlines,continentsandCOBsfrom the Müller et al. (2019) plate reconstruction model. If found, these files are returned as individual pyGPlates Feature Collections. They can be passed into:gPlot = gplately.plot.PlotTopologies(gplately.reconstruction.PlateReconstruction, time, continents, coastlines, COBs)to reconstruct features to a certain geological time. The PlotTopologiesobject provides simple methods to plot these geometries along with trenches, ridges and transforms (see documentation for more info). Note that thePlateReconstructionobject is a parameter.- Note: If the requested plate model does not have a certain geometry, a
message will be printed to alert the user. For example, if get_topology_geometries()is used with the"Matthews2016"plate model, the workflow will print the following message:No continent-ocean boundaries in Matthews2016.
 Expand source codedef get_topology_geometries(self): """Uses Pooch to download coastline, continent and COB (continent-ocean boundary) Shapely geometries from the requested plate model. These are needed to call the `PlotTopologies` object and visualise topological plates through time. Parameters ---------- verbose : bool, default True Toggle print messages regarding server/internet connection status, file availability etc. Returns ------- coastlines : instance of <pygplates.FeatureCollection> Present-day global coastline Shapely polylines cookie-cut using static polygons. Ready for reconstruction to a particular geological time and for plotting. continents : instance of <pygplates.FeatureCollection> Cookie-cutting Shapely polygons for non-oceanic regions (continents, inta-oceanic arcs, etc.) ready for reconstruction to a particular geological time and for plotting. COBs : instance of <pygplates.FeatureCollection> Shapely polylines resolved from .shp and/or .gpml topology files that represent the locations of the boundaries between oceanic and continental crust. Ready for reconstruction to a particular geological time and for plotting. Notes ----- This method accesses the plate reconstruction model ascribed to the `file_collection` string passed into the `DataServer` object. For example, if the object was called with `"Muller2019"`: gDownload = gplately.download.DataServer("Muller2019") coastlines, continents, COBs = gDownload.get_topology_geometries() the method will attempt to download `coastlines`, `continents` and `COBs` from the Müller et al. (2019) plate reconstruction model. If found, these files are returned as individual pyGPlates Feature Collections. They can be passed into: gPlot = gplately.plot.PlotTopologies(gplately.reconstruction.PlateReconstruction, time, continents, coastlines, COBs) to reconstruct features to a certain geological time. The `PlotTopologies` object provides simple methods to plot these geometries along with trenches, ridges and transforms (see documentation for more info). Note that the `PlateReconstruction` object is a parameter. * Note: If the requested plate model does not have a certain geometry, a message will be printed to alert the user. For example, if `get_topology_geometries()` is used with the `"Matthews2016"` plate model, the workflow will print the following message: No continent-ocean boundaries in Matthews2016. """ verbose = self.verbose # Locate all topology geometries from GPlately's DataCollection database = DataCollection.topology_geometries(self) coastlines = [] continents = [] COBs = [] # Find the requested plate model data collection found_collection = False for collection, url in database.items(): if self.file_collection.lower() == collection.lower(): found_collection = True if len(url) == 1: # Some plate models do not have reconstructable geometries i.e. Li et al. 2008 if url[0] is None: break else: fnames = _collection_sorter( download_from_web(url[0], verbose, model_name=self.file_collection), self.file_collection ) coastlines = _check_gpml_or_shp( _str_in_folder( _str_in_filename( fnames, strings_to_include=DataCollection.coastline_strings_to_include(self), strings_to_ignore=DataCollection.coastline_strings_to_ignore(self), file_collection=self.file_collection, file_collection_sensitive=False ), strings_to_ignore=DataCollection.coastline_strings_to_ignore(self) ) ) continents = _check_gpml_or_shp( _str_in_folder( _str_in_filename( fnames, strings_to_include=DataCollection.continent_strings_to_include(self), strings_to_ignore=DataCollection.continent_strings_to_ignore(self), file_collection=self.file_collection, file_collection_sensitive=False ), strings_to_ignore=DataCollection.continent_strings_to_ignore(self) ) ) COBs = _check_gpml_or_shp( _str_in_folder( _str_in_filename( fnames, strings_to_include=DataCollection.COB_strings_to_include(self), strings_to_ignore=DataCollection.COB_strings_to_ignore(self), file_collection=self.file_collection, file_collection_sensitive=False ), strings_to_ignore=DataCollection.COB_strings_to_ignore(self) ) ) else: for file in url[0]: if url[0] is not None: coastlines.append(_str_in_filename( download_from_web(file, verbose, model_name=self.file_collection), strings_to_include=["coastline"]) ) coastlines = _check_gpml_or_shp(coastlines) else: coastlines = [] for file in url[1]: if url[1] is not None: continents.append(_str_in_filename( download_from_web(file, verbose, model_name=self.file_collection), strings_to_include=["continent"]) ) continents = _check_gpml_or_shp(continents) else: continents = [] for file in url[2]: if url[2] is not None: COBs.append(_str_in_filename( download_from_web(file, verbose, model_name=self.file_collection), strings_to_include=["cob"]) ) COBs = _check_gpml_or_shp(COBs) else: COBs = [] break if found_collection is False: raise ValueError("{} is not in GPlately's DataServer.".format(self.file_collection)) if not coastlines: print("No coastlines in {}.".format(self.file_collection)) coastlines_featurecollection = [] else: #print(coastlines) coastlines_featurecollection = _FeatureCollection() for coastline in coastlines: coastlines_featurecollection.add(_FeatureCollection(coastline)) if not continents: print("No continents in {}.".format(self.file_collection)) continents_featurecollection = [] else: #print(continents) continents_featurecollection = _FeatureCollection() for continent in continents: continents_featurecollection.add(_FeatureCollection(continent)) if not COBs: print("No continent-ocean boundaries in {}.".format(self.file_collection)) COBs_featurecollection = [] else: #print(COBs) COBs_featurecollection = _FeatureCollection() for COB in COBs: COBs_featurecollection.add(_FeatureCollection(COB)) geometries = coastlines_featurecollection, continents_featurecollection, COBs_featurecollection return geometries
- def get_valid_times(self)
- 
Returns a tuple of the valid plate model time range, (min_time, max_time). Expand source codedef get_valid_times(self): """Returns a tuple of the valid plate model time range, (min_time, max_time). """ all_model_valid_times = DataCollection.plate_model_valid_reconstruction_times(self) min_time = None max_time = None for plate_model_name, valid_times in list(all_model_valid_times.items()): if plate_model_name.lower() == self.file_collection.lower(): min_time = valid_times[0] max_time = valid_times[1] if not min_time and not max_time: raise ValueError("Could not find the valid reconstruction time of {}".format(self.file_collection)) return (min_time, max_time)
 
-