Skip to content

Commit 050d115

Browse files
headtr1ckclaude
andcommitted
Reuse the vectorize=True example for vectorize=[dims]
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 3a4482d commit 050d115

1 file changed

Lines changed: 44 additions & 12 deletions

File tree

‎advanced/apply_ufunc/automatic-vectorizing-numpy.ipynb‎

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -344,9 +344,7 @@
344344
"source": [
345345
"## Looping over some dimensions only\n",
346346
"\n",
347-
"`vectorize=True` loops over all loop dimensions, so `debug_interp` was called 12 times. But many functions can process a whole stack of vectors at once, as long as the other inputs are the same for all of them. For example, `scipy.interpolate.make_interp_spline` interpolates all vectors along the last axis at once, but only to a single set of new latitudes.\n",
348-
"\n",
349-
"Let's use different new latitudes at every time step. They vary along `time`, but not along `lon`, so we only need to loop over `time`. Instead of `True`, we pass the dimensions to loop over to `vectorize`. All other loop dimensions, here `lon`, are passed to our function in bulk:"
347+
"Let's use different new latitudes at every time step. They now vary along `time`, but not along `lon`. The same call as above still works:"
350348
]
351349
},
352350
{
@@ -358,12 +356,45 @@
358356
},
359357
"outputs": [],
360358
"source": [
361-
"from scipy.interpolate import make_interp_spline\n",
362-
"\n",
363359
"newlat_t = xr.DataArray(\n",
364360
" np.linspace(20, 70, 100) + np.arange(4)[:, np.newaxis], dims=(\"time\", \"lat\")\n",
365361
")\n",
366362
"\n",
363+
"interped = xr.apply_ufunc(\n",
364+
" debug_interp, # first the function\n",
365+
" newlat_t,\n",
366+
" air.lat,\n",
367+
" air,\n",
368+
" input_core_dims=[[\"lat\"], [\"lat\"], [\"lat\"]],\n",
369+
" output_core_dims=[[\"lat\"]],\n",
370+
" exclude_dims={\"lat\"}, # dimensions allowed to change size. Must be set!\n",
371+
" vectorize=True,\n",
372+
")"
373+
]
374+
},
375+
{
376+
"cell_type": "markdown",
377+
"id": "16",
378+
"metadata": {
379+
"tags": []
380+
},
381+
"source": [
382+
"`debug_interp` is again called 12 times, but the 3 calls for the `lon` values of each `time` all use the same new latitudes. Many functions can process a whole stack of vectors at once in that case. For example, `scipy.interpolate.make_interp_spline` interpolates all vectors along the last axis at once, to a single set of new latitudes.\n",
383+
"\n",
384+
"So we only need to loop over `time`. Instead of `True`, we pass the dimensions to loop over to `vectorize`. All other loop dimensions, here `lon`, are passed to our function in bulk:"
385+
]
386+
},
387+
{
388+
"cell_type": "code",
389+
"execution_count": null,
390+
"id": "17",
391+
"metadata": {
392+
"tags": []
393+
},
394+
"outputs": [],
395+
"source": [
396+
"from scipy.interpolate import make_interp_spline\n",
397+
"\n",
367398
"\n",
368399
"def debug_interp_batched(xi, x, data):\n",
369400
" print(f\"data: {data.shape} | x: {x.shape} | xi: {xi.shape}\")\n",
@@ -372,34 +403,35 @@
372403
" return make_interp_spline(x, data, k=1, axis=-1)(xi)\n",
373404
"\n",
374405
"\n",
375-
"interped = xr.apply_ufunc(\n",
376-
" debug_interp_batched,\n",
406+
"interped_batched = xr.apply_ufunc(\n",
407+
" debug_interp_batched, # only the function and vectorize changed\n",
377408
" newlat_t,\n",
378409
" air.lat,\n",
379410
" air,\n",
380411
" input_core_dims=[[\"lat\"], [\"lat\"], [\"lat\"]],\n",
381412
" output_core_dims=[[\"lat\"]],\n",
382-
" exclude_dims={\"lat\"},\n",
413+
" exclude_dims={\"lat\"}, # dimensions allowed to change size. Must be set!\n",
383414
" vectorize=[\"time\"], # only loop over time\n",
384415
")\n",
385-
"interped"
416+
"xr.testing.assert_allclose(interped, interped_batched)\n",
417+
"interped_batched"
386418
]
387419
},
388420
{
389421
"cell_type": "markdown",
390-
"id": "16",
422+
"id": "18",
391423
"metadata": {
392424
"tags": []
393425
},
394426
"source": [
395-
"Now `debug_interp_batched` is called only 4 times, once per `time`, and receives all 3 `lon` at once: `data` has shape `(lon, lat)`.\n",
427+
"Now `debug_interp_batched` is called only 4 times, once per `time`, and receives all 3 `lon` at once: `data` has shape `(lon, lat)`. The result is the same.\n",
396428
"\n",
397429
"Loop dimensions that are passed in bulk follow numpy's broadcasting rules. `xi` does not vary along `lon`, so it has size 1 along that dimension, and our function has to handle that."
398430
]
399431
},
400432
{
401433
"cell_type": "markdown",
402-
"id": "17",
434+
"id": "19",
403435
"metadata": {
404436
"tags": []
405437
},

0 commit comments

Comments
 (0)