Download notebook (.ipynb)

geom_spoke()#

import numpy as np

from lets_plot import *
LetsPlot.setup_html()
def cartesian_to_polar(xarray, yarray, rscale):
    rarray = np.sqrt(xarray**2 + yarray**2)
    return rarray / rarray.max() * rscale, np.arctan2(yarray, xarray)

def get_data(n, a, b, vector_field):
    d = (b - a) / (n - 1)
    xrange = np.linspace(a, b, n)
    yrange = np.linspace(a, b, n)
    X, Y = np.meshgrid(xrange, yrange)
    R, A, Z = vector_field(X, Y, d)
    z = [None] * X.shape[0] * X.shape[1] if Z is None else Z.reshape(-1)
    return dict(x=X.reshape(-1), y=Y.reshape(-1), r=R.reshape(-1), a=A.reshape(-1), z=z)

def vector_field(f):
    def field(xarray, yarray, d):
        return *cartesian_to_polar(*f(xarray, yarray), d), None
    return field

def gradient_field(f):
    def field(xarray, yarray, d):
        Z = f(xarray, yarray)
        return *cartesian_to_polar(*reversed(np.gradient(Z, d)), d), Z
    return field

1. Plot Vector Field#

n = 11
a, b = -5, 5
vector_field_data = get_data(n, a, b, vector_field(lambda xarray, yarray: (yarray, -xarray)))
ggplot(vector_field_data, aes('x', 'y', color='r')) + \
    geom_spoke(aes(angle='a', radius='r'), \
               arrow=arrow(type='closed', angle=12, length=15)) + \
    scale_color_gradient(low='#3288bd', high='#d53e4f', guide='none') + \
    coord_fixed(xlim=[a, b], ylim=[a, b]) + \
    ggsize(500, 500) + \
    theme_minimal() + \
    theme(axis_text=element_text(margin=10), axis_title='blank')

2. Plot Gradient of a Scalar Field#

gradient_field_data = get_data(21, -2*np.pi, 2*np.pi, gradient_field(lambda xarray, yarray: np.sin(xarray) + np.cos(yarray)))
p = ggplot(gradient_field_data, aes('x', 'y')) + coord_fixed() + theme_void() + scale_viridis(['color', 'fill'])
p + geom_bin2d(aes(fill='z'), stat='identity')
p + geom_spoke(aes(angle='a', radius='r', color='z'), arrow=arrow(type='closed', angle=15))

3. Parameter pivot#

def get_plot(pivot):
    n = 4
    a, b = -2, 2
    r = .75
    pivot_data = get_data(n, a, b, gradient_field(lambda xarray, yarray: xarray**2 + yarray**2))
    title = "pivot={0}{1}".format(pivot, " (default)" if pivot == 'tail' else "")
    return ggplot(pivot_data, aes('x', 'y')) + \
        geom_spoke(aes(angle='a'), radius=r, pivot=pivot) + \
        geom_point() + \
        coord_fixed() + \
        xlim(a - r, b + r) + ylim(a - r, b + r) + \
        ggtitle(title) + \
        theme_void() + theme(plot_title=element_text(hjust=0.5))
gggrid([get_plot('tail'), get_plot('mid'), get_plot('tip')], ncol=3)

4. On Map#

map_data = get_data(30, 0, 40, vector_field(lambda xarray, yarray: (np.sin(yarray / 4), np.cos(xarray / 4))))
ggplot() + \
    geom_livemap(zoom=5) + \
    geom_spoke(aes('x', 'y', angle='a', radius='r'), data=map_data, arrow=arrow(type='closed', angle=15))