Open ea42gh opened 6 years ago
Major feature if you want to add radial plots in both bokeh and matplotlib; what I had in mind was simpler: bokeh plot with (angle,r) treated as cartesian coordinates, and a corresponding matplotlib plot with (angle,r) treated as polar coordinates on a radial plot.
Use case: a beamformer pattern
The only reason the two plots need different hv.Curve() definitions are the angles: the bokeh version takes degrees, while the matplotlib version needs radians.
Incidentally, I can't get hv.HLine to work in the matplotlib plot
A much simplified version with most of the physics removed is
phi = np.linspace(-90, 90, 181)
phi_rad = np.pi/180 * phi
def AF(n, phi_rad):
'''array factor for n elements'''
psi2 = 0.5*phi_rad
with np.errstate(divide='ignore', invalid='ignore'):
f_phi = np.sin( n*psi2 ) / (float(n) * np.sin(psi2))
f_phi[np.isnan( f_phi )] = 1.
return 10.*np.log10( np.abs(f_phi) )
def plot_AF( n_elems ):
x_dim = hv.Dimension('x', label='ψ', unit = 'degree')
y_dim = hv.Dimension('y', label='Array Factor', unit = 'dB')
o_bokeh = {'Curve' : { 'show_grid':True,'xticks':8}}
o_mpl = {'Curve' : { 'projection':'polar', 'show_grid':True,'xticks':4}}
h_xy = hv.Curve( (phi, AF( n_elems, phi_rad)),x_dim,y_dim ) \
.redim.range(y=(-25,1))
h_rt = hv.Curve( (phi_rad, AF( n_elems, phi_rad)),x_dim, y_dim ) \
.redim.range(y=(-25,1))
h_rt = hv.Div( hv.renderer('matplotlib').html(h_rt.options(o_mpl, backend='matplotlib')) )
return (h_xy.options(o_bokeh, backend='bokeh')+h_rt).relabel('Array Factor Plot')
hv.DynamicMap( plot_AF, kdims=['n_elems'] ) \
.redim.values(n_elems=range(1,101))
Or, putting in more of the physics and hiding the global variables
def gen_AFplots():
phi = np.linspace(-90, 90, 181)
phi_rad = np.pi/180 * phi
def AF(n, d_wl, steering_angle_rad ):
'''array factor for n elements, d_wl = element_spacing/wavelength'''
ss_phi = np.sin( phi_rad )-np.sin(steering_angle_rad )
psi2 = np.pi*d_wl*ss_phi
with np.errstate(divide='ignore', invalid='ignore'):
f_phi = np.sin( n*psi2 ) / (float(n) * np.sin(psi2))
f_phi[np.isnan( f_phi )] = 1.
return 10.*np.log10( np.abs(f_phi)
)
def plot( n_elems, d_wl, steering_angle ):
x_dim = hv.Dimension('x', label='φ', unit = 'degree')
y_dim = hv.Dimension('y', label='Array Factor', unit = 'dB')
ticks = list( np.pi/9*np.arange(-8, 9, 1) )
o_bokeh = {'Curve' : { 'show_grid':True,'xticks':8}, 'VLine' : {'line_width':.5, 'color':'red'}}
o_mpl = {'Curve' : { 'projection':'polar', 'show_grid':True,'xticks':ticks}, 'VLine' : {'linewidth':1, 'color':'red'}}
af = AF( n_elems, d_wl, np.pi/180*steering_angle)
h_xy = hv.Curve( (phi, af),x_dim,y_dim ) \
.redim.range(y=(-25,1))*\
hv.VLine( steering_angle)
h_rt = hv.Curve( (phi_rad, af),x_dim, y_dim ) \
.redim.range(y=(-25,1))*\
hv.VLine( np.pi/180*steering_angle)
h_rt = hv.Div( hv.renderer('matplotlib').html(h_rt.options(o_mpl, backend='matplotlib')) )
return h_xy.options(o_bokeh, backend='bokeh')+h_rt
return plot
hv.DynamicMap( gen_AFplots(), kdims=['n_elems', 'd_wl', 'steering_angle'] ) \
.redim.values(n_elems=range(1,101)).redim.range( d_wl=(1e-1,.5), steering_angle=(-90,90))
where d_wl is the ratio of the element separation to the wavelength of the incoming signal, and phi_0 is the steering angle.
The array factor $AF$ for a uniform linear array is given by
$$ AF(\psi) = \frac{\sin (\tfrac{1}{2} N \psi) }{ N \sin( \tfrac{1}{2} \psi)} $$ where
Do you want me to put this in a notebook with some text?
Thanks for that! If it isn't too much trouble, it would be nice to see screenshots/gifs of the two versions. Of course I can run the code myself, but it is useful to show something everyone can compare...
In hv version 1.11.0 this now fails:
running it a first time yields a display with inoperable controls rerunning it a second time fails outright with
D:\PYTHON\lib\site-packages\holoviews\plotting\mpl\plot.py in _compute_gridspec(self, layout)
954 layout_dimensions, frame_ranges,
955 dict(zip(positions, subaxes)),
--> 956 num=0 if empty else layout_count)
957 subplots, adjoint_layout, _ = subplot_data
958 layout_axes[(r, c)] = subaxes
D:\PYTHON\lib\site-packages\holoviews\plotting\mpl\plot.py in _create_subplots(self, layout, positions, layout_dimensions, ranges, axes, num, create)
1067 if isinstance(view, GridSpace):
1068 plotopts['create_axes'] = ax is not None
-> 1069 plot_type = Store.registry['matplotlib'][vtype]
1070 if pos != 'main' and vtype in MPLPlot.sideplots:
1071 plot_type = MPLPlot.sideplots[vtype]
KeyError: <class 'holoviews.element.annotation.Div'>
This is an important feature for datascientist
Given
h=hv.Curve((angle,r)).options(backend='matplotlib',projection='radial')
it might be useful to have an option specifying that angles are given in degrees:I'd like to plot the same Curve with bokeh and matplotlib and actually use degrees rather than radians for the angles