Iâ€™m trying to create a contour plot with arbitrarily placed data points, but I canâ€™t seem to get it to work because contour expects x and y coordinates on a grid. Iâ€™ve sort of gotten around this using a 3D surface plot with Z=0, but it seems wrong, plus I have to get the zoom and angle right.

Is there any way to just make a contour plot out of this directly?

You can plot a contour over irregular data, by defining a regular grid that covers the initial data, and interpolating the so called z-values at the regular grid points:

import plotly.graph_objects as go
import numpy as np
from scipy.interpolate import griddata
np.random.seed(1273)
#generate irregular data
x= -1+2*np.random.rand(100)
y= np.random.rand(100)
xm, xM = x.min(), x.max()
ym, yM = y.min(), y.max()
#z-values at the irregular data
z = np.sin(np.pi*2*(x*x+y*y));
#Define a regular grid over the data
xr = np.linspace(xm, xM, 200)
yr= np.linspace(ym, yM, 100)
xr, yr = np.meshgrid(xr, yr)
#evaluate the z-values at the regular grid through cubic interpolation
Z = griddata((x, y), z, (xr, yr) , method='cubic')
fig=go.Figure(go.Contour(x=xr[0], y=yr[:, 0], z=Z,
colorscale='curl',
contours=dict(start=np.nanmin(Z),
end=np.nanmax(Z), size=0.2)))
fig.update_layout(title_text='Contour plot from irregular data',
title_x=0.5,
width=600, height=400)