def pages_queried_timeseries(df, plot_width=600, plot_height=200, rule='1T'): ts = df[['url']].resample(rule, how='count').cumsum() ts.index = ts.index.tz_convert(tzlocal()) #Bokeh=0.10.0 misencodes timestamps, so we have to shift by ts.index = ts.index.shift(ts.index[0].utcoffset().total_seconds(), freq="S") ts = pd.concat([ts[:1], ts]) # prepend 0-value for Line chart compat ts.iloc[0]['url'] = 0 formatter = DatetimeTickFormatter(formats=DATETIME_FORMAT) ticker = DatetimeTicker(desired_num_ticks=3) source = ColumnDataSource(ts) plot = Plot(plot_width=plot_width, plot_height=plot_height, x_range=DataRange1d(range_padding=0.1), y_range=DataRange1d(start=0), **PLOT_FORMATS) plot.add_glyph( source, Line(x='retrieved', y='url', **LINE_FORMATS) ) plot.add_layout( DatetimeAxis(axis_label="Date Retrieved", formatter=formatter, ticker=ticker, **AXIS_FORMATS), 'below') plot.add_layout(LinearAxis(axis_label="Total Pages", **AXIS_FORMATS), 'left') return plot
def plotLineGraph(self, x_list, y_list, value, unit): figureTitle = "{} for {}".format(value, self.dataDate.strftime(DATE_FORMAT)) logging.debug("Plotting {}".format(figureTitle)) # output to static HTML file output_file("{}Plot.html".format(value)) x_axis_label = 'Time' y_axis_label = '{} ({})'.format(value, unit) # create a new plot with a title and axis labels p = figure(plot_width=1200, plot_height=600, title=figureTitle, x_axis_label=x_axis_label, y_axis_label=y_axis_label, x_axis_type="datetime") # add a line renderer with legend and line thickness p.xaxis.ticker = DatetimeTicker(desired_num_ticks=24) p.line(x_list, y_list, legend=value, line_width=2) p.y_range.start = 0 if unit == "*C": p.y_range.end = 70 else: p.y_range.end = 50 # show the results show(p)
def getPlot(stock_name,ticked_boxes): #lookup stock name; if not found, go to error page #presume previous calendar month today = datetime.date.today() first = today.replace(day=1) lastMonthEnd = first - datetime.timedelta(days=1) lastMonthStart = lastMonthEnd.replace(day=1) sys.stderr.write(','.join(map(str,ticked_boxes))) r=requests.get("https://www.quandl.com/api/v3/datatables/WIKI/PRICES.json?ticker=%s&date.gte=%s&date.lte=%s&qopts.columns=date,%s&api_key=yFrECJyVKjZh4z--h7xq"%(stock_name,lastMonthStart.strftime("%y%m%d"),lastMonthEnd.strftime("%y%m%d"),','.join(map(str,ticked_boxes)))) data=r.json()['datatable']['data'] columns = list(ticked_boxes) columns.insert(0, 'date') pddata = pd.DataFrame([d[1:] for d in data], [pd.to_datetime(d[0]) for d in data], columns=ticked_boxes) TOOLS = "pan,wheel_zoom,box_zoom,reset,save" p = figure(x_axis_type="datetime", tools=TOOLS, plot_width=1000, title=stock_name + " Prices") p.xaxis.major_label_orientation = pi / 4 p.xaxis.axis_label = "Date (month/day)" p.xaxis.axis_label_text_font_size = "14pt" p.xaxis.major_label_text_font = "12pt" p.yaxis.axis_label = "Stock Price (USD)" p.yaxis.axis_label_text_font_size = "14pt" p.yaxis.major_label_text_font = "12pt" if all(feature in ["low","high","close","open"] for feature in ticked_boxes) and len(ticked_boxes)==4: #candlestick plot mids = (pddata.open + pddata.close) / 2 spans = abs(pddata.close - pddata.open) inc = pddata.close > pddata.open dec = pddata.open > pddata.close w = 12 * 60 * 60 * 1000 p.grid.grid_line_alpha = 0.3 p.segment(pddata.index, pddata.high, pddata.index, pddata.low, color='black') p.rect(pddata.index[inc], mids[inc], w, spans[inc], fill_color="#D5E1DD", line_color="black") p.rect(pddata.index[dec], mids[dec], w, spans[dec], fill_color="#F2583E", line_color="black") script, div = components(p) return (div, script) p.xaxis.ticker = DatetimeTicker(desired_num_ticks=6) #p.xaxis[0].ticker=DaysTicker(interval=3) colors=['blue','red','purple','black','green','orange'] legend={'close':'Closing','open':'Opening','adj_open':'Adjusted Opening','adj_close':'Adjusted Closing','low':'Lowest','high':'Highest'} for index,feature in enumerate(ticked_boxes): p.line(pddata.index, pddata[feature], line_color=colors[index],line_width=2,legend=legend[feature]) p.circle(pddata.index, pddata[feature], line_color=colors[index],fill_color=colors[index],size=5) script, div=components(p) return (div,script)
def _make_base_plot(dfs, activities, x_range, plot_width=900): plot = Plot( x_range=x_range, y_range=Range1d(0, 11), outline_line_color=None, background_fill=COLOR_PRIMARY, border_fill=COLOR_PRIMARY, plot_width=plot_width, plot_height=150, min_border_top=0, toolbar_location=None, ) yticker = BasicTicker(min_interval=3) close_ticker = DatetimeTicker(desired_num_ticks=8) close_ticks = DatetimeTickFormatter( formats={ 'years': ["%b"], 'months': ["%b"], 'days': ["%a %d %b"], 'hours': ["%I%p %d %b"] } ) plot.add_layout(LinearAxis(ticker=yticker, **AXIS_PROPERTIES), 'left') plot.add_layout(DatetimeAxis(formatter=close_ticks, ticker=close_ticker, **AXIS_PROPERTIES), 'below') plot.add_layout(Grid(dimension=1, ticker=yticker, grid_line_alpha=0.3)) palette = get_palette(activities) for i, activity in enumerate(activities): source = dfs[activity] line = Line( line_color=palette[i], line_join='round', line_cap='round', line_width=5, line_alpha=0.75, x='timestamp', y='cumsum_hrs' ) plot.add_glyph(source, line) return plot
def generate_weather_plot(webcfg, telcfg, date=None, plot_ndays=1, span_hours=24): log.info(f"Querying weather limits") weather_limits = mongo_query('weather_limits', {}, webcfg)[0] if date is None: end = datetime.utcnow() start = end - timedelta(days=plot_ndays) else: start = datetime.strptime(date, '%Y%m%dUT') end = start + timedelta(days=plot_ndays) markersize = 2 ##------------------------------------------------------------------------- ## Temperature Plot if webcfg['Weather'].get('plot_temperature', None) is not None: log.info('Build temperature plot') limit_string = webcfg['Weather'].get(f'plot_temperature_limits', '25,95') ymin, ymax = limit_string.split(',') height = webcfg['Weather'].getint('plot_temperature_height', 120) plot_temperature = figure( width=900, height=height, x_axis_type="datetime", y_range=(float(ymin), float(ymax)), x_range=(end - timedelta(hours=span_hours), end), ) plot_values = webcfg['Weather'].get('plot_temperature').split(',') query_dict = {'date': {'$gt': start, '$lt': end}} colors = ["blue", "black", "black"] alphas = [0.8, 0.4, 0.4] for i, plot_value in enumerate(plot_values): collection, name = plot_value.split(':') log.debug(f' Querying mongo collection {collection}') query_result = mongo_query(collection, query_dict, webcfg) plot_vals = [] for d in query_result: if name in d.keys(): if d.get(f"{name} units", None) == 'C': plot_vals.append((d['date'], d[name] * 1.8 + 32)) elif d.get(f"{name} unit", None) == 'C': plot_vals.append((d['date'], d[name] * 1.8 + 32)) elif d.get("temperature units", None) == 'C': plot_vals.append((d['date'], d[name] * 1.8 + 32)) else: plot_vals.append((d['date'], d[name])) plot_vals = np.array(plot_vals) if len(plot_vals) == 0: log.warning(f'Found 0 data points for {collection}:{name}') log.debug(f' Got {len(plot_vals)} entries') if len(plot_vals) > 0: plot_temperature.circle(plot_vals[:, 0], plot_vals[:, 1], legend_label=f"{plot_value}", color=colors[i], fill_alpha=alphas[i], line_alpha=alphas[i], size=markersize) if len(plot_values) > 1: plot_temperature.legend.location = "top_left" plot_temperature.legend.margin = 0 plot_temperature.legend.padding = 0 plot_temperature.legend.spacing = 0 plot_temperature.legend.label_text_font_size = '8pt' else: plot_temperature.legend.visible = False plot_temperature.yaxis.axis_label = 'Temp (F)' plot_temperature.yaxis.formatter = NumeralTickFormatter(format="0,0") plot_temperature.yaxis.ticker = [10, 30, 50, 70, 90, 110] plot_temperature.xaxis.visible = False ##------------------------------------------------------------------------- ## Humidity Plot if webcfg['Weather'].get('plot_humidity', None) is not None: log.info('Build humidity plot') limit_string = webcfg['Weather'].get(f'plot_humidity_limits', '40,100') ymin, ymax = limit_string.split(',') height = webcfg['Weather'].getint('plot_humidity_height', 120) plot_humidity = figure( width=900, height=height, x_axis_type="datetime", y_range=(float(ymin), float(ymax)), x_range=(end - timedelta(hours=span_hours), end), ) plot_values = webcfg['Weather'].get('plot_humidity').split(',') query_dict = {'date': {'$gt': start, '$lt': end}} for i, plot_value in enumerate(plot_values): collection, name = plot_value.split(':') log.debug(f' Querying mongo collection {collection}') query_result = mongo_query(collection, query_dict, webcfg) plot_vals = np.array([(d['date'], d[name]) for d in query_result if name in d.keys()]) log.debug(f' Got {len(plot_vals)} entries') if len(plot_vals) == 0: log.warning(f'Found 0 data points for {collection}:{name}') else: if i == 0: where_vhumid = np.where( plot_vals[:, 1] >= weather_limits['very humid']) plot_humidity.circle(plot_vals[where_vhumid][:, 0], plot_vals[where_vhumid][:, 1], size=markersize, color="red", line_alpha=0.8, fill_alpha=0.8) where_humid = np.where((plot_vals[:,1] < weather_limits['very humid'])\ & (plot_vals[:,1] >= weather_limits['humid'])) plot_humidity.circle(plot_vals[where_humid][:, 0], plot_vals[where_humid][:, 1], size=markersize, color="orange", line_alpha=0.8, fill_alpha=0.8) where_nothumid = np.where( plot_vals[:, 1] < weather_limits['humid']) plot_humidity.circle(plot_vals[where_nothumid][:, 0], plot_vals[where_nothumid][:, 1], legend_label=f"{plot_value}", size=markersize, color="green", line_alpha=0.8, fill_alpha=0.8) else: plot_humidity.circle(plot_vals[:, 0], plot_vals[:, 1], legend_label=f"{plot_value}", color='black', line_alpha=0.4, fill_alpha=0.4, size=markersize) if len(plot_values) > 1: plot_humidity.legend.location = "top_left" plot_humidity.legend.margin = 0 plot_humidity.legend.padding = 0 plot_humidity.legend.spacing = 0 plot_humidity.legend.label_text_font_size = '8pt' else: plot_humidity.legend.visible = False plot_humidity.yaxis.axis_label = 'Humidity (%)' plot_humidity.yaxis.formatter = NumeralTickFormatter(format="0,0") plot_humidity.yaxis.ticker = [0, 20, 40, 60, 80, 100] plot_humidity.xaxis.visible = False ##------------------------------------------------------------------------- ## Cloudiness Plot if webcfg['Weather'].get('plot_cloudiness', None) is not None: log.info('Build cloudiness plot') limit_string = webcfg['Weather'].get(f'plot_cloudiness_limits', '-50,10') ymin, ymax = limit_string.split(',') height = webcfg['Weather'].getint('plot_cloudiness_height', 120) plot_cloudiness = figure( width=900, height=height, x_axis_type="datetime", y_range=(float(ymin), float(ymax)), x_range=(end - timedelta(hours=span_hours), end), ) plot_values = webcfg['Weather'].get('plot_cloudiness').split(',') query_dict = {'date': {'$gt': start, '$lt': end}} for plot_value in plot_values: collection, name = plot_value.split(':') log.debug(f' Querying mongo collection {collection}') query_result = mongo_query(collection, query_dict, webcfg) plot_vals = np.array([(d['date'], d[name]) for d in query_result if name in d.keys()]) log.debug(f' Got {len(plot_vals)} entries') if len(plot_vals) > 0: where_vcloudy = np.where( plot_vals[:, 1] >= weather_limits['cloudy']) plot_cloudiness.circle(plot_vals[where_vcloudy][:, 0], plot_vals[where_vcloudy][:, 1], size=markersize, color="red", line_alpha=0.8, fill_alpha=0.8) where_cloudy = np.where((plot_vals[:,1] < weather_limits['cloudy'])\ & (plot_vals[:,1] >= weather_limits['clear'])) plot_cloudiness.circle(plot_vals[where_cloudy][:, 0], plot_vals[where_cloudy][:, 1], size=markersize, color="orange", line_alpha=0.8, fill_alpha=0.8) where_clear = np.where( plot_vals[:, 1] < weather_limits['clear']) plot_cloudiness.circle(plot_vals[where_clear][:, 0], plot_vals[where_clear][:, 1], size=markersize, color="green", line_alpha=0.8, fill_alpha=0.8) plot_cloudiness.yaxis.axis_label = 'Cloudiness (C)' plot_cloudiness.yaxis.formatter = NumeralTickFormatter(format="0,0") plot_cloudiness.xaxis.visible = False ##------------------------------------------------------------------------- ## Wind Plot if webcfg['Weather'].get('plot_wind_speed', None) is not None: log.info('Build wind plot') limit_string = webcfg['Weather'].get(f'plot_wind_speed_limits', '-3,85') ymin, ymax = limit_string.split(',') height = webcfg['Weather'].getint('plot_wind_speed_height', 120) plot_wind_speed = figure( width=900, height=height, x_axis_type="datetime", y_range=(float(ymin), float(ymax)), x_range=(end - timedelta(hours=span_hours), end), ) plot_values = webcfg['Weather'].get('plot_wind_speed').split(',') query_dict = {'date': {'$gt': start, '$lt': end}} for plot_value in plot_values: collection, name = plot_value.split(':') log.debug(f' Querying mongo collection {collection}') query_result = mongo_query(collection, query_dict, webcfg) plot_vals = [] for d in query_result: if name in d.keys(): if d.get(f"{name} units", None) == 'kph': plot_vals.append((d['date'], d[name] * 1.61)) elif d.get(f"{name} unit", None) == 'kph': plot_vals.append((d['date'], d[name] * 1.61)) elif d.get("wind speed units", None) == 'kph': plot_vals.append((d['date'], d[name] * 1.61)) else: plot_vals.append((d['date'], d[name])) plot_vals = np.array(plot_vals) log.debug(f' Got {len(plot_vals)} entries') if len(plot_vals) > 0: where_vwindy = np.where( plot_vals[:, 1] >= weather_limits['very windy']) plot_wind_speed.circle(plot_vals[where_vwindy][:, 0], plot_vals[where_vwindy][:, 1], size=markersize, color="red", line_alpha=0.8, fill_alpha=0.8) where_windy = np.where((plot_vals[:,1] < weather_limits['very windy'])\ & (plot_vals[:,1] >= weather_limits['windy'])) plot_wind_speed.circle(plot_vals[where_windy][:, 0], plot_vals[where_windy][:, 1], size=markersize, color="orange", line_alpha=0.8, fill_alpha=0.8) where_calm = np.where( plot_vals[:, 1] < weather_limits['windy']) plot_wind_speed.circle(plot_vals[where_calm][:, 0], plot_vals[where_calm][:, 1], legend_label=f"{plot_value}", size=markersize, color="green", line_alpha=0.8, fill_alpha=0.8) if webcfg['Weather'].get('plot_wind_gust', None) is not None: plot_values = webcfg['Weather'].get('plot_wind_gust').split(',') query_dict = {'date': {'$gt': start, '$lt': end}} for plot_value in plot_values: collection, name = plot_value.split(':') log.debug(f' Querying mongo collection {collection}') query_result = mongo_query(collection, query_dict, webcfg) plot_vals = np.array([(d['date'], d[name]) for d in query_result if name in d.keys()]) log.debug(f' Got {len(plot_vals)} entries') if len(plot_vals) > 0: plot_wind_speed.line(plot_vals[:, 0], plot_vals[:, 1], legend_label=f"{plot_value}", line_width=markersize, color="black", line_alpha=0.3) if len(plot_values) > 1 or webcfg['Weather'].get( 'plot_wind_gust', None) is not None: plot_wind_speed.legend.location = "top_left" plot_wind_speed.legend.margin = 0 plot_wind_speed.legend.padding = 0 plot_wind_speed.legend.spacing = 0 plot_wind_speed.legend.label_text_font_size = '8pt' else: plot_wind_speed.legend.visible = False plot_wind_speed.yaxis.axis_label = 'Wind (mph)' plot_wind_speed.yaxis.formatter = NumeralTickFormatter(format="0,0") plot_wind_speed.yaxis.ticker = [0, 20, 40, 60, 80] plot_wind_speed.xaxis.visible = False ##------------------------------------------------------------------------- ## Rain Plot if webcfg['Weather'].get('plot_rain', None) is not None: log.info('Build rain plot') limit_string = webcfg['Weather'].get(f'plot_rain_limits', '500,2800') ymin, ymax = limit_string.split(',') height = webcfg['Weather'].getint('plot_rain_height', 60) plot_rain = figure( width=900, height=height, x_axis_type="datetime", y_range=(float(ymin), float(ymax)), x_range=(end - timedelta(hours=span_hours), end), ) plot_values = webcfg['Weather'].get('plot_rain').split(',') query_dict = {'date': {'$gt': start, '$lt': end}} for plot_value in plot_values: collection, name = plot_value.split(':') log.debug(f' Querying mongo collection {collection}') query_result = mongo_query(collection, query_dict, webcfg) plot_vals = np.array([(d['date'], d[name]) for d in query_result if name in d.keys()]) log.debug(f' Got {len(plot_vals)} entries') if len(plot_vals) > 0: where_dry = np.where(plot_vals[:, 1] >= weather_limits['dry']) plot_rain.circle(plot_vals[where_dry][:, 0], plot_vals[where_dry][:, 1], size=markersize, color="green", line_alpha=0.8, fill_alpha=0.8) where_wet = np.where((plot_vals[:,1] < weather_limits['dry'])\ & (plot_vals[:,1] >= weather_limits['wet'])) plot_rain.circle(plot_vals[where_wet][:, 0], plot_vals[where_wet][:, 1], size=markersize, color="orange", line_alpha=0.8, fill_alpha=0.8) where_rain = np.where(plot_vals[:, 1] < weather_limits['wet']) plot_rain.circle(plot_vals[where_rain][:, 0], plot_vals[where_rain][:, 1], size=markersize, color="red", line_alpha=0.8, fill_alpha=0.8) plot_rain.yaxis.axis_label = 'Rain' plot_rain.yaxis.formatter = NumeralTickFormatter(format="0.0a") plot_rain.xaxis.visible = False ##------------------------------------------------------------------------- ## Safe Plot if webcfg['Weather'].get('plot_safe', None) is not None: log.info('Build safe plot') height = webcfg['Weather'].getint('plot_safe_height', 60) plot_safe = figure( width=900, height=height, x_axis_type="datetime", y_range=(-0.2, 1.2), x_range=(end - timedelta(hours=span_hours), end), ) plot_values = webcfg['Weather'].get('plot_safe').split(',') query_dict = {'date': {'$gt': start, '$lt': end}} for plot_value in plot_values: collection, name = plot_value.split(':') log.debug(f' Querying mongo collection {collection}') query_result = mongo_query(collection, query_dict, webcfg) plot_vals = np.array([(d['date'], d[name]) for d in query_result if name in d.keys()]) log.debug(f' Got {len(plot_vals)} entries') if len(plot_vals) > 0: where_safe = np.where(plot_vals[:, 1] == True) plot_safe.circle(plot_vals[where_safe][:, 0], plot_vals[where_safe][:, 1], size=markersize, color="green", line_alpha=0.8, fill_alpha=0.8) where_unsafe = np.where(plot_vals[:, 1] != True) plot_safe.circle(plot_vals[where_unsafe][:, 0], plot_vals[where_unsafe][:, 1], size=markersize, color="red", line_alpha=0.8, fill_alpha=0.8) plot_safe.yaxis.axis_label = 'Safe' plot_safe.xaxis.axis_label = 'Time (UT)' plot_safe.yaxis.formatter = NumeralTickFormatter(format="0,0") plot_safe.yaxis.ticker = [0, 1] plot_safe.xaxis.visible = False ##------------------------------------------------------------------------- ## Dome Status Plot ##------------------------------------------------------------------------- if webcfg['Weather'].getboolean('plot_dome', False) is True and telcfg is not None: telescope = telcfg['Telescope'].get('name') ## Telescope Status Query log.info(f"Querying dome status database") query_dict = {'date': {'$gt': start, '$lt': end}} domestatus = mongo_query(f'{telescope}_dome', query_dict, telcfg) log.info(f" Got {len(domestatus)} data points") # 0=open, 1=closed, 2=opening, 3=closing shutter_values = {0: 0, 1: 1, 2: 0.25, 3: 0.75, 4: 4} for i, d in enumerate(domestatus): if d['shutterstatus'] == 4 and i > 0: domestatus[i]['open_closed'] = domestatus[i - 1]['open_closed'] else: domestatus[i]['open_closed'] = shutter_values[ d['shutterstatus']] ## IQMon Query log.info(f"Querying IQMon results database") query_dict = { 'telescope': telescope, 'date': { '$gt': start, '$lt': end } } iqmon = mongo_query('iqmon', query_dict, telcfg) log.info(f" Got {len(iqmon)} data points") iqmon_obj_dates = [d['date'] for d in iqmon if d['imtype'] == 'OBJECT'] iqmon_obj_alt = [ d['alt'] / 90 for d in iqmon if d['imtype'] == 'OBJECT' ] iqmon_cal_dates = [ d['date'] for d in iqmon if d['imtype'] in ['BIAS', 'DARK'] ] iqmon_cal_alt = [0.5 for d in iqmon if d['imtype'] in ['BIAS', 'DARK']] iqmon_flat_dates = [ d['date'] for d in iqmon if d['imtype'] in ['FLAT', 'TWIFLAT', 'DOMEFLAT'] ] iqmon_flat_alt = [ 0.5 for d in iqmon if d['imtype'] in ['FLAT', 'TWIFLAT', 'DOMEFLAT'] ] ## Build Telescope Status plot log.info('Build Telescope Status plot') dome = [s['open_closed'] for s in domestatus] dome_date = [s['date'] for s in domestatus] height = webcfg['Weather'].getint('plot_dome_height', 60) dome_plot = figure( width=900, height=height, x_axis_type="datetime", y_range=(-0.2, 1.2), x_range=(end - timedelta(hours=span_hours), end), ) # open_date = [dome_date[i] for i,d in enumerate(dome) if d < 0.5] # open_dome = [d for i,d in enumerate(dome) if d < 0.5] # closed_date = [dome_date[i] for i,d in enumerate(dome) if d >= 0.5] # closed_dome = [d for i,d in enumerate(dome) if d >= 0.5] # dome_plot.line(closed_date, closed_dome, line_width=4, color="black") # dome_plot.line(open_date, open_dome, line_width=4, color="green") dome_plot.line(dome_date, dome, line_width=4, color="black", line_alpha=0.8) # IQMon Files dome_plot.circle(iqmon_obj_dates, iqmon_obj_alt, size=markersize, color="blue", line_alpha=0.8, fill_alpha=0.8) dome_plot.circle(iqmon_cal_dates, iqmon_cal_alt, size=markersize, color="black", line_alpha=0.8, fill_alpha=0.8) dome_plot.circle(iqmon_flat_dates, iqmon_flat_alt, size=markersize, color="yellow", line_alpha=0.8, fill_alpha=0.8) dome_plot.yaxis.axis_label = f'{telcfg["Telescope"].get("name")}' dome_plot.xaxis.axis_label = 'Time (UT)' dome_plot.yaxis.formatter = NumeralTickFormatter(format="0,0") dome_plot.yaxis.ticker = [0, 1] dome_plot.xaxis.visible = False ##------------------------------------------------------------------------- ## Render log.info(f"Overplotting twilights") plot_names = [ 'plot_temperature', 'plot_humidity', 'plot_cloudiness', 'plot_wind_speed', 'plot_rain', 'plot_safe' ] plot_info_list = [] for name in plot_names: if webcfg['Weather'].get(name, None) is not None: log.info(f" {name}") limit_string = webcfg['Weather'].get(f'{name}_limits', None) if limit_string is not None: ymin, ymax = limit_string.split(',') else: ymin, ymax = 0, 1 plot_info_list.append([name, eval(name), float(ymax), float(ymin)]) plot_column_list = [] plot_twilights_list = [] for i, plot_info in enumerate(plot_info_list): if webcfg['Weather'].get(plot_info[0], None) is not None: if i != 0: plot_info[1].x_range = plot_info_list[0][1].x_range plot_column_list.append(plot_info[1]) plot_twilights_list.append(plot_info) overplot_twilights(plot_twilights_list, end, webcfg, plot_ndays=plot_ndays, log=log) if webcfg['Weather'].getboolean('plot_dome', False) is True and telcfg is not None: plot_column_list.append(dome_plot) # Add time log plot_column_list[-1].plot_height += 40 plot_column_list[-1].xaxis.visible = True plot_column_list[-1].xaxis.formatter = DatetimeTickFormatter( hourmin=['%H:%M']) plot_column_list[-1].xaxis.ticker = DatetimeTicker(desired_num_ticks=24) plot_column_list[-1].xaxis.axis_label = 'UT Time' log.info(f"Rendering bokeh plot for {plot_column_list}") script, div = components(column(plot_column_list)) return script, div
def bokeh(windfarm='moneen', random=None, outlook=False): p("BOKEH outlook " + str(outlook)) if random: username = session.get('username', None) if not username or username.lower() != random.lower(): return redirect(url_for('login')) """ Create plot """ TOOLS="pan,wheel_zoom,box_zoom,reset" #TOOLS="wheel_zoom,box_zoom,reset" plot = plt.figure( width=800, height=200, x_axis_type="datetime", #title = "Power (kWh)", tools=TOOLS, responsive=True ) """ Get the data for the line chart - get df from db TODO: select time limit - sort index and take difference - get a rollwing window (each reading is 10 seconds so 180*10 = 30 min) """ #p("GET CONN") conn = get_db() #p("GOT CONN") #df = pd.read_sql(con=conn, sql='select * from activepower', index_col='timestamp') source = pd.read_sql(con=conn, sql='select * from source', index_col='timestamp') source = plt.ColumnDataSource(data=source) line = plot.line( x= 'timestamp', y='percent', source=source, alpha=1, color='#e24a33', line_width=2, legend = 'Power (MWh)' ) hline = Span(location=100, dimension='width', line_color='green', line_width=3) import time now = time.mktime(datetime.datetime.now().timetuple()) * 1000 vline = Span(location=now, dimension='height', line_color='red', line_width=1, line_dash=[4,4]) plot.renderers.extend([hline, vline]) # newline not respected in ticklabels !!! plot.xaxis.formatter = DatetimeTickFormatter(days=["%a %d %b"]) plot.xgrid.band_fill_color = "grey" plot.xgrid.band_fill_alpha = 0.05 #plot.xaxis.axis_label = 'Date' plot.xaxis.axis_label_text_font_size = "11pt" plot.yaxis.axis_label = '% Power' plot.yaxis.axis_label_text_font_size = "11pt" plot.yaxis.axis_label_text_font_style = "normal" plot.legend.location = "top_left" #ts = TimeSeries(rm, x='index', y='values') hover_line = HoverTool(renderers=[line]) hover_line.tooltips = """ <div> <span style="font-size: 15px; font-weight: bold;">@time</span> </div> <table border="0" cellpadding="10"> <tr> <th><span style="font-family:'Consolas', 'Lucida Console', monospace; font-size: 12px;">1/2-hourly average: </span></th> <td><span style="font-family:'Consolas', 'Lucida Console', monospace; font-size: 12px;">@power MW</span></td> </tr> <tr> <th><span style="font-family:'Consolas', 'Lucida Console', monospace; font-size: 12px;">1/2-hourly_min:</span></th> <td><span style="font-family:'Consolas', 'Lucida Console', monospace; font-size: 12px;">@hourly_min MW</span></td> </tr> <tr> <th><span style="font-family:'Consolas', 'Lucida Console', monospace; font-size: 12px;">1/2-hourly_max:</span></th> <td><span style="font-family:'Consolas', 'Lucida Console', monospace; font-size: 12px;">@hourly_max MW</span></td> </tr> </table> """ plot.add_tools(hover_line) col = None def add_outages_to_plot(plot, df): df['midpoint'] = df.startdate + (df.finishdate-df.startdate)/2 df['midpoint'] = df.midpoint.apply(lambda x: np.datetime64(x).astype('datetime64[ms]').view(np.int64)) df['duration'] = df.finishdate-df.startdate df['height'] = 100 - (df.availability) df['width'] = df.duration.apply(lambda x: x.total_seconds()*1000) df['start'] = df.startdate.dt.strftime("%A, %e %B %H:%M") df['finish'] = df.finishdate.dt.strftime("%A, %e %B %H:%M") df['y'] = 100 -(df['height']/2) rect = plot.rect( x = 'midpoint', y = 'y', height = 'height', width = 'width', color = 'purple', source=df ) return rect def create_outages_datatable(df): from bokeh.models import ColumnDataSource from bokeh.models.widgets import DataTable, DateFormatter, TableColumn source = ColumnDataSource(df) columns = [ TableColumn(field="start", title="Start"), TableColumn(field="finish", title="Finish"), TableColumn(field="availability", title="% Available"), TableColumn(field="timestamp", title="Updated At"), ] table_height = len(df) * 24 + 30 data_table = DataTable(source=source, columns=columns,row_headers=True, width=770, height=table_height, sizing_mode='scale_both' ) return source, data_table plot_div, dt_div, bokeh_script = '','','' if random: random = random.lower() conn = get_db() cursor = conn.cursor() q = """select * from appointments where random = '{r}'""".format(r=random) df = pd.read_sql(con=conn, sql=q) if not df.empty: rect = add_outages_to_plot(plot,df) hover_rect = HoverTool(renderers=[rect]) hover_rect.tooltips = """ <div> <span style="font-size: 15px; font-weight: bold;">@date</span> </div><a href="http://www.bbc.co.uk">: <table border="0" cellpadding="10"> <tr> <th><span style="font-family:'Consolas', 'Lucida Console', monospace; font-size: 12px;">Start: </span></th> <td><span style="font-family:'Consolas', 'Lucida Console', monospace; font-size: 12px;">@start MWh</span></td> </tr> <tr> <th><span style="font-family:'Consolas', 'Lucida Console', monospace; font-size: 12px;">End:</span></th> <td><span style="font-family:'Consolas', 'Lucida Console', monospace; font-size: 12px;">@finish</span></td> </tr> <tr> <th><span style="font-family:'Consolas', 'Lucida Console', monospace; font-size: 12px;">% Available:</span></th> <td><span style="font-family:'Consolas', 'Lucida Console', monospace; font-size: 12px;">@availability</span></td> </tr> </table> </a> """ plot.add_tools(hover_rect) url = "/appointment/{windfarm}/{random}/edit/@start".format(windfarm=windfarm,random=random) taptool = plot.select(type=TapTool) #taptool = rect.select(type=TapTool) alert_js = """ console.log("PARENT: " + showDiv(source.data['jobnumber'][source.selected["1d"].indices])) """ source, data_table = create_outages_datatable(df) source.callback = CustomJS( args = dict(source=source), code = alert_js ) from bokeh.layouts import column col = column(plot, data_table) bokeh_script, comps = components({"plot":plot,"dt":data_table}) plot_div, dt_div = comps['plot'], comps['dt'] if not col: col = plot bokeh_script, plot_div = components(plot) plot.xaxis[0].ticker = DatetimeTicker() if not outlook: template = "l2.html" else: template = "outlook.html" p("TEMPLATE BEING USED: " + template) return render_template(template, windfarm=windfarm, random=random, plot_div=plot_div, dt_div=dt_div, bs=bokeh_script)
def generate_iqmon_plot(cfg, date=None, plot_ndays=1, span_hours=24): telescope = cfg['Telescope'].get('name') if date is None: end = datetime.utcnow() start = end - timedelta(days=plot_ndays) else: start = datetime.strptime(date, '%Y%m%dUT') end = start + timedelta(days=plot_ndays) ##------------------------------------------------------------------------- ## IQMon Query log.info(f"Querying IQMon results database") query_dict = {'telescope': telescope, 'date': {'$gt': start, '$lt': end}} query_result = mongo_query('iqmon', query_dict, cfg) iqmon = [d for d in query_result] log.info(f" Got {len(iqmon)} data points") dates_fwhm = [d['date'] for d in iqmon if 'fwhm' in d.keys()] fwhm = [d['fwhm'] for d in iqmon if 'fwhm' in d.keys()] dates_elip = [d['date'] for d in iqmon if 'ellipticity' in d.keys()] elip = [d['ellipticity'] for d in iqmon if 'ellipticity' in d.keys()] markersize = 2 ##------------------------------------------------------------------------- ## FWHM Plot log.info('Build FWHM plot') fwhm_plot = figure( width=900, height=200, x_axis_type="datetime", y_range=(0, 10), x_range=(end - timedelta(hours=span_hours), end), ) fwhm_plot.circle(dates_fwhm, fwhm, size=markersize, color="blue", alpha=0.8) fwhm_plot.yaxis.axis_label = 'FWHM (pix)' fwhm_plot.yaxis.formatter = NumeralTickFormatter(format="0,0") fwhm_plot.xaxis.visible = False ##------------------------------------------------------------------------- ## Ellipticity Plot log.info('Build ellipticity plot') ellipticity_plot = figure( width=900, height=200, x_axis_type="datetime", y_range=(1, 2), x_range=fwhm_plot.x_range, ) ellipticity_plot.circle(dates_elip, elip, size=markersize, color="blue", alpha=0.8) ellipticity_plot.yaxis.axis_label = 'ellipticity' ellipticity_plot.yaxis.formatter = NumeralTickFormatter(format="0.0") ellipticity_plot.xaxis.visible = True ellipticity_plot.xaxis.formatter = DatetimeTickFormatter(hourmin=['%H:%M']) ellipticity_plot.xaxis.ticker = DatetimeTicker(desired_num_ticks=24) ellipticity_plot.xaxis.axis_label = 'UT Time' ##------------------------------------------------------------------------- ## Render log.info(f"Rendering bokeh plot") script, div = components(column( fwhm_plot, ellipticity_plot, )) return script, div
def create_daily_res_plot(res_forecast, load_forecast): """ Graph the res injection forecast. Arguments: res_forecast (list): list of renewable energy injection forecast load_forecast (list): list of load forecast """ # Datetime range time_of_day = [] # Create x-axis # beginning of day today = datetime.datetime.today() beginning_of_day = datetime.datetime(year=today.year, month=today.month, day=today.day) for i in range(len(res_forecast)): time_of_day.append(beginning_of_day + datetime.timedelta(minutes=i * 30)) # Compute 75 percentile percentile = np.percentile(res_forecast, 75) # Initialize dictionaries normal_dict = {'x': [], 'y': [], 'percentage': []} peak_dict = {'x': [], 'y': [], 'percentage': []} for i in range(len(res_forecast)): if res_forecast[i] >= percentile: peak_dict['x'].append(time_of_day[i]) peak_dict['y'].append(res_forecast[i]) peak_dict['percentage'].append( percentage_of(res_forecast[i], load_forecast[i])) else: normal_dict['x'].append(time_of_day[i]) normal_dict['y'].append(res_forecast[i]) normal_dict['percentage'].append( percentage_of(res_forecast[i], load_forecast[i])) # Hover tool to properly display time of day and value on hover hover = HoverTool( tooltips=[("Time of day", "@x{%H:%M}"), ("Forecast Value", "@y MWh"), ("Percentage of Daily Load", "@percentage{1.11} %")], formatters={'@x': 'datetime'}, ) # Create the figure plot = figure( x_axis_label="Time of Day", y_axis_label="Megawatts Per Hour", x_axis_type='datetime', sizing_mode="stretch_width", tools=[ hover, BoxZoomTool(), ResetTool(), LassoSelectTool(), WheelZoomTool(), PanTool(), SaveTool() ], ) plot.xaxis.formatter = DatetimeTickFormatter( minutes=["%H:%M"], hours=["%H:%M"], ) # Set x-range and y-range plot.y_range = Range1d(min(res_forecast) - 200, max(res_forecast) + 100) plot.x_range = Range1d(time_of_day[0] - datetime.timedelta(minutes=5), time_of_day[-1] + datetime.timedelta(minutes=5)) # Set a grid plot.grid.minor_grid_line_color = '#eeeeee' # Set the font and style of labels plot.axis.axis_label_text_font = "raleway" plot.axis.axis_label_text_font_style = "normal" # Set the font of ticks on the axis plot.axis.major_label_text_font = "raleway" # Set the desired ticks plot.xaxis.ticker = DatetimeTicker(desired_num_ticks=24) plot.yaxis.ticker = AdaptiveTicker(desired_num_ticks=20) # Add a line plot plot.line(time_of_day, res_forecast, line_alpha=0.2, color="#264b01", line_width=1.5) # Add two circle plots one for the normal values and one for those that # are at or above the 75-percentile plot.circle('x', 'y', source=normal_dict, size=8, color="#264b01") plot.circle('x', 'y', source=peak_dict, size=15, color="#264b01") return components(plot)
def plot_odds_goals(db_, team_home, team_away): """ Retrieves match from db, creates a dataframe of odds and plots odds over time. todo: creating the dataframe should be done in a different function """ # Retrieve match from database m = db_.matches.find_one({'team_home': team_home, 'team_away': team_away}) if m is None: return None df = utils.create_odds_df(m) # Filter over the following bookies # todo: get them from a config file bookies_to_plot = ['Bet 365', 'Sky Bet', 'Ladbrokes', "William Hill", "Marathon Bet", "Betfair Sportsbook", "SunBets", "Paddy Power", "Unibet", "Coral", "Betfred", "Bet Victor"] filters = [(df.bookie == "Bet 365") | (df.bookie == "Bet365"), (df.bookie == "Sky Bet") | (df.bookie == "Skybet"), (df.bookie == "Ladbrokes"), (df.bookie == "William Hill"), (df.bookie == "Marathon Bet"), (df.bookie == "Betfair Sportsbook"), (df.bookie == "SunBets"), (df.bookie == "Paddy Power"), (df.bookie == "Unibet"), (df.bookie == "Coral"), (df.bookie == "Betfred"), (df.bookie == "Bet Victor")] colors = itertools.cycle(palette) # output to static HTML file title = "%s | %s - %s | %s" % (str(m['match_datetime']), m['team_home'], m['team_away'], m['result']['score']) output_file("templates/goals_timeseries.html", title="Odds %s - %s" %(team_home, team_away)) # create a new plot with a title and axis labels f1 = figure(title="Over 2.5 | %s" % title, x_axis_type="datetime", x_axis_label='Time', y_axis_label='Odd', plot_width=900, plot_height=350) f2 = figure(title="Under 2.5 | %s" % title, x_axis_type="datetime", x_axis_label='Time', y_axis_label='Odd', plot_width=900, plot_height=350) for filter_, bookie, color in zip(filters, bookies_to_plot, colors): source = ColumnDataSource(df[filter_]) f1.line('datetime', 'over2_5', legend=bookie, color=color, line_width=2, source=source, alpha=0.8) f1.circle('datetime', 'over2_5', color=color, source=source) f2.line('datetime', 'under2_5', legend=bookie, color=color, line_width=2, source=source, alpha=0.8) f2.circle('datetime', 'under2_5',color=color, source=source) f1.xaxis.ticker = DatetimeTicker(desired_num_ticks=15) f2.xaxis.ticker = DatetimeTicker(desired_num_ticks=15) f1.legend.location = "top_left" f2.legend.location = "top_left" save(column(f1,f2)) return True
def bokehs(windfarm='moneen', user='', outlook=False): p("BOKEH outlook " + str(outlook)) username = session.get('username', None) username = session.get('username', '') if not username or username.lower() != user.lower(): #return redirect(url_for('login')) pass """ Create plot """ TOOLS = "pan,wheel_zoom,box_zoom,reset" #TOOLS="wheel_zoom,box_zoom,reset" plot = plt.figure( width=800, height=200, x_axis_type="datetime", #title = "Power (kWh)", tools=TOOLS, responsive=True) plot = plt.figure( width=600, height=200, x_axis_type="datetime", #title = "Power (kWh)", tools=TOOLS, responsive=True, toolbar_location="above") plot.xaxis[0].ticker = DatetimeTicker() """ Get the data for the line chart - get df from db TODO: select time limit - sort index and take difference - get a rollwing window (each reading is 10 seconds so 180*10 = 30 min) """ #p("GET CONN") conn = get_db() #p("GOT CONN") #df = pd.read_sql(con=conn, sql='select * from activepower', index_col='timestamp') power_df = pd.read_sql(con=conn, sql='select * from source order by timestamp') power_df['setpoint'] = 100 #hline = Span(location=100, dimension='width', line_color='green', line_width=3) import time now = time.mktime(datetime.datetime.now().timetuple()) * 1000 vline = Span(location=now, dimension='height', line_color='red', line_width=1, line_dash=[4, 4]) plot.renderers.extend([vline]) # newline not respected in ticklabels !!! plot.xaxis.formatter = DatetimeTickFormatter(days=["%a %d %b"]) p(dir(plot.xaxis)) plot.xaxis.major_label_text_font = 'verdana' plot.xaxis.major_label_text_font_size = '9pt' plot.xgrid.band_fill_color = "grey" plot.xgrid.band_fill_alpha = 0.05 #plot.xaxis.axis_label = 'Date' plot.yaxis.axis_label = '% Power' plot.yaxis.axis_label_text_font_size = "11pt" plot.yaxis.axis_label_text_font_style = "normal" plot.legend.location = "top_left" #ts = TimeSeries(rm, x='index', y='values') col = None def create_outages_datatable(df): #p("datatable columns\n"+df.columns) from bokeh.models import ColumnDataSource from bokeh.models.widgets import DataTable, DateFormatter, TableColumn datefmt = DateFormatter(format="dd M yy h:mm") df['startdate'] = pd.to_datetime(df['startdate'], unit='s').astype(str) df['finishdate'] = pd.to_datetime(df['finishdate'], unit='s').astype(str) df['timestamp'] = pd.to_datetime(df['timestamp'], unit='s').astype(str) source = ColumnDataSource(df) p(dir(TableColumn)) columns = [ TableColumn(field="startdate", title="Start"), TableColumn(field="finishdate", title="Finish"), TableColumn(field="availability", title="%", width=16), TableColumn(field="timestamp", title="Updated At"), ] table_height = len(df) * 24 + 30 data_table = DataTable(source=source, columns=columns, row_headers=True, width=600, height=table_height, sizing_mode='scale_both') return source, data_table plot_div, dt_div, bokeh_script = '', '', '' user = user.lower() conn = get_db() cursor = conn.cursor() q = """select * from appointments where random = '{r}'""".format(r=user) df = pd.read_sql(con=conn, sql=q) if not df.empty: appointments = df for a, i in appointments.iterrows(): start = i.startdate finish = i.finishdate setpoint = i.availability row_indexer = power_df[(power_df.timestamp > start) & (power_df.timestamp < finish)].index p(len(row_indexer)) power_df.loc[row_indexer, 'setpoint'] = setpoint url = "/appointment/{windfarm}/{random}/edit/@start".format( windfarm=windfarm, random=user) #taptool = plot.select(type=TapTool) #taptool = rect.select(type=TapTool) alert_js = """ console.log("PARENT: " + showDiv(source.data['jobnumber'][source.selected["1d"].indices])) """ # Add OLD Forecast Power by jittering averages of old values # get average values_to_take numbers and add randint i = 0 values_to_take = 30 import random max_index = max(power_df.index) while i < max_index: floor, ceiling = i, min(i + values_to_take - 1, max_index) values = power_df.loc[floor:ceiling, 'percent'] avg = sum(values) / len(values) guess = avg + random.randint(-10, 10) guess = 0 if guess < 0 else guess guess = 100 if guess > 100 else guess power_df.loc[floor:ceiling, 'forecast'] = guess i += values_to_take now = pd.Timestamp.now().tz_localize('GMT') readings = [] if appointments.finishdate.max().tz_localize('GMT') > now: targeted_end = ( appointments.finishdate.max() + datetime.timedelta(days=2)).round('24h').tz_localize('GMT') else: targeted_end = ( power_df.timestamp.max() + datetime.timedelta(days=7)).round('24h').tz_convert('GMT') freq = pd.Timedelta('0 days 00:10:00') d = now # test comment for git while d < targeted_end: readings.append({'timestamp': d, 'setpoint': 100}) d += freq #p(d) forecast_av_df = pd.DataFrame(readings) for a, i in appointments.iterrows(): #print(i) start = i.startdate finish = i.finishdate setpoint = i.availability #print("start", start, finish) row_indexer = forecast_av_df[(forecast_av_df.timestamp > start) & (forecast_av_df.timestamp < finish)].index #print(row_indexer, setpoint) forecast_av_df.loc[row_indexer, 'setpoint'] = setpoint previous_forecast = power_df.iloc[-1, ]['forecast'] i = 0 values_to_take = 6 import random while i < max(forecast_av_df.index): floor, ceiling = i, min(i + values_to_take - 1, max(forecast_av_df.index)) guess = previous_forecast + random.randint(-1, 1) guess = 0 if guess < 0 else guess guess = 100 if guess > 100 else guess forecast_av_df.loc[floor:ceiling, 'forecast'] = guess i += values_to_take previous_forecast = guess power_source = plt.ColumnDataSource(data=power_df) step = plot.line(x='timestamp', y='setpoint', source=power_source, alpha=1, color='orange', line_width=1) old_power = plot.line(x='timestamp', y='forecast', source=power_source, alpha=1, color='pink', line_width=1) power = plot.line(x='timestamp', y='percent', source=power_source, alpha=1, color='green', line_width=1) forecast_source = plt.ColumnDataSource(data=forecast_av_df) forecast = plot.line(x='timestamp', y='setpoint', source=forecast_source, color='orange', line_dash=[6, 3]) forecast_power = plot.line(x='timestamp', y='forecast', source=forecast_source, color='pink', line_dash=[6, 6]) legend = Legend( items=[ ("Availability", [step]), ("Old Forecast Power", [old_power]), ("Actual Power", [power]), ("Forecast Power", [forecast_power]), ("Forecast Availability", [forecast]), #("Now", [vline]) ], location=(0, -40)) plot.add_layout(legend, 'right') hover_line = HoverTool(renderers=[old_power]) hover_line.tooltips = """ <div> <span style="font-size: 15px;">@date @time</span> </div> <table border="0" cellpadding="10"> <tr> <th><span style="font-family:'Consolas', 'Lucida Console', monospace; font-size: 12px;">30m avg: </span></th> <td><span style="font-family:'Consolas', 'Lucida Console', monospace; font-size: 12px;">@power MW</span></td> </tr> <tr> <th><span style="font-family:'Consolas', 'Lucida Console', monospace; font-size: 12px;">30m min:</span></th> <td><span style="font-family:'Consolas', 'Lucida Console', monospace; font-size: 12px;">@hourly_min MW</span></td> </tr> <tr> <th><span style="font-family:'Consolas', 'Lucida Console', monospace; font-size: 12px;">30m max:</span></th> <td><span style="font-family:'Consolas', 'Lucida Console', monospace; font-size: 12px;">@hourly_max MW</span></td> </tr> </table> """ plot.add_tools(hover_line) source, data_table = create_outages_datatable(df) source.callback = CustomJS(args=dict(source=source), code=alert_js) #plot.legend.location = "top_left" plot.legend.click_policy = "hide" #plot.legend.background_fill_alpha = 0.01 #plot.legend.location=(10, -30) from bokeh.layouts import column col = column(plot, data_table) leg = [ rend for rend in plot.renderers if type(rend) == bokeh.models.annotations.Legend ][0] bokeh_script, comps = components({ "plot": plot, "dt": data_table, "legend": leg }) plot_div, dt_div, legend_div = comps['plot'], comps['dt'], comps['legend'] if not col: col = plot bokeh_script, plot_div = components(plot) if not outlook: template = "l2.html" else: template = "outlook.html" p("TEMPLATE BEING USED: " + template) return render_template(template, windfarm=windfarm, random=user, plot_div=plot_div, dt_div=dt_div, bs=bokeh_script, legend_div=legend_div)
def get_plot(raw, today): dfs, cats = get_sources_and_categories(raw) # Some times first_day = raw.loc[0, 'timestamp'] one_week_ago = today - datetime.timedelta(weeks=1) two_weeks_ago = today - datetime.timedelta(weeks=2) one_week_forward = today + datetime.timedelta(weeks=1) # The ranges all_range = Range1d(start=first_day, end=today) month_range = Range1d(start=two_weeks_ago, end=one_week_forward) week_range = Range1d(start=one_week_ago, end=today) # Selection indicators highlight = Quad( left='start', right='end', bottom=0, top=12, fill_color='white', line_color=COLOR_PRIMARY_CONTRAST, fill_alpha=0.2, ) lowlight = Quad( left='start', right='end', bottom=0, top=12, fill_color=COLOR_PRIMARY, line_color=COLOR_PRIMARY_CONTRAST, fill_alpha=0.5, ) # Make the complete timeline plot all_plot = _make_base_plot(dfs, cats, all_range) detail_selection_source = ColumnDataSource({ 'start': [all_range.start, month_range.end], 'end': [month_range.start, all_range.end] }) all_plot.add_glyph(detail_selection_source, lowlight) # add a second axis to all_layout plot for presentation year_ticker = DatetimeTicker(desired_num_ticks=4) year_ticks = DatetimeTickFormatter( formats={ 'years': ["%Y"], 'months': ["%Y"], 'days': ["%Y"], 'hours': ["%Y"] } ) all_plot.add_layout( DatetimeAxis(formatter=year_ticks, ticker=year_ticker, **AXIS_PROPERTIES), 'below' ) # Make the detail plot detail_plot = _make_base_plot(dfs, cats, month_range) detail_plot.add_tools(PanTool(dimensions=['width'])) detail_plot.add_tools(WheelZoomTool(dimensions=['width'])) detail_plot.add_tools(ResetTool()) week_selection_source = ColumnDataSource({'start': [week_range.start], 'end': [week_range.end]}) detail_plot.add_glyph(week_selection_source, highlight) detail_code = """ // Update the month selection box on the all_data plot when month pans var detail_selection_data = detail_selection_source.get('data'); var detail_start = cb_obj.get('frame').get('x_range').get('start'); var detail_end = cb_obj.get('frame').get('x_range').get('end'); new_detail_selection = { 'start': [detail_selection_data['start'][0], detail_end], 'end': [detail_start, detail_selection_data['end'][1]] }; detail_selection_source.set('data', new_detail_selection); // Always make sure the week highlight box on detail is visible and centered var x = moment.duration(detail_end - detail_start).asWeeks() / 2.4; var start = moment(detail_start); var week_end = start.add(x, 'weeks').format('x'); $("#one_week_before").text(start.format('ddd, DD MMM YYYY')); var newStart = start.format('YYYY-MM-DD'); var week_start = start.add(6, 'days').format('x'); $("#today").text(start.format('ddd, DD MMM YYYY')); new_week_selection = { 'start': [week_start, ], 'end': [week_end, ] }; week_selection_source.set('data', new_week_selection); var url = '/timesheet/?start=' + newStart; $("#timesheet_submit").attr('href', url).addClass("mdl-button--colored"); """ detail_xrange_callback = CustomJS(args={}, code=detail_code) detail_xrange_callback.args['detail_selection_source'] = detail_selection_source detail_xrange_callback.args['week_selection_source'] = week_selection_source detail_plot.x_range.callback = detail_xrange_callback return all_plot, detail_plot
result['end_shares'] = shares results.append(result) if bal < 1 and shares < 1: break print('Starting position: %s' % results[0]) print('Ending position: %s' % results[-1]) output_file("datetime.html") # create a new plot with a datetime axis type p = figure(width=800, height=800, x_axis_type="datetime") p.line([r['snap_dt'] for r in results], [r['end_bal'] for r in results], color='navy', alpha=0.5) p.xaxis[0].ticker = DatetimeTicker(desired_num_ticks=20) p.xaxis.formatter = DatetimeTickFormatter( hours=["%Y-%m-%d"], days=["%Y-%m-%d"], months=["%Y-%m-%d"], years=["%Y-%m-%d"], ) p.xaxis.major_label_orientation = pi / 4 output_file('balance.html') show(p)
def plot_2T(date_time, stations, models): """ :param date_time: 必须是'YYMMDDHH'形式 :param stations: :param models: :return: """ tabs = [] output_file('D:/LPWF/2T_Forecast.html', title=u'2米温度预报', mode='inline') names = [name for name in stations] + ['date_time_X', 'date_time_str'] tools_to_show = 'hover,box_zoom,pan,save,resize,reset,wheel_zoom' #注意颜色的个数一定要与站点个数相同,不然以少的为准 colors = ['red', 'blue', 'green', 'orange', 'yellow', 'purple', 'pink', 'violet'] for model in models: #######添加新模式需要注意修改的地方: # 处理u'河南WRF_RUC'的'YYYYMMDDHH'形式 if model == u'河南WRF_RUC': date_time_condition = (datetime.strptime('20' + date_time, '%Y%m%d%H') - timedelta(hours=8)).strftime( '%Y%m%d%H') elif model == u'GRAPES_MESO集合平均': date_time_condition = (datetime.strptime('20' + date_time, '%Y%m%d%H') - timedelta(hours=8)).strftime( '%y%m%d%H') else: date_time_condition = date_time data = [] files_list = searchProductFiles(date_time_condition, models[model]) for each in files_list: d = Diamond4(each) lon_lat_s = [stations[name][1] for name in stations] extracted_values = d.IDW(lon_lat_s) #######添加新模式需要注意修改的地方: # 处理时间索引 date_time_index = d.valid_time if model in [u'河南WRF_RUC', u'GRAPES_GFS', u'GRAPES_MESO', u'T639粗',u'GRAPES_MESO集合平均']: date_time_index += timedelta(hours=8) # 注意bokeh在将时间对象作为X轴时会将本地时间转换为世界时,为了避免这种转换,需要再本地时间上再加上8h(北京时比世界时快8h) extracted_values.extend([date_time_index + timedelta(hours=8), date_time_index.strftime("%m/%d %Hh")]) data.append(pd.DataFrame(extracted_values, index=names).T) # 如果没有数据,则返回,防止出错 if not data: continue df = pd.concat(data).sort_values('date_time_X', ascending=False) del data n_series = len(df) p = figure(plot_width=1920 - 140, plot_height=1200 - 250, x_axis_type="datetime", tools=tools_to_show, active_scroll="wheel_zoom") # 分别为每个站点绘制时间序列变化曲线 for name, color in zip(stations, colors): source = ColumnDataSource(data={ 'dateX': df['date_time_X'], 'v': df[name], 'dateX_str': df['date_time_str'], 'name': [name for n in xrange(n_series)] }) p.line('dateX', 'v', color=color, legend=name, source=source) circle = p.circle('dateX', 'v', fill_color="white", size=8, color=color, legend=name, source=source) p.tools[0].renderers.append(circle) # 图例显示策略 p.legend.click_policy = "hide" # 显示标签 hover = p.select(dict(type=HoverTool)) hover.tooltips = [(u"温度", "@v{0.0}"), (u"站点", "@name"), (u"时间", "@dateX_str")] hover.mode = 'mouse' # 标题设置 if model == u'EC细 2TMax_3h': title = ' '.join([date_time, u'EC细', u'过去3小时2米最高温度预报']) elif model == u'EC细 2TMin_3h': title = ' '.join([date_time, u'EC细', u'过去3小时2米最低温度预报']) else: title = ' '.join([date_time, model, u'2米温度预报']) p.title.text = title p.title.align = "center" p.title.text_font_size = "25px" # p.title.background_fill_color = "#aaaaee" # p.title.text_color = "orange" p.xaxis.axis_label = u'日期/时间' p.yaxis.axis_label = u'温度(℃)' p.xaxis[0].formatter = DatetimeTickFormatter(hours=['%m/%d %Hh', '%m/%d %H:%M'], days=['%m/%d %Hh']) p.xaxis[0].ticker = DatetimeTicker(desired_num_ticks=20, num_minor_ticks=4) # todo.根据上午还是下午确定不同的日界线 #location使用实数表示,所以必须把时间转换成时间戳,但不清楚为什么要乘以1000 dateX = df['date_time_X'].tolist() del df n_days = (dateX[0] - dateX[-1]).days + 1 forecast_span = [ Span(location=time.mktime((dateX[-1] + timedelta(days=i) + timedelta(hours=12)).timetuple()) * 1000, dimension='height', line_color='red', line_dash='dashed', line_width=2) for i in xrange(n_days)] for span in forecast_span: p.add_layout(span) tab = Panel(child=p, title=model) tabs.append(tab) tabs = Tabs(tabs=tabs) save(tabs) # 直接保存就行