{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "Axis\n", "====\n", "\n", "These objects manipulate axes as they can be found in NetCDF files:\n", "\n", "```\n", "float lat(lat) ;\n", " lat:long_name = \"latitude\" ;\n", " lat:units = \"degrees_north\" ;\n", " lat:standard_name = \"latitude\" ;\n", "float lon(lon) ;\n", " lon:long_name = \"longitude\" ;\n", " lon:units = \"degrees_east\" ;\n", " lon:standard_name = \"longitude\" ;\n", "```\n", "\n", "Regular axis\n", "--------------\n", "\n", "For example, let's construct an axis representing a regular axis." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import numpy\n", "import pyinterp\n", "\n", "axis = pyinterp.Axis(numpy.arange(-90, 90, 0.25))\n", "axis" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This object can be queried to obtain its properties." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(f\"is ascending ? {axis.is_ascending()}\")\n", "print(f\"is regular ? {axis.is_regular()}\")\n", "print(f\"is circle ? {axis.is_circle}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The most useful interfaces allow you to search for the index of the\n", "closest value." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "axis.find_index([1e-3])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It is also possible to find the indices around a value." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "axis.find_indexes([1e-3])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The list of available methods is described in the\n", "[online help](https://pangeo-pyinterp.readthedocs.io/en/latest/generated/pyinterp.Axis.html#pyinterp.Axis).\n", "\n", "Irregular axis\n", "---------------\n", "\n", "When the axis is regular, the pitch is constant between each element of\n", "the axis, the search is performed using a simple calculation and\n", "therefore very fast. When the pitch is not constant between two\n", "successive elements of the axis, the search is performed by a binary\n", "search. Even these two operating modes are managed by the same object.\n", "So let's build an irregular axis:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "MERCATOR_LATITUDES = numpy.array([\n", " -89.000000, -88.908818, -88.809323, -88.700757, -88.582294, -88.453032,\n", " -88.311987, -88.158087, -87.990161, -87.806932, -87.607008, -87.388869,\n", " -87.150861, -86.891178, -86.607851, -86.298736, -85.961495, -85.593582,\n", " -85.192224, -84.754402, -84.276831, -83.755939, -83.187844, -82.568330,\n", " -81.892820, -81.156357, -80.353575, -79.478674, -78.525397, -77.487013,\n", " -76.356296, -75.125518, -73.786444, -72.330344, -70.748017, -69.029837,\n", " -67.165823, -65.145744, -62.959262, -60.596124, -58.046413, -55.300856,\n", " -52.351206, -49.190700, -45.814573, -42.220632, -38.409866, -34.387043,\n", " -30.161252, -25.746331, -21.161107, -16.429384, -11.579629, -6.644331,\n", " -1.659041, 3.338836, 8.311423, 13.221792, 18.035297, 22.720709, 27.251074,\n", " 31.604243, 35.763079, 39.715378, 43.453560, 46.974192, 50.277423,\n", " 53.366377, 56.246554, 58.925270, 61.411164, 63.713764, 65.843134,\n", " 67.809578, 69.623418, 71.294813, 72.833637, 74.249378, 75.551083,\n", " 76.747318, 77.846146, 78.855128, 79.781321, 80.631294, 81.411149,\n", " 82.126535, 82.782681, 83.384411, 83.936179, 84.442084, 84.905904,\n", " 85.331111, 85.720897, 86.078198, 86.405707, 86.705898, 86.981044,\n", " 87.233227, 87.464359, 87.676195, 87.870342, 88.048275, 88.211348,\n", " 88.360799, 88.497766, 88.623291, 88.738328, 88.843755, 88.940374\n", "])\n", "\n", "axis = pyinterp.Axis(MERCATOR_LATITUDES)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's display its properties." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(f\"is ascending ? {axis.is_ascending()}\")\n", "print(f\"is regular ? {axis.is_regular()}\")\n", "print(f\"is circle ? {axis.is_circle}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It is possible to query this axis as before." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "axis.find_index([1e-3])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Longitude\n", "------------\n", "\n", "It is also possible to represent longitudes going around the earth, i.e.\n", "making a circle." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "axis = pyinterp.Axis(numpy.arange(0, 360, 1), is_circle=True)\n", "axis" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this case, you don't have to worry about the bounds of the axis." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "axis.find_index([-180]), axis.find_index([180])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "TemporalAxis\n", "===========\n", "\n", "Time axes allow for manipulating axes representing dates or time\n", "differences. These objects are specialized to handle the 64-bit integers\n", "used by numpy to describe dates without losing information during\n", "calculations. In a netCDF file these axes are described as follows:\n", "\n", "```\n", "double time(time) ;\n", " time:long_name = \"time\" ;\n", " time:units = \"days since 1990-1-1 0:0:0\" ;\n", "```\n", "\n", "---\n", "**Note**\n", "\n", "These axes can be regular or irregular as before.\n", "\n", "---" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "dates = numpy.datetime64(\"2020-01-01\") + numpy.arange(\n", " 10**6, step=500).astype(\"timedelta64[ms]\")\n", "axis = pyinterp.TemporalAxis(dates)\n", "axis" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It is possible to search for a date in this axis." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "axis.find_index(numpy.array([numpy.datetime64('2020-01-01T00:10:34.000')]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can pass any date unit to the axis." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "axis.find_index(numpy.array([numpy.datetime64('2020-01-01')]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This object also makes it possible to manipulate timedeltas." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "axis = pyinterp.TemporalAxis(dates - numpy.datetime64('2020-01-01'))\n", "axis" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.8.5" } }, "nbformat": 4, "nbformat_minor": 1 }