Remove Bokeh Logo in HoloViews - python-3.x

Is it possible to remove the Bokeh logo from plots generated with HoloViews? Nothing against it... it's just that it may not make sense to display it in certain reports. :)
I know that in Bokeh I can simply do:
p = bkp.figure(...)
...
p.toolbar.logo = None
UPDATE
Here's my import section:
import sys
import os
import numpy as np
np.random.seed(0)
import random
random.seed(0)
import pandas as pd
from bokeh.models import HoverTool
import holoviews as hv
hv.extension("bokeh", logo=False)

Currently (as of holoviews 1.9.1) the option to disable the bokeh logo in the toolbar is not directly exposed, but you can supply a so called finalize_hook which lets you modify the plot directly. You can add such a hook directly on the ElementPlot to set it globally:
def disable_logo(plot, element):
plot.state.toolbar.logo = None
hv.plotting.bokeh.ElementPlot.finalize_hooks.append(disable_logo)
or set it as a plot option:
hv.Curve(range(10)).opts(plot=dict(finalize_hooks=[disable_logo])

To remove the Bokeh logo for more complicated layouts, I think you need to render it to a Bokeh figure, and then use Bokeh's native method to remove it.
layout = C + D
plot = renderer.get_plot(layout)
p = plot.state
p.children[0].toolbar.logo = None
show(p)

hv.extension("bokeh",logo=False)

1) This is almost the same as philippjfr answer, but slightly shorter using hooks:
def remove_bokeh_logo(plot, element):
plot.state.toolbar.logo = None
hv.Scatter(df).opts(hooks=[remove_bokeh_logo])
2) And there's Andrew's answer, rendering the plot as bokeh and then removing the logo:
from bokeh.plotting import show
hv_plot = hv.Scatter(df)
bokeh_plot = hv.render(hv_plot, backend='bokeh')
bokeh_plot.toolbar.logo = None
show(bokeh_plot)

Related

Bokeh plot title 'str' object is not callable

In Jupyter Notebooks I read in a dataframe and create several plots with Pandas / Bokeh.
While creating one of the latter I get an error.
Search for similar problems said, that there might be somewhere above in the script something like
plt.title = "Title"
which overwrites the method. But this is not the case for me. I have nothing similar in the code above -exept in the figure parameters. Here the Bokeh documentation describes to set a figure title like I used it.
Using the part of the code that leads the the error in the complete notebook in a stand-alone script only does NOT lead to the error. So, also in my case the problem might have something to do with my code above. But maybe some of you has an idea when seeing this..(?)
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from bokeh.plotting import figure, show, output_notebook, ColumnDataSource
from bokeh.io import output_notebook
from bokeh.layouts import column, gridplot
from bokeh.models import Label, Title
from bokeh.models import Div
data = df
output_notebook()
# Title of the overall plot
abovetitle = ("This should be the overall title of all graphs")
# GRAPH 1
s1 = figure(width = 250, plot_height = 250, title="Graph 1", x_axis_label = "axis title 1", y_axis_label = 'µs')
s1.line(x, y, width=1, color="black", alpha=1, source = data)
# s1.title.text = "Title With Options" # this is a instead-off 'title=' test, but does not solve the problem
# GRAPH 2
s2 = figure(width = 250, plot_height = 250, title="Graph 2", x_axis_label = "axis title 2, y_axis_label = 'µs')
s2.line(x, y, width=1, color="blue", alpha=1, source = data)
#s2.title.text = "Title With Options" # this is a instead-off 'title=' test, but does not solve the problem
# plot graphs:
p = gridplot([[s1, s2]])
show(column(Div(text=abovetitle), p))
leads to the type error
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-24-33e4828b986d> in <module>
31 # plot graphs:
32 p = gridplot([[s1, s2]])
---> 33 show(column(Div(text=title), p))
TypeError: 'str' object is not callable
Recalling
import matplotlib.pyplot as plt
does not solve the problem. Hence, recalling
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from bokeh.plotting import figure, show, output_notebook, ColumnDataSource
from bokeh.io import output_notebook
from bokeh.layouts import column, gridplot
from bokeh.models import Label, Title
from bokeh.models import Div
solves the problem. Any further idea what might cause this error?
In the mean time I got a very useful hint: In one of the prior cells I accidentially used a Bokeh API function name as variable name and overwrote the function. If someone faces a comparable problem have a look at your variable naming. Maybe there happend the same accident... ;-)
#############################
# Define column names of XData binary part
header = ["Col1","Col2","Col3"]
# Split XData in single, space separated columns
x_df = selected_df.XData.str.split(' ', expand=True)
x_df.drop(0, inplace=True, axis=1)
x_df.columns = header
#print(x_df)
# Binary XData to integer
for column in x_df: # DONT DO THAT!!!!! THIS OVERWRITES BOKEH API FUNCTION. EG. USE `col` INSTEAD OF `column`
x_df[column] = x_df[column].apply(int, base=16) # DONT DO THAT!!!!! THIS OVERWRITES BOKEH API FUNCTION. EG. USE `col` INSTEAD OF `column`

How to convert bokeh plots to BytesIO object to encode the plot with base64 module

I have a plot object of bokeh where I plot sin(x) curve.
from math import *
from io import BytesIO
from bokeh.plotting import (figure, output_file, show)
from bokeh.io import (export_png, export_svgs)
import base64
import numpy as np
plot = figure(plot_width=1000, plot_height=500)
x = np.linspace(-2*np.pi, 2*np.pi, 1000)
y = np.array([sin(i) for i in x])
plot.line(x, y, line_width=1)
Now, instead of saving it to some html file by some name, output_file('sine.html') I want to create a BytesIO() object so that I can further do base64 encoding.
I kindly need community help.
The reason why I desire is in matplotlib I can export an image as BytesIO() object and work with it smoothly rendering it back in Flask or Dash app like this,
figfile = BytesIO()
plt.savefig(figfile, format='png')
plt.clf()
figfile.seek(0)
figdata_png = base64.b64encode(figfile.getvalue())
return figdata_png.decode('UTF-8')
and I want the same applicability with bokeh.
Please guide me with this.
Bokeh provides this functionality in bokeh.io.export.get_screenshot_as_png:
from bokeh.io.export import get_screenshot_as_png
img = get_screenshot_as_png(plot)
img is a PIL image instance which contains the image.
Off-topic: This can also be used to have the plot displayed as a PNG in JupyterLab. Just call get_screenshot_as_png(plot) and you are done.

Arranging widgets in ipywidgets interactive

I have this interactive graph code using ipywidgets; but not sure how to arragne the each variable inside the interactive function in widgets. the default layout is vertical. But I want to arrange them in horizontal way.
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
plt.style.use('seaborn')
%config InlineBackend.figure_format = 'svg'
from ipywidgets import interactive,interact
#function to plot the different curves
def plot_function(u=1,v=2,w=3,x=4,y=5,z=6):
time=np.arange(0,1,0.01)
df=pd.DataFrame({"Y1":np.sin(time*u*2*np.pi),"y2":np.sin(time*v*2*np.pi),"y3":np.sin(time*w*2*np.pi),
"y4":np.sin(time*x*2*np.pi),"y5":np.sin(time*y*2*np.pi),"y6":np.sin(time*z*2*np.pi)})
df.plot()
widget=interactive(plot_function,u=1,v=2,w=3,x=4,y=5,z=6)
widget
interactive is restricted to fairly simple widget layouts. Have a look at the Flexbox options if you want to customize them some more.
One simple get around is to use the interactive call to generate and link your widgets and functions, then restructure the widgets inside a HBox. Then add a layout that tells the box to wrap at line ends. I added a couple more imports and three lines at the end to achieve this.
1) controls - an HBox of your input widgets.
2) The Output widget generated by the interactive call.
3) A VBox that wraps the two together.
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
plt.style.use('seaborn')
%config InlineBackend.figure_format = 'svg'
#importing the necessary items from the Ipywidgets library
from ipywidgets import interactive,interact, HBox, Layout,VBox
#function to plot the different curves
def plot_function(u=1,v=2,w=3,x=4,y=5,z=6):
time=np.arange(0,1,0.01)
df=pd.DataFrame({"Y1":np.sin(time*u*2*np.pi),"y2":np.sin(time*v*2*np.pi),"y3":np.sin(time*w*2*np.pi),
"y4":np.sin(time*x*2*np.pi),"y5":np.sin(time*y*2*np.pi),"y6":np.sin(time*z*2*np.pi)})
df.plot()
widget=interactive(plot_function,u=1,v=2,w=3,x=4,y=5,z=6)
controls = HBox(widget.children[:-1], layout = Layout(flex_flow='row wrap'))
output = widget.children[-1]
display(VBox([controls, output]))
Hi this is the decorator which I am using instead of #interact:
def interact_delayed(_InteractFactory__interact_f=None, **kwargs):
def patch(obj):
if hasattr(obj.widget, 'layout'):
obj.widget.layout = Layout(flex_flow='row wrap')
for child in obj.widget.children:
if hasattr(child, 'continuous_update'):
child.continuous_update = False
return obj
if _InteractFactory__interact_f is None:
def decorator(f):
obj = interact(f, **kwargs)
return patch(obj)
return decorator
else:
obj = interact(_InteractFactory__interact_f, **kwargs)
return patch(obj)
The patch function modifies default attributes of ipywidget object: applies the Layout suggested in the previous answer and also sets continuous_update to false which I found useful in my cases.
The if-else branches takes care about decorator versus function use-case scenarios.
There is no way to arrange widgets by adding a parameter in "interact" or interactive.

Why doesn't holoviews show colors?

I am trying to reproduce a simple example from holoviews. I am running bokeh Version: 0.12.11 and holoviews Version: 1.9.1.
Here is how it goes.
import numpy as np
import pandas as pd
import holoviews as hv
hv.extension('bokeh')
macro_df = pd.read_csv('http://assets.holoviews.org/macro.csv', '\t')
key_dimensions = [('year', 'Year'), ('country', 'Country')]
value_dimensions = [('unem', 'Unemployment'), ('capmob', 'Capital Mobility'),
('gdp', 'GDP Growth'), ('trade', 'Trade')]
macro = hv.Table(macro_df, key_dimensions, value_dimensions)
%%opts Scatter [width=700 height=400 scaling_method='width' scaling_factor=2 size_index=2 show_grid=True]
%%opts Scatter (color=Cycle('Category20') line_color='k')
%%opts NdOverlay [legend_position='left' show_frame=False]
gdp_unem_scatter = macro.to.scatter('Year', ['GDP Growth', 'Unemployment'])
gdp_unem_scatter.overlay('Country')
This is my result:
No matter what I do, I can't color the categories as depicted in the example here. Even if I define my own color...
What am I doing wrong?

Animation in iPython notebook

I am trying to put animations in an iPython notebook and am not finding a solution. I saw one post that discussed using interactive widgets, but there are a couple problems that I have with this: First, every example I see with widgets uses a slider or some other input, whereas I just want the animation to run automatically when the cell is run. Second, all the documentation seems out of date on Jupyter's site--whenever I download and run their notebooks I get these messages about certain modules being deprecated and then later in the file something fails to run, presumably because they're trying to import and access files that no longer exist.
I've seen a few other pages on the topic but they often require downloading binaries or other modules, but I'm partly using this to teach some students Math and I've gotten them to download Anaconda--I was hoping to not further confuse the issue by making them also download and install more complicated things all while spending time not talking about the Math.
So in short, is there a way that I can create animations in an iPython notebook that only require the use of simple import commands that will run out-of-the-box so to speak with the software that comes from Anaconda?
[Edit: I should also note that I've used Tkinter to make animations, and I could make one in matplotlib I'm sure. So if there were a way to get the animations you produce with those to render in an iPython notebook, that would certainly be a working solution for me.]
[Further edit: I suppose I could also say what I am hoping to animate at the moment, although I really want to be pretty flexible about the range of things I could animate if I decide to. Right now I'm trying to make a digital clock that displays each digit in Sumerian base-60 numerals to illustrate a different counting and base system. So it should initially display | then after a second || and so on until ten gets represented as < and so on until eventually the clock ticks over to a minute where it now displays |:| to represent one minute, one second.]
[Note to future humans: If you're implementing some animation and are willing to publicly host it, please leave a link to it in the comments! I'm curious to see how people are making animations these days, and also a little curious to see what they're animating.]
Some options you have for animating plots in Jupyter/IPython, using matplotlib:
Using display in a loop Use IPython.display.display(fig) to display a figure in the output. Using a loop you would want to clear the output before a new figure is shown. Note that this technique gives in general not so smooth resluts. I would hence advice to use any of the below.
import matplotlib.pyplot as plt
import matplotlib.animation
import numpy as np
from IPython.display import display, clear_output
t = np.linspace(0,2*np.pi)
x = np.sin(t)
fig, ax = plt.subplots()
l, = ax.plot([0,2*np.pi],[-1,1])
animate = lambda i: l.set_data(t[:i], x[:i])
for i in range(len(x)):
animate(i)
clear_output(wait=True)
display(fig)
plt.show()
%matplotlib notebook Use IPython magic %matplotlib notebook to set the backend to the notebook backend. This will keep the figure alive instead of displaying a static png file and can hence also show animations.
Complete example:
%matplotlib notebook
import matplotlib.pyplot as plt
import matplotlib.animation
import numpy as np
t = np.linspace(0,2*np.pi)
x = np.sin(t)
fig, ax = plt.subplots()
l, = ax.plot([0,2*np.pi],[-1,1])
animate = lambda i: l.set_data(t[:i], x[:i])
ani = matplotlib.animation.FuncAnimation(fig, animate, frames=len(t))
plt.show()
%matplotlib tk Use IPython magic %matplotlib tk to set the backend to the tk backend. This will open the figure in a new plotting window, which is interactive and can thus also show animations.
Complete example:
%matplotlib tk
import matplotlib.pyplot as plt
import matplotlib.animation
import numpy as np
t = np.linspace(0,2*np.pi)
x = np.sin(t)
fig, ax = plt.subplots()
l, = ax.plot([0,2*np.pi],[-1,1])
animate = lambda i: l.set_data(t[:i], x[:i])
ani = matplotlib.animation.FuncAnimation(fig, animate, frames=len(t))
plt.show()
Convert animation to mp4 video (option mentionned by #Perfi already):
from IPython.display import HTML
HTML(ani.to_html5_video())
or use plt.rcParams["animation.html"] = "html5" at the beginning of the notebook.
This will require to have ffmpeg video codecs available to convert to HTML5 video. The video is then shown inline. This is therefore compatible with %matplotlib inline backend. Complete example:
%matplotlib inline
import matplotlib.pyplot as plt
plt.rcParams["animation.html"] = "html5"
import matplotlib.animation
import numpy as np
t = np.linspace(0,2*np.pi)
x = np.sin(t)
fig, ax = plt.subplots()
l, = ax.plot([0,2*np.pi],[-1,1])
animate = lambda i: l.set_data(t[:i], x[:i])
ani = matplotlib.animation.FuncAnimation(fig, animate, frames=len(t))
ani
%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib.animation
import numpy as np
t = np.linspace(0,2*np.pi)
x = np.sin(t)
fig, ax = plt.subplots()
l, = ax.plot([0,2*np.pi],[-1,1])
animate = lambda i: l.set_data(t[:i], x[:i])
ani = matplotlib.animation.FuncAnimation(fig, animate, frames=len(t))
from IPython.display import HTML
HTML(ani.to_html5_video())
Convert animation to JavaScript:
from IPython.display import HTML
HTML(ani.to_jshtml())
or use plt.rcParams["animation.html"] = "jshtml" at the beginning of the notebook.
This will display the animation as HTML with JavaScript. This highly compatible with most new browsers and also with the %matplotlib inline backend. It is available in matplotlib 2.1 or higher.
Complete example:
%matplotlib inline
import matplotlib.pyplot as plt
plt.rcParams["animation.html"] = "jshtml"
import matplotlib.animation
import numpy as np
t = np.linspace(0,2*np.pi)
x = np.sin(t)
fig, ax = plt.subplots()
l, = ax.plot([0,2*np.pi],[-1,1])
animate = lambda i: l.set_data(t[:i], x[:i])
ani = matplotlib.animation.FuncAnimation(fig, animate, frames=len(t))
ani
%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib.animation
import numpy as np
t = np.linspace(0,2*np.pi)
x = np.sin(t)
fig, ax = plt.subplots()
l, = ax.plot([0,2*np.pi],[-1,1])
animate = lambda i: l.set_data(t[:i], x[:i])
ani = matplotlib.animation.FuncAnimation(fig, animate, frames=len(t))
from IPython.display import HTML
HTML(ani.to_jshtml())
You may find this tutorial interesting.
If you can turn what you need into a matplotlib animation, and I'm fairly sure from your description that it's possible, you can then use
from matplotlib import rc, animation
rc('animation', html='html5')
and display your animation using
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=N, interval=20, blit=True)
anim
Might come in handy!
Jupyter widgets is a good way of displaying animations. The code below displays an animated gif.....
from ipywidgets import Image
from IPython import display
animatedGif = "animatedGifs/01-progress.gif" #path relative to your notebook
file = open(animatedGif , "rb")
image = file.read()
progress= Image(
value=image,
format='gif',
width=100,
height=100)
display.display(progress)
You can close this animation using:
progress.close()
N.B. I found a few nice animated gifs from http://www.downgraf.com/inspiration/25-beautiful-loading-bar-design-examples-gif-animated/.
I had a similar problem, and this question helped me get started. I put together a notebook that illustrates using FuncAnimation along with good explanations of why the notebook does some things the way it does. It also has links to instructions on FFmpeg. It also has links to the examples I used in developing and understanding of animations. You can view my contribution at:
Animation Illustration
For your question, you might find interactive sliders a better tool. I also created a notebook which demonstrates interactive widgets in Jupyter. It is available here; however, the interactive parts don't work there.
Both are available in a GitHub Repostory

Resources