Jupyter: How to change color for widgets like SelectMultiple()?
The short answer is: You can't do that without creating your own "custom widget".
Those attributes of style
and layout
objects are hard-coded in both the server-side and client-side libraries of ipywidgets
.
There is a dirty way to get a similar effect though, by mixing the ButtonStyle
with SelectMultiple
.
# Tested on JupyterLab 0.35.3 with Python 3.6 kernel
import ipywidgets as widgets
from ipywidgets.widgets import widget_serialization, trait_types
from traitlets import Unicode, Instance, CaselessStrEnum
class MySelectMultiple(widgets.SelectMultiple):
style=trait_types.InstanceDict(widgets.ButtonStyle).tag(sync=True, **widget_serialization)
wdg2 = MySelectMultiple(
options=['Apples', 'Oranges', 'Pears'],
value=['Oranges'],
description='Fruits',
layout=widgets.Layout(width='75%', height='80px'),
style= {'button_color':'red'},
disabled=False
)
wdg2
wdg2.style.button_color = 'green'
Another dirty way is to inject a CSS rule into the notebook which affects all select
widget.
%%html
<style>
.widget-select > select {background-color: red;}
</style>
Custom widget
The ultimate solution is to make your own custom widget. Unfortunately you need to write both server- and client side codes for it. For classical jupyter notebook, the client side code (JavaScript) can be put in a cell. But this feature may be dropped in the "next-generation" of Jupyter, i.e. JupyterLab, for security reasons.
Cell 1
%%javascript
require.undef('myselectmultiple');
define('myselectmultiple', ["@jupyter-widgets/base"], function(widgets) {
class selectmultipleView extends widgets.SelectMultipleView {
render () {
super.render();
this.mycolor_changed();
this.model.on('change:mycolor', this.mycolor_changed, this);
}
mycolor_changed () {
var mycolor = this.model.get('mycolor')
this.el.childNodes[1].style.backgroundColor = mycolor;
}
}
return {
myselectmultipleview : selectmultipleView
};
});
Cell 2
class MySelectMultipleC(widgets.SelectMultiple):
_view_name = Unicode('myselectmultipleview').tag(sync=True)
_view_module = Unicode('myselectmultiple').tag(sync=True)
_view_module_version = Unicode('0.1.0').tag(sync=True)
mycolor = Unicode('white', help='background color').tag(sync=True)
wdg3 = MySelectMultipleC(
options=['Apples', 'Oranges', 'Pears'],
value=['Oranges'],
description='Fruits',
mycolor = 'green',
disabled=False
)
wdg3
Cell 3
wdg3.mycolor = 'red'
JupyterLab uses a completely different framework. To make the above custom widget working in the "Lab" interface, the client-side code should be translated to TypeScript, and then be compiled, built and installed on the Lab server.
Late to the party, but here is my simple solution, for the case where the color will be used to encode simple two (or a number of) states: use unicode!
sample:
code (in python 3... :) )
from ipywidgets import interactive, Layout
from IPython.display import clear_output
import ipywidgets as widgets
from IPython.display import display
c_base = int("1F534",base=16)
# widget 1
options=['Apples', 'Oranges', 'Pears']
state = [False,True,True]
colored_options = ['{} {}'.format(chr(c_base+s), o) for s,o in zip(state,options)]
wdg = widgets.SelectMultiple(
options=colored_options,
description='Fruits',
disabled=False
)
display(wdg)
Try searching with this code if you need more colours...:
for i in range (10):
ii = int('0x1f7e0',base=16)+i
print('{:>15}'.format('[{}: {}] '.format(hex(ii),chr(ii))),end='')
if i%7==6:
print()