Open Gordon90s opened 6 years ago
You can add arbitrary information into the title for each Curve if you want:
import numpy as np, pandas as pd, holoviews as hv
hv.extension('bokeh')
frequencies = [0.5, 0.75, 1.0, 1.25]
def sine_curve(phase, freq):
xvals = [0.1* i for i in range(100)]
return hv.Curve((xvals, [np.sin(phase+freq*x) for x in xvals])).relabel("b: {}".format(freq**2))
curve_dict = {f:sine_curve(0,f) for f in frequencies}
hv.HoloMap(curve_dict, kdims=['a'])
I'm not sure if that's precisely what you're after here, though.
Kind of thanks. I would have liked to change it at the HoloMap level - or more generally at the layout level - and that did not work. Though I'm happy with the result.
(I would have liked to change pythagoras_viz
in the following plot
import holoviews as hv
from holoviews import Image, HoloMap, DynamicMap, Polygons, Text
import numpy as np
from numpy import array
hv.extension('bokeh')
import bokeh.palettes as bp # for color palettes
# Pythagoras a^2 + b^2 = c^2 visual proof
# define function that returns coordinates of rectangle and line
def rectangle(x=0, y=0, width=.05, height=.05):
return array([(x, y), (x + width, y), (x + width, y + height), (x, y + height)])
def line(x=0, y=0, width=.05, height=.05):
return array([(x, y), (x + width, y + height)])
# choose color for plotting
color_palette = 'Inferno'
col_sq_1 = bp.all_palettes[color_palette][256][20]
col_sq_2 = bp.all_palettes[color_palette][256][20]
col_sq_3 = bp.all_palettes[color_palette][256][20]
col_rect = bp.all_palettes[color_palette][256][145]
# options for plot styling
opts = {'Polygons': dict(toolbar=None, xaxis=None, yaxis=None, width=350, height=350, line_width=1.5)}
# left part of the visual proof, squares of area a^2 and b^2 + 4 triangles of area a*b/2
def square_left(a=1):
# we set a + b = 100 then convert to a + b = 1
a = a / 100.0
b = 1.0 - a
poly_1 = Polygons([rectangle(0, 0, a, b)]).options(color=col_rect) * Polygons([line(0, 0, a, b)])
poly_2 = Polygons([rectangle(0, b, a, a)]).options(color=col_sq_1)
poly_3 = Polygons([rectangle(a, 0, b, b)]).options(color=col_sq_2)
poly_4 = Polygons([rectangle(a, b, b, a)]).options(color=col_rect) * Polygons([line(a, b, b, a)])
text_1 = Text(a / 2, -0.05, 'a') * Text(-0.05, b / 2, 'b')
text_11 = Text(a / 2, 1.05, 'a') * Text(1.05, b / 2, 'b')
text_2 = Text(a + b / 2, -0.05, 'b') * Text(-0.05, b + a / 2, 'a')
text_22 = Text(a + b / 2, 1.05, 'b') * Text(1.05, b + a / 2, 'a')
text_3 = Text(a / 2, b + a / 2, 'a\u00b2').options(color='white') * Text(a + b / 2, b / 2, 'b\u00b2').options(
color='white')
text_4 = Text(a / 2.5, (b + 0.1 / a) / 2.5, 'c') * Text(a + (b - 0.082 / a) / 2, b + a / 2, 'c')
output = (poly_1 * poly_2 * poly_3 * poly_4 * text_1 * text_11 * text_2 * text_22 * text_3 * text_4).options(opts)
output = output.relabel("a\u00b2: {}".format(np.round((a)*100)**2), "b\u00b2: {}".format(np.round((1-a)*100)**2))
return output
# right part of the visual proof, squares of area c^2 + 4 triangles of area a*b/2
def square_right(a=1):
a = a / 100.0
b = 1.0 - a
poly_5 = Polygons([rectangle(0, 0, a + b, b + a)]).options(color=col_rect)
poly_6 = Polygons([array([[a, 0], [a + b, a], [b, b + a], [0, b], [a, 0]])]).options(color=col_sq_3)
text_1 = Text(a / 2, -0.05, 'a') * Text(-0.05, b / 2, 'b')
text_11 = Text(b / 2, 1.05, 'b') * Text(1.05, a / 2, 'a')
text_2 = Text(a + b / 2, -0.05, 'b') * Text(-0.05, b + a / 2, 'a')
text_22 = Text(b + a / 2, 1.05, 'a') * Text(1.05, a + b / 2, 'b')
text_3 = Text((b + a) / 2, (b + a) / 2, 'c\u00b2').options(color='white')
output = (poly_5 * poly_6 * text_1 * text_11 * text_2 * text_22 * text_3).options(opts)
output = output.relabel("c\u00b2: {}".format(np.round((a)*100)**2+np.round((1-a)*100)**2))
return output
# create dynamic maps of square_left and square_right
dmap_left = DynamicMap(square_left, kdims=['a'])
dmap_right = DynamicMap(square_right, kdims=['a'])
# and plot together
range_a = (20, 80)
pythagoras_viz = (dmap_left.redim.range(a=range_a) + dmap_right.redim.range(a=range_a))
pythagoras_viz = pythagoras_viz.options(toolbar=None).redim.range(x=(-0.1, 1.1), y=(-0.1, 1.1))
pythagoras_viz = pythagoras_viz
pythagoras_viz
)
P.S.: By the way I'm surprised at the lack of fluidity in my plot. I guess it's because Bokeh renders pixelwize with no vector objects?
Cool demo, but indeed pretty slow. I'll do some profiling to figure out what's taking so long. One thing worth trying is to combine the text elements into an hv.Labels
element.
There are a bunch of things we could improve to speed things up when plotting a lot of objects but you can also achieve a significant speedup by combining the polygons and labels as much as possible, here's my initial attempt:
# left part of the visual proof, squares of area a^2 and b^2 + 4 triangles of area a*b/2
def square_left(a=1):
# we set a + b = 100 then convert to a + b = 1
a = a / 100.0
b = 1.0 - a
poly_1 = Polygons([rectangle(a, b, b, a), rectangle(0, 0, a, b)]).options(color=col_rect)
poly_2 = Polygons([rectangle(0, b, a, a), rectangle(a, 0, b, b)]).options(color=col_sq_1)
poly_3 = Polygons([line(0, 0, a, b), line(a, b, b, a)])
text_1 = [
(a / 2, -0.05, 'a'), (-0.05, b / 2, 'b'),
(a / 2, 1.05, 'a'), (1.05, b / 2, 'b'),
(a + b / 2, -0.05, 'b'), (-0.05, b + a / 2, 'a'),
(a + b / 2, 1.05, 'b'), (1.05, b + a / 2, 'a'),
(a / 2.5, (b + 0.1 / a) / 2.5, 'c'),
(a + (b - 0.082 / a) / 2, b + a / 2, 'c')
]
text_2 = [
(a / 2, b + a / 2, 'a\u00b2'), (a + b / 2, b / 2, 'b\u00b2')
]
output = (poly_1 * poly_2 * poly_3 * hv.Labels(text_1) * hv.Labels(text_2).options(text_color='white')).options(opts)
output = output.relabel("a\u00b2: {}".format(np.round((a)*100)**2), "b\u00b2: {}".format(np.round((1-a)*100)**2))
return output
# right part of the visual proof, squares of area c^2 + 4 triangles of area a*b/2
def square_right(a=1):
a = a / 100.0
b = 1.0 - a
poly_5 = Polygons([rectangle(0, 0, a + b, b + a)]).options(color=col_rect)
poly_6 = Polygons([array([[a, 0], [a + b, a], [b, b + a], [0, b], [a, 0]])]).options(color=col_sq_3)
text_1 = [
(a / 2, -0.05, 'a'), (-0.05, b / 2, 'b'),
(b / 2, 1.05, 'b'), (1.05, a / 2, 'a'),
(a + b / 2, -0.05, 'b'), (-0.05, b + a / 2, 'a'),
(b + a / 2, 1.05, 'a'), (1.05, a + b / 2, 'b')
]
text_2 = Text((b + a) / 2, (b + a) / 2, 'c\u00b2').options(color='white')
output = (poly_5 * poly_6 * hv.Labels(text_1) * text_2).options(opts)
output = output.relabel("c\u00b2: {}".format(np.round((a)*100)**2+np.round((1-a)*100)**2))
return output
Didn't improve speed that much, but the code looks a lot nicer that way!
The labels are definitely the ones slowing down the graphic. Without them, everything runs smoothly. Maybe a HoloMap would have been a better choice with the labels? Anyways, I'm happy with this version now! :)
Hmmm, well with another visualization I am not quite able to solve my issue with the proposed .relabel("b: {}".format(freq**2))
solution.
Is there any way to do it at the HoloMap level after all? Say something like
hv.HoloMap(curve_dict, kdims=['freq']).relabel("b: {}".format(freq**2))
?
Say
kdims = 'a'
in a HoloMap. In the title of the plot, the default is then in the form "a: [value of a]".I would like to have something of the form "a: [value of a], b: [value of a]^2" in the title, who would I do that?
For example of this example: