I'm trying to achieve an effect similar to bicubic interpolation in matlotlib.
Here is the minimal code in matlotlib:
%pylab inline
import matplotlib.pyplot as plt
import numpy as np
grid = np.random.rand(4, 4)
plt.subplot(121)
plt.imshow(grid)
plt.subplot(122)
plt.imshow(grid, interpolation = 'bicubic')
which produces:

And here is a starter code from the simple heat map Altair example:
import altair as alt
import pandas as pd
import numpy as np
# Compute x^2 + y^2 across a 2D grid
x, y = np.meshgrid(range(-5, 5), range(-5, 5))
z = x ** 2 + y ** 2
# Convert this grid to columnar data expected by Altair
source = pd.DataFrame({'x': x.ravel(),
'y': y.ravel(),
'z': z.ravel()})
alt.Chart(source).mark_rect().encode(
x='x:O',
y='y:O',
color='z:Q'
)

P.S. there are other interpolation schemes as well and many of these will probably work for me, in case bicubic specifically isn't available.

This is not yet possible in Altair. The Vega-Lite feature request is here: https://github.com/vega/vega-lite/issues/6043
@firasm You can do this outside of altair -- I followed an example here and by controlling the pixel_size and the method in scipy's griddata (there's definitely a cubic option, a few others as well...), I think you can get what you're looking for!
e.g. something along the lines of:
from scipy.interpolate import griddata
import numpy as np
import pandas as pd
# Given your dataframe = df
# Define size of pixels in grid -- smaller = smoother grid
pixel_size = .08
# Determine extent of observations and create pixel_size-spaced array
x_range = np.arange(df.x.min() - df.x.min() % pixel,
df.x.max(), pixel)
y_range = np.arange(df.y.min() - df.y.min() % pixel,
df.y.max(), pixel)[::-1]
shape = (len(y_range), len(x_range))
xmin, xmax, ymin, ymax = x_range.min(), x_range.max(), y_range.min(), y_range.max()
extent = (xmin, xmax, ymin, ymax)
# Create grid
x_mesh, y_mesh = np.meshgrid(x_range, y_range)
# Create dataframe to store interpolated points in
interp_df = pd.DataFrame({'y':y_mesh.flatten(), 'x': x_mesh.flatten()})
# Interpolate using desired method with scipy's griddata
pm_interp = griddata((df['longitude'], df['latitude']), df[date], (x_mesh, y_mesh), method = 'linear')
interp_df['interpolated value'] = pm_interp.flatten()
Then you can plot in altair your interp_df as a heatmap.
Great! Thanks @cgostic !
For anyone interested, here's what the final product looks like and the associated code:
import altair as alt
alt.data_transformers.disable_max_rows()
import pandas as pd
import numpy as np
from scipy.interpolate import griddata
# Compute x^2 + y^2 across a 2D grid
x, y = np.meshgrid(range(-5, 5), range(-5, 5))
z = x ** 2 + y ** 2
# Convert this grid to columnar data expected by Altair
source = pd.DataFrame({'x': x.ravel(),
'y': y.ravel(),
'z': z.ravel()})
# ---------
df = source
# Define size of pixels in grid -- smaller = smoother grid
pixel_size = .10
# Determine extent of observations and create pixel_size-spaced array
x_range = np.arange(df.x.min() - df.x.min() % pixel_size,
df.x.max(), pixel_size)
y_range = np.arange(df.y.min() - df.y.min() % pixel_size,
df.y.max(), pixel_size)[::-1]
shape = (len(y_range), len(x_range))
xmin, xmax, ymin, ymax = x_range.min(), x_range.max(), y_range.min(), y_range.max()
extent = (xmin, xmax, ymin, ymax)
# Create grid
x_mesh, y_mesh = np.meshgrid(x_range, y_range)
# Create dataframe to store interpolated points in
interp_df = pd.DataFrame({'y':y_mesh.flatten(), 'x': x_mesh.flatten()})
# Interpolate using desired method with scipy's griddata
pm_interp = griddata((df['x'], df['y']), df['z'], (x_mesh, y_mesh), method = 'linear')
interp_df['interpolated value'] = pm_interp.flatten()
alt.Chart(interp_df).mark_rect().encode(
x='x:O',
y='y:O',
color='interpolated value:Q'
)
You probably still want to mess around with the x and y-axes (switching them to :Q) does something funny (because of where the origin is I think).
