<jupyter_start><jupyter_text>Filter: weighted rolling averageWe are applying `wgt` to the data along the time dimension as a weighed rolling average. That essentially means that the solution at some time, `t` should be\begin{equation}y(t) = \sum_{i = t-(m/2)}^{i = t + (m/2)} w_i x_i\end{equation}where $m$ is the size of the filter (`len(wgt)`). And I'm assuming normalized weights, so $\sum_i w_i = 1$. methodsThere are numerous ways to do this operation. I will show three of them in the next cell that all give the same answer. Really, I think these all actually boil down to even running the same underlying code, or nearly so. The first uses just xarray; it makes the rolling object that is then operated on with construct and the dot product with `wgt`. I find this method to be a little hard to write and to understand. The other two methods use numpy's convolve function. The complication is that convolve works only on 1D arrays, so we have to loop over all the longitudes. The first approach uses `apply_along_axis`  and an anonymous function (`lambda`) to do that. The second approach (commented) uses a loop over longitudes to do the same operation. The two approaches give the same answer because they do the same convolution, but the first one is faster.The xarray version keeps the coordinates in the result, but the numpy ways both result in a plain numpy array. So I show how to copy the coordinate information from the original array to the result.<jupyter_code>%%time

#
# Apply weighed rolling mean with xarray:
#
yhov0 = tmp.rolling(time=len(wgt), center=True).construct("window").dot(wgt)
printVarSummary(yhov0)

#
# using numpy only
#
yhov_np = np.apply_along_axis(lambda m: np.convolve(m, wgt, mode='same'), axis=0, arr=tmp)

# Equivalent to this loop (but a bit faster):
# yhov_np = np.zeros(tmp.shape)
# for x in range(len(tmp.lon)):
#     yhov_np[:,x] = np.convolve(tmp[:,x].values, wgt.values, mode='same')

f"Min: {np.nanmin(yhov_np)}, Max: {np.nanmax(yhov_np)}" # Matches NCL values

# copy coordinates from tmp:
yhov = xr.DataArray(yhov_np, dims=tmp.dims, coords=tmp.coords)
yhov.name = "CHI"
yhov.attrs["long_name"] = "smoothed CHI"
printVarSummary(yhov)
#
# create plot (mimic the NCL one)
#
fig, ax = plt.subplots(figsize=(6,8))

ax.set_title("Pacific Region")
levels = np.arange(-10, 12, 2)
cnFillPalette        = "bwr"
ax.set_yticks([0. ,  30.,  61.,   89., 120., 150.])
ax.set_yticklabels(["DEC","JAN","FEB","MAR" ,"APR","MAY"])
ax.invert_yaxis()


meshlon, meshtime = np.meshgrid(yhov0['lon'].sel(lon=slice(100,220)).values, yhov0['time'].values, )
img = ax.contourf(meshlon, meshtime, yhov0.sel(lon=slice(100,220)), cmap=cnFillPalette, levels=levels) 

fig.colorbar(img, orientation='horizontal')

fig.savefig("../../docs/assets/filters_1_py.png")<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12176073837415691, 'fraction_numerical': 0.01526446574369897, 'mean_word_length': 4.983014861995754, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '1', 'dir': 'jupyter-structured-clean-dedup', 'id': '407827', 'license': 'MIT', 'n_tokens_mistral': 983, 'n_tokens_neox': 922, 'n_words': 340, 'path': 'Examples/Notebooks/filters_1.ipynb', 'repo_name': 'jenkayco/hacknostics', 'size': '2817'}