diff --git a/python/examples/hrrr_hourly.ipynb b/python/examples/hrrr_hourly.ipynb
new file mode 100644
index 0000000..2e14a6b
--- /dev/null
+++ b/python/examples/hrrr_hourly.ipynb
@@ -0,0 +1,1936 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import fsspec\n",
+ "\n",
+ "fs_read = fsspec.filesystem('s3', anon=True, skip_instance_cache=True, use_ssl=False) # For now SSL false is solving my cert issues **shrug**\n",
+ "fs_write = fsspec.filesystem('')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Read 49 HRRR files\n"
+ ]
+ }
+ ],
+ "source": [
+ "hrr_hourly_member_files = fs_read.glob('s3://noaa-hrrr-bdp-pds/hrrr.20230722/conus/hrrr.t18z.wrfsfcf*.grib2')\n",
+ "\n",
+ "files = sorted(['s3://'+f for f in hrr_hourly_member_files])\n",
+ "print(f'Read {len(files)} HRRR files')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import re\n",
+ "import datetime\n",
+ "\n",
+ "def parse_model_run_datestamp_offset(key: str):\n",
+ " '''\n",
+ " Parse the model run forecast time key from the key of the file in the HRRR S3 bucket, given the HRRR naming convention: \n",
+ " 's3://noaa-hrrr-bdp-pds/hrrr.20230722/conus/hrrr.t12z.wrfsfcf01.grib2' \n",
+ " where the model_date is 20230315 and the model_hour is 00 and the offset is 1, this would result in a key of 20230315T01\n",
+ " '''\n",
+ " model_date, model_hour, offset = re.search(r'hrrr\\.(\\d{8})\\/conus\\/hrrr\\.t(\\d{2})z\\.wrfsfcf(\\d{2})', key).groups()\n",
+ " model_date = datetime.datetime.strptime(f'{model_date}T{model_hour}', '%Y%m%dT%H') + datetime.timedelta(hours=int(offset))\n",
+ " model_date_key = model_date.strftime('%Y%m%dT%H')\n",
+ " return model_date_key, int(offset)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import ujson\n",
+ "from gribberish.kerchunk import scan_gribberish\n",
+ "\n",
+ "so = {\"anon\": True, \"use_ssl\": False}\n",
+ "json_dir = 'hrrr_hourly/'\n",
+ "\n",
+ "def make_json_name(file_url, message_number): #create a unique name for each reference file\n",
+ " date, _ = parse_model_run_datestamp_offset(file_url)\n",
+ " name = file_url.split('/')[5].split('.')[0:3]\n",
+ " return f'{json_dir}{name[0]}_{date}_message{message_number}.json'\n",
+ "\n",
+ "def gen_json(file_url):\n",
+ " out = scan_gribberish(\n",
+ " file_url, \n",
+ " storage_options=so, \n",
+ " only_variables=['apcp', 'prate', 'cpofp', 'vis', 'tcdc', 'tmp', 'pres', 'ugrd', 'vgrd', 'dpt'], \n",
+ " skip=10,\n",
+ " filter_by_variable_attrs={\n",
+ " 'ugrd': {\n",
+ " 'statistical_process': '', \n",
+ " 'fixed_surface_value': '10',\n",
+ " }, \n",
+ " 'vgrd': {\n",
+ " 'statistical_process': '', \n",
+ " 'fixed_surface_value': '10',\n",
+ " }, \n",
+ " 'tmp': {\n",
+ " 'fixed_surface_type': 'ground or water surface',\n",
+ " }, \n",
+ " 'dpt': {\n",
+ " 'fixed_surface_type': 'specific height level above ground',\n",
+ " 'fixed_surface_value': '2'\n",
+ " },\n",
+ " 'tcdc': {\n",
+ " 'fixed_surface_value': 'entire atmosphere',\n",
+ " },\n",
+ " 'pres': {\n",
+ " 'fixed_surface_type': 'ground or water surface',\n",
+ " }\n",
+ " }\n",
+ " )\n",
+ " for i, message in enumerate(out):\n",
+ " out_file_name = make_json_name(file_url, i) # get name\n",
+ " with fs_write.open(out_file_name, \"w\") as f: \n",
+ " f.write(ujson.dumps(message)) # write to file"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from dask.distributed import Client, progress\n",
+ "\n",
+ "client = Client(processes=False)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "87038a6acb304d06b21141e5ab81a955",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "VBox()"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "futures = client.map(gen_json, files[1:], retries=1)\n",
+ "progress(futures)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "client.shutdown()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Found 479 reference files\n"
+ ]
+ }
+ ],
+ "source": [
+ "from kerchunk.combine import MultiZarrToZarr\n",
+ "\n",
+ "reference_jsons = sorted(fs_write.ls(json_dir)) #get list of file names\n",
+ "\n",
+ "print(f'Found {len(reference_jsons)} reference files')\n",
+ "\n",
+ "# combine individual references into single consolidated reference\n",
+ "mzz = MultiZarrToZarr(reference_jsons,\n",
+ " concat_dims = ['time'],\n",
+ " identical_dims=['x', 'y', 'latitude', 'longitude'])\n",
+ "\n",
+ "d = mzz.translate()\n",
+ "\n",
+ "with open(f'{json_dir}/hrrr_kerchunk.json', 'w') as f:\n",
+ " f.write(ujson.dumps(d))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "
\n",
+ "
<xarray.Dataset>\n",
+ "Dimensions: (time: 48, y: 1059, x: 1799)\n",
+ "Coordinates:\n",
+ " latitude (y, x) float64 dask.array<chunksize=(1059, 1799), meta=np.ndarray>\n",
+ " longitude (y, x) float64 dask.array<chunksize=(1059, 1799), meta=np.ndarray>\n",
+ " * time (time) datetime64[s] 2023-07-22T19:00:00 ... 2023-07-24T18:00:00\n",
+ " * x (x) float64 -2.701e+06 -2.698e+06 ... 2.69e+06 2.693e+06\n",
+ " * y (y) float64 -1.581e+06 -1.578e+06 ... 1.59e+06 1.593e+06\n",
+ "Data variables:\n",
+ " apcp (time, y, x) float64 dask.array<chunksize=(1, 1059, 1799), meta=np.ndarray>\n",
+ " cpofp (time, y, x) float64 dask.array<chunksize=(1, 1059, 1799), meta=np.ndarray>\n",
+ " dpt (time, y, x) float64 dask.array<chunksize=(1, 1059, 1799), meta=np.ndarray>\n",
+ " prate (time, y, x) float64 dask.array<chunksize=(1, 1059, 1799), meta=np.ndarray>\n",
+ " pres (time, y, x) float64 dask.array<chunksize=(1, 1059, 1799), meta=np.ndarray>\n",
+ " tmp (time, y, x) float64 dask.array<chunksize=(1, 1059, 1799), meta=np.ndarray>\n",
+ " ugrd (time, y, x) float64 dask.array<chunksize=(1, 1059, 1799), meta=np.ndarray>\n",
+ " vgrd (time, y, x) float64 dask.array<chunksize=(1, 1059, 1799), meta=np.ndarray>\n",
+ " vis (time, y, x) float64 dask.array<chunksize=(1, 1059, 1799), meta=np.ndarray>\n",
+ "Attributes:\n",
+ " meta: Generated with gribberishpy
latitude
(y, x)
float64
dask.array<chunksize=(1059, 1799), meta=np.ndarray>
- long_name :
- latitude
- standard_name :
- latitude
- unit :
- degrees_north
\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " | \n",
+ " Array | \n",
+ " Chunk | \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " Bytes | \n",
+ " 14.54 MiB | \n",
+ " 14.54 MiB | \n",
+ " \n",
+ " \n",
+ " \n",
+ " Shape | \n",
+ " (1059, 1799) | \n",
+ " (1059, 1799) | \n",
+ " \n",
+ " \n",
+ " Dask graph | \n",
+ " 1 chunks in 2 graph layers | \n",
+ " \n",
+ " \n",
+ " Data type | \n",
+ " float64 numpy.ndarray | \n",
+ " \n",
+ " \n",
+ " \n",
+ " | \n",
+ " \n",
+ " \n",
+ " | \n",
+ "
\n",
+ "
longitude
(y, x)
float64
dask.array<chunksize=(1059, 1799), meta=np.ndarray>
- long_name :
- longitude
- standard_name :
- longitude
- unit :
- degrees_east
\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " | \n",
+ " Array | \n",
+ " Chunk | \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " Bytes | \n",
+ " 14.54 MiB | \n",
+ " 14.54 MiB | \n",
+ " \n",
+ " \n",
+ " \n",
+ " Shape | \n",
+ " (1059, 1799) | \n",
+ " (1059, 1799) | \n",
+ " \n",
+ " \n",
+ " Dask graph | \n",
+ " 1 chunks in 2 graph layers | \n",
+ " \n",
+ " \n",
+ " Data type | \n",
+ " float64 numpy.ndarray | \n",
+ " \n",
+ " \n",
+ " \n",
+ " | \n",
+ " \n",
+ " \n",
+ " | \n",
+ "
\n",
+ "
time
(time)
datetime64[s]
2023-07-22T19:00:00 ... 2023-07-...
- axis :
- T
- long_name :
- time
- standard_name :
- time
- unit :
- seconds since 1970-01-01 00:00:00
- _FillValue :
- 1970-01-01T00:00:00
array(['2023-07-22T19:00:00', '2023-07-22T20:00:00', '2023-07-22T21:00:00',\n",
+ " '2023-07-22T22:00:00', '2023-07-22T23:00:00', '2023-07-23T00:00:00',\n",
+ " '2023-07-23T01:00:00', '2023-07-23T02:00:00', '2023-07-23T03:00:00',\n",
+ " '2023-07-23T04:00:00', '2023-07-23T05:00:00', '2023-07-23T06:00:00',\n",
+ " '2023-07-23T07:00:00', '2023-07-23T08:00:00', '2023-07-23T09:00:00',\n",
+ " '2023-07-23T10:00:00', '2023-07-23T11:00:00', '2023-07-23T12:00:00',\n",
+ " '2023-07-23T13:00:00', '2023-07-23T14:00:00', '2023-07-23T15:00:00',\n",
+ " '2023-07-23T16:00:00', '2023-07-23T17:00:00', '2023-07-23T18:00:00',\n",
+ " '2023-07-23T19:00:00', '2023-07-23T20:00:00', '2023-07-23T21:00:00',\n",
+ " '2023-07-23T22:00:00', '2023-07-23T23:00:00', '2023-07-24T00:00:00',\n",
+ " '2023-07-24T01:00:00', '2023-07-24T02:00:00', '2023-07-24T03:00:00',\n",
+ " '2023-07-24T04:00:00', '2023-07-24T05:00:00', '2023-07-24T06:00:00',\n",
+ " '2023-07-24T07:00:00', '2023-07-24T08:00:00', '2023-07-24T09:00:00',\n",
+ " '2023-07-24T10:00:00', '2023-07-24T11:00:00', '2023-07-24T12:00:00',\n",
+ " '2023-07-24T13:00:00', '2023-07-24T14:00:00', '2023-07-24T15:00:00',\n",
+ " '2023-07-24T16:00:00', '2023-07-24T17:00:00', '2023-07-24T18:00:00'],\n",
+ " dtype='datetime64[s]')
x
(x)
float64
-2.701e+06 -2.698e+06 ... 2.693e+06
- axis :
- X
- long_name :
- x coordinate of projection
- standard_name :
- projection_x_coordinate
- unit :
- m
array([-2701000.130325, -2698000.130325, -2695000.130325, ..., 2686999.869675,\n",
+ " 2689999.869675, 2692999.869675])
y
(y)
float64
-1.581e+06 -1.578e+06 ... 1.593e+06
- axis :
- Y
- long_name :
- y coordinate of projection
- standard_name :
- projection_y_coordinate
- unit :
- m
array([-1580581.336877, -1577581.336877, -1574581.336877, ..., 1587418.663123,\n",
+ " 1590418.663123, 1593418.663123])
apcp
(time, y, x)
float64
dask.array<chunksize=(1, 1059, 1799), meta=np.ndarray>
- crs :
- +proj=lcc lon_0=262.5 lat_0=38.5 lat_1=38.5 lat_2=38.5
- fixed_surface_type :
- ground or water surface
- fixed_surface_value :
- 0
- forecast_date :
- 2023-07-22T18:00:00+00:00
- generating_process :
- forecast
- long_name :
- totalprecipitation
- proj_params :
- {'lat_0': 38.5, 'lat_1': 38.5, 'lat_2': 38.5, 'lon_0': 262.5, 'proj': 'lcc'}
- reference_date :
- 2023-07-22T18:00:00+00:00
- standard_name :
- totalprecipitation
- statistical_process :
- accumulation
- time_interval_end :
- 2023-07-22T19:00:00+00:00
- unit :
- kgm-2
\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " | \n",
+ " Array | \n",
+ " Chunk | \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " Bytes | \n",
+ " 697.68 MiB | \n",
+ " 14.54 MiB | \n",
+ " \n",
+ " \n",
+ " \n",
+ " Shape | \n",
+ " (48, 1059, 1799) | \n",
+ " (1, 1059, 1799) | \n",
+ " \n",
+ " \n",
+ " Dask graph | \n",
+ " 48 chunks in 2 graph layers | \n",
+ " \n",
+ " \n",
+ " Data type | \n",
+ " float64 numpy.ndarray | \n",
+ " \n",
+ " \n",
+ " \n",
+ " | \n",
+ " \n",
+ " \n",
+ " | \n",
+ "
\n",
+ "
cpofp
(time, y, x)
float64
dask.array<chunksize=(1, 1059, 1799), meta=np.ndarray>
- crs :
- +proj=lcc lon_0=262.5 lat_0=38.5 lat_1=38.5 lat_2=38.5
- fixed_surface_type :
- ground or water surface
- fixed_surface_value :
- 0
- forecast_date :
- 2023-07-22T19:00:00+00:00
- generating_process :
- forecast
- long_name :
- percentfrozenprecipitation
- proj_params :
- {'lat_0': 38.5, 'lat_1': 38.5, 'lat_2': 38.5, 'lon_0': 262.5, 'proj': 'lcc'}
- reference_date :
- 2023-07-22T18:00:00+00:00
- standard_name :
- percentfrozenprecipitation
- statistical_process :
- time_interval_end :
- unit :
- %
\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " | \n",
+ " Array | \n",
+ " Chunk | \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " Bytes | \n",
+ " 697.68 MiB | \n",
+ " 14.54 MiB | \n",
+ " \n",
+ " \n",
+ " \n",
+ " Shape | \n",
+ " (48, 1059, 1799) | \n",
+ " (1, 1059, 1799) | \n",
+ " \n",
+ " \n",
+ " Dask graph | \n",
+ " 48 chunks in 2 graph layers | \n",
+ " \n",
+ " \n",
+ " Data type | \n",
+ " float64 numpy.ndarray | \n",
+ " \n",
+ " \n",
+ " \n",
+ " | \n",
+ " \n",
+ " \n",
+ " | \n",
+ "
\n",
+ "
dpt
(time, y, x)
float64
dask.array<chunksize=(1, 1059, 1799), meta=np.ndarray>
- crs :
- +proj=lcc lon_0=262.5 lat_0=38.5 lat_1=38.5 lat_2=38.5
- fixed_surface_type :
- specific height level above ground
- fixed_surface_value :
- 2
- forecast_date :
- 2023-07-22T19:00:00+00:00
- generating_process :
- forecast
- long_name :
- dewpointtemperature
- proj_params :
- {'lat_0': 38.5, 'lat_1': 38.5, 'lat_2': 38.5, 'lon_0': 262.5, 'proj': 'lcc'}
- reference_date :
- 2023-07-22T18:00:00+00:00
- standard_name :
- dewpointtemperature
- statistical_process :
- time_interval_end :
- unit :
- K
\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " | \n",
+ " Array | \n",
+ " Chunk | \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " Bytes | \n",
+ " 697.68 MiB | \n",
+ " 14.54 MiB | \n",
+ " \n",
+ " \n",
+ " \n",
+ " Shape | \n",
+ " (48, 1059, 1799) | \n",
+ " (1, 1059, 1799) | \n",
+ " \n",
+ " \n",
+ " Dask graph | \n",
+ " 48 chunks in 2 graph layers | \n",
+ " \n",
+ " \n",
+ " Data type | \n",
+ " float64 numpy.ndarray | \n",
+ " \n",
+ " \n",
+ " \n",
+ " | \n",
+ " \n",
+ " \n",
+ " | \n",
+ "
\n",
+ "
prate
(time, y, x)
float64
dask.array<chunksize=(1, 1059, 1799), meta=np.ndarray>
- crs :
- +proj=lcc lon_0=262.5 lat_0=38.5 lat_1=38.5 lat_2=38.5
- fixed_surface_type :
- ground or water surface
- fixed_surface_value :
- 0
- forecast_date :
- 2023-07-22T19:00:00+00:00
- generating_process :
- forecast
- long_name :
- precipitationrate
- proj_params :
- {'lat_0': 38.5, 'lat_1': 38.5, 'lat_2': 38.5, 'lon_0': 262.5, 'proj': 'lcc'}
- reference_date :
- 2023-07-22T18:00:00+00:00
- standard_name :
- precipitationrate
- statistical_process :
- time_interval_end :
- unit :
- kgm-2s-1
\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " | \n",
+ " Array | \n",
+ " Chunk | \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " Bytes | \n",
+ " 697.68 MiB | \n",
+ " 14.54 MiB | \n",
+ " \n",
+ " \n",
+ " \n",
+ " Shape | \n",
+ " (48, 1059, 1799) | \n",
+ " (1, 1059, 1799) | \n",
+ " \n",
+ " \n",
+ " Dask graph | \n",
+ " 48 chunks in 2 graph layers | \n",
+ " \n",
+ " \n",
+ " Data type | \n",
+ " float64 numpy.ndarray | \n",
+ " \n",
+ " \n",
+ " \n",
+ " | \n",
+ " \n",
+ " \n",
+ " | \n",
+ "
\n",
+ "
pres
(time, y, x)
float64
dask.array<chunksize=(1, 1059, 1799), meta=np.ndarray>
- crs :
- +proj=lcc lon_0=262.5 lat_0=38.5 lat_1=38.5 lat_2=38.5
- fixed_surface_type :
- ground or water surface
- fixed_surface_value :
- 0
- forecast_date :
- 2023-07-22T19:00:00+00:00
- generating_process :
- forecast
- long_name :
- pressure
- proj_params :
- {'lat_0': 38.5, 'lat_1': 38.5, 'lat_2': 38.5, 'lon_0': 262.5, 'proj': 'lcc'}
- reference_date :
- 2023-07-22T18:00:00+00:00
- standard_name :
- pressure
- statistical_process :
- time_interval_end :
- unit :
- pa
\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " | \n",
+ " Array | \n",
+ " Chunk | \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " Bytes | \n",
+ " 697.68 MiB | \n",
+ " 14.54 MiB | \n",
+ " \n",
+ " \n",
+ " \n",
+ " Shape | \n",
+ " (48, 1059, 1799) | \n",
+ " (1, 1059, 1799) | \n",
+ " \n",
+ " \n",
+ " Dask graph | \n",
+ " 48 chunks in 2 graph layers | \n",
+ " \n",
+ " \n",
+ " Data type | \n",
+ " float64 numpy.ndarray | \n",
+ " \n",
+ " \n",
+ " \n",
+ " | \n",
+ " \n",
+ " \n",
+ " | \n",
+ "
\n",
+ "
tmp
(time, y, x)
float64
dask.array<chunksize=(1, 1059, 1799), meta=np.ndarray>
- crs :
- +proj=lcc lon_0=262.5 lat_0=38.5 lat_1=38.5 lat_2=38.5
- fixed_surface_type :
- ground or water surface
- fixed_surface_value :
- 0
- forecast_date :
- 2023-07-22T19:00:00+00:00
- generating_process :
- forecast
- long_name :
- temperature
- proj_params :
- {'lat_0': 38.5, 'lat_1': 38.5, 'lat_2': 38.5, 'lon_0': 262.5, 'proj': 'lcc'}
- reference_date :
- 2023-07-22T18:00:00+00:00
- standard_name :
- temperature
- statistical_process :
- time_interval_end :
- unit :
- K
\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " | \n",
+ " Array | \n",
+ " Chunk | \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " Bytes | \n",
+ " 697.68 MiB | \n",
+ " 14.54 MiB | \n",
+ " \n",
+ " \n",
+ " \n",
+ " Shape | \n",
+ " (48, 1059, 1799) | \n",
+ " (1, 1059, 1799) | \n",
+ " \n",
+ " \n",
+ " Dask graph | \n",
+ " 48 chunks in 2 graph layers | \n",
+ " \n",
+ " \n",
+ " Data type | \n",
+ " float64 numpy.ndarray | \n",
+ " \n",
+ " \n",
+ " \n",
+ " | \n",
+ " \n",
+ " \n",
+ " | \n",
+ "
\n",
+ "
ugrd
(time, y, x)
float64
dask.array<chunksize=(1, 1059, 1799), meta=np.ndarray>
- crs :
- +proj=lcc lon_0=262.5 lat_0=38.5 lat_1=38.5 lat_2=38.5
- fixed_surface_type :
- specific height level above ground
- fixed_surface_value :
- 10
- forecast_date :
- 2023-07-22T19:00:00+00:00
- generating_process :
- forecast
- long_name :
- ucomponentwindspeed
- proj_params :
- {'lat_0': 38.5, 'lat_1': 38.5, 'lat_2': 38.5, 'lon_0': 262.5, 'proj': 'lcc'}
- reference_date :
- 2023-07-22T18:00:00+00:00
- standard_name :
- ucomponentwindspeed
- statistical_process :
- time_interval_end :
- unit :
- ms-1
\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " | \n",
+ " Array | \n",
+ " Chunk | \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " Bytes | \n",
+ " 697.68 MiB | \n",
+ " 14.54 MiB | \n",
+ " \n",
+ " \n",
+ " \n",
+ " Shape | \n",
+ " (48, 1059, 1799) | \n",
+ " (1, 1059, 1799) | \n",
+ " \n",
+ " \n",
+ " Dask graph | \n",
+ " 48 chunks in 2 graph layers | \n",
+ " \n",
+ " \n",
+ " Data type | \n",
+ " float64 numpy.ndarray | \n",
+ " \n",
+ " \n",
+ " \n",
+ " | \n",
+ " \n",
+ " \n",
+ " | \n",
+ "
\n",
+ "
vgrd
(time, y, x)
float64
dask.array<chunksize=(1, 1059, 1799), meta=np.ndarray>
- crs :
- +proj=lcc lon_0=262.5 lat_0=38.5 lat_1=38.5 lat_2=38.5
- fixed_surface_type :
- specific height level above ground
- fixed_surface_value :
- 10
- forecast_date :
- 2023-07-22T19:00:00+00:00
- generating_process :
- forecast
- long_name :
- vcomponentwindspeed
- proj_params :
- {'lat_0': 38.5, 'lat_1': 38.5, 'lat_2': 38.5, 'lon_0': 262.5, 'proj': 'lcc'}
- reference_date :
- 2023-07-22T18:00:00+00:00
- standard_name :
- vcomponentwindspeed
- statistical_process :
- time_interval_end :
- unit :
- ms-1
\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " | \n",
+ " Array | \n",
+ " Chunk | \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " Bytes | \n",
+ " 697.68 MiB | \n",
+ " 14.54 MiB | \n",
+ " \n",
+ " \n",
+ " \n",
+ " Shape | \n",
+ " (48, 1059, 1799) | \n",
+ " (1, 1059, 1799) | \n",
+ " \n",
+ " \n",
+ " Dask graph | \n",
+ " 48 chunks in 2 graph layers | \n",
+ " \n",
+ " \n",
+ " Data type | \n",
+ " float64 numpy.ndarray | \n",
+ " \n",
+ " \n",
+ " \n",
+ " | \n",
+ " \n",
+ " \n",
+ " | \n",
+ "
\n",
+ "
vis
(time, y, x)
float64
dask.array<chunksize=(1, 1059, 1799), meta=np.ndarray>
- crs :
- +proj=lcc lon_0=262.5 lat_0=38.5 lat_1=38.5 lat_2=38.5
- fixed_surface_type :
- ground or water surface
- fixed_surface_value :
- 0
- forecast_date :
- 2023-07-22T19:00:00+00:00
- generating_process :
- forecast
- long_name :
- visibility
- proj_params :
- {'lat_0': 38.5, 'lat_1': 38.5, 'lat_2': 38.5, 'lon_0': 262.5, 'proj': 'lcc'}
- reference_date :
- 2023-07-22T18:00:00+00:00
- standard_name :
- visibility
- statistical_process :
- time_interval_end :
- unit :
- m
\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " | \n",
+ " Array | \n",
+ " Chunk | \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " Bytes | \n",
+ " 697.68 MiB | \n",
+ " 14.54 MiB | \n",
+ " \n",
+ " \n",
+ " \n",
+ " Shape | \n",
+ " (48, 1059, 1799) | \n",
+ " (1, 1059, 1799) | \n",
+ " \n",
+ " \n",
+ " Dask graph | \n",
+ " 48 chunks in 2 graph layers | \n",
+ " \n",
+ " \n",
+ " Data type | \n",
+ " float64 numpy.ndarray | \n",
+ " \n",
+ " \n",
+ " \n",
+ " | \n",
+ " \n",
+ " \n",
+ " | \n",
+ "
\n",
+ "
PandasIndex
PandasIndex(DatetimeIndex(['2023-07-22 19:00:00', '2023-07-22 20:00:00',\n",
+ " '2023-07-22 21:00:00', '2023-07-22 22:00:00',\n",
+ " '2023-07-22 23:00:00', '2023-07-23 00:00:00',\n",
+ " '2023-07-23 01:00:00', '2023-07-23 02:00:00',\n",
+ " '2023-07-23 03:00:00', '2023-07-23 04:00:00',\n",
+ " '2023-07-23 05:00:00', '2023-07-23 06:00:00',\n",
+ " '2023-07-23 07:00:00', '2023-07-23 08:00:00',\n",
+ " '2023-07-23 09:00:00', '2023-07-23 10:00:00',\n",
+ " '2023-07-23 11:00:00', '2023-07-23 12:00:00',\n",
+ " '2023-07-23 13:00:00', '2023-07-23 14:00:00',\n",
+ " '2023-07-23 15:00:00', '2023-07-23 16:00:00',\n",
+ " '2023-07-23 17:00:00', '2023-07-23 18:00:00',\n",
+ " '2023-07-23 19:00:00', '2023-07-23 20:00:00',\n",
+ " '2023-07-23 21:00:00', '2023-07-23 22:00:00',\n",
+ " '2023-07-23 23:00:00', '2023-07-24 00:00:00',\n",
+ " '2023-07-24 01:00:00', '2023-07-24 02:00:00',\n",
+ " '2023-07-24 03:00:00', '2023-07-24 04:00:00',\n",
+ " '2023-07-24 05:00:00', '2023-07-24 06:00:00',\n",
+ " '2023-07-24 07:00:00', '2023-07-24 08:00:00',\n",
+ " '2023-07-24 09:00:00', '2023-07-24 10:00:00',\n",
+ " '2023-07-24 11:00:00', '2023-07-24 12:00:00',\n",
+ " '2023-07-24 13:00:00', '2023-07-24 14:00:00',\n",
+ " '2023-07-24 15:00:00', '2023-07-24 16:00:00',\n",
+ " '2023-07-24 17:00:00', '2023-07-24 18:00:00'],\n",
+ " dtype='datetime64[ns]', name='time', freq=None))
PandasIndex
PandasIndex(Float64Index([-2701000.130325057, -2698000.130325057, -2695000.130325057,\n",
+ " -2692000.130325057, -2689000.130325057, -2686000.130325057,\n",
+ " -2683000.130325057, -2680000.130325057, -2677000.130325057,\n",
+ " -2674000.130325057,\n",
+ " ...\n",
+ " 2665999.869674943, 2668999.869674943, 2671999.869674943,\n",
+ " 2674999.869674943, 2677999.869674943, 2680999.869674943,\n",
+ " 2683999.869674943, 2686999.869674943, 2689999.869674943,\n",
+ " 2692999.869674943],\n",
+ " dtype='float64', name='x', length=1799))
PandasIndex
PandasIndex(Float64Index([-1580581.3368766531, -1577581.3368766531, -1574581.3368766531,\n",
+ " -1571581.3368766531, -1568581.3368766531, -1565581.3368766531,\n",
+ " -1562581.3368766531, -1559581.3368766531, -1556581.3368766531,\n",
+ " -1553581.3368766531,\n",
+ " ...\n",
+ " 1566418.6631233469, 1569418.6631233469, 1572418.6631233469,\n",
+ " 1575418.6631233469, 1578418.6631233469, 1581418.6631233469,\n",
+ " 1584418.6631233469, 1587418.6631233469, 1590418.6631233469,\n",
+ " 1593418.6631233469],\n",
+ " dtype='float64', name='y', length=1059))
- meta :
- Generated with gribberishpy
"
+ ],
+ "text/plain": [
+ "\n",
+ "Dimensions: (time: 48, y: 1059, x: 1799)\n",
+ "Coordinates:\n",
+ " latitude (y, x) float64 dask.array\n",
+ " longitude (y, x) float64 dask.array\n",
+ " * time (time) datetime64[s] 2023-07-22T19:00:00 ... 2023-07-24T18:00:00\n",
+ " * x (x) float64 -2.701e+06 -2.698e+06 ... 2.69e+06 2.693e+06\n",
+ " * y (y) float64 -1.581e+06 -1.578e+06 ... 1.59e+06 1.593e+06\n",
+ "Data variables:\n",
+ " apcp (time, y, x) float64 dask.array\n",
+ " cpofp (time, y, x) float64 dask.array\n",
+ " dpt (time, y, x) float64 dask.array\n",
+ " prate (time, y, x) float64 dask.array\n",
+ " pres (time, y, x) float64 dask.array\n",
+ " tmp (time, y, x) float64 dask.array\n",
+ " ugrd (time, y, x) float64 dask.array\n",
+ " vgrd (time, y, x) float64 dask.array\n",
+ " vis (time, y, x) float64 dask.array\n",
+ "Attributes:\n",
+ " meta: Generated with gribberishpy"
+ ]
+ },
+ "execution_count": 11,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "import xarray as xr\n",
+ "\n",
+ "# open dataset as zarr object using fsspec reference file system and xarray\n",
+ "fs = fsspec.filesystem(\"reference\", fo=f'./hrrr_hourly/hrrr_kerchunk.json', remote_protocol='s3', remote_options={'anon':True, 'use_ssl': False})\n",
+ "m = fs.get_mapper(\"\")\n",
+ "ds = xr.open_dataset(m, engine=\"zarr\", backend_kwargs=dict(consolidated=False), chunks={'time': 1})\n",
+ "ds"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import pyproj\n",
+ "to_xy = pyproj.Transformer.from_crs('epsg:4326', ds.prate.crs, always_xy=True).transform\n",
+ "lat, lng = 41.42717976016072, -71.462122760827\n",
+ "x_sel, y_sel = to_xy(lng, lat)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 15,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ "