daylight#
A plot showing the daylight hours in a city’s local time (which are
discontinuous due to summer time) using the Patch
and Line
plot
elements to draw custom outlines and fills.
Details
- Sampledata:
- Bokeh APIs:
bokeh.models.Line
,bokeh.models.Patch
,bokeh.models.add_glyph
,bokeh.document.document.Document
- More info:
- Keywords:
outline, shading, fill
import datetime as dt
from time import mktime
import numpy as np
from bokeh.core.properties import value
from bokeh.document import Document
from bokeh.embed import file_html
from bokeh.models import (ColumnDataSource, DatetimeAxis, DatetimeTickFormatter,
FixedTicker, Legend, LegendItem, Line, Patch, Plot, Text)
from bokeh.resources import INLINE
from bokeh.sampledata import daylight
from bokeh.util.browser import view
df = daylight.daylight_warsaw_2013
source = ColumnDataSource(dict(
dates = df.Date,
sunrises = df.Sunrise,
sunsets = df.Sunset,
))
patch1_source = ColumnDataSource(dict(
dates = np.concatenate((df.Date, df.Date[::-1])),
times = np.concatenate((df.Sunrise, df.Sunset[::-1]))
))
summer = df[df.Summer == 1]
patch2_source = ColumnDataSource(dict(
dates = np.concatenate((summer.Date, summer.Date[::-1])),
times = np.concatenate((summer.Sunrise, summer.Sunset[::-1]))
))
summer_start = df.Summer.tolist().index(1)
summer_end = df.Summer.tolist().index(0, summer_start)
calendar_start = df.Date.iloc[0]
summer_start = df.Date.iloc[summer_start]
summer_end = df.Date.iloc[summer_end]
calendar_end = df.Date.iloc[-1]
d1 = calendar_start + (summer_start - calendar_start)/2
d2 = summer_start + (summer_end - summer_start)/2
d3 = summer_end + (calendar_end - summer_end)/2
text_source = ColumnDataSource(dict(
dates = [d1, d2, d3],
times = [dt.time(11, 30)]*3,
texts = ["CST (UTC+1)", "CEST (UTC+2)", "CST (UTC+1)"],
))
plot = Plot(width=800, height=400)
plot.title.text = "Daylight Hours 2013 - Warsaw, Poland"
plot.toolbar_location = None
plot.x_range.range_padding = 0
patch1 = Patch(x="dates", y="times", fill_color="#282e54")
plot.add_glyph(patch1_source, patch1)
patch2 = Patch(x="dates", y="times", fill_color="#ffdd91")
plot.add_glyph(patch2_source, patch2)
sunrise_line = Line(x="dates", y="sunrises", line_color="orange", line_width=4)
sunrise_line_renderer = plot.add_glyph(source, sunrise_line)
sunset_line = Line(x="dates", y="sunsets", line_color="crimson", line_width=4)
sunset_line_renderer = plot.add_glyph(source, sunset_line)
text = Text(x="dates", y="times", text="texts", text_align="center", text_color="grey")
plot.add_glyph(text_source, text)
xformatter = DatetimeTickFormatter(months="%b %d %Y")
min_time = dt.datetime.min.time()
xticker = FixedTicker(ticks=[
mktime(dt.datetime.combine(summer_start, min_time).timetuple()) * 1000,
mktime(dt.datetime.combine(summer_end, min_time).timetuple()) * 1000
])
xaxis = DatetimeAxis(formatter=xformatter, ticker=xticker)
plot.add_layout(xaxis, 'below')
yaxis = DatetimeAxis()
yaxis.formatter.hours = '%H:%M'
plot.add_layout(yaxis, 'left')
legend = Legend(items=[
LegendItem(label=value('sunset'), renderers=[sunset_line_renderer]),
LegendItem(label=value('sunrise'), renderers=[sunrise_line_renderer]),
])
plot.add_layout(legend)
doc = Document()
doc.add_root(plot)
if __name__ == "__main__":
doc.validate()
filename = "daylight.html"
with open(filename, "w") as f:
f.write(file_html(doc, INLINE, "Daylight Plot"))
print(f"Wrote {filename}")
view(filename)