plotting API legend

I’ve spent 30
minutes reading the docs and searching through “legend” examples
in Bokeh. I can’t figure out how to get legends in place for the
plot I’m creating.

from bokeh.models import HoverTool, ColumnDataSource
from bokeh.io import output_notebook, show
from bokeh.plotting import figure
from bokeh.sampledata.autompg import autompg
hover = HoverTool(
tooltips=[
("Vehicle", "@name, 19@yr"            ),
("MPG", "@mpg"            ),
("Engine", "@displ cu in @cyl cylinder @hp HP"        ),
]
)
cmap = dict(zip([1,2,3], 'red green blue'.split()))
omap = dict(zip([1,2,3], 'American European Asian'.split()))
colors = [cmap[o] for o in autompg.origin]
origin = [omap[o] for o in autompg.origin]
p = figure(tools=[hover], width=800, height=400)
p.circle('mpg', 'weight', color=colors, size=10, alpha=0.3, source=ColumnDataSource(autompg))
show(p)

    I realize I could

call p.circle()
three times, and each one having legend=
and color=
arguments, something like:

p = figure(tools=[hover], width=800, height=400
)
p.circle('mpg', 'weight', color='red', legend='American', size=10, alpha=0.3, source=ColumnDataSource(autompg[autompg.origin == 1]))
p.circle('mpg', 'weight', color='green', legend='European', size=10, alpha=0.3, source=ColumnDataSource(autompg[autompg.origin == 2]))
p.circle('mpg', 'weight', color='blue', legend='Asian', size=10, alpha=0.3, source=ColumnDataSource(autompg[autompg.origin == 3
]))
show(p)

    But it feels like I

should be able to achieve this with a single call to
p.circle(). Maybe not.

Ian

Hey,

You can pass the column which defines your classes to the legend keyword. But you would need to add your colors to the ColumnDataSource (which you need to do anyway, since your method is depricated), so:

autompg[‘colors’] = [cmap[o] for o in autompg.origin]

p = figure(tools=[hover], width=800, height=400)
p.circle(‘mpg’, ‘weight’, color=‘colors’, size=10, alpha=0.3, source=ColumnDataSource(autompg), legend=‘colors’)

``

See the result at:

Apparently Bokeh does something clever where they check if the string exists as a column in the datasource. If it doesnt the string is used as a single legend key, otherwise the datasource is used.

Regards,
Rutger

···

On Tuesday, November 1, 2016 at 9:50:12 AM UTC+1, Ian Stokes-Rees wrote:

    I’ve spent 30

minutes reading the docs and searching through “legend” examples
in Bokeh. I can’t figure out how to get legends in place for the
plot I’m creating.

from bokeh.models import HoverTool, ColumnDataSource
from [bokeh.io](http://bokeh.io) import output_notebook, show
from bokeh.plotting import figure
from bokeh.sampledata.autompg import autompg
hover = HoverTool(
tooltips=[
("Vehicle", "@name, 19@yr"            ),
("MPG", "@mpg"            ),
("Engine", "@displ cu in @cyl cylinder @hp HP"        ),
]
)
cmap = dict(zip([1,2,3], 'red green blue'.split()))
omap = dict(zip([1,2,3], 'American European Asian'.split()))
colors = [cmap[o] for o in autompg.origin]
origin = [omap[o] for o in autompg.origin]
p = figure(tools=[hover], width=800, height=400)
p.circle('mpg', 'weight', color=colors, size=10, alpha=0.3, source=ColumnDataSource(autompg))
show(p)

    I realize I could

call p.circle()
three times, and each one having legend=
and color=
arguments, something like:

p = figure(tools=[hover], width=800, height=400
)
p.circle('mpg', 'weight', color='red', legend='American', size=10, alpha=0.3, source=ColumnDataSource(autompg[autompg.origin == 1]))
p.circle('mpg', 'weight', color='green', legend='European', size=10, alpha=0.3, source=ColumnDataSource(autompg[autompg.origin == 2]))
p.circle('mpg', 'weight', color='blue', legend='Asian', size=10, alpha=0.3, source=ColumnDataSource(autompg[autompg.origin == 3
]))
show(p)

    But it feels like I

should be able to achieve this with a single call to
p.circle(). Maybe not.

Ian

Hey,

Sorry for this correction, i wasn’t looking properly at what you actually wanted as a legend. You can map the origin to your tags, which pure Panda, and the pass the new column as your legend:

autompg[‘colors’] = [cmap[o] for o in autompg.origin]
autompg[‘origin_tag’] = autompg.origin.map({1: ‘American’, 2: ‘European’, 3:‘Asian’})

p = figure(tools=[hover], width=800, height=400)
p.circle(‘mpg’, ‘weight’, color=‘colors’, size=10, alpha=0.3, source=ColumnDataSource(autompg), legend=‘origin_tag’)

``

Whats really cool, and i just found out, is that you can even supply a column as legend which doesn’t map 1-on-1 with the colors you used, try for example with ‘hp’ or something. Thats actually a really nice feature.

Updated gist:

Regards,
Rutger

···

On Tuesday, November 1, 2016 at 10:26:31 AM UTC+1, Rutger Kassies wrote:

Hey,

You can pass the column which defines your classes to the legend keyword. But you would need to add your colors to the ColumnDataSource (which you need to do anyway, since your method is depricated), so:

autompg[‘colors’] = [cmap[o] for o in autompg.origin]

p = figure(tools=[hover], width=800, height=400)
p.circle(‘mpg’, ‘weight’, color=‘colors’, size=10, alpha=0.3, source=ColumnDataSource(autompg), legend=‘colors’)

``

See the result at:
http://nbviewer.jupyter.org/gist/RutgerK/62ae5a2f8ca46fa84b404646b53b38cf

Apparently Bokeh does something clever where they check if the string exists as a column in the datasource. If it doesnt the string is used as a single legend key, otherwise the datasource is used.

Regards,
Rutger

On Tuesday, November 1, 2016 at 9:50:12 AM UTC+1, Ian Stokes-Rees wrote:

    I’ve spent 30

minutes reading the docs and searching through “legend” examples
in Bokeh. I can’t figure out how to get legends in place for the
plot I’m creating.

from bokeh.models import HoverTool, ColumnDataSource
from [bokeh.io](http://bokeh.io) import output_notebook, show
from bokeh.plotting import figure
from bokeh.sampledata.autompg import autompg
hover = HoverTool(
tooltips=[
("Vehicle", "@name, 19@yr"            ),
("MPG", "@mpg"            ),
("Engine", "@displ cu in @cyl cylinder @hp HP"        ),
]
)
cmap = dict(zip([1,2,3], 'red green blue'.split()))
omap = dict(zip([1,2,3], 'American European Asian'.split()))
colors = [cmap[o] for o in autompg.origin]
origin = [omap[o] for o in autompg.origin]
p = figure(tools=[hover], width=800, height=400)
p.circle('mpg', 'weight', color=colors, size=10, alpha=0.3, source=ColumnDataSource(autompg))
show(p)

    I realize I could

call p.circle()
three times, and each one having legend=
and color=
arguments, something like:

p = figure(tools=[hover], width=800, height=400
)
p.circle('mpg', 'weight', color='red', legend='American', size=10, alpha=0.3, source=ColumnDataSource(autompg[autompg.origin == 1]))
p.circle('mpg', 'weight', color='green', legend='European', size=10, alpha=0.3, source=ColumnDataSource(autompg[autompg.origin == 2]))
p.circle('mpg', 'weight', color='blue', legend='Asian', size=10, alpha=0.3, source=ColumnDataSource(autompg[autompg.origin == 3
]))
show(p)

    But it feels like I

should be able to achieve this with a single call to
p.circle(). Maybe not.

Ian

You can also combine this with a CategoricalColorMapper (or other computed transform) to have the colors computed in in the browser instead of having to do it up front in python:

  from bokeh.io import show
  from bokeh.models import ColumnDataSource, CategoricalColorMapper
  from bokeh.palettes import RdBu3
  from bokeh.plotting import figure

  source = ColumnDataSource(dict(
      x=[1, 2, 3, 4, 5, 6],
      y=[2, 1, 2, 1, 2, 1],
      label=['hi', 'lo', 'hi', 'lo', 'hi', 'lo']
  ))
  color_mapper = CategoricalColorMapper(factors=['hi', 'lo'], palette=[RdBu3[2], RdBu3[0]])

  p = figure(x_range=(0, 7), y_range=(0, 3), height=300, tools='save')
  p.circle(
      x='x', y='y', radius=0.5, source=source,
      color={'field': 'label', 'transform': color_mapper},
      legend='label'
  )
  show(p)

Ian,

The ability to have legends based on grouping a column in bokeh.plotting is one of Bokeh's very newest features. There is even an open issue to add more examples:

  https://github.com/bokeh/bokeh/issues/5112

Previous to this it was never assumed that any kind of "groupby" options would occur in the browser, that there would always be e.g. a 1-1 correspondence between one glyph and one legend row at the model level. Which also meant three calls to p.circe as you saw. The idea was that bokeh.charts could be a higher level (in python) where these kinds of aggregations would happen, generating the multiple glyphs as needed. But for various reasons (such as: no current maintainer for bokeh.charts, and a desire to have this kind of convenience combined with the flexibility in bokeh.plotting) this new capability was added, but as I said, only extremely recently. Please be patient while we try to catch up our documentation as best we can with the resources available.

Thanks,

Bryan

···

On Nov 1, 2016, at 4:35 AM, Rutger Kassies <[email protected]> wrote:

Hey,

Sorry for this correction, i wasn't looking properly at what you actually wanted as a legend. You can map the origin to your tags, which pure Panda, and the pass the new column as your legend:

autompg['colors'] = [cmap[o] for o in autompg.origin]
autompg['origin_tag'] = autompg.origin.map({1: 'American', 2: 'European', 3:'Asian'})

p = figure(tools=[hover], width=800, height=400)
p.circle('mpg', 'weight', color='colors', size=10, alpha=0.3, source=ColumnDataSource(autompg),legend='origin_tag')

Whats really cool, and i just found out, is that you can even supply a column as legend which doesn't map 1-on-1 with the colors you used, try for example with 'hp' or something. Thats actually a really nice feature.

Updated gist:
Jupyter Notebook Viewer

Regards,
Rutger

On Tuesday, November 1, 2016 at 10:26:31 AM UTC+1, Rutger Kassies wrote:
Hey,

You can pass the column which defines your classes to the legend keyword. But you would need to add your colors to the ColumnDataSource (which you need to do anyway, since your method is depricated), so:

autompg['colors'] = [cmap[o] for o in autompg.origin]

p = figure(tools=[hover], width=800, height=400)
p.circle('mpg', 'weight', color='colors', size=10, alpha=0.3, source=ColumnDataSource(autompg),legend='colors')

See the result at:
Jupyter Notebook Viewer

Apparently Bokeh does something clever where they check if the string exists as a column in the datasource. If it doesnt the string is used as a single legend key, otherwise the datasource is used.

Regards,
Rutger

On Tuesday, November 1, 2016 at 9:50:12 AM UTC+1, Ian Stokes-Rees wrote:
I’ve spent 30 minutes reading the docs and searching through “legend” examples in Bokeh. I can’t figure out how to get legends in place for the plot I’m creating.

from bokeh.models import
HoverTool, ColumnDataSource

from bokeh.io import
output_notebook, show

from bokeh.plotting import
figure

from bokeh.sampledata.autompg import
autompg

hover = HoverTool(
        tooltips=[
            (
"Vehicle", "@name, 19@yr"
),
            (
"MPG", "@mpg"
),
            (
"Engine", "@displ cu in @cyl cylinder @hp HP"
),
        ]
    )

cmap = dict(zip([
1,2,3], 'red green blue'
.split()))
omap = dict(zip([
1,2,3], 'American European Asian'
.split()))
colors = [cmap[o]
for o in
autompg.origin]
origin = [omap[o]
for o in
autompg.origin]

p = figure(tools=[hover], width=
800, height=400
)
p.circle(
'mpg', 'weight', color=colors, size=10, alpha=0.3, source=ColumnDataSource(
autompg))
show(p)

I realize I could call p.circle() three times, and each one having legend= and color= arguments, something like:

p = figure(tools=[hover], width=800, height=400
)

p.circle(
'mpg', 'weight', color='red', legend='American', size=10, alpha=0.3, source=ColumnDataSource(autompg[autompg.origin == 1
]))
p.circle(
'mpg', 'weight', color='green', legend='European', size=10, alpha=0.3, source=ColumnDataSource(autompg[autompg.origin == 2
]))
p.circle(
'mpg', 'weight', color='blue', legend='Asian', size=10, alpha=0.3, source=ColumnDataSource(autompg[autompg.origin == 3
]))

show(p)

But it feels like I should be able to achieve this with a single call to `p.circle()`. Maybe not.

Ian

--
You received this message because you are subscribed to the Google Groups "Bokeh Discussion - Public" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/680a23c0-7c3a-4810-bf2f-fd69203404d1%40continuum.io\.
For more options, visit https://groups.google.com/a/continuum.io/d/optout\.