From 2cdf0a1b0d79da8053c828b3d2753718ed767d96 Mon Sep 17 00:00:00 2001 From: konstntokas Date: Tue, 10 Dec 2024 13:24:32 +0100 Subject: [PATCH 1/4] preload method added --- .gitignore | 2 + environment.yml | 3 + examples/zenodo_data_store.ipynb | 2 +- examples/zenodo_data_store_preload.ipynb | 4426 ++++++++++++++++++++++ pyproject.toml | 3 + xcube_zenodo/_utils.py | 27 +- xcube_zenodo/constants.py | 5 + xcube_zenodo/preload.py | 299 ++ xcube_zenodo/store.py | 121 +- 9 files changed, 4861 insertions(+), 27 deletions(-) create mode 100644 examples/zenodo_data_store_preload.ipynb create mode 100644 xcube_zenodo/preload.py diff --git a/.gitignore b/.gitignore index 82f9275..2f41357 100644 --- a/.gitignore +++ b/.gitignore @@ -160,3 +160,5 @@ cython_debug/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ + +examples/preload_cache/ \ No newline at end of file diff --git a/environment.yml b/environment.yml index 62f8418..d170b8e 100644 --- a/environment.yml +++ b/environment.yml @@ -4,7 +4,10 @@ channels: dependencies: # Required - python>=3.10 + - IPython + - numpy - requests + - tabulate - xarray - xcube >= 1.7.0 # for testing diff --git a/examples/zenodo_data_store.ipynb b/examples/zenodo_data_store.ipynb index 22b1a82..43af87c 100644 --- a/examples/zenodo_data_store.ipynb +++ b/examples/zenodo_data_store.ipynb @@ -116,7 +116,7 @@ ], "source": [ "%%time\n", - "access_token = \"ZsZVfyPCmLYRZQtfSYWruNwXYBykonv0pXZYnrQYNNL0gGMJipYsx0CYvOSB\"\n", + "access_token = \"fill in you Zenodo access token here\"\n", "store = new_data_store(\"zenodo\", access_token=access_token)" ] }, diff --git a/examples/zenodo_data_store_preload.ipynb b/examples/zenodo_data_store_preload.ipynb new file mode 100644 index 0000000..1ea6038 --- /dev/null +++ b/examples/zenodo_data_store_preload.ipynb @@ -0,0 +1,4426 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# This notebook gives an introduction to the xcube's \"zenodo\" data store and its preload_data method\n", + "\n", + "This notebook shows an example how to preload compressed files published on the [https://zenodo.org](https://zenodo.org) webpage. The compressed files will be downloaded, unpacked and the the individual files will be made available as a Zarr file, which can be subsequently used by the data store as usual. \n", + "\n", + "### Setup\n", + "In order to run this notebook you need to get an access token for the Zenodo API following the [documentation](https://zenodo.org/login/?next=%2Faccount%2Fsettings%2Fapplications%2Ftokens%2Fnew%2F). Furthermore, make sure that [`xcube_zenodo`](https://github.com/xcube-dev/xcube-zenodo) is installed. You may install [`xcube_zenodo`](https://github.com/xcube-dev/xcube-zenodo) directly from the git repository by cloning the repository, directing into `xcube-zenodo`, and following the steps below:\n", + "\n", + "```bash\n", + "conda env create -f environment.yml\n", + "conda activate xcube-zenodo\n", + "pip install .\n", + "```\n", + "\n", + "Note that [`xcube_zenodo`](https://github.com/xcube-dev/xcube-zenodo) is a plugin of [`xcube`](https://xcube.readthedocs.io/en/latest/), where `xcube` is included in the `environment.yml`. \n", + "\n", + "Now, we first import everything we need:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 2.91 s, sys: 193 ms, total: 3.1 s\n", + "Wall time: 1.24 s\n" + ] + } + ], + "source": [ + "%%time\n", + "from xcube.core.store import new_data_store\n", + "from xcube.core.store import get_data_store_params_schema\n", + "import logging\n", + "\n", + "logging.basicConfig(\n", + " level=logging.INFO,\n", + " format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', # Log format\n", + " datefmt='%Y-%m-%d %H:%M:%S', # Timestamp format\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First, we get the store parameters needed to initialize a zenodo [data store](https://xcube.readthedocs.io/en/latest/dataaccess.html#data-store-framework). " + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 33.9 ms, sys: 7.05 ms, total: 40.9 ms\n", + "Wall time: 40.2 ms\n" + ] + }, + { + "data": { + "application/json": { + "additionalProperties": false, + "properties": { + "access_token": { + "title": "Zenodo access token.", + "type": "string" + }, + "preload_cache_folder": { + "description": "Datasets which are accessed using prelaod_data will be stored in this folder in a prepared way.", + "title": "Preload cache folder.", + "type": "string" + } + }, + "required": [ + "access_token" + ], + "type": "object" + }, + "text/plain": [ + "" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%%time\n", + "store_params = get_data_store_params_schema(\"zenodo\")\n", + "store_params" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We initiate a zenodo [data store](https://xcube.readthedocs.io/en/latest/dataaccess.html#data-store-framework) with the access_token. Note that the `xcube-zenodo` plugin is recognized after installation by setting the first argument to `\"zenodo\"` in the `new_data_store` function. We can add a relative path to a folder where preloaded data will be stored. " + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 5.04 ms, sys: 4 μs, total: 5.05 ms\n", + "Wall time: 4.98 ms\n" + ] + } + ], + "source": [ + "%%time\n", + "access_token = \"fill in you Zenodo access token here\"\n", + "store = new_data_store(\"zenodo\", access_token=access_token, preload_cache_folder=\"preload_cache\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Compressed files can be preloaded using the `preload_data` method. Also this method uses `preload_params`, which can be viewed in the next cell." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 30 μs, sys: 2 μs, total: 32 μs\n", + "Wall time: 34.1 μs\n" + ] + }, + { + "data": { + "application/json": { + "additionalProperties": false, + "properties": { + "merge": { + "default": false, + "description": "If True, xarray.merge is applied to the files stored in a compressed format. If False, each dataset is stored individually. The data ID will be extended by the filename.", + "title": "Merge multiple dataset of compressed data IDs.", + "type": "boolean" + }, + "monitor_preload": { + "default": true, + "description": "If True, the progress of preload will be visualized", + "title": "Monitor preload_data method.", + "type": "boolean" + } + }, + "type": "object" + }, + "text/plain": [ + "" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%%time\n", + "preload_params = store.get_preload_data_params()\n", + "preload_params" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " This approach enables the downloading of compressed files that cannot be lazily loaded, allowing them to be stored and readily available for the duration of the project. The `preload_data` method is non-blocking and returns a handler which can be used to cancel the preload by typing `handler.cancel()` indto the next cell." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
Data ID Status Progress Message
13333034/belgium.zipPreloadednan%
13333034/denmark.zipPreloadednan%
" + ], + "text/plain": [ + "'\\n\\n\\n\\n\\n\\n\\n\\n
Data ID Status Progress Message
13333034/belgium.zipPreloadednan%
13333034/denmark.zipPreloadednan%
'" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "handler = store.preload_data(\"13333034/belgium.zip\", \"13333034/denmark.zip\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The data IDs can be view by using the following line. Note that in this example the zipped file contain multiple files. If this is the case and `merge=False` (which is the default), each file is written to a Zarr file. The data ID is extended by the individual file names where the file extension is adjusted. " + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['13333034/belgium/number_disturbances_belgium.zarr',\n", + " '13333034/belgium/annual_disturbances_1985_2023_belgium.zarr',\n", + " '13333034/belgium/latest_disturbance_belgium.zarr',\n", + " '13333034/belgium/disturbance_agent_1985_2023_belgium.zarr',\n", + " '13333034/belgium/forest_mask_belgium.zarr',\n", + " '13333034/belgium/disturbance_agent_aggregated_belgium.zarr',\n", + " '13333034/belgium/greatest_disturbance_belgium.zarr',\n", + " '13333034/belgium/disturbance_probability_1985_2023_belgium.zarr',\n", + " '13333034/belgium/disturbance_severity_1985_2023_belgium.zarr',\n", + " '13333034/denmark/disturbance_severity_1985_2023_denmark.zarr',\n", + " '13333034/denmark/latest_disturbance_denmark.zarr',\n", + " '13333034/denmark/disturbance_probability_1985_2023_denmark.zarr',\n", + " '13333034/denmark/disturbance_agent_aggregated_denmark.zarr',\n", + " '13333034/denmark/number_disturbances_denmark.zarr',\n", + " '13333034/denmark/annual_disturbances_1985_2023_denmark.zarr',\n", + " '13333034/denmark/greatest_disturbance_denmark.zarr',\n", + " '13333034/denmark/forest_mask_denmark.zarr',\n", + " '13333034/denmark/disturbance_agent_1985_2023_denmark.zarr']" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "store.cache_store.list_data_ids()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next we want to open one of the datasets. We first view the availbale parameters to open the data. " + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 2.09 ms, sys: 153 μs, total: 2.25 ms\n", + "Wall time: 1.82 ms\n" + ] + }, + { + "data": { + "application/json": { + "additionalProperties": false, + "properties": { + "cache_size": { + "minimum": 0, + "type": "integer" + }, + "chunks": { + "additionalProperties": true, + "description": "Optional chunk sizes along each dimension. Chunk size values may be None, \"auto\" or an integer value.", + "examples": [ + { + "lat": "auto", + "lon": 90, + "time": null + }, + { + "time": 1, + "x": 512, + "y": 512 + } + ], + "properties": {}, + "type": "object" + }, + "consolidated": { + "default": false, + "description": "Whether to open the store using Zarr's consolidated metadata capability. Only works for stores that have already been consolidated.", + "type": "boolean" + }, + "data_type": { + "enum": [ + "dataset", + "mldataset", + "geodataframe" + ], + "title": "Optional data type", + "type": "string" + }, + "decode_cf": { + "default": true, + "description": "Whether to decode these variables, assuming they were saved according to CF conventions.", + "type": "boolean" + }, + "decode_coords": { + "default": true, + "description": "If True, decode the \"coordinates\" attribute to identify coordinates in the resulting dataset.", + "type": "boolean" + }, + "decode_times": { + "default": true, + "description": "If True, decode times encoded in the standard NetCDF datetime format into datetime objects. Otherwise, leave them encoded as numbers.", + "type": "boolean" + }, + "drop_variables": { + "items": { + "minLength": 1, + "type": "string" + }, + "type": "array" + }, + "group": { + "description": "Group path. (a.k.a. path in zarr terminology.).", + "minLength": 1, + "type": "string" + }, + "log_access": { + "default": false, + "type": "boolean" + }, + "mask_and_scale": { + "default": true, + "description": "If True, replace array values equal to attribute \"_FillValue\" with NaN. Use \"scale_factor\" and \"add_offset\" attributes to compute actual values.", + "type": "boolean" + } + }, + "type": "object" + }, + "text/plain": [ + "" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%%time\n", + "open_params = store.get_open_data_params_schema(data_id=\"13333034/belgium/disturbance_probability_1985_2023_belgium.zarr\")\n", + "open_params" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 24.7 ms, sys: 5.98 ms, total: 30.6 ms\n", + "Wall time: 30 ms\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.Dataset> Size: 27GB\n",
+       "Dimensions:      (y: 9084, x: 9390)\n",
+       "Coordinates:\n",
+       "    spatial_ref  int64 8B ...\n",
+       "  * x            (x) float64 75kB 3.795e+06 3.795e+06 ... 4.076e+06 4.076e+06\n",
+       "  * y            (y) float64 73kB 3.189e+06 3.189e+06 ... 2.917e+06 2.917e+06\n",
+       "Data variables: (12/39)\n",
+       "    band_1       (y, x) float64 682MB dask.array<chunksize=(512, 512), meta=np.ndarray>\n",
+       "    band_10      (y, x) float64 682MB dask.array<chunksize=(512, 512), meta=np.ndarray>\n",
+       "    band_11      (y, x) float64 682MB dask.array<chunksize=(512, 512), meta=np.ndarray>\n",
+       "    band_12      (y, x) float64 682MB dask.array<chunksize=(512, 512), meta=np.ndarray>\n",
+       "    band_13      (y, x) float64 682MB dask.array<chunksize=(512, 512), meta=np.ndarray>\n",
+       "    band_14      (y, x) float64 682MB dask.array<chunksize=(512, 512), meta=np.ndarray>\n",
+       "    ...           ...\n",
+       "    band_4       (y, x) float64 682MB dask.array<chunksize=(512, 512), meta=np.ndarray>\n",
+       "    band_5       (y, x) float64 682MB dask.array<chunksize=(512, 512), meta=np.ndarray>\n",
+       "    band_6       (y, x) float64 682MB dask.array<chunksize=(512, 512), meta=np.ndarray>\n",
+       "    band_7       (y, x) float64 682MB dask.array<chunksize=(512, 512), meta=np.ndarray>\n",
+       "    band_8       (y, x) float64 682MB dask.array<chunksize=(512, 512), meta=np.ndarray>\n",
+       "    band_9       (y, x) float64 682MB dask.array<chunksize=(512, 512), meta=np.ndarray>\n",
+       "Attributes:\n",
+       "    source:   file:///home/konstantin/bc_kon/01_coding/01_github/xcube-zenodo...
" + ], + "text/plain": [ + " Size: 27GB\n", + "Dimensions: (y: 9084, x: 9390)\n", + "Coordinates:\n", + " spatial_ref int64 8B ...\n", + " * x (x) float64 75kB 3.795e+06 3.795e+06 ... 4.076e+06 4.076e+06\n", + " * y (y) float64 73kB 3.189e+06 3.189e+06 ... 2.917e+06 2.917e+06\n", + "Data variables: (12/39)\n", + " band_1 (y, x) float64 682MB dask.array\n", + " band_10 (y, x) float64 682MB dask.array\n", + " band_11 (y, x) float64 682MB dask.array\n", + " band_12 (y, x) float64 682MB dask.array\n", + " band_13 (y, x) float64 682MB dask.array\n", + " band_14 (y, x) float64 682MB dask.array\n", + " ... ...\n", + " band_4 (y, x) float64 682MB dask.array\n", + " band_5 (y, x) float64 682MB dask.array\n", + " band_6 (y, x) float64 682MB dask.array\n", + " band_7 (y, x) float64 682MB dask.array\n", + " band_8 (y, x) float64 682MB dask.array\n", + " band_9 (y, x) float64 682MB dask.array\n", + "Attributes:\n", + " source: file:///home/konstantin/bc_kon/01_coding/01_github/xcube-zenodo..." + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%%time\n", + "ds = store.open_data(\"13333034/belgium/disturbance_probability_1985_2023_belgium.zarr\")\n", + "ds" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We plot parts of the opened data as an example below." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 543 ms, sys: 65.8 ms, total: 609 ms\n", + "Wall time: 551 ms\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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zz//PM6dO4eioiK6H1nsWc6ePQugbpHNz8+HzWbDP/7xD0RGRtL9gq358v777+PRRx/1shheuHABN954Y1BjE3grR5s2bQAA06dPxy9+8QvhMYH+n2AtREa8++67XqnyLP379wcA7Ny5E3379qXba2pqsHfvXjz44IMBzU8ikTQuUtwEybhx43D06FHk5+ejY8eOWLNmDTIyMrBz504kJSXh//2//4fu3bvjH//4BzIyMuB2u3HnnXdi8eLF8lthM6RLly548skn8dlnn+Grr77SvHb16lV88sknGtfUBx98AEVRcMcddwDwCISIiAiNxaGyshKrV6/2OpfdbjdtdbFYLF5Buv/85z9x6tQp9OzZ0/T1+UOvXr2QlJSEHTt2hNwNu3nzZlP7devWzfD1YcOGoUOHDli5ciUeeOABuv2vf/0rysvLdUWZRCIJb6S4CYJDhw7hww8/xMmTJ9GxY0cAHhN8UVER3n33XSxYsACHDx/GsWPHUFBQgPfeew8ulwtTpkzBL3/5S6xdu7aRr0ASLGVlZfjpT3+Khx56CL1790bLli2xefNmFBUVeS2MrVu3xuOPP47jx48jOTkZn376Kf74xz/i8ccfp5lRP/vZz7B06VI89NBDmDBhAi5evIglS5YIs4f69++P/Px8fPTRR+jevTsiIyOpJYLn5z//OVauXInevXtjwIAB2Lp1K15++WWagl1f/OEPf0BmZibS09Pxq1/9CjfddBMuXbqEPXv24JtvvkFBQUFA4w4ZMiQk87NarVi8eDFycnLw29/+Fg8++CAOHDiAadOmweFwICMjIyTnkUgkDYsUN0HwzTffwO12Izk5WbPd6XRSN4OqqnA6nXjvvffofn/6058wePBg7Nu3T7qqmjiRkZEYNmwYVq9ejaNHj6K6uhpdunTBc889h2nTpmn2TUhIwJtvvompU6di586daNWqFWbMmIE5c+bQfUaPHo0///nPWLRoEe666y7cdNNN+M1vfoN27drhv//7vzXjzZkzB2fOnMFvfvMbXL16FV27dsXRo0eF83z11Vdhs9mwcOFClJeXY9CgQfi///s/vPDCCyG/Jyw//elP8fXXX2P+/PmYPHkyLl++jNatW6Nv3764//776/XcZnnkkUdgtVrx0ksvYeXKlWjVqhUeffRRzJ8/v7GnJpFIAsTidjOVwSSGWCwWrFmz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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%time\n", + "ds.band_1[::10, ::10].plot()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.7" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/pyproject.toml b/pyproject.toml index 69756f4..79b0486 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,7 +18,10 @@ readme = {file = "README.md", content-type = "text/markdown"} license = {text = "MIT"} requires-python = ">=3.10" dependencies = [ + "IPython", + "numpy", "requests", + "tabulate", "xarray", "xcube" ] diff --git a/xcube_zenodo/_utils.py b/xcube_zenodo/_utils.py index bb2141a..a630d43 100644 --- a/xcube_zenodo/_utils.py +++ b/xcube_zenodo/_utils.py @@ -19,13 +19,9 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -from typing import Any, Container - -from xcube.core.store import DATASET_TYPE -from xcube.core.store import MULTI_LEVEL_DATASET_TYPE -from xcube.core.store import DataTypeLike - +from typing import Any, Container, Union +from .constants import COMPRESSED_FORMATS from .constants import MAP_FILE_EXTENSION_FORMAT @@ -70,18 +66,27 @@ def get_attrs_from_record( return attrs -def estimate_file_format(data_id: str) -> str: - ext = data_id.split(".")[-1] - format_id = MAP_FILE_EXTENSION_FORMAT.get(ext.lower()) - return format_id +def estimate_file_format(data_id: str) -> Union[str, None]: + for key, val in MAP_FILE_EXTENSION_FORMAT.items(): + if data_id.endswith(key.lower()): + return val + return None def is_supported_file_format(data_id: str) -> bool: return estimate_file_format(data_id) is not None -def translate_data_id2uri(data_id: str) -> str: +def is_supported_compressed_file_format(data_id: str) -> bool: + return estimate_file_format(data_id) in COMPRESSED_FORMATS + + +def translate_data_id2fs_path(data_id: str) -> str: components = data_id.split("/") record_id = components[0] file_key = "/".join(components[1:]) return f"records/{record_id}/files/{file_key}" + + +def translate_data_id2uri(data_id: str) -> str: + return f"https://zenodo.org/{translate_data_id2fs_path(data_id)}" diff --git a/xcube_zenodo/constants.py b/xcube_zenodo/constants.py index eea475c..4aaeeb3 100644 --- a/xcube_zenodo/constants.py +++ b/xcube_zenodo/constants.py @@ -21,6 +21,7 @@ DATA_STORE_ID = "zenodo" API_RECORDS_ENDPOINT = "https://zenodo.org/api/records" +PRELOAD_CACHE_FOLDER = "preload_cache/" MAP_FILE_EXTENSION_FORMAT = { "zarr": "zarr", @@ -31,4 +32,8 @@ "geotiff": "geotiff", "shp": "shapefile", "geojson": "geojson", + "zip": "zip", + "tar": "tar", + "tar.gz": "tar.gz", } +COMPRESSED_FORMATS = list(MAP_FILE_EXTENSION_FORMAT.keys())[-3:] diff --git a/xcube_zenodo/preload.py b/xcube_zenodo/preload.py new file mode 100644 index 0000000..ff1387f --- /dev/null +++ b/xcube_zenodo/preload.py @@ -0,0 +1,299 @@ +# The MIT License (MIT) +# Copyright (c) 2024 by the xcube development team and contributors +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import logging +import os +import shutil +import threading +import time +from typing import Callable, Union +import tarfile +import zipfile + +import IPython +import IPython.display +import numpy as np +import tabulate +import requests +import xarray as xr +from xcube.core.store import DataStoreError +from xcube.core.store import MutableDataStore + +from ._utils import estimate_file_format +from ._utils import translate_data_id2uri + +LOG = logging.getLogger(__name__) + + +class Event: + + def __init__(self, data_id: str, total_size: Union[int, float]): + self.data_id = data_id + self.status = "Not started" + self.progress = 0.0 + self.message = "Preloading not started jet." + self.total_size = total_size + self._callback = None + + def subscribe(self, callback: Callable[[], None]): + self._callback = callback + + def notify(self): + if self._callback is not None: + self._callback() + + def update(self, status: str, progress: float, message: str): + self.status = status + self.progress = progress + self.message = message + self.notify() + + +class PreloadHandle: + + def __init__(self, cache_store: MutableDataStore, *data_ids: str, **preload_params): + self._is_cancelled = False + self._is_closed = False + self._cache_store = cache_store + self._data_ids = data_ids + self._preload_params = preload_params + self._cache_root = preload_params.pop("cache_root") + self._download_folder_name = "downloads" + self._download_folder = os.path.join( + self._cache_root, self._download_folder_name + ) + self._events = [Event(data_id, np.nan) for data_id in data_ids] + self.lock = threading.Lock() + if preload_params.get("monitor_preload"): + for event in self._events: + event.subscribe(self._monitor_preload) + self._thread_download = None + self._thread_decompress = None + self._thread_prepare = None + + @property + def is_cancelled(self) -> bool: + return self._is_cancelled + + def cancel(self): + self._is_cancelled = True + self._thread_prepare.join() + self._thread_decompress.join() + self._thread_download.join() + for event in self._events: + event.update("Canceled", np.nan, "Preload has been canceled by user.") + self.close() + + @property + def is_closed(self) -> bool: + return self._is_closed + + def close(self): + self._is_closed = True + for event in self._events: + if event.status != "Preloaded": + if self._cache_store.has_data(event.data_id): + self._cache_store.delete_data(event.data_id) + else: + record, filename = event.data_id.split("/") + format_id = estimate_file_format(event.data_id) + dirname = filename.replace(f".{format_id}", "") + data_id_mod = f"{record}/{dirname}" + list_data_ids = self._cache_store.list_data_ids() + list_data_ids_mod = [ + data_id for data_id in list_data_ids if data_id_mod in data_id + ] + for data_id in list_data_ids_mod: + self._cache_store.delete_data(data_id) + if os.path.isdir(self._download_folder): + shutil.rmtree(self._download_folder) + + def _monitor_preload(self): + rows = [ + [ + event.data_id, + event.status, + f"{event.progress * 100:.2f}%", + event.message, + ] + for event in self._events + ] + if is_jupyter(): + table = tabulate.tabulate( + rows, + headers=["Data ID", "Status", "Progress", "Message"], + tablefmt="html", + ) + IPython.display.clear_output(wait=True) + IPython.display.display(table) + else: + table = tabulate.tabulate( + rows, + headers=["Dataset", "Status", "Progress", "Message"], + ) + os.system("clear" if os.name == "posix" else "cls") + print(table) + + def preload_data(self, *data_ids: str, **preload_params): + self._download_data(*data_ids) + self._decompress_data(*data_ids) + self._prepare_data(*data_ids, **preload_params) + + def _download_data(self, *data_ids: str): + # get first total size of all datasets and initialize it as Events + for i, data_id in enumerate(data_ids): + uri = translate_data_id2uri(data_id) + with requests.get(uri, stream=True) as response: + if not response.ok: + raise DataStoreError(response.raise_for_status()) + self._events[i].total_size = int( + response.headers.get("content-length", 0) + ) + + # start downloading + chunk_size = 1024 * 1024 + + def download(): + for i, data_id in enumerate(data_ids): + download_size = 0 + self._events[i].update("Download started", 0, "") + uri = translate_data_id2uri(data_id) + with requests.get(uri, stream=True) as response: + if not response.ok: + raise DataStoreError(response.raise_for_status()) + record, filename = data_id.split("/") + record_folder = os.path.join(self._download_folder, record) + if not os.path.exists(record_folder): + os.makedirs(record_folder) + download_path = os.path.join(record_folder, filename) + with open(download_path, "wb") as file: + for chunk in response.iter_content(chunk_size=chunk_size): + file.write(chunk) + download_size += len(chunk) + self._events[i].update( + "Download started", + download_size / self._events[i].total_size, + "", + ) + if self._is_cancelled: + break + self._events[i].update("Downloaded", 1.0, "") + + self._thread_download = threading.Thread( + target=download, daemon=True, name="download_data" + ) + self._thread_download.start() + + def _decompress_data(self, *data_ids): + def decompress(): + for i, data_id in enumerate(data_ids): + while not self._events[i].status == "Downloaded": + time.sleep(1) + self._events[i].update("Decompression started", np.nan, "") + record, filename = data_id.split("/") + file_path = os.path.join(self._download_folder, record, filename) + if zipfile.is_zipfile(file_path): + with zipfile.ZipFile(file_path, "r") as zip_ref: + dirname = filename.replace(".zip", "") + extract_dir = os.path.join( + self._download_folder, record, dirname + ) + zip_ref.extractall(extract_dir) + elif file_path.endswith(".tar"): + with tarfile.open(file_path, "r") as tar_ref: + dirname = filename.replace(".tar", "") + extract_dir = os.path.join( + self._download_folder, record, dirname + ) + tar_ref.extractall(path=extract_dir) + elif file_path.endswith(".tar.gz"): + with tarfile.open(file_path, "r:gz") as tar_ref: + dirname = filename.replace(".tar.gz", "") + extract_dir = os.path.join( + self._download_folder, record, dirname + ) + tar_ref.extractall(path=extract_dir) + self._events[i].update("Decompressed", np.nan, "") + if self._is_cancelled: + break + + self._thread_decompress = threading.Thread( + target=decompress, daemon=True, name="decompress_data" + ) + self._thread_decompress.start() + + def _prepare_data(self, *data_ids, **preload_params): + def prepare(): + for i, data_id in enumerate(data_ids): + while not self._events[i].status == "Decompressed": + time.sleep(1) + self._events[i].update("File processing started", np.nan, "") + record, filename = data_id.split("/") + format_id = estimate_file_format(data_id) + dirname = filename.replace(f".{format_id}", "") + extract_dir = os.path.join(self._download_folder, record, dirname) + dss = [] + sub_fnames = os.listdir(extract_dir) + for sub_fname in sub_fnames: + sub_data_id = ( + f"{self._download_folder_name}/{record}/{dirname}/{sub_fname}" + ) + if not self._cache_store.has_data(sub_data_id): + LOG.debug( + f"File with data ID {sub_data_id} cannot be opened, " + f"and thus will not be considered." + ) + dss.append(self._cache_store.open_data(sub_data_id)) + if len(dss) == 1: + self._cache_store.write_data( + dss[0], data_id, writer_id="dataset:zarr:file" + ) + elif preload_params.get("merge"): + ds = xr.merge(dss) + self._cache_store.write_data( + ds, data_id, writer_id="dataset:zarr:file" + ) + else: + for ds, sub_fname in zip(dss, sub_fnames): + data_id = ( + f"{record}/{dirname}/" + f"{".".join(sub_fname.split(".")[:-1])}.zarr" + ) + self._cache_store.write_data( + ds, data_id, writer_id="dataset:zarr:file" + ) + LOG.info( + f"Merge is set to False. The sub-dataset is " + f"written to {data_id}" + ) + self._events[i].update("Preloaded", np.nan, "") + if self._is_cancelled: + break + self.close() + + self._thread_prepare = threading.Thread( + target=prepare, daemon=True, name="prepare_data" + ) + self._thread_prepare.start() + + +def is_jupyter(): + return "ZMQInteractiveShell" in IPython.get_ipython().__class__.__name__ diff --git a/xcube_zenodo/store.py b/xcube_zenodo/store.py index 3af893e..ea504f9 100644 --- a/xcube_zenodo/store.py +++ b/xcube_zenodo/store.py @@ -20,44 +20,63 @@ # SOFTWARE. import logging +import os from typing import Tuple, Iterator, Container, Any, Union import requests import xarray as xr from xcube.util.jsonschema import ( + JsonBooleanSchema, JsonObjectSchema, JsonStringSchema, ) from xcube.core.store import ( DataDescriptor, DataStore, + DataStoreError, DataTypeLike, new_data_store, ) from .constants import API_RECORDS_ENDPOINT +from .constants import COMPRESSED_FORMATS +from .constants import PRELOAD_CACHE_FOLDER +from .preload import PreloadHandle +from ._utils import estimate_file_format from ._utils import get_attrs_from_record from ._utils import is_supported_file_format -from ._utils import translate_data_id2uri +from ._utils import is_supported_compressed_file_format +from ._utils import translate_data_id2fs_path -_LOG = logging.getLogger("xcube") +LOG = logging.getLogger(__name__) class ZenodoDataStore(DataStore): """Implementation of the Zenodo data store defined in the ``xcube_zenodo`` plugin.""" - def __init__(self, access_token: str): + def __init__(self, access_token: str, preload_cache_folder: str = None): self._requests_params = {"access_token": access_token} self._https_data_store = new_data_store("https", root="zenodo.org") + self._cache_root = os.path.join( + os.getcwd(), preload_cache_folder or PRELOAD_CACHE_FOLDER + ) + self.cache_store = new_data_store("file", root=self._cache_root, max_depth=3) @classmethod def get_data_store_params_schema(cls) -> JsonObjectSchema: params = dict( access_token=JsonStringSchema( title="Zenodo access token.", - ) + ), + preload_cache_folder=JsonStringSchema( + title="Preload cache folder.", + description=( + "Datasets which are accessed using prelaod_data will be stored " + "in this folder in a prepared way." + ), + ), ) return JsonObjectSchema( properties=dict(**params), @@ -71,7 +90,7 @@ def get_data_types(cls) -> Tuple[str, ...]: return store.get_data_types() def get_data_types_for_data(self, data_id: str) -> Tuple[str, ...]: - uri = translate_data_id2uri(data_id) + uri = translate_data_id2fs_path(data_id) return self._https_data_store.get_data_types_for_data(uri) def get_data_ids( @@ -104,13 +123,13 @@ def get_data_ids( page += 1 def has_data(self, data_id: str, data_type: str = None) -> bool: - uri = translate_data_id2uri(data_id) + uri = translate_data_id2fs_path(data_id) return self._https_data_store.has_data(data_id=uri, data_type=data_type) def describe_data( self, data_id: str, data_type: DataTypeLike = None ) -> DataDescriptor: - uri = translate_data_id2uri(data_id) + uri = translate_data_id2fs_path(data_id) descriptor = self._https_data_store.describe_data( data_id=uri, data_type=data_type ) @@ -121,7 +140,7 @@ def get_data_opener_ids( self, data_id: str = None, data_type: DataTypeLike = None ) -> Tuple[str, ...]: if data_id is not None: - uri = translate_data_id2uri(data_id) + uri = translate_data_id2fs_path(data_id) else: uri = data_id return self._https_data_store.get_data_opener_ids( @@ -132,7 +151,7 @@ def get_open_data_params_schema( self, data_id: str = None, opener_id: str = None ) -> JsonObjectSchema: if data_id is not None: - uri = translate_data_id2uri(data_id) + uri = translate_data_id2fs_path(data_id) else: uri = data_id return self._https_data_store.get_open_data_params_schema( @@ -142,14 +161,86 @@ def get_open_data_params_schema( def open_data( self, data_id: str, opener_id: str = None, **open_params ) -> xr.Dataset: - uri = translate_data_id2uri(data_id) - return self._https_data_store.open_data( - data_id=uri, opener_id=opener_id, **open_params + format_id = estimate_file_format(data_id) + if format_id in COMPRESSED_FORMATS: + if not self.cache_store.has_data(data_id): + raise DataStoreError( + f"The dataset {data_id} is stored in a compressed format. " + f"Please use store.preload_data({data_id}) first." + ) + return self.cache_store.open_data( + data_id=data_id, opener_id="dataset:zarr:file", **open_params + ) + elif self.cache_store.has_data(data_id): + return self.cache_store.open_data(data_id=data_id, **open_params) + else: + uri = translate_data_id2fs_path(data_id) + return self._https_data_store.open_data( + data_id=uri, opener_id=opener_id, **open_params + ) + + def preload_data(self, *data_ids: str, **preload_params) -> PreloadHandle: + schema = self.get_preload_data_params() + schema.validate_instance(preload_params) + preload_params["merge"] = preload_params.get("merge", False) + preload_params["monitor_preload"] = preload_params.get("monitor_preload", True) + data_ids_sel = [] + for data_id in data_ids: + format_id = estimate_file_format(data_id) + data_id_mod = data_id.replace(f".{format_id}", "/") + list_data_ids = self.cache_store.list_data_ids() + list_data_ids_mod = [i for i in list_data_ids if data_id_mod in i] + if list_data_ids_mod: + LOG.info( + f"{data_id} is already pre-loaded. The datasets can be " + f"opened with the following data IDs: " + f"\n{'\n'.join(str(item) for item in list_data_ids_mod)}" + ) + elif self.cache_store.has_data(data_id): + LOG.info(f"{data_id} is already pre-loaded.") + else: + if is_supported_compressed_file_format(data_id): + data_ids_sel.append(data_id) + else: + LOG.warning( + f"{data_id} cannot be preloaded. Only 'zip', 'tar', and " + "'tar.gz' compressed files are supported. The preload " + "request is discarded." + ) + preload_handle = PreloadHandle( + self.cache_store, + *data_ids_sel, + cache_root=self._cache_root, + **preload_params, + ) + if data_ids_sel: + preload_handle.preload_data(*data_ids_sel, **preload_params) + return preload_handle + + def get_preload_data_params(self) -> JsonObjectSchema: + params = dict( + merge=JsonBooleanSchema( + title="Merge multiple dataset of compressed data IDs.", + description=( + "If True, xarray.merge is applied to the files stored in a " + "compressed format. If False, each dataset is stored individually. " + "The data ID will be extended by the filename." + ), + default=False, + ), + monitor_preload=JsonBooleanSchema( + title="Monitor preload_data method.", + description="If True, the progress of preload will be visualized", + default=True, + ), + ) + return JsonObjectSchema( + properties=dict(**params), + required=[], + additional_properties=False, ) - def search_data( - self, data_type: DataTypeLike = None, **search_params - ) -> Iterator[DataDescriptor]: + def search_data(self, data_type: DataTypeLike = None, **search_params): schema = self.get_search_params_schema() schema.validate_instance(search_params) raise NotImplementedError("search_data() operation is not supported.") From a7409f6c49f2479a44c98896cc93c1a7b404d202 Mon Sep 17 00:00:00 2001 From: konstntokas Date: Wed, 11 Dec 2024 16:32:17 +0100 Subject: [PATCH 2/4] yogesh pr addressed --- examples/zenodo_data_store_preload.ipynb | 28 ++++++++++++------------ xcube_zenodo/_utils.py | 6 ++--- xcube_zenodo/preload.py | 8 +++---- xcube_zenodo/store.py | 6 ++--- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/examples/zenodo_data_store_preload.ipynb b/examples/zenodo_data_store_preload.ipynb index 1ea6038..2bf61b1 100644 --- a/examples/zenodo_data_store_preload.ipynb +++ b/examples/zenodo_data_store_preload.ipynb @@ -31,8 +31,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 2.91 s, sys: 193 ms, total: 3.1 s\n", - "Wall time: 1.24 s\n" + "CPU times: user 2.5 s, sys: 422 ms, total: 2.92 s\n", + "Wall time: 2.65 s\n" ] } ], @@ -65,8 +65,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 33.9 ms, sys: 7.05 ms, total: 40.9 ms\n", - "Wall time: 40.2 ms\n" + "CPU times: user 40.8 ms, sys: 10.6 ms, total: 51.4 ms\n", + "Wall time: 61.2 ms\n" ] }, { @@ -90,7 +90,7 @@ "type": "object" }, "text/plain": [ - "" + "" ] }, "execution_count": 2, @@ -113,15 +113,15 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 5.04 ms, sys: 4 μs, total: 5.05 ms\n", - "Wall time: 4.98 ms\n" + "CPU times: user 8.1 ms, sys: 43 μs, total: 8.14 ms\n", + "Wall time: 7.66 ms\n" ] } ], @@ -140,15 +140,15 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 30 μs, sys: 2 μs, total: 32 μs\n", - "Wall time: 34.1 μs\n" + "CPU times: user 68 μs, sys: 11 μs, total: 79 μs\n", + "Wall time: 83.7 μs\n" ] }, { @@ -172,10 +172,10 @@ "type": "object" }, "text/plain": [ - "" + "" ] }, - "execution_count": 4, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -195,7 +195,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": {}, "outputs": [ { diff --git a/xcube_zenodo/_utils.py b/xcube_zenodo/_utils.py index a630d43..6468a4f 100644 --- a/xcube_zenodo/_utils.py +++ b/xcube_zenodo/_utils.py @@ -66,7 +66,7 @@ def get_attrs_from_record( return attrs -def estimate_file_format(data_id: str) -> Union[str, None]: +def identify_file_format(data_id: str) -> Union[str, None]: for key, val in MAP_FILE_EXTENSION_FORMAT.items(): if data_id.endswith(key.lower()): return val @@ -74,11 +74,11 @@ def estimate_file_format(data_id: str) -> Union[str, None]: def is_supported_file_format(data_id: str) -> bool: - return estimate_file_format(data_id) is not None + return identify_file_format(data_id) is not None def is_supported_compressed_file_format(data_id: str) -> bool: - return estimate_file_format(data_id) in COMPRESSED_FORMATS + return identify_file_format(data_id) in COMPRESSED_FORMATS def translate_data_id2fs_path(data_id: str) -> str: diff --git a/xcube_zenodo/preload.py b/xcube_zenodo/preload.py index ff1387f..656b36e 100644 --- a/xcube_zenodo/preload.py +++ b/xcube_zenodo/preload.py @@ -37,7 +37,7 @@ from xcube.core.store import DataStoreError from xcube.core.store import MutableDataStore -from ._utils import estimate_file_format +from ._utils import identify_file_format from ._utils import translate_data_id2uri LOG = logging.getLogger(__name__) @@ -49,7 +49,7 @@ def __init__(self, data_id: str, total_size: Union[int, float]): self.data_id = data_id self.status = "Not started" self.progress = 0.0 - self.message = "Preloading not started jet." + self.message = "Preloading not started yet." self.total_size = total_size self._callback = None @@ -114,7 +114,7 @@ def close(self): self._cache_store.delete_data(event.data_id) else: record, filename = event.data_id.split("/") - format_id = estimate_file_format(event.data_id) + format_id = identify_file_format(event.data_id) dirname = filename.replace(f".{format_id}", "") data_id_mod = f"{record}/{dirname}" list_data_ids = self._cache_store.list_data_ids() @@ -247,7 +247,7 @@ def prepare(): time.sleep(1) self._events[i].update("File processing started", np.nan, "") record, filename = data_id.split("/") - format_id = estimate_file_format(data_id) + format_id = identify_file_format(data_id) dirname = filename.replace(f".{format_id}", "") extract_dir = os.path.join(self._download_folder, record, dirname) dss = [] diff --git a/xcube_zenodo/store.py b/xcube_zenodo/store.py index ea504f9..76e046b 100644 --- a/xcube_zenodo/store.py +++ b/xcube_zenodo/store.py @@ -42,7 +42,7 @@ from .constants import COMPRESSED_FORMATS from .constants import PRELOAD_CACHE_FOLDER from .preload import PreloadHandle -from ._utils import estimate_file_format +from ._utils import identify_file_format from ._utils import get_attrs_from_record from ._utils import is_supported_file_format from ._utils import is_supported_compressed_file_format @@ -161,7 +161,7 @@ def get_open_data_params_schema( def open_data( self, data_id: str, opener_id: str = None, **open_params ) -> xr.Dataset: - format_id = estimate_file_format(data_id) + format_id = identify_file_format(data_id) if format_id in COMPRESSED_FORMATS: if not self.cache_store.has_data(data_id): raise DataStoreError( @@ -186,7 +186,7 @@ def preload_data(self, *data_ids: str, **preload_params) -> PreloadHandle: preload_params["monitor_preload"] = preload_params.get("monitor_preload", True) data_ids_sel = [] for data_id in data_ids: - format_id = estimate_file_format(data_id) + format_id = identify_file_format(data_id) data_id_mod = data_id.replace(f".{format_id}", "/") list_data_ids = self.cache_store.list_data_ids() list_data_ids_mod = [i for i in list_data_ids if data_id_mod in i] From 03973f93cd1121bc78d7266a062a86448c725fe2 Mon Sep 17 00:00:00 2001 From: konstntokas Date: Fri, 13 Dec 2024 17:37:58 +0100 Subject: [PATCH 3/4] reveiw addressed --- .gitignore | 2 +- environment.yml | 2 +- examples/zenodo_data_store.ipynb | 188 +++++++++++------------ examples/zenodo_data_store_preload.ipynb | 156 +++++++++---------- pyproject.toml | 2 +- xcube_zenodo/_utils.py | 4 +- xcube_zenodo/constants.py | 6 +- xcube_zenodo/preload.py | 73 +++++---- xcube_zenodo/store.py | 27 ++-- 9 files changed, 231 insertions(+), 229 deletions(-) diff --git a/.gitignore b/.gitignore index 2f41357..435dc68 100644 --- a/.gitignore +++ b/.gitignore @@ -161,4 +161,4 @@ cython_debug/ # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ -examples/preload_cache/ \ No newline at end of file +examples/zenodo_cache/ \ No newline at end of file diff --git a/environment.yml b/environment.yml index d170b8e..f0202df 100644 --- a/environment.yml +++ b/environment.yml @@ -4,7 +4,7 @@ channels: dependencies: # Required - python>=3.10 - - IPython + - fsspec - numpy - requests - tabulate diff --git a/examples/zenodo_data_store.ipynb b/examples/zenodo_data_store.ipynb index 43af87c..76d0a1c 100644 --- a/examples/zenodo_data_store.ipynb +++ b/examples/zenodo_data_store.ipynb @@ -24,15 +24,15 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 3.04 s, sys: 234 ms, total: 3.27 s\n", - "Wall time: 1.41 s\n" + "CPU times: user 7 μs, sys: 1 μs, total: 8 μs\n", + "Wall time: 10 μs\n" ] } ], @@ -52,15 +52,15 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 31.6 ms, sys: 13.8 ms, total: 45.5 ms\n", - "Wall time: 44.6 ms\n" + "CPU times: user 33.4 ms, sys: 8.93 ms, total: 42.3 ms\n", + "Wall time: 41.6 ms\n" ] }, { @@ -71,6 +71,11 @@ "access_token": { "title": "Zenodo access token.", "type": "string" + }, + "preload_cache_folder": { + "description": "Datasets which are accessed using prelaod_data will be stored in this folder in a prepared way.", + "title": "Preload cache folder.", + "type": "string" } }, "required": [ @@ -79,10 +84,10 @@ "type": "object" }, "text/plain": [ - "" + "" ] }, - "execution_count": 2, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -102,21 +107,21 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 3.44 ms, sys: 1.04 ms, total: 4.48 ms\n", - "Wall time: 4.43 ms\n" + "CPU times: user 5.17 ms, sys: 15 μs, total: 5.18 ms\n", + "Wall time: 5.1 ms\n" ] } ], "source": [ "%%time\n", - "access_token = \"fill in you Zenodo access token here\"\n", + "access_token = \"XVYlYi840itHkdbVXN2PtQk9cBeIY2WQ9OlVQeIssaP9YgMDAAyjlnIc6H6l\"\n", "store = new_data_store(\"zenodo\", access_token=access_token)" ] }, @@ -129,33 +134,33 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 365 ms, sys: 30.8 ms, total: 396 ms\n", - "Wall time: 2min 18s\n" + "CPU times: user 43.9 ms, sys: 5.57 ms, total: 49.4 ms\n", + "Wall time: 25.5 s\n" ] }, { "data": { "text/plain": [ - "['14054126/AVIRIS-NG-methane-emissions_v2024-11-04.nc',\n", - " '14052963/CESM.b.T31_g37.HighPrec.SO.pop.DIC.nc',\n", - " '14052963/CESM.b.T31_g37.Equilibration.500-1000.pop.nc',\n", - " '14052963/CESM.b.T31_g37.NoPrec.SH.cam.nc',\n", - " '14052963/CESM.b.T31_g37.HighPrec.SH.cam.nc',\n", - " '14052963/CESM.b.T31_g37.Equilibration.0-500.pop.nc',\n", - " '14052963/CESM.b.T31_g37.NoPrec.SO.pop.nc',\n", - " '14052963/CESM.b.T31_g37.NoPrec.SO.pop.DIC.nc',\n", - " '14052963/CESM.b.T31_g37.HighPrec.SO.pop.nc',\n", - " '14051280/Mitoflash_CM-8bit.tif']" + "['14446470/pretrained.zip',\n", + " '14446770/mastodon-sc/mastodon-deep-lineage-mastodon-deep-lineage-0.4.3.zip',\n", + " '14446677/MeTech/haptic-oriring-public-v1.1.zip',\n", + " '14446628/magicrjk/treeofrobots-ToR-V1.0.zip',\n", + " '14446620/Ahmet-Agaoglu/The-Corridor-Method-0.1.0.zip',\n", + " '14446612/FAIRmat-NFDI/pynxtools-xps-v0.4.9.zip',\n", + " '14446605/PowerGridModel/power-grid-model-v1.10.22.zip',\n", + " '14446598/FerdinandKlingenberg/tree-cover-density-comparison-V1.0.0.zip',\n", + " '14446582/KatieWillis/DriveSelectionBalance-DriveSelectionBalance.zip',\n", + " '14441477/simulation_data.zip']" ] }, - "execution_count": 4, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -182,7 +187,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -271,10 +276,10 @@ ] }, "text/plain": [ - "" + "" ] }, - "execution_count": 5, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -292,15 +297,15 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 192 μs, sys: 19 μs, total: 211 μs\n", - "Wall time: 214 μs\n" + "CPU times: user 217 μs, sys: 20 μs, total: 237 μs\n", + "Wall time: 239 μs\n" ] }, { @@ -348,10 +353,10 @@ "type": "object" }, "text/plain": [ - "" + "" ] }, - "execution_count": 6, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -364,15 +369,15 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 203 ms, sys: 3.83 ms, total: 207 ms\n", - "Wall time: 206 ms\n" + "CPU times: user 21.2 ms, sys: 4.01 ms, total: 25.2 ms\n", + "Wall time: 24.1 ms\n" ] }, { @@ -750,9 +755,9 @@ "Data variables:\n", " band_1 (y, x) uint8 25GB dask.array<chunksize=(1024, 1024), meta=np.ndarray>\n", "Attributes:\n", - " source: https://zenodo.org/records/8154445/files/planet_canopy_cover_30..." + " dtype='float64', name='y', length=149363))
  • source :
    https://zenodo.org/records/8154445/files/planet_canopy_cover_30m_v0.1.tif
  • " ], "text/plain": [ " Size: 25GB\n", @@ -876,7 +881,7 @@ " source: https://zenodo.org/records/8154445/files/planet_canopy_cover_30..." ] }, - "execution_count": 14, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -899,24 +904,24 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 321 ms, sys: 68.4 ms, total: 389 ms\n", - "Wall time: 3.06 s\n" + "CPU times: user 661 ms, sys: 122 ms, total: 783 ms\n", + "Wall time: 4 s\n" ] }, { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 15, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" }, @@ -945,15 +950,15 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 5.15 ms, sys: 0 ns, total: 5.15 ms\n", - "Wall time: 4.9 ms\n" + "CPU times: user 5.73 ms, sys: 1.12 ms, total: 6.85 ms\n", + "Wall time: 161 ms\n" ] }, { @@ -962,7 +967,7 @@ "1" ] }, - "execution_count": 16, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -979,7 +984,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 11, "metadata": {}, "outputs": [ { @@ -1357,9 +1362,9 @@ "Data variables:\n", " band_1 (y, x) uint8 25GB dask.array<chunksize=(1024, 1024), meta=np.ndarray>\n", "Attributes:\n", - " source: https://zenodo.org/records/8154445/files/planet_canopy_cover_30..." + " dtype='float64', name='y', length=149363))
  • source :
    https://zenodo.org/records/8154445/files/planet_canopy_cover_30m_v0.1.tif
  • " ], "text/plain": [ " Size: 25GB\n", @@ -1483,7 +1488,7 @@ " source: https://zenodo.org/records/8154445/files/planet_canopy_cover_30..." ] }, - "execution_count": 17, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -1509,15 +1514,15 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 83.2 ms, sys: 15.3 ms, total: 98.4 ms\n", - "Wall time: 9.03 s\n" + "CPU times: user 65.9 ms, sys: 21.8 ms, total: 87.7 ms\n", + "Wall time: 8.05 s\n" ] }, { @@ -1910,7 +1915,7 @@ " Modelrun: ERA5weather\n", " Modelconfig: newfriction\n", " TimeStamp: 11-Jun-2024 13:01:44\n", - " Notes: Statistics based on ERA5 hindcast run from 1980 to 2022. \\n...