Repository: bokeh/bokeh

Issue:
Add examples from PyCon.PL tutorial




Discussion:

Resolving patch:
diff --git a/examples/plotting/file/eclipse.py b/examples/plotting/file/eclipse.py
new file mode 100644
--- /dev/null
+++ b/examples/plotting/file/eclipse.py
@@ -0,0 +1,75 @@
+# Based on https://www.reddit.com/r/dataisbeautiful/comments/6qnkg0/google_search_interest_follows_the_path_of_the/
+
+import shapefile as shp
+import pandas as pd
+
+from bokeh.plotting import figure, show
+from bokeh.palettes import YlOrRd5
+from bokeh.models import ColumnDataSource, LinearColorMapper, Label, ColorBar
+from bokeh.sampledata.us_states import data
+
+states = pd.DataFrame.from_dict(data, orient="index")
+states.drop(["AK", "HI"], inplace=True)
+
+trends = pd.read_csv("eclipse_data/trends.csv")
+
+states.set_index("name", inplace=True)
+trends.set_index("Region", inplace=True)
+
+states["trend"] = trends["solar eclipse"]
+
+upath17 = shp.Reader("eclipse_data/upath17")
+(totality_path,) = upath17.shapes()
+
+p = figure(plot_width=1000, plot_height=600)
+
+p.grid.grid_line_color = None
+
+p.title.text = "Google Search Trends and the Path of Solar Eclipse, 21 August 2017"
+p.title.align = "center"
+p.title.text_font_size = "16pt"
+
+mapper = LinearColorMapper(palette=list(reversed(YlOrRd5)), low=0, high=100)
+
+source = ColumnDataSource(data=dict(
+    state_xs=list(states.lons),
+    state_ys=list(states.lats),
+    trend=states.trend,
+))
+us = p.patches("state_xs", "state_ys",
+    fill_color=dict(field="trend", transform=mapper),
+    source=source,
+    line_color="white", line_width=1)
+
+p.x_range.renderers = [us]
+p.y_range.renderers = [us]
+
+totality_x, totality_y = zip(*totality_path.points)
+p.patch(totality_x, totality_y,
+    fill_color="black", fill_alpha=0.7,
+    line_color=None)
+
+path = Label(
+    x=-76.3, y=31.4,
+    angle=-36.5, angle_units="deg",
+    text="Solar eclipse path of totality",
+    text_baseline="middle", text_font_size="8pt", text_color="silver")
+p.add_layout(path)
+
+color_bar = ColorBar(
+    color_mapper=mapper,
+    location="bottom_left", orientation="horizontal",
+    title="Popularity of \"solar eclipse\" search term",
+    title_text_font_size="12pt", title_text_font_style="bold",
+    background_fill_alpha=0.0)
+p.add_layout(color_bar)
+
+notes = Label(
+    x=0, y=0, x_units="screen", y_units="screen",
+    x_offset=40, y_offset=20,
+    text="Source: Google Trends, NASA Scientific Visualization Studio",
+    level="overlay",
+    text_font_size="8pt", text_color="gray")
+p.add_layout(notes)
+
+show(p)
diff --git a/examples/models/file/sprint.py b/examples/plotting/file/sprint.py
similarity index 50%
rename from examples/models/file/sprint.py
rename to examples/plotting/file/sprint.py
--- a/examples/models/file/sprint.py
+++ b/examples/plotting/file/sprint.py
@@ -1,15 +1,16 @@
+# Based on http://www.nytimes.com/interactive/2012/08/05/sports/olympics/the-100-meter-dash-one-race-every-medalist-ever.html
+
 from __future__ import print_function
 
-from bokeh.document import Document
-from bokeh.embed import file_html
-from bokeh.util.browser import view
-from bokeh.resources import INLINE
-from bokeh.models.glyphs import Circle, Text
-from bokeh.models import ColumnDataSource, Range1d, DataRange1d, Plot, LinearAxis, SingleIntervalTicker, Grid, HoverTool
+from bokeh.plotting import figure, show, output_file
+from bokeh.models import (
+    ColumnDataSource,
+    Range1d, DataRange1d,
+    LinearAxis, SingleIntervalTicker, FixedTicker,
+    Label, Arrow, NormalHead,
+    HoverTool, TapTool, CustomJS)
 from bokeh.sampledata.sprint import sprint
 
-# Based on http://www.nytimes.com/interactive/2012/08/05/sports/olympics/the-100-meter-dash-one-race-every-medalist-ever.html
-
 abbrev_to_country = {
     "USA": "United States",
     "GBR": "Britain",
@@ -58,34 +59,56 @@ def selected_name(name, medal, year):
 
 source = ColumnDataSource(sprint)
 
-xdr = Range1d(start=sprint.MetersBack.max()+2, end=0)                  # XXX: +2 is poor-man's padding (otherwise misses last tick)
-ydr = DataRange1d(range_padding=0.05) # XXX: should be 2 years (both sides)
+xdr = Range1d(start=sprint.MetersBack.max()+2, end=0)               # XXX: +2 is poor-man's padding (otherwise misses last tick)
+ydr = DataRange1d(range_padding=4, range_padding_units="absolute")
+
+plot = figure(
+    x_range=xdr, y_range=ydr,
+    plot_width=1000, plot_height=600,
+    toolbar_location=None,
+    outline_line_color=None, y_axis_type=None)
 
-plot = Plot(x_range=xdr, y_range=ydr, plot_width=1000, plot_height=600, toolbar_location=None, outline_line_color=None)
 plot.title.text = "Usain Bolt vs. 116 years of Olympic sprinters"
+plot.title.text_font_size = "14pt"
 
-xticker = SingleIntervalTicker(interval=5, num_minor_ticks=0)
-xaxis = LinearAxis(ticker=xticker, axis_line_color=None, major_tick_line_color=None,
-    axis_label="Meters behind 2012 Bolt", axis_label_text_font_size="10pt", axis_label_text_font_style="bold")
-plot.add_layout(xaxis, "below")
-xgrid = Grid(dimension=0, ticker=xaxis.ticker, grid_line_dash="dashed")
-plot.add_layout(xgrid)
-yticker = SingleIntervalTicker(interval=12, num_minor_ticks=0)
+plot.xaxis.ticker = SingleIntervalTicker(interval=5, num_minor_ticks=0)
+plot.xaxis.axis_line_color = None
+plot.xaxis.major_tick_line_color = None
+plot.xgrid.grid_line_dash = "dashed"
+
+yticker = FixedTicker(ticks=[1900, 1912, 1924, 1936, 1952, 1964, 1976, 1988, 2000, 2012])
 yaxis = LinearAxis(ticker=yticker, major_tick_in=-5, major_tick_out=10)
 plot.add_layout(yaxis, "right")
 
-radius = dict(value=5, units="screen")
-medal_glyph = Circle(x="MetersBack", y="Year", radius=radius, fill_color="MedalFill", line_color="MedalLine", fill_alpha=0.5)
-medal = plot.add_glyph(source, medal_glyph)
+medal = plot.circle(x="MetersBack", y="Year", radius=dict(value=5, units="screen"),
+    fill_color="MedalFill", line_color="MedalLine", fill_alpha=0.5, source=source, level="overlay")
 
-athlete_glyph = Text(x="MetersBack", y="Year", x_offset=10, text="SelectedName",
-    text_align="left", text_baseline="middle", text_font_size="9pt")
-athlete = plot.add_glyph(source, athlete_glyph)
+plot.text(x="MetersBack", y="Year", x_offset=10, y_offset=-5, text="SelectedName",
+    text_align="left", text_baseline="middle", text_font_size="9pt", source=source)
 
-no_olympics_glyph = Text(x=7.5, y=1942, text=["No Olympics in 1940 or 1944"],
+no_olympics_label = Label(
+    x=7.5, y=1942,
+    text="No Olympics in 1940 or 1944",
     text_align="center", text_baseline="middle",
     text_font_size="9pt", text_font_style="italic", text_color="silver")
-no_olympics = plot.add_glyph(no_olympics_glyph)
+no_olympics = plot.add_layout(no_olympics_label)
+
+x = sprint[sprint.Year == 1900].MetersBack.min() - 0.5
+arrow = Arrow(x_start=x, x_end=5, y_start=1900, y_end=1900, start=NormalHead(fill_color="black", size=6), end=None, line_width=1.5)
+plot.add_layout(arrow)
+
+meters_back = Label(
+    x=5, x_offset=10, y=1900,
+    text="Meters behind 2012 Bolt",
+    text_align="left", text_baseline="middle",
+    text_font_size="10pt", text_font_style="bold")
+plot.add_layout(meters_back)
+
+disclaimer = Label(
+    x=0, y=0, x_units="screen", y_units="screen",
+    text="This chart includes medals for the United States and Australia in the \"Intermediary\" Games of 1906, which the I.O.C. does not formally recognize.",
+    text_font_size="8pt", text_color="silver")
+plot.add_layout(disclaimer, "below")
 
 tooltips = """
 <div>
@@ -99,16 +122,17 @@ def selected_name(name, medal, year):
 <div style="font-size: 11px; color: #666;">@{MetersBack}{0.00} meters behind</div>
 """
 
-hover = HoverTool(tooltips=tooltips, renderers=[medal])
-plot.add_tools(hover)
+plot.add_tools(HoverTool(tooltips=tooltips, renderers=[medal]))
+
+open_url = CustomJS(args=dict(source=source), code="""
+source.inspected._1d.indices.forEach(function(index) {
+    var name = source.data["Name"][index];
+    var url = "http://en.wikipedia.org/wiki/" + encodeURIComponent(name);
+    window.open(url);
+});
+""")
 
-doc = Document()
-doc.add_root(plot)
+plot.add_tools(TapTool(callback=open_url, renderers=[medal], behavior="inspect"))
 
-if __name__ == "__main__":
-    doc.validate()
-    filename = "sprint.html"
-    with open(filename, "w") as f:
-        f.write(file_html(doc, INLINE, plot.title.text))
-    print("Wrote %s" % filename)
-    view(filename)
+output_file("sprint.html", plot.title.text)
+show(plot)


Test patch:
diff --git a/tests/test_code_quality.py b/tests/test_code_quality.py
--- a/tests/test_code_quality.py
+++ b/tests/test_code_quality.py
@@ -36,7 +36,7 @@ def use_tab_rule(fname):
 
 exclude_paths = ("CHANGELOG",)
 
-exclude_exts = (".png", ".jpg", ".pxm", ".ico", ".ics", ".gz", ".gif", ".enc", ".svg", ".xml")
+exclude_exts = (".png", ".jpg", ".pxm", ".ico", ".ics", ".gz", ".gif", ".enc", ".svg", ".xml", ".shp", ".dbf", ".shx")
 
 exclude_dirs = ("sphinx/draw.io",)