:refs: :ref:`userguide_plotting` > :ref:`userguide_plotting_twin_axes` :keywords: add_layout, axis, axis_label, axis_label_text_color, cirlce, extra_y_ranges, LinearAxis ''' from numpy import arange, linspace, pi, sin from bokeh.models import LinearAxis, Range1d from bokeh.plotting import figure, output_file, show x = arange(-2 * pi, 2 * pi, 0.2) y = sin(x) y2 = linspace(0, 100, len(x)) p = figure(x_range=(-6.5, 6.5), y_range=(-1.1, 1.1), min_border=80) p.background_fill_color = "#fafafa" p.circle(x, y, color="crimson", size=8) p.yaxis.axis_label = "red circles" p.yaxis.axis_label_text_color = "crimson" p.extra_y_ranges['foo'] = Range1d(0, 100) p.circle(x, y2, color="navy", size=8, y_range_name="foo") ax2 = LinearAxis(y_range_name="foo", axis_label="blue circles") ax2.axis_label_text_color = "navy" p.add_layout(ax2, 'left') output_file("twin_axis.html", title="twin_axis.py example") show(p)
# Create a new plot and add a renderer top = Figure(tools=tools, title=None, x_range=day_range, **figure_style_kws) top.line('day', 'S', source=source, line_color=colors[0], line_width=3, line_cap='round') top.y_range = Range1d(0., 40.) top.yaxis.axis_label = "Salinity (g/kg)" top.xaxis.axis_label_text_font_size = label_fontsize top.yaxis.axis_label_text_font_size = label_fontsize # overlay volume level chart to salinity tc = "MediumBlue" # tide color tide_range = Range1d(start=0, end=15) tide_axis = LinearAxis(y_range_name="Z") tide_axis.axis_label = "Tidal Height (m)" tide_axis.axis_label_text_color = tc tide_axis.axis_label_text_font_size = label_fontsize tide_axis.major_tick_line_color = tc tide_axis.major_label_text_color = tc tide_axis.minor_tick_line_alpha = 0. top.extra_y_ranges = {"Z": tide_range} # top.line('day', 'Z', source=source, # line_color=tc, line_width=2, line_cap='round') top.add_layout(tide_axis, "right") top.line('day', 'Z', source=source, line_color=tc, line_width=2, line_cap='round', y_range_name="Z") mid = Figure(title=None, x_range=top.x_range, toolbar_location=None, **figure_style_kws)
def home(): ref_date = UtilsDatetime(Settings.query.first().current_month_date) # Add day(s) to database if it does not exist yet. days = Days.query.filter(Days.id >= ref_date.month_first_date).filter( Days.id <= ref_date.month_last_date).all() days_in_db = [day.id for day in days] for day_index in ref_date.month_all_dates: if day_index not in days_in_db: db.session.add(Days(id=day_index)) db.session.commit() days = Days.query.filter(Days.id >= ref_date.month_first_date).filter( Days.id <= ref_date.month_last_date).all() # Extra fields to display in row summary (_s) row_with_totals = { 'ds': timedelta(), 'dev': timedelta(), 'pol': timedelta(), 'ge': timedelta(), 'crt': timedelta(), 'hs': timedelta() } cum_TargetHours = timedelta() cum_TargetHours_till_today = timedelta() cum_TotalProductive = timedelta() cum_TotalNegative = timedelta() cum_alk = 0 cum_days0 = 0 for i, day in enumerate(days, start=1): # Target Productive Hours depending on weekday day.s_TargetHours = Defaults.productive_hours_by_weekday(day.id) # Total Productive Time day.s_TotalProductive = timedelta(seconds=0) for col in row_with_totals: value = getattr(day, col) if value is not None: row_with_totals[col] += value day.s_TotalProductive += value # Total Negative from Alk day.s_TotalNegative = timedelta(seconds=0) if day.alk is not None: day.s_TotalNegative = max(day.alk - 2.86, 0) * timedelta(minutes=20) cum_alk += day.alk if day.id <= date.today() and day.alk <= 0: cum_days0 += 1 else: if day.id <= date.today(): cum_days0 += 1 # % of target day.s_PercOfTarget = (day.s_TotalProductive - day.s_TotalNegative) / day.s_TargetHours # Cummulative values cum_TargetHours += day.s_TargetHours if day.id <= date.today(): cum_TargetHours_till_today += day.s_TargetHours cum_TotalProductive += day.s_TotalProductive cum_TotalNegative += day.s_TotalNegative day.cum_PercOfTarget = (cum_TotalProductive - cum_TotalNegative) / cum_TargetHours day.cum_alk = (cum_alk / i) / 7.8 * 750 # Styles: # Rows with today's date day.style_today_tr_hd = "" day.style_today_tr_td = "" if day.id == date.today(): day.style_today_tr_hd = "today_header" day.style_today_tr_td = "today_cell" day_of_month_for_statistics = get_day_of_month_for_avg_sja( ref_date.month_first_date, ref_date.month_last_date) row_with_totals['targethours'] = cum_TargetHours row_with_totals['totalproductive'] = cum_TotalProductive row_with_totals['totalnegative'] = cum_TotalNegative row_with_totals['totalsja'] = round(cum_alk / day_of_month_for_statistics, 2) row_with_totals['totalml'] = int( round(row_with_totals['totalsja'] / 7.8 * 750, 0)) row_with_totals['totaldays0'] = cum_days0 # Planned till today row_with_totals['targethours_tilltoday'] = cum_TargetHours_till_today # Change current month settings form_settings = EditSettings() settings = Settings.query.first( ) # There is only one setting (one date of current month) # MonthlyTargets monthlytargets = MonthlyTargets.query.get( date(year=settings.current_month_date.year, month=settings.current_month_date.month, day=1)) monthlytargets.ml = int(round(monthlytargets.alk / 7.8 * 750, 0)) monthlytargets.total_allocated = timedelta(seconds=sum([ getattr(monthlytargets, hrscol).total_seconds() for hrscol in ['ds', 'dev', 'pol', 'ge', 'crt', 'hs'] ])) row_with_totals['ds_tilltoday'] = monthlytargets.ds * ( day_of_month_for_statistics / ref_date.month_last_date.day) row_with_totals['dev_tilltoday'] = monthlytargets.dev * ( day_of_month_for_statistics / ref_date.month_last_date.day) row_with_totals['pol_tilltoday'] = monthlytargets.pol * ( day_of_month_for_statistics / ref_date.month_last_date.day) row_with_totals['ge_tilltoday'] = monthlytargets.ge * ( day_of_month_for_statistics / ref_date.month_last_date.day) row_with_totals['crt_tilltoday'] = monthlytargets.crt * ( day_of_month_for_statistics / ref_date.month_last_date.day) row_with_totals['hs_tilltoday'] = monthlytargets.hs * ( day_of_month_for_statistics / ref_date.month_last_date.day) row_with_totals['total_tilltoday'] = timedelta(seconds=sum([ row_with_totals[f"{hrscol}_tilltoday"].total_seconds() for hrscol in ['ds', 'dev', 'pol', 'ge', 'crt', 'hs'] ])) # Backlog (normal subtraction of timedelta does not work correctly if bigger is subtrackted from smaller object) row_with_totals[ 'ds_backlog'] = UtilsDataConversion.string_from_timedelta_subtraction( row_with_totals['ds'], row_with_totals['ds_tilltoday']) row_with_totals[ 'dev_backlog'] = UtilsDataConversion.string_from_timedelta_subtraction( row_with_totals['dev'], row_with_totals['dev_tilltoday']) row_with_totals[ 'pol_backlog'] = UtilsDataConversion.string_from_timedelta_subtraction( row_with_totals['pol'], row_with_totals['pol_tilltoday']) row_with_totals[ 'ge_backlog'] = UtilsDataConversion.string_from_timedelta_subtraction( row_with_totals['ge'], row_with_totals['ge_tilltoday']) row_with_totals[ 'crt_backlog'] = UtilsDataConversion.string_from_timedelta_subtraction( row_with_totals['crt'], row_with_totals['crt_tilltoday']) row_with_totals[ 'hs_backlog'] = UtilsDataConversion.string_from_timedelta_subtraction( row_with_totals['hs'], row_with_totals['hs_tilltoday']) row_with_totals[ 'total_backlog'] = UtilsDataConversion.string_from_timedelta_subtraction( row_with_totals['totalproductive'], row_with_totals['total_tilltoday']) # Change displayed month if request.method == 'POST': settings.current_month_date = form_settings.current_month_date.data # Check if monthly targets exist targets_date = date(year=settings.current_month_date.year, month=settings.current_month_date.month, day=1) if MonthlyTargets.query.get(targets_date) is None: db.session.add(MonthlyTargets(id=targets_date)) db.session.commit() return redirect(url_for('home')) # Daily graph y_alk_cum = [row.cum_alk for row in days] y_alk_cum_text = [str(int(row.cum_alk)) for row in days] y_score_cum = [row.cum_PercOfTarget for row in days] y_score_cum_text = [ str(int(round(row.cum_PercOfTarget, 2) * 100)) for row in days ] x_days = [i for i, day in enumerate(ref_date.month_all_dates, start=1)] y_todaybar_top = [ max(y_alk_cum) if day == date.today() else None for day in ref_date.month_all_dates ] source = ColumnDataSource(data=dict(x_days=x_days, y_alk_cum=y_alk_cum, y_score_cum=y_score_cum, y_score_cum_text=y_score_cum_text, y_alk_cum_text=y_alk_cum_text, y_todaybar_top=y_todaybar_top)) plot = figure(title='Daily Progress', x_axis_label='day', y_axis_label='ml cumm.%', plot_width=600, plot_height=400, toolbar_location=None) # Today selection plot.vbar(x='x_days', width=1, top='y_todaybar_top', source=source, color='#98FB98', alpha=0.5) # Alk plot.line(x='x_days', y='y_alk_cum', color="maroon", source=source) plot.circle(x='x_days', y='y_alk_cum', color="maroon", fill_color="white", size=5, source=source) labels_alk = LabelSet(x='x_days', y='y_alk_cum', text='y_alk_cum_text', text_font_size='10px', text_color='maroon', y_offset=5, level='annotation', source=source, render_mode='canvas') # Score plot.extra_y_ranges['y_axis_for_target_perc'] = Range1d( min(0, min(source.data.get('y_score_cum'))), max(max(source.data.get('y_score_cum')), 1) * 1.05) plot.line(x='x_days', y='y_score_cum', source=source, color="cornflowerblue", y_range_name='y_axis_for_target_perc') plot.circle(x='x_days', y='y_score_cum', source=source, color="cornflowerblue", fill_color="white", size=5, y_range_name='y_axis_for_target_perc') labels_score = LabelSet(x='x_days', y='y_score_cum', text='y_score_cum_text', text_font_size='10px', text_color='cornflowerblue', y_offset=5, y_range_name='y_axis_for_target_perc', level='annotation', source=source, render_mode='canvas') ax_right = LinearAxis(y_range_name="y_axis_for_target_perc", axis_label="% of target cum.") ax_right.axis_label_text_color = "blue" plot.add_layout(ax_right, 'right') plot.add_layout(labels_score) plot.add_layout(labels_alk) bokeh_daily_script, bokeh_daily_div = components(plot) # Monthly graph month_summary_table = MonthlyGraph(Days).df_months.to_html() bokeh_monthly_script, bokeh_monthly_div = MonthlyGraph( Days).bokeh_monthly_components dataset_for_daily_tracking = DataSet(ref_date) bokeh_tracking_time_script, bokeh_bracking_time_div = Graph.get_graph_components_tracking_daily_time( dataset_for_daily_tracking.tracking_df_daily_datetime, dataset_for_daily_tracking.tracking_current_score_series) return render_template( 'home.html', days=days, f_string_from_duration=UtilsDataConversion.string_from_timedelta, f_string_from_float=UtilsDataConversion.string_from_float_none, form_settings=form_settings, settings=settings, monthlytargets=monthlytargets, row_with_totals=row_with_totals, bokeh_daily_script=bokeh_daily_script, bokeh_daily_div=bokeh_daily_div, f_round=round, month_summary_table=month_summary_table, bokeh_monthly_script=bokeh_monthly_script, bokeh_monthly_div=bokeh_monthly_div, bokeh_tracking_time_script=bokeh_tracking_time_script, bokeh_bracking_time_div=bokeh_bracking_time_div)