def retrieve(self, request, id=None): """ Gets the chart and saves as an html file when this route is hit """ parsed_url = request.current_route_url() chart_type = urlparse(parsed_url).query.split('=')[1] if chart_type == 'candlestick': res = requests.get(f'{API_URL}/stock/{id}/chart/5y') data = res.json() df = pd.DataFrame(data) seqs = np.arange(df.shape[0]) df['seqs'] = pd.Series(seqs) df['changePercent'] = df['changePercent'].apply( lambda x: str(x) + '%') # axis of one means go down the comumns, not the whole row. Default of 0 operates on the rows. df['mid'] = df.apply(lambda x: (x['open'] + x['close']) / 2, axis=1) df.head(1) df['height'] = df.apply(lambda x: x['close'] - x['open'] if x['close'] != x['open'] else 0.001, axis=1) df.sample(2) inc = df.close > df.open dec = df.close < df.open w = .3 sourceInc = bk.ColumnDataSource(df.loc[inc]) sourceDec = bk.ColumnDataSource(df.loc[dec]) hover = HoverTool(tooltips=[ ('date', '@date'), ('low', '@low'), ('high', '@high'), ('open', '@open'), ('close', '@close'), ('percent', '@percent'), ]) TOOLS = [ hover, BoxZoomTool(), PanTool(), ZoomInTool(), ZoomOutTool(), ResetTool() ] p = bk.figure(plot_width=1500, plot_height=800, tools=TOOLS, title=f'{id.upper()}', toolbar_location='above') p.xaxis.major_label_orientation = np.pi / 4 p.grid.grid_line_alpha = w descriptor = Label(x=70, y=70, text=f'{id}') # adds label onto the chart p.add_layout(descriptor) # set up your outer tails, and then the rectangles that go inside of the tails p.segment(df.seqs[inc], df.high[inc], df.seqs[inc], df.low[inc], color='green') p.segment(df.seqs[dec], df.high[dec], df.seqs[dec], df.low[dec], color='red') p.rect(x='seqs', y='mid', width=w, height='height', fill_color='green', line_color='green', source=sourceInc) p.rect(x='seqs', y='mid', width=w, height='height', fill_color='red', line_color='red', source=sourceDec) bk.save(p, f'./stocks_api_project/static/candle_stick_{id}.html', title=f'5yr_candlestick_{id}') f = codecs.open( f'./stocks_api_project/static/candle_stick_{id}.html', 'r') body = f.read() return Response(body=body, status=200) if chart_type == 'bar': res = requests.get(f'{API_URL}/stock/{id}/chart/5y') data = res.json() df = pd.DataFrame(data) df['date'] = pd.to_datetime(df['date']) df['MONTH'] = df['date'].dt.month df['DAY'] = df['date'].dt.day df['YEAR'] = df['date'].dt.year df[['low']].groupby(df.YEAR).mean() plot = bk.figure(plot_width=400, plot_height=400) plot.vbar(x=df.YEAR, width=0.5, bottom=0, top=df.low, color="firebrick") bk.save(plot, f'./stocks_api_project/static/year_versus_low_{id}.html', title=f'5yr_low_bar_{id}') f = codecs.open( f'./stocks_api_project/static/year_versus_low_{id}.html', 'r') body = f.read() return Response(body=body, status=200) if chart_type == 'volatility': res = requests.get(f'{API_URL}/stock/{id}/chart/5y') data = res.json() df = pd.DataFrame(data) df['date'] = pd.to_datetime(df['date']) df['MONTH'] = df['date'].dt.month df['DAY'] = df['date'].dt.day df['YEAR'] = df['date'].dt.year df[['change']].groupby(df.DAY).mean() plot_2 = bk.figure(plot_width=400, plot_height=400) plot_2.vbar(x=df.DAY, width=0.5, bottom=0, top=df.change, color="blue") bk.save(plot_2, f'./stocks_api_project/static/volatility_{id}.html', title=f'5yr_volitility_bar_{id}') f = codecs.open( f'./stocks_api_project/static/volatility_{id}.html', 'r') body = f.read() return Response(body=body, status=200)
def std_distance_time_plot(nx, ny, source, x_range=None): groups = list(related_statistics(source, ACTIVE_TIME)) if not groups: # original monochrome plot return multi_dot_plot(nx, ny, TIME, [ACTIVE_TIME_H, ACTIVE_DISTANCE_KM], source, ['black', 'grey'], alphas=[1, 0.5], x_range=x_range, rescale=True) times = [f'{ACTIVE_TIME} ({group})' for group in groups] distances = [f'{ACTIVE_DISTANCE} ({group})' for group in groups] time_y_range = make_range(source, ACTIVE_TIME_H) distance_y_range = make_range(source, ACTIVE_DISTANCE_KM) colours = list(evenly_spaced_hues(len(groups))) tools = [ PanTool(dimensions='width'), ZoomInTool(dimensions='width'), ZoomOutTool(dimensions='width'), ResetTool(), HoverTool(tooltips=[ tooltip(x) for x in (ACTIVE_TIME_H, ACTIVE_DISTANCE_KM, ACTIVITY_GROUP, LOCAL_TIME) ], names=['with_hover']) ] f = figure(plot_width=nx, plot_height=ny, x_axis_type='datetime', tools=tools) f.yaxis.axis_label = ACTIVE_TIME_H f.y_range = time_y_range f.extra_y_ranges = {ACTIVE_DISTANCE: distance_y_range} f.add_layout( LinearAxis(y_range_name=ACTIVE_DISTANCE, axis_label=ACTIVE_DISTANCE_KM), 'right') plotter = dot_plotter() for time, colour in zip(times, colours): time_h = _slash(time, H) source[time_h] = source[time] / 3600 plotter(f, x=TIME, y=time_h, source=source, color=colour, alpha=1, name='with_hover') for distance, colour in zip(distances, colours): distance_km = _slash(distance, KM) source[distance_km] = source[distance] / 1000 plotter(f, x=TIME, y=distance_km, source=source, color=colour, alpha=0.5, name='with_hover', y_range_name=ACTIVE_DISTANCE) f.xaxis.axis_label = TIME f.toolbar.logo = None if ny < 300: f.toolbar_location = None if x_range: f.x_range = x_range return f
def list(self, id=None): res = requests.get(f'{API_URL}stock/{SYMBOL}/company') data = res.json() company_name = data['companyName'] data = res.json() df = pd.DataFrame(data) df.shape seqs = np.arange(df.shape[0]) df['seqs'] = pd.Series(seqs) df['changePercent'] = df['changePercent'].apply( lambda x: float(x) + '%') df.sample(20) df['mid'] = df.apply(lambda x: (x['open'] + x['close']) / 2, axis=1) df['height'] = df.apply(lambda x: x['close'] - x['open'] if x['close'] != x['open'] else 0.000, axis=1) inc = df.close > df.open dec = df.close < df.open w = .3 sourceInc = bk.ColumnDataSource(df.loc[inc]) sourceDec = bk.ColumnDataSource(df.loc[dec]) hover = HoverTool(tooltips=[ ('date', '@date'), ('low', '@low'), ('high', '@high'), ('open', '@open'), ('close', '@close'), ('percent', '@changePercent'), ]) TOOLS = [ hover, BoxZoomTool(), PanTool(), ZoomInTool(), ZoomOutTool(), ResetTool() ] p = bk.figure(plot_width=1000, plot_height=800, tools=TOOLS, title=f'{company_name}', toolbar_location='above') p.xaxis.major_label_orientation = np.pi / 4 p.grid.grid_line_alpha = w descriptor = Label(x=70, y=70, text='') p.add_layout(descriptor) p.segment(df.seqs[inc], df.high[inc], df.seqs[inc], df.low[inc], color='green') p.segment(df.seqs[dec], df.high[dec], df.seqs[dec], df.low[dec], color='red') p.rect(x='seqs', y='mid', width=w, height='height', fill_color='green', line_color='green', source=sourceInc) p.rect(x='seqs', y='mid', width=w, height='height', fill_color='red', line_color='red', source=sourceDec) bk.save(p, f'../static/{company_name}_candle_stick.html', title=f'{company_name}_5yr_candlestick') return Response(json='Graph Visuals', status=200)
def large_plot(n): from bokeh.models import (Plot, LinearAxis, Grid, GlyphRenderer, ColumnDataSource, DataRange1d, PanTool, ZoomInTool, ZoomOutTool, WheelZoomTool, BoxZoomTool, BoxSelectTool, SaveTool, ResetTool) from bokeh.models.layouts import Column from bokeh.models.glyphs import Line col = Column() objects = set([col]) for i in range(n): source = ColumnDataSource(data=dict(x=[0, i + 1], y=[0, i + 1])) xdr = DataRange1d() ydr = DataRange1d() plot = Plot(x_range=xdr, y_range=ydr) xaxis = LinearAxis() plot.add_layout(xaxis, "below") yaxis = LinearAxis() plot.add_layout(yaxis, "left") xgrid = Grid(dimension=0) plot.add_layout(xgrid, "center") ygrid = Grid(dimension=1) plot.add_layout(ygrid, "center") tickers = [ xaxis.ticker, xaxis.formatter, yaxis.ticker, yaxis.formatter ] glyph = Line(x='x', y='y') renderer = GlyphRenderer(data_source=source, glyph=glyph) plot.renderers.append(renderer) pan = PanTool() zoom_in = ZoomInTool() zoom_out = ZoomOutTool() wheel_zoom = WheelZoomTool() box_zoom = BoxZoomTool() box_select = BoxSelectTool() save = SaveTool() reset = ResetTool() tools = [ pan, zoom_in, zoom_out, wheel_zoom, box_zoom, box_select, save, reset ] plot.add_tools(*tools) col.children.append(plot) objects |= set([ xdr, ydr, xaxis, yaxis, xgrid, ygrid, renderer, renderer.view, glyph, source, source.selected, source.selection_policy, plot, plot.x_scale, plot.y_scale, plot.toolbar, plot.title, box_zoom.overlay, box_select.overlay, ] + tickers + tools) return col, objects
def visualize(self): # Suppress various bokeh warnings warnings.filterwarnings("ignore") flag_list = [] acuteImpacts = AcuteImpacts(targetDir=self.sourceDir, facilityIds=self.facilityIds, parameters=[self.basepath]) flag_df = acuteImpacts.createDataframe() for index, row in flag_df.iterrows(): if row[hq_rel] >= 1.5: flag_list.append((row[fac_id], row.pollutant, "REL")) if row[hq_aegl1] >= 1.5: flag_list.append((row[fac_id], row.pollutant, "AEGL-1 1-hr")) if row[hq_erpg1] >= 1.5: flag_list.append((row[fac_id], row.pollutant, "ERPG-1")) if row[hq_aegl2] >= 1.5: flag_list.append((row[fac_id], row.pollutant, "AEGL-2 1-hr")) if row[hq_erpg2] >= 1.5: flag_list.append((row[fac_id], row.pollutant, "ERPG-2")) flag_list.sort() # If the flag file has no cases of interest, don't do anything. # Otherwise, create a directory for the created acute files. if len(flag_list) == 0: Logger.logMessage( "Acute impacts visualization - " + "No acute impact was greater than or equal to 1.5. No HTML files were generated." ) return else: if os.path.isdir(self.sourceDir + '/Acute Maps') == 0: os.mkdir(self.sourceDir + '/Acute Maps') # Find the HEM dose-response library and create df of it # Under the HEM4 dir names, "Reference" would be "Resources" RefFile = 'resources/Dose_Response_Library.xlsx' RefDF = pd.read_excel(RefFile) RefDF['Pollutant'] = RefDF['Pollutant'].str.lower() RefDF.set_index('Pollutant', inplace=True) RefDict = {'REL': 'REL\n(mg/m3)',\ 'AEGL-1 1-hr':'AEGL-1 (1-hr)\n(mg/m3)',\ 'ERPG-1':'ERPG-1\n(mg/m3)',\ 'AEGL-2 1-hr':'AEGL-2 (1-hr)\n(mg/m3)',\ 'ERPG-2':'ERPG-2\n(mg/m3)',\ 'AEGL-1 8-hr':'AEGL-1 (8-hr)\n(mg/m3)',\ 'AEGL-2 8-hr':'AEGL-2 (8-hr)\n(mg/m3)'} tablist = [] for acuteset in (flag_list): Fac = acuteset[0] HAP = acuteset[1] refType = acuteset[2] path = self.sourceDir + '/' + Fac + '/' HAP = HAP.lower() # Find the all polar file for a given facility, create df of it allpolar = AllPolarReceptors(targetDir=path, facilityId=Fac, acuteyn='Y') allpolar_df = allpolar.createDataframe() allpolar_df[pollutant] = allpolar_df[pollutant].str.lower() # Find the reference value ref_typ_col = RefDict[refType] refVal = RefDF.loc[HAP, ref_typ_col] # Aggregate the all polar file to get HQ for each receptor allpolar_df.set_index('pollutant', inplace=True) HAP_df = allpolar_df.loc[HAP, :] f = {distance: 'first', angle: 'first', aconc: 'sum'} df = HAP_df.groupby([lat, lon], as_index=False).agg(f) df['HQ'] = df[aconc] / refVal / 1000 ac_File = '%s%s%s%s%s' % (self.sourceDir, '/Acute Maps/', Fac + '_', HAP + '_', refType + '.csv') df.to_csv(path_or_buf=ac_File, mode='w+') #Convert df to geo df df['Coordinates'] = list(zip(df.lon, df.lat)) df['Coordinates'] = df['Coordinates'].apply(Point) gdf = gp.GeoDataFrame(df, geometry='Coordinates', crs={'init': 'epsg:4326'}) gdf = gdf.to_crs(epsg=3857) ESRI_tile = WMTSTileSource( url= 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{Z}/{Y}/{X}.jpg' ) gdf['x'] = gdf.centroid.map(lambda p: p.x) gdf['y'] = gdf.centroid.map(lambda p: p.y) avg_x = gdf['x'].mean() avg_y = gdf['y'].mean() gdf = gdf.drop('Coordinates', axis=1) gdf['HQ'] = gdf['HQ'].map(lambda x: '%.1g' % x) gdf['lat'] = gdf['lat'].map(lambda x: '%.6f' % x) gdf['lon'] = gdf['lon'].map(lambda x: '%.6f' % x) gdf['angle'] = gdf['angle'].map(lambda x: '%.1f' % x) source = ColumnDataSource(gdf) tooltips = [("Latitude", "@lat"), ("Longitude", "@lon"), ("Acute HQ", "@HQ"), ("Distance (m)", "@distance"), ("Angle (deg)", "@angle")] title = '%s %s Acute HQ (%s)' % (Fac, HAP.title(), refType) tools = [ZoomInTool(), ZoomOutTool(), PanTool(),\ WheelZoomTool(), ResetTool(), HoverTool(tooltips=tooltips)] p = figure(plot_width=800, plot_height=600, tools = tools,\ x_range=(avg_x-3000, avg_x+3000), y_range=(avg_y-3000, avg_y+3000),\ title=title) p.toolbar.active_scroll = p.select_one(WheelZoomTool) p.add_tile(ESRI_tile) p.add_tile(STAMEN_TONER_LABELS) p.circle('x', 'y', color='yellow', size=7, source=source) p.xaxis.visible = False p.yaxis.visible = False p.xgrid.visible = False p.ygrid.visible = False p.background_fill_color = None p.border_fill_color = None # labels = LabelSet(x='x', y='y', text='HQ', source = source,\ # level='glyph', x_offset=0, y_offset=0, text_font_size='8pt',\ # text_color='black', background_fill_color='yellow',\ # text_font_style='bold', text_align='center', text_baseline='middle') labels = LabelSet(x='x', y='y', text='HQ', source = source,\ x_offset=0, y_offset=0, text_font_size='8pt',\ text_color='black', background_fill_color='yellow',\ text_font_style='bold', text_align='center', text_baseline='middle') p.add_layout(labels) curdoc().add_root(p) mapName = '%s%s%s%s%s' % (self.sourceDir, '/Acute Maps/', Fac + '_', HAP + '_', refType + '.html') save(p, filename=mapName) tab = Panel(child=p, title=HAP.title() + " (" + refType + ")") tablist.append(tab) tabs = Tabs(tabs=tablist) curdoc().add_root(tabs) mapName2 = '%s%s%s' % (self.sourceDir, '/Acute Maps/', "All Acute Maps.html") save(tabs, filename=mapName2, title="All Acute HQ Maps") Logger.logMessage( "Acute impacts visualization - HTML files successfully created.")
def make_tools(y): tools = [PanTool(dimensions='width'), ZoomInTool(dimensions='width'), ZoomOutTool(dimensions='width'), ResetTool(), HoverTool(tooltips=[tooltip(x) for x in (y, DISTANCE_KM, LOCAL_TIME)])] return tools
"html/{}-service-graphs.html".format(team).lower())) plot_list = [] hover = HoverTool( tooltips=[('Service', '@service_name'), ( 'Check Number', '@check_num'), ('Total Points', '@total_points'), ('Check Time', '@str_datetimes')]) TOOLS = [ PanTool(), WheelZoomTool(), BoxZoomTool(), ZoomInTool(), ZoomOutTool(), UndoTool(), hover, ResetTool(), SaveTool() ] all_services_plot = figure( title="{} - {}".format(team, service), x_axis_label='Time', y_axis_label='{} Service Points'.format(service), x_axis_type="datetime", x_range=Range1d(x_start, x_end), width=GRAPH_WIDTH, height=GRAPH_HEIGHT, tools=TOOLS)
hover_bar = HoverTool(tooltips=[('Rating','@x1'), ('Number of Business','@y1') ]) hover_pie = HoverTool(tooltips=[('Percentage','@ratio') ]) select_day = Select( options=['Sunday','Monday', 'Tuesday', 'Wednesday', 'Thursday','Friday','Saturday'], value='Monday', title='Day of the Week' ) chosen_tools =[hover,ResetTool(),BoxSelectTool(), SaveTool(),PanTool(), UndoTool(),RedoTool(),ZoomInTool(), ZoomOutTool() ] #data data = pd.read_csv(r'~/Desktop/yelp/yelp_business.csv',index_col='business_id') hour = pd.read_csv(r'~/Desktop/yelp/yelp_business_hours.csv',index_col='business_id') #data = pd.read_csv(r'E:\project\CIS4170\yelp\yelp_business.csv',index_col='business_id') #hour = pd.read_csv(r'E:\project\CIS4170\yelp\yelp_business_hours.csv',index_col='business_id') whole = pd.merge(data,hour, left_index=True, right_index=True) #data = pd.read_csv(r'E:\Software\WinPython\notebooks\yelp\yelp_business.csv',index_col='business_id') state_data = whole[whole.state=='NV'] categoricaldata = state_data.categories.str.contains('') open_data = state_data.loc[state_data[select_day.value.lower()] != 'None'] new_data = open_data.where(categoricaldata).dropna(thresh = 19).sort_values(by=['stars'],ascending=False)
def map_create(prot_pop_geo, prot_pop): geosource = GeoJSONDataSource( geojson=simplejson.dumps(simplejson.loads(prot_pop_geo.to_json()))) # ----- Raw count map ----- # initialize figure palette = cividis(256) hover_a = HoverTool(tooltips=[('Country', '@name'), ('Protests', '@protest')]) color_mapper_a = LogColorMapper(palette=palette, low=1, high=prot_pop['protest'].max() + 5, nan_color='#ffffff') color_bar_a = ColorBar( color_mapper=color_mapper_a, ticker=LogTicker(), orientation='horizontal', border_line_color=None, location=(0, 0), label_standoff=8, major_label_text_font='Raleway', major_label_text_font_size='12pt', title='Number of registered Fridays for Future protests', title_text_font_style='normal', title_text_font='Raleway', title_text_font_size='15pt') p_a = figure( title= 'The Fridays for Future movement grew to global scale within only 10 months', tools=[hover_a, ZoomInTool(), ZoomOutTool(), ResetTool(), PanTool()], plot_height=600, plot_width=980) # add patch renderer p_a.patches('xs', 'ys', source=geosource, fill_color={ 'field': 'protest', 'transform': color_mapper_a }, line_color='black', line_width=0.25, fill_alpha=1) # prettify p_a.xgrid.grid_line_color = None p_a.ygrid.grid_line_color = None p_a.outline_line_color = None p_a.axis.visible = False p_a.add_layout(color_bar_a, 'below') p_a.toolbar.logo = None p_a.title.text_font = "Raleway" p_a.title.text_font_style = "normal" p_a.title.align = 'center' p_a.title.text_color = 'black' p_a.title.text_font_size = '20pt' tab_a = Panel(child=p_a, title="Absolute number") # ----- Population adjusted count map ----- # initialize figure hover_b = HoverTool(tooltips=[( 'Country', '@name'), ('Protests per 10 million', '@prot_ptm'), ('Protests', '@protest'), ('Population', '@population')]) color_mapper_b = LogColorMapper( palette=palette, low=prot_pop['prot_ptm'].min(), high=float(prot_pop.loc[prot_pop['code'] == 'GRL']['prot_ptm']) + 10, nan_color='#ffffff') color_bar_b = ColorBar( color_mapper=color_mapper_b, ticker=LogTicker(), orientation='horizontal', border_line_color=None, location=(0, 0), label_standoff=8, major_label_text_font='Raleway', major_label_text_font_size='12pt', title='Number of registered Fridays for Future protests per 10 million', title_text_font_style='normal', title_text_font='Raleway', title_text_font_size='15pt') p_b = figure( title= 'The Fridays for Future movement grew to global scale within only 10 months', tools=[hover_b, ZoomInTool(), ZoomOutTool(), ResetTool(), PanTool()], plot_height=600, plot_width=980) # add patch renderer p_b.patches('xs', 'ys', source=geosource, fill_color={ 'field': 'prot_ptm', 'transform': color_mapper_b }, line_color='black', line_width=0.25, fill_alpha=1) # prettify p_b.xgrid.grid_line_color = None p_b.ygrid.grid_line_color = None p_b.outline_line_color = None p_b.axis.visible = False p_b.add_layout(color_bar_b, 'below') p_b.toolbar.logo = None p_b.title.text_font = "Raleway" p_b.title.text_font_style = "normal" p_b.title.align = 'center' p_b.title.text_color = 'black' p_b.title.text_font_size = '20pt' tab_b = Panel(child=p_b, title="Population normalized") tabs = Tabs(tabs=[tab_a, tab_b]) return tabs
plot_width=1200, title='S&P 500', x_axis_label='Date', y_axis_label='Close (in USD)') p.line(sp500_df['Date'], sp500_df['Close'], color='blue', legend='') # Hover tool with vline mode hover = HoverTool( tooltips=[('Close', '$@{Close}{%0.2f}'), ('Date', '@date{%F}')], formatters={ 'date': 'datetime', # use 'datetime' formatter for 'date' field 'Close': 'printf', # use 'printf' formatter for 'adj close' field # use default 'numeral' formatter for other fields }, mode='vline') p.add_tools(hover) p.add_tools(LassoSelectTool()) p.add_tools(PolySelectTool()) p.add_tools(TapTool()) p.add_tools(UndoTool()) p.add_tools(RedoTool()) p.add_tools(ResetTool()) p.add_tools(ZoomInTool()) p.add_tools(ZoomOutTool()) p.add_tools(CrosshairTool()) html = file_html(p, CDN, "my plot") with open("./test_bokeh.html", "w") as html_file: html_file.write(html)
def __make_daybyday_interactive_timeline( df: pd.DataFrame, *, geo_df: geopandas.GeoDataFrame, value_col: str, transform_df_func: Callable[[pd.DataFrame], pd.DataFrame] = None, stage: Union[DiseaseStage, Literal[Select.ALL]] = Select.ALL, count: Union[Counting, Literal[Select.ALL]] = Select.ALL, out_file_basename: str, subplot_title_prefix: str, plot_aspect_ratio: float = None, cmap=None, n_cbar_buckets: int = None, n_buckets_btwn_major_ticks: int = None, n_minor_ticks_btwn_major_ticks: int = None, per_capita_denominator: int = None, x_range: Tuple[float, float], y_range: Tuple[float, float], min_visible_y_range: float, should_make_video: bool, ) -> InfoForAutoload: """Create the bokeh interactive timeline plot(s) This function takes the given DataFrame, which must contain COVID data for locations on different dates, and a GeoDataFrame, which contains the long/lat coords for those locations, and creates an interactive choropleth of the COVID data over time. :param df: The COVID data DataFrame :type df: pd.DataFrame :param geo_df: The geometry GeoDataFrame for the locations in `df` :type geo_df: geopandas.GeoDataFrame :param value_col: The column of `df` containing the values to plot in the choropleth; should be something like "Case_Counts" or "Case_Diff_From_Prev_Day" :type value_col: str :param stage: The DiseaseStage to plot, defaults to Select.ALL. If ALL, then all stages are plotted and are stacked vertically. :type stage: Union[DiseaseStage, Literal[Select.ALL]], optional :param count: The Counting to plot, defaults to Select.ALL. If ALL, then all count types are plotted and are stacked horizontally. :type count: Union[Counting, Literal[Select.ALL]], optional :param out_file_basename: The basename of the file to save the interactive plots to (there are two components, the JS script and the HTML <div>) :type out_file_basename: str :param subplot_title_prefix: What the first part of the subplot title should be; probably a function of `value_col` (if value_col is "Case_Counts" then this param might be "Cases" or "# of Cases") :type subplot_title_prefix: str :param x_range: The range of the x-axis as (min, max) :type x_range: Tuple[float, float] :param y_range: The range of the y-axis as (min, max) :type y_range: Tuple[float, float] :param min_visible_y_range: The minimum height (in axis units) of the y-axis; it will not be possible to zoom in farther than this on the choropleth. :type min_visible_y_range: float :param should_make_video: Optionally run through the timeline day by day, capture a screenshot for each day, and then stitch the screenshots into a video. The video shows the same info as the interactive plots, but not interactively. This easily takes 20x as long as just making the graphs themselves, so use with caution. :type should_make_video: bool :param transform_df_func: This function expects data in a certain format, and does a bunch of preprocessing (expected to be common) before plotting. This gives you a chance to do any customization on the postprocessed df before it's plotted. Defaults to None, in which case no additional transformation is performed. :type transform_df_func: Callable[[pd.DataFrame], pd.DataFrame], optional :param plot_aspect_ratio: The aspect ratio of the plot as width/height; if set, the aspect ratio will be fixed to this. Defaults to None, in which case the aspect ratio is determined from the x_range and y_range arguments :type plot_aspect_ratio: float, optional :param cmap: The colormap to use as either a matplotlib-compatible colormap or a list of hex strings (e.g., ["#ae8f1c", ...]). Defaults to None in which case a reasonable default is used. :type cmap: Matplotlib-compatible colormap or List[str], optional :param n_cbar_buckets: How many colorbar buckets to use. Has little effect if the colormap is continuous, but always works in conjunction with n_buckets_btwn_major_ticks to determine the number of major ticks. Defaults to 6. :type n_cbar_buckets: int, optional :param n_buckets_btwn_major_ticks: How many buckets are to lie between colorbar major ticks, determining how many major ticks are drawn. Defaults to 1. :type n_buckets_btwn_major_ticks: int, optional :param n_minor_ticks_btwn_major_ticks: How many minor ticks to draw between colorbar major ticks. Defaults to 8 (which means each pair of major ticks has 10 ticks total). :type n_minor_ticks_btwn_major_ticks: int, optional :param per_capita_denominator: When describing per-capita numbers, what to use as the denominator (e.g., cases per 100,000 people). If None, it is automatically computed per plot to be appropriately scaled for the data. :type per_capita_denominator: int, optional :raises ValueError: [description] :return: The two pieces of info required to make a Bokeh autoloading HTML+JS plot: the HTML div to be inserted somewhere in the HTML body, and the JS file that will load the plot into that div. :rtype: InfoForAutoload """ Counting.verify(count, allow_select=True) DiseaseStage.verify(stage, allow_select=True) # The date as a string, so that bokeh can use it as a column name STRING_DATE_COL = "String_Date_" # A column whose sole purpose is to be a (the same) date associated with each # location FAKE_DATE_COL = "Fake_Date_" # The column we'll actually use for the colors; it's computed from value_col COLOR_COL = "Color_" # Under no circumstances may you change this date format # It's not just a pretty date representation; it actually has to match up with the # date strings computed in JS DATE_FMT = r"%Y-%m-%d" ID_COLS = [ REGION_NAME_COL, Columns.DATE, Columns.STAGE, Columns.COUNT_TYPE, ] if cmap is None: cmap = cmocean.cm.matter if n_cbar_buckets is None: n_cbar_buckets = 6 if n_buckets_btwn_major_ticks is None: n_buckets_btwn_major_ticks = 1 if n_minor_ticks_btwn_major_ticks is None: n_minor_ticks_btwn_major_ticks = 8 n_cbar_major_ticks = n_cbar_buckets // n_buckets_btwn_major_ticks + 1 try: color_list = [ # Convert matplotlib colormap to bokeh (list of hex strings) # https://stackoverflow.com/a/49934218 RGB(*rgb).to_hex() for i, rgb in enumerate((255 * cmap(range(256))).astype("int")) ] except TypeError: color_list = cmap color_list: List[BokehColor] if stage is Select.ALL: stage_list = list(DiseaseStage) else: stage_list = [stage] if count is Select.ALL: count_list = list(Counting) else: count_list = [count] stage_list: List[DiseaseStage] count_list: List[Counting] stage_count_list: List[Tuple[DiseaseStage, Counting]] = list( itertools.product(stage_list, count_list)) df = df.copy() # Unadjust dates (see SaveFormats._adjust_dates) normalized_dates = df[Columns.DATE].dt.normalize() is_at_midnight = df[Columns.DATE] == normalized_dates df.loc[is_at_midnight, Columns.DATE] -= pd.Timedelta(days=1) df.loc[~is_at_midnight, Columns.DATE] = normalized_dates[~is_at_midnight] min_date, max_date = df[Columns.DATE].agg(["min", "max"]) dates: List[pd.Timestamp] = pd.date_range(start=min_date, end=max_date, freq="D") max_date_str = max_date.strftime(DATE_FMT) # Get day-by-day case diffs per location, date, stage, count-type # Make sure data exists for every date for every state so that the entire country is # plotted each day; fill missing data with 0 (missing really *is* as good as 0) # enums will be replaced by their name (kind of important) id_cols_product: pd.MultiIndex = pd.MultiIndex.from_product( [ df[REGION_NAME_COL].unique(), dates, [s.name for s in DiseaseStage], [c.name for c in Counting], ], names=ID_COLS, ) df = (id_cols_product.to_frame(index=False).merge( df, how="left", on=ID_COLS, ).sort_values(ID_COLS)) df[STRING_DATE_COL] = df[Columns.DATE].dt.strftime(DATE_FMT) df[Columns.CASE_COUNT] = df[Columns.CASE_COUNT].fillna(0) if transform_df_func is not None: df = transform_df_func(df) df = geo_df.merge(df, how="inner", on=REGION_NAME_COL)[[ REGION_NAME_COL, Columns.DATE, STRING_DATE_COL, Columns.STAGE, Columns.COUNT_TYPE, value_col, ]] dates: List[pd.Timestamp] = [ pd.Timestamp(d) for d in df[Columns.DATE].unique() ] values_mins_maxs = (df[df[value_col] > 0].groupby( [Columns.STAGE, Columns.COUNT_TYPE])[value_col].agg(["min", "max"])) vmins: pd.Series = values_mins_maxs["min"] vmaxs: pd.Series = values_mins_maxs["max"] pow10s_series: pd.Series = vmaxs.map( lambda x: int(10**(-np.floor(np.log10(x))))) # _pow_10s_series_dict = {} # for stage in DiseaseStage: # _pow_10s_series_dict.update( # { # (stage.name, Counting.TOTAL_CASES.name): 100000, # (stage.name, Counting.PER_CAPITA.name): 10000, # } # ) # pow10s_series = pd.Series(_pow_10s_series_dict) vmins: dict = vmins.to_dict() vmaxs: dict = vmaxs.to_dict() for stage in DiseaseStage: _value_key = (stage.name, Counting.PER_CAPITA.name) if per_capita_denominator is None: _max_pow10 = pow10s_series.loc[(slice(None), Counting.PER_CAPITA.name)].max() else: _max_pow10 = per_capita_denominator vmins[_value_key] *= _max_pow10 vmaxs[_value_key] *= _max_pow10 pow10s_series[_value_key] = _max_pow10 percap_pow10s: pd.Series = df.apply( lambda row: pow10s_series[ (row[Columns.STAGE], row[Columns.COUNT_TYPE])], axis=1, ) _per_cap_rows = df[Columns.COUNT_TYPE] == Counting.PER_CAPITA.name df.loc[_per_cap_rows, value_col] *= percap_pow10s.loc[_per_cap_rows] # Ideally we wouldn't have to pivot, and we could do a JIT join of state longs/lats # after filtering the data. Unfortunately this is not possible, and a long data # format leads to duplication of the very large long/lat lists; pivoting is how we # avoid that. (This seems to be one downside of bokeh when compared to plotly) df = (df.pivot_table( index=[REGION_NAME_COL, Columns.STAGE, Columns.COUNT_TYPE], columns=STRING_DATE_COL, values=value_col, aggfunc="first", ).reset_index().merge( geo_df[[REGION_NAME_COL, LONG_COL, LAT_COL]], how="inner", on=REGION_NAME_COL, )) # All three oclumns are just initial values; they'll change with the date slider df[value_col] = df[max_date_str] df[FAKE_DATE_COL] = max_date_str df[COLOR_COL] = np.where(df[value_col] > 0, df[value_col], "NaN") # Technically takes a df but we don't need the index bokeh_data_source = ColumnDataSource( {k: v.tolist() for k, v in df.to_dict(orient="series").items()}) filters = [[ GroupFilter(column_name=Columns.STAGE, group=stage.name), GroupFilter(column_name=Columns.COUNT_TYPE, group=count.name), ] for stage, count in stage_count_list] figures = [] for subplot_index, (stage, count) in enumerate(stage_count_list): # fig = bplotting.figure() # ax: plt.Axes = fig.add_subplot( # len(stage_list), len(count_list), subplot_index # ) # # Add timestamp to top right axis # if subplot_index == 2: # ax.text( # 1.25, # Coords are arbitrary magic numbers # 1.23, # f"Last updated {NOW_STR}", # horizontalalignment="right", # fontsize="small", # transform=ax.transAxes, # ) view = CDSView(source=bokeh_data_source, filters=filters[subplot_index]) vmin = vmins[(stage.name, count.name)] vmax = vmaxs[(stage.name, count.name)] # Compute and set axes titles if stage is DiseaseStage.CONFIRMED: fig_stage_name = "Cases" elif stage is DiseaseStage.DEATH: fig_stage_name = "Deaths" else: raise ValueError fig_title_components: List[str] = [] if subplot_title_prefix is not None: fig_title_components.append(subplot_title_prefix) fig_title_components.append(fig_stage_name) if count is Counting.PER_CAPITA: _per_cap_denom = pow10s_series[(stage.name, count.name)] fig_title_components.append(f"Per {_per_cap_denom:,d} people") formatter = PrintfTickFormatter(format=r"%2.3f") label_standoff = 12 tooltip_fmt = "{0.000}" else: formatter = NumeralTickFormatter(format="0.0a") label_standoff = 10 tooltip_fmt = "{0}" color_mapper = LogColorMapper( color_list, low=vmin, high=vmax, nan_color="#f2f2f2", ) fig_title = " ".join(fig_title_components) if plot_aspect_ratio is None: if x_range is None or y_range is None: raise ValueError("Must provide both `x_range` and `y_range`" + " when `plot_aspect_ratio` is None") plot_aspect_ratio = (x_range[1] - x_range[0]) / (y_range[1] - y_range[0]) # Create figure object p = bplotting.figure( title=fig_title, title_location="above", tools=[ HoverTool( tooltips=[ ("Date", f"@{{{FAKE_DATE_COL}}}"), ("State", f"@{{{REGION_NAME_COL}}}"), ("Count", f"@{{{value_col}}}{tooltip_fmt}"), ], toggleable=False, ), PanTool(), BoxZoomTool(match_aspect=True), ZoomInTool(), ZoomOutTool(), ResetTool(), ], active_drag=None, aspect_ratio=plot_aspect_ratio, output_backend="webgl", lod_factor=4, lod_interval=400, lod_threshold=1000, lod_timeout=300, ) p.xgrid.grid_line_color = None p.ygrid.grid_line_color = None # Finally, add the actual choropleth data we care about p.patches( LONG_COL, LAT_COL, source=bokeh_data_source, view=view, fill_color={ "field": COLOR_COL, "transform": color_mapper }, line_color="black", line_width=0.25, fill_alpha=1, ) # Add evenly spaced ticks and their labels to the colorbar # First major, then minor # Adapted from https://stackoverflow.com/a/50314773 bucket_size = (vmax / vmin)**(1 / n_cbar_buckets) tick_dist = bucket_size**n_buckets_btwn_major_ticks # Simple log scale math major_tick_locs = ( vmin * (tick_dist**np.arange(0, n_cbar_major_ticks)) # * (bucket_size ** 0.5) # Use this if centering ticks on buckets ) # Get minor locs by linearly interpolating between major ticks minor_tick_locs = [] for major_tick_index, this_major_tick in enumerate( major_tick_locs[:-1]): next_major_tick = major_tick_locs[major_tick_index + 1] # Get minor ticks as numbers in range [this_major_tick, next_major_tick] # and exclude the major ticks themselves (once we've used them to # compute the minor tick locs) minor_tick_locs.extend( np.linspace( this_major_tick, next_major_tick, n_minor_ticks_btwn_major_ticks + 2, )[1:-1]) color_bar = ColorBar( color_mapper=color_mapper, ticker=FixedTicker(ticks=major_tick_locs, minor_ticks=minor_tick_locs), formatter=formatter, label_standoff=label_standoff, major_tick_out=0, major_tick_in=13, major_tick_line_color="white", major_tick_line_width=1, minor_tick_out=0, minor_tick_in=5, minor_tick_line_color="white", minor_tick_line_width=1, location=(0, 0), border_line_color=None, bar_line_color=None, orientation="vertical", ) p.add_layout(color_bar, "right") p.hover.point_policy = "follow_mouse" # Bokeh axes (and most other things) are splattable p.axis.visible = False figures.append(p) # Make all figs pan and zoom together by setting their axes equal to each other # Also fix the plots' aspect ratios figs_iter = iter(np.ravel(figures)) anchor_fig = next(figs_iter) if x_range is not None and y_range is not None: data_aspect_ratio = (x_range[1] - x_range[0]) / (y_range[1] - y_range[0]) else: data_aspect_ratio = plot_aspect_ratio if x_range is not None: anchor_fig.x_range = Range1d( *x_range, bounds="auto", min_interval=min_visible_y_range * data_aspect_ratio, ) if y_range is not None: anchor_fig.y_range = Range1d(*y_range, bounds="auto", min_interval=min_visible_y_range) for fig in figs_iter: fig.x_range = anchor_fig.x_range fig.y_range = anchor_fig.y_range # 2x2 grid (for now) gp = gridplot( figures, ncols=len(count_list), sizing_mode="scale_both", toolbar_location="above", ) plot_layout = [gp] # Ok, pause # Now we're going into a whole other thing: we're doing all the JS logic behind a # date slider that changes which date is shown on the graphs. The structure of the # data is one column per date, one row per location, and a few extra columns to # store the data the graph will use. When we adjust the date of the slider, we copy # the relevant column of the df into the columns the graphs are looking at. # That's the easy part; the hard part is handling the "play button" functionality, # whereby the user can click one button and the date slider will periodically # advance itself. That requires a fair bit of logic to schedule and cancel the # timers and make it all feel right. # Create unique ID for the JS playback info object for this plot (since it'll be on # the webpage with other plots, and their playback info isn't shared) _THIS_PLOT_ID = uuid.uuid4().hex __TIMER = "'timer'" __IS_ACTIVE = "'isActive'" __SELECTED_INDEX = "'selectedIndex'" __BASE_INTERVAL_MS = "'BASE_INTERVAL'" # Time (in MS) btwn frames when speed==1 __TIMER_START_DATE = "'startDate'" __TIMER_ELAPSED_TIME_MS = "'elapsedTimeMS'" __TIMER_ELAPSED_TIME_PROPORTION = "'elapsedTimeProportion'" __SPEEDS_KEY = "'SPEEDS'" __PLAYBACK_INFO = f"window._playbackInfo_{_THIS_PLOT_ID}" _PBI_TIMER = f"{__PLAYBACK_INFO}[{__TIMER}]" _PBI_IS_ACTIVE = f"{__PLAYBACK_INFO}[{__IS_ACTIVE}]" _PBI_SELECTED_INDEX = f"{__PLAYBACK_INFO}[{__SELECTED_INDEX}]" _PBI_TIMER_START_DATE = f"{__PLAYBACK_INFO}[{__TIMER_START_DATE}]" _PBI_TIMER_ELAPSED_TIME_MS = f"{__PLAYBACK_INFO}[{__TIMER_ELAPSED_TIME_MS}]" _PBI_TIMER_ELAPSED_TIME_PROPORTION = ( f"{__PLAYBACK_INFO}[{__TIMER_ELAPSED_TIME_PROPORTION}]") _PBI_BASE_INTERVAL = f"{__PLAYBACK_INFO}[{__BASE_INTERVAL_MS}]" _PBI_SPEEDS = f"{__PLAYBACK_INFO}[{__SPEEDS_KEY}]" _PBI_CURR_INTERVAL_MS = ( f"{_PBI_BASE_INTERVAL} / {_PBI_SPEEDS}[{_PBI_SELECTED_INDEX}]") _SPEED_OPTIONS = [0.25, 0.5, 1.0, 2.0] _DEFAULT_SPEED = 1.0 _DEFAULT_SELECTED_INDEX = _SPEED_OPTIONS.index(_DEFAULT_SPEED) _SETUP_WINDOW_PLAYBACK_INFO = f""" if (typeof({__PLAYBACK_INFO}) === 'undefined') {{ {__PLAYBACK_INFO} = {{ {__TIMER}: null, {__IS_ACTIVE}: false, {__SELECTED_INDEX}: {_DEFAULT_SELECTED_INDEX}, {__TIMER_START_DATE}: null, {__TIMER_ELAPSED_TIME_MS}: 0, {__TIMER_ELAPSED_TIME_PROPORTION}: 0, {__BASE_INTERVAL_MS}: 1000, {__SPEEDS_KEY}: {_SPEED_OPTIONS} }}; }} """ _DEFFUN_INCR_DATE = f""" // See this link for why this works (it's an undocumented feature?) // https://discourse.bokeh.org/t/5254 // Tl;dr we need this to automatically update the hover as the play button plays // Without this, the hover tooltip only updates when we jiggle the mouse // slightly let prev_val = null; source.inspect.connect(v => prev_val = v); function updateDate() {{ {_PBI_TIMER_START_DATE} = new Date(); {_PBI_TIMER_ELAPSED_TIME_MS} = 0 if (dateSlider.value < maxDate) {{ dateSlider.value += 86400000; }} if (dateSlider.value >= maxDate) {{ console.log(dateSlider.value, maxDate) console.log('reached end') clearInterval({_PBI_TIMER}); {_PBI_IS_ACTIVE} = false; playPauseButton.active = false; playPauseButton.change.emit(); playPauseButton.label = 'Restart'; }} dateSlider.change.emit(); // This is pt. 2 of the prev_val/inspect stuff above if (prev_val !== null) {{ source.inspect.emit(prev_val); }} }} """ _DO_START_TIMER = f""" function startLoopTimer() {{ updateDate(); if ({_PBI_IS_ACTIVE}) {{ {_PBI_TIMER} = setInterval(updateDate, {_PBI_CURR_INTERVAL_MS}) }} }} {_PBI_TIMER_START_DATE} = new Date(); // Should never be <0 or >1 but I am being very defensive here const proportionRemaining = 1 - ( {_PBI_TIMER_ELAPSED_TIME_PROPORTION} <= 0 ? 0 : {_PBI_TIMER_ELAPSED_TIME_PROPORTION} >= 1 ? 1 : {_PBI_TIMER_ELAPSED_TIME_PROPORTION} ); const remainingTimeMS = ( {_PBI_CURR_INTERVAL_MS} * proportionRemaining ); const initialInterval = ( {_PBI_TIMER_ELAPSED_TIME_MS} === 0 ? 0 : remainingTimeMS ); {_PBI_TIMER} = setTimeout( startLoopTimer, initialInterval ); """ _DO_STOP_TIMER = f""" const now = new Date(); {_PBI_TIMER_ELAPSED_TIME_MS} += ( now.getTime() - {_PBI_TIMER_START_DATE}.getTime() ); {_PBI_TIMER_ELAPSED_TIME_PROPORTION} = ( {_PBI_TIMER_ELAPSED_TIME_MS} / {_PBI_CURR_INTERVAL_MS} ); clearInterval({_PBI_TIMER}); """ update_on_date_change_callback = CustomJS( args={"source": bokeh_data_source}, code=f""" {_SETUP_WINDOW_PLAYBACK_INFO} const sliderValue = cb_obj.value; const sliderDate = new Date(sliderValue) // Ugh, actually requiring the date to be YYYY-MM-DD (matching DATE_FMT) const dateStr = sliderDate.toISOString().split('T')[0] const data = source.data; {_PBI_TIMER_ELAPSED_TIME_MS} = 0 if (typeof(data[dateStr]) !== 'undefined') {{ data['{value_col}'] = data[dateStr] const valueCol = data['{value_col}']; const colorCol = data['{COLOR_COL}']; const fakeDateCol = data['{FAKE_DATE_COL}'] for (var i = 0; i < data['{value_col}'].length; i++) {{ const value = valueCol[i] if (value == 0) {{ colorCol[i] = 'NaN'; }} else {{ colorCol[i] = value; }} fakeDateCol[i] = dateStr; }} source.change.emit(); }} """, ) # Taking day-over-day diffs means the min slider day is one more than the min data # date (might be off by 1 if not using day over diffs but in practice not an issue) min_slider_date = min_date + pd.Timedelta(days=1) date_slider = DateSlider( start=min_slider_date, end=max_date, value=max_date, step=1, sizing_mode="stretch_width", width_policy="fit", ) date_slider.js_on_change("value", update_on_date_change_callback) play_pause_button = Toggle( label="Start playing", button_type="success", active=False, sizing_mode="stretch_width", ) animate_playback_callback = CustomJS( args={ "source": bokeh_data_source, "dateSlider": date_slider, "playPauseButton": play_pause_button, "maxDate": max_date, "minDate": min_slider_date, }, code=f""" {_SETUP_WINDOW_PLAYBACK_INFO} {_DEFFUN_INCR_DATE} if (dateSlider.value >= maxDate) {{ if (playPauseButton.active) {{ dateSlider.value = minDate; dateSlider.change.emit(); // Hack to get timer to wait after date slider wraps; any positive // number works but the smaller the better {_PBI_TIMER_ELAPSED_TIME_MS} = 1; }} }} const active = cb_obj.active; {_PBI_IS_ACTIVE} = active; if (active) {{ playPauseButton.label = 'Playing – Click/tap to pause' {_DO_START_TIMER} }} else {{ playPauseButton.label = 'Paused – Click/tap to play' {_DO_STOP_TIMER} }} """, ) play_pause_button.js_on_click(animate_playback_callback) change_playback_speed_callback = CustomJS( args={ "source": bokeh_data_source, "dateSlider": date_slider, "playPauseButton": play_pause_button, "maxDate": max_date, }, code=f""" {_SETUP_WINDOW_PLAYBACK_INFO} {_DEFFUN_INCR_DATE} // Must stop timer before handling changing the speed, as stopping the timer // saves values based on the current (unchaged) speed selection if ({_PBI_TIMER} !== null) {{ {_DO_STOP_TIMER} }} const selectedIndex = cb_obj.active; {_PBI_SELECTED_INDEX} = selectedIndex; if ({_PBI_IS_ACTIVE}) {{ {_DO_START_TIMER} }} else {{ {_PBI_TIMER_ELAPSED_TIME_MS} = 0 }} console.log({__PLAYBACK_INFO}) """, ) playback_speed_radio = RadioButtonGroup( labels=[f"{speed:.2g}x speed" for speed in _SPEED_OPTIONS], active=_DEFAULT_SELECTED_INDEX, sizing_mode="stretch_width", ) playback_speed_radio.js_on_click(change_playback_speed_callback) plot_layout.append( layout_column( [ date_slider, layout_row( [play_pause_button, playback_speed_radio], height_policy="min", ), ], width_policy="fit", height_policy="min", )) plot_layout = layout_column(plot_layout, sizing_mode="scale_both") # grid = gridplot(figures, ncols=len(count_list), sizing_mode="stretch_both") # Create the autoloading bokeh plot info (HTML + JS) js_path = str(Path(out_file_basename + "_autoload").with_suffix(".js")) tag_html_path = str( Path(out_file_basename + "_div_tag").with_suffix(".html")) js_code, tag_code = autoload_static(plot_layout, CDN, js_path) tag_uuid = re.search(r'id="([^"]+)"', tag_code).group(1) tag_code = re.sub(r'src="([^"]+)"', f'src="\\1?uuid={tag_uuid}"', tag_code) with open(Paths.DOCS / js_path, "w") as f_js, open(Paths.DOCS / tag_html_path, "w") as f_html: f_js.write(js_code) f_html.write(tag_code) # Create the video by creating stills of the graphs for each date and then stitching # the images into a video if should_make_video: save_dir: Path = PNG_SAVE_ROOT_DIR / out_file_basename save_dir.mkdir(parents=True, exist_ok=True) STILL_WIDTH = 1500 STILL_HEIGHT = int(np.ceil(STILL_WIDTH / plot_aspect_ratio) * 1.05) # Unclear why *1.05 is necessary gp.height = STILL_HEIGHT gp.width = STILL_WIDTH gp.sizing_mode = "fixed" orig_title = anchor_fig.title.text for date in dates: date_str = date.strftime(DATE_FMT) anchor_fig.title = Title(text=f"{orig_title} {date_str}") for p in figures: p.title = Title(text=p.title.text, text_font_size="20px") # Just a reimplementation of the JS code in the date slider's callback data = bokeh_data_source.data data[value_col] = data[date_str] for i, value in enumerate(data[value_col]): if value == 0: data[COLOR_COL][i] = "NaN" else: data[COLOR_COL][i] = value data[FAKE_DATE_COL][i] = date_str save_path: Path = (save_dir / date_str).with_suffix(".png") export_png(gp, filename=save_path) resize_to_even_dims(save_path, pad_bottom=0.08) if date == max(dates): poster_path: Path = ( PNG_SAVE_ROOT_DIR / (out_file_basename + "_poster")).with_suffix(".png") poster_path.write_bytes(save_path.read_bytes()) make_video(save_dir, out_file_basename, 0.9) print(f"Did interactive {out_file_basename}") return (js_code, tag_code)
def plot_pca(self, parameter, a, b): result = self.result source1 = column_source(result, "FDA") source2 = column_source(result, "PPI") source3 = column_source(result, "MACRO") source4 = column_source(result, "NP") source5 = column_source(result, "FDA PEP") source6 = column_source(result, "linear") source7 = column_source(result, "cyclic") hover = HoverTool(tooltips=[ ("PCA 1", "$x"), ("PCA 2", "$y"), ("NAME", "@N"), ]) p = figure( title="PCA based on " + parameter[0], x_axis_label="PC 1" + "(" + str(a) + "%)", y_axis_label="PC 2" + "(" + str(b) + "%)", x_range=(-4, 8), y_range=(-4, 8), tools=[hover], plot_width=1000, plot_height=800, ) p.add_tools(LassoSelectTool(), ZoomInTool(), ZoomOutTool(), SaveTool(), PanTool()) FDA_plot = p.circle(x="x", y="y", source=source1, color="darkslateblue", size=5) PPI_plot = p.circle(x="x", y="y", source=source2, color="yellowgreen", size=5) MACRO_plot = p.circle(x="x", y="y", source=source3, color="lightsteelblue", size=5) NP_plot = p.circle(x="x", y="y", source=source4, color="olive", size=5) PEP_FDA_plot = p.circle(x="x", y="y", source=source5, color="lightcoral", size=5) LIN_plot = p.circle(x="x", y="y", source=source6, color="teal", size=5) CYC_plot = p.circle(x="x", y="y", source=source7, color="mediumvioletred", size=5) legend = Legend( items=[ ("FDA", [FDA_plot]), ("PPI", [PPI_plot]), ("MACRO", [MACRO_plot]), ("NP", [NP_plot]), ("PEP FDA", [PEP_FDA_plot]), ("LIN", [LIN_plot]), ("CYC", [CYC_plot]), ], location="center", orientation="vertical", click_policy="hide", ) p.add_layout(legend, place="right") p.xaxis.axis_label_text_font_size = "20pt" p.yaxis.axis_label_text_font_size = "20pt" p.xaxis.axis_label_text_color = "black" p.yaxis.axis_label_text_color = "black" p.xaxis.major_label_text_font_size = "18pt" p.yaxis.major_label_text_font_size = "18pt" p.title.text_font_size = "22pt" return p
def main(): """ An example sequence of commands to make a measurement with the P1125 REST API. The internal Calibration loads will be used to plot essentially DC currents of various magnitudes. Since internal loads are used, the Probe is not connected. """ # check if the P1125 is reachable success, result = p1125.ping() logger.info("ping: {}".format(result)) if not success: return False success, result = p1125.status() logger.info("status: {}".format(result)) if not success: return False success, result = p1125.probe(connect=False) logger.info("probe: {}".format(result)) if not success: return False success, result = p1125.calibrate() logger.info("calibrate: {}".format(result)) if not success: return False success, result = p1125.set_timebase(SPAN) logger.info("set_timebase: {}".format(result)) if not success: return False success, result = p1125.set_trigger(src=P1125API.TRIG_SRC_NONE, pos=P1125API.TRIG_POS_LEFT, slope=P1125API.TRIG_SLOPE_RISE, level=1) logger.info("set_trigger: {}".format(result)) if not success: return False for vout in VOUT: success, result = p1125.set_vout(vout) logger.info("set_vout: {}".format(result)) if not success: return False for load, resistance in LOADS_TO_PLOT: expected_i_ua = float(vout) / resistance * 1000.0 if expected_i_ua < CURRENT_MIN_UA or expected_i_ua > CURRENT_MAX_UA: logger.info( "SKIP (Current out of range): {} mV, {:0.3f} Ohms, expected {:.1f} uA" .format(vout, resistance, expected_i_ua)) continue logger.info("{} mV, {}, expected {} uA".format( vout, resistance, expected_i_ua)) success, result = p1125.set_cal_load(loads=load) logger.info("set_cal_load: {}".format(result)) if not success: break sleep(0.1) # allow load time to settle success, result = p1125.acquisition_start( mode=P1125API.ACQUIRE_MODE_SINGLE) logger.info("acquisition_start: {}".format(result)) if not success: break success, result = p1125.acquisition_complete() logger.info("acquisition_complete: {}".format(result)) if not success: break p1125.set_cal_load(loads=[P1125API.DEMO_CAL_LOAD_NONE]) p1125.acquisition_stop() _, result = p1125.acquisition_get_data() samples = len(result["i"]) data["vout"].append(vout) data["min"].append(min(result["i"])) data["max"].append(max(result["i"])) data["avg"].append(sum(result["i"]) / samples) data["exp"].append(expected_i_ua) data["err"].append( (abs(data["avg"][-1] - data["exp"][-1]) * 100.0) / data["exp"][-1]) data["res"].append(resistance) # find the peak error from the acquistion peak_error = max(abs(data["exp"][-1] - data["min"][-1]), abs(data["exp"][-1] - data["max"][-1])) data["errp"].append(peak_error * 100.0 / data["exp"][-1]) sigma = np.std(result["i"]) data["sigma"].append(sigma) sigma_as_percent = sigma * 100.0 / data["exp"][-1] data["sigma_percent"].append(sigma_as_percent) logger.info( """VOUT {} mV, Expected {:9.2f} uA, min/avg/max: {:9.2f} {:9.2f} {:9.2f} uA, sigma {:8.3f} ({:3.1}%), {} samples""" .format(data["vout"][-1], data["exp"][-1], data["min"][-1], data["avg"][-1], data["max"][-1], sigma, sigma_as_percent, samples)) # large error... #if data["errp"][-1] > PLOT_CIRCLE_ERR: logger.error(result["i"]) plot.cross(x="vout", y="avg", size=10, color="blue", source=source) plot.dot(x="vout", y="exp", size=20, color="olive", source=source) plot.dash(x="vout", y="min", size=10, color="red", source=source) plot.dash(x="vout", y="max", size=10, color="red", source=source) _tooltips_sigma = [ ("Sigma", "@sigma_percent{0.0} %"), ] dotssigma = plot_sigma.circle_dot(x="vout", y="exp", size="sigma_percent", fill_alpha=0.2, line_width=1, color="red", source=source) plot_sigma.circle(x="vout", y="exp", size=PLOT_CIRCLE_ERR, fill_alpha=0.2, line_width=0, color="green", source=source) htsigma = HoverTool(tooltips=_tooltips_sigma, mode='vline', show_arrow=True, renderers=[dotssigma]) plot_sigma.tools = [ htsigma, BoxZoomTool(), ZoomInTool(), ResetTool(), UndoTool(), PanTool() ] _tooltips_peak = [ ("Error", "@errp{0.0} %"), ] dotsp = plot_errp.circle_dot(x="vout", y="exp", size="errp", fill_alpha=0.2, color="red", source=source) plot_errp.circle(x="vout", y="exp", size=PLOT_CIRCLE_ERR, fill_alpha=0.2, line_width=0, color="green", source=source) htp = HoverTool(tooltips=_tooltips_peak, mode='vline', show_arrow=True, renderers=[dotsp]) plot_errp.tools = [ htp, BoxZoomTool(), ZoomInTool(), ResetTool(), UndoTool(), PanTool() ] doc_layout.children.append(row(plot, plot_errp, plot_sigma)) show(doc_layout) return True
def plot_pca(self, parameter, a, b): result = self.result print(a, b) source1 = column_source(result, "APEXBIO") source2 = column_source(result, "Asinex") source3 = column_source(result, "ChemDiv") source4 = column_source(result, "Enamine") source5 = column_source(result, "Life_Chemicals") source6 = column_source(result, "MedChemExpress") source7 = column_source(result, "OTAVA_DNMT1") source8 = column_source(result, "OTAVA_DNMT3b") source9 = column_source(result, "SelleckChem") source10 = column_source(result, "Targetmol") source11 = column_source(result, "Tocris") hover = HoverTool(tooltips=[ ("PCA 1", "$x"), ("PCA 2", "$y"), ("ID", "@N"), ]) p = figure( # title="PCA based on: " + parameter, x_axis_label="PC 1 " + str(a) + "%", y_axis_label="PC 2 " + str(b) + "%", x_range=(-5, 10), y_range=(-5, 8), tools=[hover], plot_width=1000, plot_height=800, ) p.add_tools(LassoSelectTool(), ZoomInTool(), ZoomOutTool(), SaveTool(), PanTool()) APEXBIO_plot = p.circle(x="x", y="y", source=source1, color="mediumvioletred", size=5) Asinex_plot = p.circle(x="x", y="y", source=source2, color="mediumslateblue", size=5) ChemDiv_plot = p.circle(x="x", y="y", source=source3, color="lightsalmon", size=5) Enamine_plot = p.circle(x="x", y="y", source=source4, color="gold", size=5) Life_Chemicals_plot = p.circle(x="x", y="y", source=source5, color="violet", size=5) MedChemExpress_plot = p.circle(x="x", y="y", source=source6, color="mediumaquamarine", size=5) OTAVA_DNMT1_plot = p.circle(x="x", y="y", source=source7, color="steelblue", size=5) OTAVA_DNMT3b_plot = p.circle(x="x", y="y", source=source8, color="navy", size=5) SelleckChem_plot = p.circle(x="x", y="y", source=source9, color="darkred", size=5) Targetmol_plot = p.circle(x="x", y="y", source=source10, color="indigo", size=5) Tocris_plot = p.circle(x="x", y="y", source=source11, color="pink", size=5) legend = Legend( items=[ ("APEXBIO", [APEXBIO_plot]), ("Asinex", [Asinex_plot]), ("ChemDiv", [ChemDiv_plot]), ("Enamine", [Enamine_plot]), ("Life_Chemicals", [Life_Chemicals_plot]), ("MedChemExpress", [MedChemExpress_plot]), ("OTAVA_DNMT1", [OTAVA_DNMT1_plot]), ("OTAVA_DNMT3b", [OTAVA_DNMT3b_plot]), ("SelleckChem", [SelleckChem_plot]), ("Targetmol", [Targetmol_plot]), ("Tocris", [Tocris_plot]), ], location="center", orientation="vertical", click_policy="hide", ) p.add_layout(legend, place="right") p.xaxis.axis_label_text_font_size = "20pt" p.yaxis.axis_label_text_font_size = "20pt" p.xaxis.axis_label_text_color = "black" p.yaxis.axis_label_text_color = "black" p.xaxis.major_label_text_font_size = "18pt" p.yaxis.major_label_text_font_size = "18pt" p.title.text_font_size = "22pt" # show(p) # save p.output_backend = "svg" export_svgs( p, filename="/Users/eurijuarez/Desktop/Alexis/Plots/SVG_files/" + "ChemSpace_PCA" + ".svg", )
graph_circle.node_renderer.glyph = Circle(size=10, fill_alpha=0.8, fill_color='royalblue') graph_circle.node_renderer.selection_glyph = Circle(size=10, fill_alpha=0.8, fill_color='red') graph_circle.node_renderer.hover_glyph = Circle(size=10, fill_alpha=0.8, fill_color='yellow') graph_circle.edge_renderer.glyph = MultiLine(line_width=3, line_alpha=0.8, line_color='color') graph_circle.edge_renderer.selection_glyph = MultiLine(line_width=4, line_alpha=0.8, line_color='red') graph_circle.edge_renderer.hover_glyph = MultiLine(line_width=4, line_alpha=0.8, line_color='yellow') graph_circle.edge_renderer.glyph.line_width = {'field': 'weight'} graph_circle.selection_policy = NodesAndLinkedEdges() graph_circle.inspection_policy = NodesAndLinkedEdges() plot_circle.add_tools(WheelZoomTool()) plot_circle.add_tools(ZoomOutTool()) plot_circle.add_tools(ZoomInTool()) plot_circle.add_tools(ResetTool()) plot_circle.add_tools(UndoTool()) plot_circle.add_tools(RedoTool()) plot_circle.add_tools(PanTool()) plot_circle.add_tools(TapTool()) plot_circle.add_tools(SaveTool()) plot_circle.add_tools(BoxSelectTool()) plot_circle.add_tools(LassoSelectTool()) # !!! Hover the node attributes !!! node_hover = HoverTool(tooltips=[('Name', '@index'), ('Degree', '@degree'), ('Min Weight', '@minweight'), ('Max Weight', '@maxweight'), ('Sum Weight', '@sumweight')]) plot_circle.add_tools(node_hover) plot_circle.add_layout(color_bar, 'right')
def plot(self, source1, source2, source3, source4, source5, source6, source7, source8, source9): hover = HoverTool(tooltips=[ ("Similarity", "($x)"), ("ECF", "($y)"), ]) p = figure(title="TOPOLOGICAL FP/Tanimoto Similarity", x_axis_label="Similarity", y_axis_label="Cumulative Distribution Function", x_range=(0, 1), y_range=(0, 1), tools=[hover], plot_width=1000, plot_height=800) FDA_plot = p.line(x="x", y="y", source=source1, line_width=3, color="darkslateblue") PPI_plot = p.line(x="x", y="y", source=source2, line_width=3, color="yellowgreen") MACRO_plot = p.line(x="x", y="y", source=source3, line_width=3, color="lightsteelblue") NP_plot = p.line(x="x", y="y", source=source4, line_width=3, color="olive") PEP_FDA_plot = p.line(x="x", y="y", source=source5, line_width=3, color="darkslategray") LIN_plot = p.line(x="x", y="y", source=source6, line_width=3, color="aquamarine") LIN_NM_plot = p.line(x="x", y="y", source=source7, line_width=3, color="teal") CYC_plot = p.line(x="x", y="y", source=source8, line_width=3, color="lightpink") CYC_NM_plot = p.line(x="x", y="y", source=source9, line_width=3, color="mediumvioletred") p.add_tools(LassoSelectTool(), ZoomInTool(), ZoomOutTool(), SaveTool(), PanTool()) legend = Legend(items=[ ("FDA", [FDA_plot]), ("PPI", [PPI_plot]), ("MACRO", [MACRO_plot]), ("NP", [NP_plot]), ("PEP FDA", [PEP_FDA_plot]), ("LIN", [LIN_plot]), ("LIN NM", [LIN_NM_plot]), ("CYC", [CYC_plot]), ("CYC NM", [CYC_NM_plot]), ], location="center", orientation="vertical", click_policy="hide") p.add_layout(legend, place='right') p.xaxis.axis_label_text_font_size = "20pt" p.yaxis.axis_label_text_font_size = "20pt" p.xaxis.axis_label_text_color = "black" p.yaxis.axis_label_text_color = "black" p.xaxis.major_label_text_font_size = "18pt" p.yaxis.major_label_text_font_size = "18pt" p.title.text_font_size = "22pt" return p
def multi_plot(nx, ny, x, ys, source, colors, alphas=None, x_range=None, y_label=None, rescale=False, plotters=None): if not ys or not present(source, x, *ys): return None tools = [ PanTool(dimensions='width'), ZoomInTool(dimensions='width'), ZoomOutTool(dimensions='width'), ResetTool(), HoverTool(tooltips=[tooltip(x) for x in ys + [LOCAL_TIME]], names=['with_hover']) ] f = figure(plot_width=nx, plot_height=ny, x_axis_type='datetime' if TIME in x else 'linear', tools=tools) if y_label: f.yaxis.axis_label = y_label elif rescale: f.yaxis.axis_label = ys[0] else: f.yaxis.axis_label = ', '.join(ys) if rescale: f.extra_y_ranges = {} if alphas is None: alphas = [1 for _ in ys] while len(plotters) < len(ys): plotters += plotters for y, color, alpha, plotter in zip(ys, colors, alphas, plotters): y_range = make_range(source, y) if rescale and y != ys[0]: f.extra_y_ranges[y] = y_range f.add_layout(LinearAxis(y_range_name=y, axis_label=y), 'right') plotter(f, x=x, y=y, source=source, color=color, alpha=alpha, y_range_name=y, name='with_hover') else: f.y_range = y_range plotter(f, x=x, y=y, source=source, color=color, alpha=alpha, name='with_hover') f.xaxis.axis_label = x f.toolbar.logo = None if ny < 300: f.toolbar_location = None if x_range: f.x_range = x_range return f
def std_distance_time_plot(nx, ny, source, x_range=None, output_backend=DEFAULT_BACKEND): # avoid range errors if len(source[N.ACTIVE_TIME_S].dropna()) < 2: return None groups = [ group for statistic, group in related_statistics(source, N.ACTIVE_TIME) ] if not groups: # original monochrome plot return multi_dot_plot(nx, ny, N.TIME, [N.ACTIVE_TIME_H, N.ACTIVE_DISTANCE_KM], source, ['black', 'grey'], alphas=[1, 0.5], x_range=x_range, rescale=True) times = [f'{N.ACTIVE_TIME}:{group}' for group in groups] distances = [f'{N.ACTIVE_DISTANCE}:{group}' for group in groups] time_y_range = make_range(source[N.ACTIVE_TIME_H]) distance_y_range = make_range(source[N.ACTIVE_DISTANCE_KM]) colours = list(evenly_spaced_hues(len(groups))) tooltip_names = [ N.ACTIVE_TIME_H, N.ACTIVE_DISTANCE_KM, N.ACTIVITY_GROUP, N.LOCAL_TIME ] tooltip_names += [ name for name in like(N._delta(N.FITNESS_ANY), source.columns) if ':' not in name ] tooltip_names += [ name for name in like(N._delta(N.FATIGUE_ANY), source.columns) if ':' not in name ] tools = [ PanTool(dimensions='width'), ZoomInTool(dimensions='width'), ZoomOutTool(dimensions='width'), ResetTool(), HoverTool(tooltips=[tooltip(name) for name in tooltip_names], names=['with_hover']) ] f = figure(output_backend=output_backend, plot_width=nx, plot_height=ny, x_axis_type='datetime', tools=tools) f.yaxis.axis_label = f'lines - {N.ACTIVE_TIME_H}' f.y_range = time_y_range f.extra_y_ranges = {N.ACTIVE_DISTANCE: distance_y_range} f.add_layout( LinearAxis(y_range_name=N.ACTIVE_DISTANCE, axis_label=f'dots - {N.ACTIVE_DISTANCE_KM}'), 'right') plotter = comb_plotter() for time, colour, group in zip(times, colours, groups): time_h = N._slash(time, U.H) source[time_h] = source[time] / 3600 source[N.ACTIVITY_GROUP] = group plotter(f, x=N.TIME, y=time_h, source=source, color=colour, alpha=1) plotter = dot_plotter() for distance, colour, group in zip(distances, colours, groups): distance_km = N._slash(distance, U.KM) source[distance_km] = source[distance] source[N.ACTIVITY_GROUP] = group plotter(f, x=N.TIME, y=distance_km, source=source, color=colour, alpha=1, name='with_hover', y_range_name=N.ACTIVE_DISTANCE) f.xaxis.axis_label = N.TIME f.toolbar.logo = None if ny < 300: f.toolbar_location = None if x_range: f.x_range = x_range return f
def SIF_Explorer_tab(): ################################# # Initialize all layers ################################# # Load from a save file if path.exists(LAYERS_FILE): with open(LAYERS_FILE, 'rb') as layers_file: us_county_layer, us_state_layer, world_grid_2_degree_layer = pickle.load(layers_file) # Load from scratch else: us_county_layer = US_County_Layer() us_state_layer = US_State_Layer() world_grid_2_degree_layer = US_World_Grid_2_Degree_Layer() # Save the layers to file with open(LAYERS_FILE, 'wb') as layers_file: layers = (us_county_layer, \ us_state_layer, world_grid_2_degree_layer) pickle.dump(layers, layers_file) # Want the custom layer to be new every time custom_shapes_layer = Custom_Shapes_Layer() world_grid_dynamic_layer = World_Grid_Dynamic_Layer() # Set the active layer to be the county layer active_layer = us_county_layer ################################# # Set up layer selector ################################# # Once a new layer is selected, use that layer to refresh the page # and all data def refresh_page(): # Get initial map details xs, ys, names = active_layer.get_map_details() if type(active_layer) != Custom_Shapes_Layer: # Obtain and update date boundaries start_date, end_date = active_layer.get_date_range() date_range_slider.start = start_date date_range_slider.end = end_date # Unpack the current range range_start, range_end = date_range_slider.value # Convert to SQL format range_start = utc_from_timestamp(range_start) range_end = utc_from_timestamp(range_end) # Get the initial sif values sifs = active_layer.get_data_for_date_range(range_start, range_end) # Dictionary to hold the data new_source_dict = dict( x= xs, y= ys, name= np.array(names), sifs= np.array(sifs)) # Update all source data values source.data = new_source_dict # Turn off custom layer custom_data_source.data = dict(x= np.array([]), y= np.array([]), name = np.array([])) else: # Turn off the other layers source.data = dict(x= np.array([]), y= np.array([]), name= np.array([]), sifs= np.array([])) # Safeguard - that at least one custom shape is drawn if (xs.size != 0): # Dictionary to hold the selected shape data new_source_dict = dict( x= xs, y= ys, name = np.array(names)) custom_data_source.data = new_source_dict # Trigger for when a new layer is selected def layer_selected(new): # We want to modify the overall active layer (not local to this func) nonlocal active_layer # Simple dictionary to switch out the active layer switcher = { 0 : custom_shapes_layer, 1 : us_state_layer, 2 : us_county_layer, 3 : world_grid_2_degree_layer, 4 : world_grid_dynamic_layer, } # Swap out the active layer active_layer = switcher.get(new, active_layer) # Fetch new dates, shapes, names, etc. and refresh the page refresh_page() # Define selection labels layer_selector = RadioButtonGroup( labels=["Custom", "US States", "US Counties", "World", "World (Dynamic)"], active=2) # Set up layer selection callback layer_selector.on_click(layer_selected) ################################# # Set up date range slider ################################# # Obtain date boundaries start_date, end_date = active_layer.get_date_range() # create a callback for when the date slider is changed def date_range_selected(attr, old, new): t0 = time.time() # Unpack the new range range_start, range_end = new # Convert to SQL format range_start = utc_from_timestamp(range_start) range_end = utc_from_timestamp(range_end) # Get the new day's data sifs = active_layer.get_data_for_date_range(range_start, range_end) # Update the sif values source.data["sifs"] = np.array(sifs) # Set the title of the map to reflect the selected date range p.title.text = "SIF Average: %s to %s" % (range_start, range_end) print("Took " + str(time.time() - t0) + " seconds to update") # Create the date slider date_range_slider = DateRangeSlider(title="Date Range: ", start=start_date, end=end_date, value=(START_DATE_INIT, END_DATE_INIT), step=1) # Assign the callback for when the date slider changes date_range_slider.callback_policy = "throttle" date_range_slider.callback_throttle = 200 date_range_slider.on_change('value_throttled', date_range_selected) ################################# # Set up the map and its source ################################# # Get initial map details xs, ys, names = active_layer.get_map_details() # Get the initial sif values sifs = active_layer.get_data_for_date_range(START_DATE_INIT, END_DATE_INIT) # Dictionary to hold the data source=ColumnDataSource(data = dict( x= np.array(xs), y= np.array(ys), name= np.array(names), sifs= np.array(sifs)) ) # Which tools should be available to the user TOOLS = "pan,wheel_zoom,reset,hover,save,tap" # Obtain map provider tile_provider = get_provider(Vendors.CARTODBPOSITRON_RETINA) # tile_options = {} # tile_options['url'] = 'https://mt1.google.com/vt/lyrs=m&x={x}&y={y}&z={z}' # tile_options['attribution'] = """ # Map tiles by <a href="http://stamen.com">Stamen Design</a>, under # <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>. # Data by <a href="http://openstreetmap.org">OpenStreetMap</a>, # under <a href="http://www.openstreetmap.org/copyright">ODbL</a>. # """ # mq_tile_source = WMTSTileSource(**tile_options) # Don't want the map to wrap around tile_provider.wrap_around = False # Configure the figure p = figure( title="SIF Average by County: %s" % end_date, tools=TOOLS, active_scroll = "wheel_zoom", x_axis_location=None, y_axis_location=None, tooltips=[ ("Name", "@name"), ("Average SIF", "@sifs") ], x_axis_type='mercator', y_axis_type='mercator', plot_height = 900, plot_width = 1100, output_backend="webgl", x_range=Range1d(-20000000, 20000000, bounds = 'auto')) # Add the map! p.add_tile(tile_provider) p.lod_threshold = None # No downsampling #p.lod_interval = 150 p.toolbar.logo = None # No logo p.grid.grid_line_color = None # No grid # Policy for hovering p.hover.point_policy = "follow_mouse" # Color mapper color_mapper = LinearColorMapper(palette=palette, low = SIF_MIN, high = SIF_MAX) color_transform = {'field': 'sifs', 'transform': color_mapper} # Patch all the information onto the map patch_renderer = p.patches('x', 'y', source=source, fill_color=color_transform, fill_alpha=0.9, line_color="white", line_width=0.1, selection_fill_alpha = 1.0, selection_fill_color = color_transform, nonselection_line_color="black", nonselection_fill_alpha=0.7, nonselection_fill_color= color_transform) p.title.text_font_size = '16pt' # Add a color bar ticker = FixedTicker(ticks=[-1,0,1,2]) color_bar = ColorBar(color_mapper=color_mapper, ticker = ticker, label_standoff=12, border_line_color=None, location=(0,0)) p.add_layout(color_bar, 'right') # Add zoom in / out tools zoom_in = ZoomInTool(factor=ZOOM_FACTOR) zoom_out = ZoomOutTool(factor=ZOOM_FACTOR) def range_changed(param, old, new): if (type(active_layer) == World_Grid_Dynamic_Layer): x1 = p.x_range.start x2 = p.x_range.end y1 = p.y_range.start y2 = p.y_range.end new_x1, new_y1 = to_lat_lon(y1, x1) new_x2, new_y2 = to_lat_lon(y2, x2) if (active_layer.range_changed(new_x1, new_y1, new_x2, new_y2)): refresh_page() #convert_shapes_to_mercator(np.array([[x1], [x2]]), #np.array([[y1], [y2]])) #print("(%s, %s) to (%s, %s)" % (x1, y1, x2, y2)) #40000000 # # p.callback_policy = "throttle" # p.callback_throttle = 200 p.x_range.on_change('end', range_changed) p.add_tools(zoom_in) p.add_tools(zoom_out) ################################# # Set up custom plot data ################################# # Data source for custom shapes custom_data_source = ColumnDataSource(data = \ dict(x= np.array([]), y= np.array([]), name=np.array([]))) # Patch the custom data onto the map p.patches('x', 'y', source=custom_data_source, line_color="darkslategray", line_width=1, fill_alpha=0.3, fill_color="lightgray") # On geometry selection # zoom = WheelZoomTool() # p.on_event() # p.add_tools(lasso) # p.on_event(SelectionGeometry, shape_drawn) ################################# # Set up time series ################################# def color_gen(): yield from itertools.cycle(time_pltt[10]) color = color_gen() def shape_drawn(event): # Check if more than one point # Otherwise a tap triggers this function if (type(event.geometry['x']) != float): # Notify the custom selection layer that this # shape was selected and obtain relevant info # custom_shapes_layer.patch_selected(event) # Change to the custom layer layer_selector.active = 0 layer_selected(0) # Notify the layer that this patch was created. active_layer.patch_created(event) # Clear all time series sif_series.renderers = [] # Update the title and get new data from the active layer sif_series.title.text, time_srs_src_list, names = \ active_layer.patch_clicked(source, None) # Plot each series returned for i in range(len(time_srs_src_list)): sif_series.scatter('date', 'sif', source=time_srs_src_list[i], color=time_pltt[10][i]) # Make sure the current shape is drawn refresh_page() def patch_clicked(event): """ When a patch is clicked, update the time series chart. """ # Clear all time series sif_series.renderers = [] # Update the title and get new data from the active layer sif_series.title.text, time_srs_src_list, names = \ active_layer.patch_clicked(source, event) # Plot each series returned for i in range(len(time_srs_src_list)): sif_series.scatter('date', 'sif', source=time_srs_src_list[i], color=time_pltt[10][i]) # Which tools should be available to the user for the timer series TOOLS = "pan,wheel_zoom,reset,hover,save" # Figure that holds the time-series sif_series = figure(plot_width=750, plot_height=400, x_axis_type='datetime', tools=TOOLS, title= "SIF Time-Series (Select a county...)", active_scroll = "wheel_zoom", tooltips=[ ("Day", "@date"), ("Average SIF", "@sif") ], x_axis_label = 'Date', y_axis_label = 'SIF Average', y_range = (SIF_MIN, SIF_MAX)) # Some font choices sif_series.title.text_font_size = '16pt' sif_series.xaxis.axis_label_text_font_size = "12pt" sif_series.yaxis.axis_label_text_font_size = "12pt" # Policy for hovering sif_series.hover.point_policy = "follow_mouse" # No logo sif_series.toolbar.logo = None # When a patch is selected, trigger the patch_time_series function p.on_event(Tap, patch_clicked) # On geometry selection lasso = LassoSelectTool(select_every_mousemove = False) p.add_tools(lasso) p.on_event(SelectionGeometry, shape_drawn) ################################# # TODO: Set up download area ################################# # def save_data(): # active_layer.save_data() # print("Button Clicked") # callback = active_layer.get_save_data_js_callback() button = Button(label="Save Data", button_type="success") # button.on_click(active_layer.save_data) #button.js_on_event(ButtonClick, callback) ################################# # Set up tab ################################# # The layout of the view layout = row(column(p, date_range_slider, layer_selector), column(sif_series, row(column(), button))) # Create tab using layout tab = Panel(child=layout, title = 'US Visualization') # Return the created tab return tab
def make_weight_graph(stock_name=None): """ """ try: API_URL = 'https://api.iextrading.com/1.0' res = requests.get(f'{ API_URL }/stock/{ stock_name }/chart/5y') data = res.json() except JSONDecodeError: abort(404) df = pd.DataFrame(data) # df['date'] = pd.to_datetime(df['date']) df['adjVolume'] = 6 * df['volume'] // df['volume'].mean() df = df[['date', 'vwap', 'volume', 'adjVolume']] seqs = np.arange(df.shape[0]) df['seqs'] = pd.Series(seqs) source = ColumnDataSource(df) colors = [ "#75968f", "#a5bab7", "#c9d9d3", "#e2e2e2", "#dfccce", "#ddb7b1", "#cc7878", "#933b41", "#550b1d" ] mapper = LinearColorMapper(palette=colors, low=df.adjVolume.min(), high=df.adjVolume.max()) hover = HoverTool(tooltips=[ ('Date', '@date'), ('Vwap', '@vwap'), ('Volume', '@volume'), ], names=["circle"]) TOOLS = [ hover, BoxZoomTool(), PanTool(), ZoomInTool(), ZoomOutTool(), ResetTool() ] p = figure(plot_width=1000, plot_height=800, title=f'5 year weighted performace of {stock_name}', tools=TOOLS, toolbar_location='above') p.circle(x="seqs", y="vwap", source=source, size='adjVolume', fill_color=transform('adjVolume', mapper), name="circle") color_bar = ColorBar(color_mapper=mapper, location=(0, 0), ticker=BasicTicker(desired_num_ticks=len(colors)), formatter=PrintfTickFormatter(format="%s%%")) p.add_layout(color_bar, 'right') p.axis.axis_line_color = None p.axis.major_tick_line_color = None p.axis.major_label_text_font_size = "5pt" p.axis.major_label_standoff = 0 p.xaxis.major_label_orientation = 1.0 script, div = components(p) return script, div, stock_name
def draw(S, position=None, with_labels=False): """Plot the given signed social network. Args: S: The network position (dict, optional): The position for the nodes. If no position is provided, a layout will be calculated. If the nodes have 'color' attributes, a Kamanda-Kawai layout will be used to group nodes of the same color together. Otherwise, a circular layout will be used. Returns: A dictionary of positions keyed by node. Examples: >>> import dwave_structural_imbalance_demo as sbdemo >>> gssn = sbdemo.GlobalSignedSocialNetwork() >>> nld_before = gssn.get_node_link_data('Syria', 2013) >>> nld_after = gssn.solve_structural_imbalance('Syria', 2013) # draw Global graph before solving; save node layout for reuse >>> position = sbdemo.draw('syria.png', nld_before) # draw the Global graph; reusing the above layout, and calculating a new grouped layout >>> sbdemo.draw('syria_imbalance.png', nld_after, position) >>> sbdemo.draw('syria_imbalance_grouped', nld_after) """ # we need a consistent ordering of the edges edgelist = S.edges() nodelist = S.nodes() def layout_wrapper(S): pos = position if pos is None: try: # group bipartition if nodes are colored dist = defaultdict(dict) for u, v in product(nodelist, repeat=2): if u == v: # node has no distance from itself dist[u][v] = 0 elif nodelist[u]['color'] == nodelist[v]['color']: # make same color nodes closer together dist[u][v] = 1 else: # make different color nodes further apart dist[u][v] = 2 pos = nx.kamada_kawai_layout(S, dist) except KeyError: # default to circular layout if nodes aren't colored pos = nx.circular_layout(S) return pos # call layout wrapper once with all nodes to store position for calls with partial graph position = layout_wrapper(S) plot = Plot(plot_width=600, plot_height=400, x_range=Range1d(-1.2, 1.2), y_range=Range1d(-1.2, 1.2)) tools = [WheelZoomTool(), ZoomInTool(), ZoomOutTool(), PanTool()] plot.add_tools(*tools) plot.toolbar.active_scroll = tools[0] def get_graph_renderer(S, line_dash): # we need a consistent ordering of the edges edgelist = S.edges() nodelist = S.nodes() # get the colors assigned to each edge based on friendly/hostile sign_edge_color = ['#87DACD' if S[u][v]['sign'] == 1 else '#FC9291' for u, v in edgelist] # get the colors assigned to each node by coloring try: coloring_node_color = ['#4378F8' if nodelist[v]['color'] else '#FFE897' for v in nodelist] except KeyError: coloring_node_color = ['#FFFFFF' for __ in nodelist] graph_renderer = from_networkx(S, layout_wrapper) circle_size = 10 graph_renderer.node_renderer.data_source.add(coloring_node_color, 'color') graph_renderer.node_renderer.glyph = Circle(size=circle_size, fill_color='color') edge_size = 2 graph_renderer.edge_renderer.data_source.add(sign_edge_color, 'color') try: graph_renderer.edge_renderer.data_source.add([S[u][v]['event_year'] for u, v in edgelist], 'event_year') graph_renderer.edge_renderer.data_source.add( [S[u][v]['event_description'] for u, v in edgelist], 'event_description') plot.add_tools(HoverTool(tooltips=[("Year", "@event_year"), ("Description", "@event_description")], line_policy="interp")) except KeyError: pass graph_renderer.edge_renderer.glyph = MultiLine(line_color='color', line_dash=line_dash) graph_renderer.inspection_policy = EdgesAndLinkedNodes() return graph_renderer try: S_dash = S.edge_subgraph(((u, v) for u, v in edgelist if S[u][v]['frustrated'])) S_solid = S.edge_subgraph(((u, v) for u, v in edgelist if not S[u][v]['frustrated'])) plot.renderers.append(get_graph_renderer(S_dash, 'dashed')) plot.renderers.append(get_graph_renderer(S_solid, 'solid')) except KeyError: plot.renderers.append(get_graph_renderer(S, 'solid')) plot.background_fill_color = "#202239" positions = layout_wrapper(S) if with_labels: data = { 'xpos': [], 'ypos': [], 'label': [] } for label, pos in positions.items(): data['label'].append(label) data['xpos'].append(pos[0]) data['ypos'].append(pos[1]) labels = LabelSet(x='xpos', y='ypos', text='label', level='glyph', source=ColumnDataSource(data), x_offset=-5, y_offset=10, text_color="#F5F7FB", text_font_size='12pt') plot.add_layout(labels) show(Row(plot)) return positions
def make_candle_chart(stock_name=None): """ """ try: API_URL = 'https://api.iextrading.com/1.0' res = requests.get(f'{ API_URL }/stock/{ stock_name }/chart/5y') data = res.json() except JSONDecodeError: abort(404) df = pd.DataFrame(data) # df["date"] = pd.to_datetime(df["date"]) # import pdb; pdb.set_trace() seqs = np.arange(df.shape[0]) df['seqs'] = pd.Series(seqs) df['changePercent'] = df['changePercent'].apply(lambda x: str(x) + '%') df['mid'] = df.apply(lambda x: (x['open'] + x['close']) / 2, axis=1) df['height'] = df.apply(lambda x: x['close'] - x['open'] if x['close'] != x['open'] else 0.01, axis=1) inc = df.close > df.open dec = df.close < df.open w = .3 sourceInc = bk.ColumnDataSource(df.loc[inc]) sourceDec = bk.ColumnDataSource(df.loc[dec]) hover = HoverTool(tooltips=[ ('Date', '@date'), ('Low', '@low'), ('High', '@high'), ('Open', '@open'), ('Close', '@close'), ('Percent', '@changePercent'), ], names=["rect1", "rect2"]) TOOLS = [ hover, BoxZoomTool(), PanTool(), ZoomInTool(), ZoomOutTool(), ResetTool() ] p = figure(plot_width=1000, plot_height=800, title=stock_name, tools=TOOLS, toolbar_location='above') p.xaxis.major_label_orientation = np.pi / 4 p.grid.grid_line_alpha = w # descriptor = Label(x=70, y=70, text=f"5-year stock chart of {stock_name}") # p.add_layout(descriptor) p.segment(df.seqs[inc], df.high[inc], df.seqs[inc], df.low[inc], color='green') p.segment(df.seqs[dec], df.high[dec], df.seqs[dec], df.low[dec], color='red') p.rect(x='seqs', y='mid', width=w, height='height', fill_color='red', line_color='red', source=sourceDec, name="rect1") p.rect(x='seqs', y='mid', width=w, height='height', fill_color='green', line_color='green', source=sourceInc, name="rect2") script, div = components(p) return script, div, stock_name
def plot_similarity(self, result, parameter): source1 = column_source(result, "FDA") source2 = column_source(result, "PPI") source3 = column_source(result, "MACRO") source4 = column_source(result, "NP") source5 = column_source(result, "FDA PEP") source6 = column_source(result, "linear") source7 = column_source(result, "cyclic") hover = HoverTool(tooltips=[ ("sim", "$x"), ("CDF", "$y"), ]) p = figure( title="CDF of Tanimoto Similarity, based on: " + parameter[0], x_axis_label="Similarity", y_axis_label="Cumulative Distribution Function", x_range=(0, 1), y_range=(0, 1), tools=[hover], plot_width=1000, plot_height=800, ) p.add_tools(LassoSelectTool(), ZoomInTool(), ZoomOutTool(), SaveTool(), PanTool()) FDA_plot = p.line(x="x", y="y", source=source1, color="darkslateblue", line_width=3) PPI_plot = p.line(x="x", y="y", source=source2, color="yellowgreen", line_width=3) MACRO_plot = p.line(x="x", y="y", source=source3, color="lightsteelblue", line_width=3) NP_plot = p.line(x="x", y="y", source=source4, color="olive", line_width=3) PEP_FDA_plot = p.line(x="x", y="y", source=source5, color="darkslategray", line_width=3) LIN_plot = p.line(x="x", y="y", source=source6, color="teal", line_width=3) CYC_plot = p.line(x="x", y="y", source=source7, color="mediumvioletred", line_width=3) legend = Legend( items=[ ("FDA", [FDA_plot]), ("PPI", [PPI_plot]), ("MACRO", [MACRO_plot]), ("NP", [NP_plot]), ("PEP FDA", [PEP_FDA_plot]), ("LIN", [LIN_plot]), ("CYC", [CYC_plot]), ], location="center", orientation="vertical", click_policy="hide", ) p.add_layout(legend, place="right") p.xaxis.axis_label_text_font_size = "20pt" p.yaxis.axis_label_text_font_size = "20pt" p.xaxis.axis_label_text_color = "black" p.yaxis.axis_label_text_color = "black" p.xaxis.major_label_text_font_size = "18pt" p.yaxis.major_label_text_font_size = "18pt" p.title.text_font_size = "22pt" return p
def create(self, request, symbol=None): """ """ if not symbol: return Response(json='Company not found', status=404) url = f'https://api.iextrading.com/1.0/stock/{symbol}/chart/5y' data = requests.get(url) if not data: return Response(json='Invalid Company', status=404) import pdb pdb.set_trace() df = pd.DataFrame(data) seqs = np.arange(df.shape[0]) df['seqs'] = pd.Series(seqs) df['changePercent'] = df['changePercent'].apply(lambda x: str(x) + '%') df['mid'] = df.apply(lambda x: (x['open'] + x['close']) / 2, axis=1) df['height'] = df.apply(lambda x: x['close'] - x['open'] if x['close'] != x['open'] else 0.001, axis=1) inc = df.close > df.open dec = df.close < df.open w = .3 sourceInc = bk.ColumnDataSource(df.loc[inc]) sourceDec = bk.ColumnDataSource(df.loc[dec]) hover = HoverTool( tooltips=[('date', '@date'), ('low', '@low'), ( 'high', '@high'), ('open', '@open'), ('close', '@close'), ('percent', '@changePercent')]) TOOLS = [ hover, BoxZoomTool(), PanTool(), ZoomInTool(), ZoomOutTool(), ResetTool() ] p = bk.figure(plot_width=1500, plot_height=800, tools=TOOLS, title=f'{symbol}', toolbar_location='above') p.xaxis.major_label_orientation = np.pi / 4 p.grid.grid_line_alpha = w descriptor = Label(x=70, y=70, text='Past 5 years') p.add_layout(descriptor) p.segment(df.seqs[inc], df.high[inc], df.seqs[inc], df.low[inc], color='green') p.segment(df.seqs[dec], df.high[dec], df.seqs[dec], df.low[dec], color='red') p.rect(x='seqs', y='mid', width=w, height='height', fill_color='green', line_color='green', source=sourceInc) p.rect(x='seqs', y='mid', width=w, height='height', fill_color='red', line_color='red', source=sourceDec) bk.save(p, f'./static/{symbol}candle_stick.html', filename=f'5yr_candlestock') return Response(json='Data Created', status=200)
def plot_tsne(self, parameter): result = self.result source1 = column_source(result, 'INACTIVO') source2 = column_source(result, 'PQSR-AGONISTA') source3 = column_source(result, 'RHLR-ANTAGONISTA') source4 = column_source(result, 'LASR-AGONISTA') source5 = column_source(result, 'PQSR-ANTAGONISTA') source6 = column_source(result, 'BIOFACQUIM_V2') source7 = column_source(result, 'LASR-ANTAGONISTA') source8 = column_source(result, 'QUIPRONAB') source9 = column_source(result, 'NuBBE') source10 = column_source(result, 'RHLR-AGONISTA') hover = HoverTool(tooltips=[ ("PCA 1", "$x"), ("PCA 2", "$y"), ("NAME", "@N"), ]) p = figure( title="tSNE based on " + parameter, x_axis_label="PC 1", y_axis_label="PC 2", x_range=(-7, 7), y_range=(-7, 7), tools=[hover], plot_width=1000, plot_height=800, ) p.add_tools(LassoSelectTool(), ZoomInTool(), ZoomOutTool(), SaveTool(), PanTool()) INACTIVO_plot = p.circle(x="x", y="y", source=source1, color="indigo", size=5) PQSR_AGONISTA_plot = p.circle(x="x", y="y", source=source2, color="hotpink", size=5) RHLR_ANTAGONISTA_plot = p.circle(x="x", y="y", source=source3, color="navy", size=5) LASR_AGONISTA_plot = p.circle(x="x", y="y", source=source4, color="dodgerblue", size=5) PQSR_ANTAGONISTA_plot = p.circle(x="x", y="y", source=source5, color="lightcoral", size=5) BIOFACQUIM_V2_plot = p.circle(x="x", y="y", source=source6, color="gold", size=5) LASR_ANTAGONISTA_plot = p.circle(x="x", y="y", source=source7, color="yellowgreen", size=5) QUIPRONAB_plot = p.circle(x="x", y="y", source=source8, color="green", size=5) NuBBE_plot = p.circle(x="x", y="y", source=source9, color="orangered", size=5) RHLR_AGONISTA_plot = p.circle(x="x", y="y", source=source10, color="mediumvioletred", size=5) legend = Legend( items=[ ('INACTIVO', [INACTIVO_plot]), ('PQSR-AGONISTA', [PQSR_AGONISTA_plot]), ('RHLR-ANTAGONISTA', [RHLR_ANTAGONISTA_plot]), ('LASR-AGONISTA', [LASR_AGONISTA_plot]), ('PQSR-ANTAGONISTA', [PQSR_ANTAGONISTA_plot]), ('BIOFACQUIM_V2', [BIOFACQUIM_V2_plot]), ('LASR-ANTAGONISTA', [LASR_ANTAGONISTA_plot]), ('QUIPRONAB', [QUIPRONAB_plot]), ('NuBBE', [NuBBE_plot]), ('RHLR-AGONISTA', [RHLR_AGONISTA_plot]), ], location="center", orientation="vertical", click_policy="hide", ) p.add_layout(legend, place="right") p.xaxis.axis_label_text_font_size = "20pt" p.yaxis.axis_label_text_font_size = "20pt" p.xaxis.axis_label_text_color = "black" p.yaxis.axis_label_text_color = "black" p.xaxis.major_label_text_font_size = "18pt" p.yaxis.major_label_text_font_size = "18pt" p.title.text_font_size = "22pt" show(p)
def plotGeoPoints(data_dict, data_title, offset=0.25, pt_size=7, save_dir=None): if save_dir is not None: path = os.path.expanduser(save_dir) if os.path.exists(path) and os.path.isdir(path): os.chdir(path) else: print( "Warning: either {} does not exist or is not a valid directory; writing html file to {}" .format(path, os.getcwd())) noPunc = re.compile("[%s\\…]" % re.escape(string.punctuation)) out_file_name = "{}.html".format( noPunc.sub("", data_title).replace(" ", "_")) ''' Plot the points collected from GeoMesa''' fid, x, y, what, who, when, why = zip(*[(key, row['x'], row['y'], row['what'], row['who'], row['when'], row['why']) for key, row in data_dict.items()]) ''' Put the time fields into mm/dd/yyyy h:m am/pm format: ''' when = [tm.strftime("%M/%d/%Y %I:%M %p") for tm in when] data_source = ColumnDataSource( dict(fid=fid, x=x, y=y, what=what, who=who, when=when, why=why)) hover = HoverTool(tooltips=[ ("fid", "@fid"), ("(x,y)", "($x, $y)"), ("Who", "@who"), ("What", "@what"), ("When", "@when"), ("Why", "@why"), ]) tools = [ PanTool(), BoxZoomTool(), CrosshairTool(), hover, WheelZoomTool(), ZoomInTool(), ZoomOutTool(), ResetTool(), SaveTool() ] ''' Set the values to show with hover: ''' output_file(out_file_name, title="Results of {}".format(data_title)) geo_plt = figure(title="GeoMesa--{}".format(data_title), tools=tools, plot_width=600, plot_height=600) geo_plt.title.align = 'center' geo_plt.toolbar.logo = None geo_plt.toolbar_sticky = False geo_plt.xaxis.axis_label = "Lat" geo_plt.yaxis.axis_label = "Long" geo_plt.y_range = Range1d(start=min(y) - offset, end=max(y) + offset) geo_plt.x_range = Range1d(start=min(x) - offset, end=max(x) + offset) geo_plt.square("x", "y", fill_color="red", line_color=None, source=data_source, size=pt_size) show(geo_plt) reset_output()
def plot_bokeh(title): global topic_names, authors topic_names = grab_topics(t_model, feature_names, 5) x_ = [] y_ = [] t_ = [] o_=[] topic_ = [] global source source = ColumnDataSource( data =dict( x=x_, y=y_, t=t_, o=o_, desc=titles, topics=topic_, auth=authors, year=years )) #Draw plots update_plot() global year_from, year_to, custom_text, search_text, radio_search, search_items, Keyword_text, custom_text1 #Year filtering controls year_from = Slider(title="Include papers from", value=1981, start=1981, end=2017, step=1) year_to = Slider(title="Inlude papers to", value=2017, start=year_from.value-1, end=2017, step=1) year_from.on_change('value', update_years) year_to.on_change('value', update_years) now_change = Button(label="Update", button_type="success") now_change.on_click(update_plot) #Custom text placement controls #sizing_mode = 'scale_both' -- need to look for scaling the text box size #sizing_mode = 'stretch_both' custom_text = TextAreaInput(value=" ", title="Enter some text you are working on here:",width=600,height=400) text_button = Button(label="Process", button_type="success") # for i in custom_text.value: # if i == '.': # process_text() # callback1 = CustomJS( code=""" # // the event that triggered the callback is cb_obj: # // The event type determines the relevant attributes # console.log('Tap event occurred at x-position: ' + cb_obj.x) # """) # custom_text.on_change("value", my_text_input_handler) # custom_text.js_on_event('tap', callback1) # custom_text.on_event(MouseEnter, callback1) text_button.on_click(process_text) text_button.on_click(update_table) custom_text1 = TextAreaInput(value=" ", title="Enter text here if you want to search for individual words or lines:",width=600,height=200) text_button1 = Button(label="Process", button_type="success") text_button1.on_click(process_text1) text_button1.on_click(update_table) template200 = """ <div style="font-size: 15px;"> <%= value %> </div> """ keyword_data = ColumnDataSource(data ={}) columns =[TableColumn(field ="keywords_", title ="<b> Keyword </b>", width = 700, formatter=HTMLTemplateFormatter(template=template200))] # Keyword_text = TextAreaInput(value ="default",title="Keywords", width = 800, height = 100) Keyword_text = DataTable(source=keyword_data, columns=columns, width=800, row_height=50, editable=True, fit_columns = True) Keyword_text.source.selected.on_change("indices", some_func) #Search button controls search_text = TextInput(value="", title="Search box: (separate terms with ';' - not for DOIs)") search_button = Button(label="Search", button_type="success") search_button.on_click(process_search) radio_search = RadioButtonGroup(labels=["Title", "Full Text", "doi","Author"], active=1) print("helllllll") #increase size #txtIn_rng = widgetbox(children=[custom_text], width=wd) #curdoc().add_root(txtIn_rng) #Data Table for selected papers global table_data, chosen_papers,dict2,table_row, table_cell_column_1, value1, value2, table_cell_column_2, summary3, dict4 template = """<span href="#" data-toggle="tooltip" title="<%= value %>" style="font-size:15px"><%= value %></span>""" template_str = '<a href="http://dx.doi.org/<%=dois_%>" target="_blank"><%= value %></a>' # output_file("openurl.html") table_data = ColumnDataSource(data = {}) print("***********") columns = [TableColumn(field="years_", title="<b>Year</b>",width = 50, formatter=HTMLTemplateFormatter(template=template)), TableColumn(field="titles_", title="<b>Paper Title</b>", width = 200, formatter=HTMLTemplateFormatter(template=template)), TableColumn(field="authors_", title="<b>Authors</b>", width = 100, formatter=HTMLTemplateFormatter(template=template)), TableColumn(field="dois_", title="<b>Link</b>",width = 100, formatter=HTMLTemplateFormatter(template=template_str)),TableColumn(field="summary_", title="<b>Summary</b>", width =600,formatter=HTMLTemplateFormatter(template=template))] print("1*") chosen_papers = DataTable(source=table_data, columns=columns, width=600, row_height=100, editable=True, fit_columns = True) table_row = TextInput(value = '', title = "Row index:") value1 =[] value2 = int(0) value3 =[] dict4 =[] table_cell_column_1 = TextAreaInput(value = '', title = "Papers from table", height = 100) table_cell_column_2 = TextAreaInput(value = '', title = "Papers from graph", height = 100) summary3 = TextAreaInput(value = '', title = "Summary of the recently selected paper", height = 300) # table_cell_column_2 = TextInput(value= '', title = "Author", height = 100) chosen_papers.source.selected.on_change('indices', function_source) # Adding a title for data table pre = Div(text="""Please hover over each column to see the full text. </br> By clicking on each row, the desirable papers can be added to the 'Papers from table' list below.</br> By clicking on authors column, authors can be directly placed in search.""", width=600, height=50, style={'font-size': '100%', 'color': 'black', 'font-weight':'bold'}) # pre = PreText(text="""Please hover over each column to see the full text.\n # By clicking on each row, the desirable papers can be added to the 'Papers from table' list below.\n # By clicking on authors column, authors can be directly placed in search""", # width=500, height=100) # Adding title for keyword data table pre1 = Div(text=""" If you click on keywords, the keyword will be directly placed in the 'Search Box' """, width=500, height=20,style={'font-size': '100%', 'color': 'black', 'font-weight':'bold'}) # chosen_papers.append(HoverTool(tooltips=[("Summary", "@summary_")])) # para5 = Paragraph(text = 'summary' , height = 1) #chosen_papers.source.data.update(update_table()) # chosen_papers.source.on_change('data', update_table1) # global table_data1, chosen_papers1 # template = """<span href="#" data-toggle="tooltip" title="<%= value %>"><%= value %></span>""" # table_data1 = ColumnDataSource(data = {}) # print("***********") # columns = [TableColumn(field="summary_", title="Summary", formatter=HTMLTemplateFormatter(template=template))] # print("1*") # chosen_papers1 = DataTable(source=table_data, columns=columns, width=800, row_height=100, editable=True,fit_columns = True, scroll_to_selection = True) # df = pd.DataFrame([ # ['this is a longer text that needs a tooltip, because otherwise we do not see the whole text', 'this is a short text'], # ['this is another loooooooooooooooong text that needs a tooltip', 'not much here'], # ], columns=['a', 'b']) # columns = [TableColumn(field=c, title=c, width=20, formatter=HTMLTemplateFormatter(template=template)) for c in ['a', 'b']] # table = DataTable(source=ColumnDataSource(df), columns=columns) # create a new plot with a title and axis labels global patch, value6, value7 p = figure(title="CHI scatter", tools="tap", x_axis_label='x', y_axis_label='y', width=800, plot_height=850) p.add_tools(BoxZoomTool()) p.add_tools(ZoomInTool()) p.add_tools(ZoomOutTool()) p.add_tools(ResetTool()) p.add_tools(HoverTool(tooltips=[("Title", "@desc"), ("Topic", "@topics"), ("Authors", "@auth"), ("Year", "@year")])) patch = p.circle(x='x', y='y', fill_color='t', nonselection_fill_color='t', radius=0.01, fill_alpha='o', nonselection_fill_alpha='o', line_color=None, source=source) url = "http://dx.doi.org/@dois" taptool = p.select(type=TapTool) taptool.callback = OpenURL(url=url) value6 = [] value7 = [] patch.data_source.on_change('selected', callback) p.on_event(Tap, callback1) l = gridplot([[ row([column(row([widgetbox(year_from, year_to, now_change), widgetbox(search_text, radio_search, search_button)]),widgetbox(custom_text, text_button), widgetbox(custom_text1, text_button1),widgetbox(pre,chosen_papers))]) ,column([p,widgetbox(pre1,Keyword_text)]) ],[table_cell_column_1], [table_cell_column_2], [summary3] ]) curdoc().add_root(l)
def candlestick_chart(symbol): """To generate a candlestick chart of the chosen company.""" url = f'https://api.iextrading.com/1.0/stock/{symbol}/chart/5y' res = req.get(url) data_5_year = res.json() df = pd.DataFrame(data_5_year) df['date_pd'] = pd.to_datetime(df.date) df['year'] = df.date_pd.dt.year year_num = df.year[int(len(df) - 1)] - df.year[3] if year_num >= 5: # 5 YEARS OF HISTORY IS AVAILABLE # PASS DATA INTO DATAFRAME seqs = np.arange(df.shape[0]) df['seqs'] = pd.Series(seqs) df['mid'] = (df.high + df.low) // 2 df['height'] = df.apply(lambda x: x['close'] - x['open'] if x['close'] != x['open'] else 0.01, axis=1) inc = df.close > df.open dec = df.close < df.open w = .3 sourceInc = bk.ColumnDataSource(df.loc[inc]) sourceDec = bk.ColumnDataSource(df.loc[dec]) hover = HoverTool(tooltips=[ ('Date', '@date'), ('Low', '@low'), ('High', '@high'), ('Open', '@open'), ('Close', '@close'), ('Mid', '@mid'), ]) TOOLS = [ hover, BoxZoomTool(), PanTool(), ZoomInTool(), ZoomOutTool(), ResetTool() ] # PLOTTING THE CHART p = bk.figure(plot_width=600, plot_height=450, title=f'{symbol}', tools=TOOLS, toolbar_location='above') p.xaxis.major_label_orientation = np.pi / 4 p.grid.grid_line_alpha = w descriptor = Label(x=180, y=2000, text='5-Year Data Of Your Chosen Company') p.add_layout(descriptor) # CHART LAYOUT p.segment(df.seqs[inc], df.high[inc], df.seqs[inc], df.low[inc], color='green') p.segment(df.seqs[dec], df.high[dec], df.seqs[dec], df.low[dec], color='red') p.rect(x='seqs', y='mid', width=w, height='height', fill_color='red', line_color='red', source=sourceDec) p.rect(x='seqs', y='mid', width=w, height='height', fill_color='green', line_color='green', source=sourceInc) script, div = components(p) return render_template("candlestick_chart.html", the_div=div, the_script=script) else: # 5-YEAR DATA IS NOT AVAILABLE flash('Company does not have a 5-year history.') return redirect(url_for('.portfolio_detail'))
def plot(self, source1, source2, source3, source4, source5, source6, source7, source8, source9): a = self.a b = self.b hover = HoverTool(tooltips=[ ("PCA1", "($x)"), ("PCA2", "($y)"), ("NAME", "(@N)"), ]) p = figure(title="CHEMICAL SPACE BY MORGAN2 FP", x_axis_label="PC 1 " + "(" + str(a) + "%)", y_axis_label="PC 2 " + "(" + str(b) + "%)", x_range=(-7, 7), y_range=(-7, 7), tools=[hover], plot_width=1000, plot_height=800) FDA_plot = p.circle(x="x", y="y", source=source1, color="darkslateblue", size=5) PPI_plot = p.circle(x="x", y="y", source=source2, color="yellowgreen", size=5) MACRO_plot = p.circle(x="x", y="y", source=source3, color="lightsteelblue", size=5) NP_plot = p.circle(x="x", y="y", source=source4, color="olive", size=5) PEP_FDA_plot = p.circle(x="x", y="y", source=source5, color="darkslategray", size=5) LIN_plot = p.circle(x="x", y="y", source=source6, color="aquamarine", size=5) LIN_NM_plot = p.circle(x="x", y="y", source=source7, color="teal", size=5) CYC_plot = p.circle(x="x", y="y", source=source8, color="lightpink", size=5) CYC_NM_plot = p.circle(x="x", y="y", source=source9, color="mediumvioletred", size=5) p.add_tools(LassoSelectTool(), ZoomInTool(), ZoomOutTool(), SaveTool(), PanTool()) legend = Legend(items=[ ("FDA", [FDA_plot]), ("PPI", [PPI_plot]), ("MACRO", [MACRO_plot]), ("NP", [NP_plot]), ("PEP FDA", [PEP_FDA_plot]), ("LIN", [LIN_plot]), ("LIN NM", [LIN_NM_plot]), ("CYC", [CYC_plot]), ("CYC NM", [CYC_NM_plot]), ], location="center", orientation="vertical", click_policy="hide") p.add_layout(legend, place='right') p.xaxis.axis_label_text_font_size = "20pt" p.yaxis.axis_label_text_font_size = "20pt" p.xaxis.axis_label_text_color = "black" p.yaxis.axis_label_text_color = "black" p.xaxis.major_label_text_font_size = "18pt" p.yaxis.major_label_text_font_size = "18pt" p.title.text_font_size = "22pt" return p
def xrayvis_app(doc): def load_wav_cb(attr, old, new): '''Handle selection of audio file to be loaded.''' if new == '': return global wavname global snd spkr, fname = os.path.split(new) wavname = get_cached_fname( fname, f'https://linguistics.berkeley.edu/phonapps/xray_microbeam_database/{spkr}', spkr) # wavname = new if not wavname.endswith('.wav'): return snd = parselmouth.Sound(wavname) srcdf = pd.DataFrame( dict( seconds=snd.ts().astype(np.float32), ch0=snd.values[0, :].astype(np.float32), )) #! TODO: do file caching phdf = allphdf.loc[allphdf.wavpath == new, :].copy() phdf['t1'] = phdf['t1'].astype(np.float32) wddf = allwddf.loc[allwddf.wavpath == new, :].copy() wddf['t1'] = wddf['t1'].astype(np.float32) uttdiv.text = '<b>Utterance:</b> ' + ' '.join( wddf.word.str.replace('sp', '')).strip() phwddf = pd.merge_asof(phdf[['t1', 'phone']], wddf[['t1', 'word']], on='t1', suffixes=['_ph', '_wd']) # TODO: separate t1_ph and t1_wd columns srcdf = pd.merge_asof(srcdf, phwddf, left_on='seconds', right_on='t1') srcdf[['phone', 'word']] = srcdf[['phone', 'word']].fillna('') srcdf = srcdf.drop('t1', axis='columns') dfs['srcdf'] = srcdf source.data = srcdf tngsource.data = {'x': [], 'y': []} othsource.data = {'x': [], 'y': []} timesource.data = {k: [] for k in timesource.data.keys()} lasttngtimesource.data = {'x': [], 'y': []} lastothtimesource.data = {'x': [], 'y': []} playvisbtn.channels = channels playvisbtn.disabled = False playselbtn.channels = channels playselbtn.disabled = False playvisbtn.fs = snd.sampling_frequency playvisbtn.start = snd.start_time playvisbtn.end = snd.end_time playselbtn.fs = snd.sampling_frequency playselbtn.start = 0.0 playselbtn.end = 0.0 selbox.left = 0.0 selbox.right = 0.0 selbox.visible = False cursor.location = 0.0 cursor.visible = False ch0.visible = True update_sgram() load_artic() set_limits(0.0, srcdf['seconds'].max()) def load_artic(): '''Load articulation data.''' trace.title.text = 'Static trace' traj.title.text = 'Trajectories' tngfile = os.path.splitext(wavname)[0] + '.txy' palfile = os.path.join(os.path.dirname(wavname), 'PAL.DAT') phafile = os.path.join(os.path.dirname(wavname), 'PHA.DAT') tngdf = pd.read_csv(tngfile, sep='\t', names=[ 'sec', 'ULx', 'ULy', 'LLx', 'LLy', 'T1x', 'T1y', 'T2x', 'T2y', 'T3x', 'T3y', 'T4x', 'T4y', 'MIx', 'MIy', 'MMx', 'MMy' ]) # Convert to seconds tngdf['sec'] = tngdf['sec'] / 1e6 tngdf = tngdf.set_index(['sec']) # Convert to mm tngdf[[ 'ULx', 'ULy', 'LLx', 'LLy', 'T1x', 'T1y', 'T2x', 'T2y', 'T3x', 'T3y', 'T4x', 'T4y', 'MIx', 'MIy', 'MMx', 'MMy' ]] = tngdf[[ 'ULx', 'ULy', 'LLx', 'LLy', 'T1x', 'T1y', 'T2x', 'T2y', 'T3x', 'T3y', 'T4x', 'T4y', 'MIx', 'MIy', 'MMx', 'MMy' ]] * 1e-3 # Find global x/y max/min in this recording to set axis limits. # Exclude bad values (1000000 in data file; 1000 mm in scaled dataframe). cmpdf = tngdf[tngdf < badval] xmax = np.max( np.max( cmpdf[['ULx', 'LLx', 'T1x', 'T2x', 'T3x', 'T4x', 'MIx', 'MMx']])) xmin = np.min( np.min( cmpdf[['ULx', 'LLx', 'T1x', 'T2x', 'T3x', 'T4x', 'MIx', 'MMx']])) ymax = np.max( np.max( cmpdf[['ULy', 'LLy', 'T1y', 'T2y', 'T3y', 'T4y', 'MIy', 'MMy']])) ymin = np.min( np.min( cmpdf[['ULy', 'LLy', 'T1y', 'T2y', 'T3y', 'T4y', 'MIy', 'MMy']])) paldf = pd.read_csv(palfile, sep='\s+', header=None, names=['x', 'y']) paldf = paldf * 1e-3 palsource.data = {'x': paldf['x'], 'y': paldf['y']} phadf = pd.read_csv(phafile, sep='\s+', header=None, names=['x', 'y']) phadf = phadf * 1e-3 phasource.data = {'x': phadf['x'], 'y': phadf['y']} xmin = np.min([xmin, np.min(paldf['x']), np.min(phadf['x'])]) xmax = np.max([xmax, np.max(paldf['x']), np.max(phadf['x'])]) ymin = np.min([ymin, np.min(paldf['y']), np.min(phadf['y'])]) ymax = np.max([ymax, np.max(paldf['y']), np.max(phadf['y'])]) xsz = xmax - xmin ysz = ymax - ymin xrng = [xmin - (xsz * 0.05), xmax + (xsz * 0.05)] yrng = [ymin - (ysz * 0.05), ymax + (ysz * 0.05)] dfs['tngdf'] = tngdf dfs['paldf'] = paldf dfs['phadf'] = phadf def update_sgram(): '''Update spectrogram based on current values.''' if snd.end_time < 15: sgrams[0] = snd2specgram(snd, 0.005) specsource.data = dict( sgram0=[sgrams[0].values.astype(np.float32)]) spec0img.glyph.dw = sgrams[0].x_grid().max() spec0img.glyph.dh = sgrams[0].y_grid().max() spec0cmap.low = _low_thresh() spec0.visible = True else: specsource.data = dict(sgram0=[]) spec0.visible = False def update_trace(): '''Update the static trace at the cursor time.''' trace.title.text = f'Static trace ({cursor.location:0.4f})' tidx = dfs['tngdf'].index.get_loc(cursor.location, method='nearest') row = dfs['tngdf'].iloc[tidx] tngsource.data = { 'x': [row.T1x, row.T2x, row.T3x, row.T4x], 'y': [row.T1y, row.T2y, row.T3y, row.T4y] } othsource.data = { 'x': [row.ULx, row.LLx, row.MIx, row.MMx], 'y': [row.ULy, row.LLy, row.MIy, row.MMy] } def update_traj(): '''Update the trajectories during the selected time range.''' traj.title.text = f'Trajectories ({selbox.left:0.4f} - {selbox.right:0.4f})' seldf = dfs['tngdf'].loc[(dfs['tngdf'].index >= selbox.left) & (dfs['tngdf'].index <= selbox.right)] dfs['seldf'] = seldf pts = ('T1x', 'T1y', 'T2x', 'T2y', 'T3x', 'T3y', 'T4x', 'T4y', 'ULx', 'ULy', 'LLx', 'LLy', 'MIx', 'MIy', 'MMx', 'MMy') # Create a list of line segments for each tracked element. newdata = { pt: list(np.squeeze(np.dstack((seldf[pt].iloc[:-1], seldf[pt].iloc[1:])))) \ for pt in pts } newdata['color'] = np.arange(1, len(seldf)) newdata['sec'] = seldf.index[1:] timesource.data = newdata anim_slider.start = seldf.index[0] anim_slider.end = seldf.index[-1] anim_slider.step = np.diff(newdata['sec']).mean() anim_slider.value = anim_slider.end anim_slider.disabled = False anim_btn.disabled = False lastrow = seldf.iloc[-1] lasttngtimesource.data = { 'x': [lastrow.T1x, lastrow.T2x, lastrow.T3x, lastrow.T4x], 'y': [lastrow.T1y, lastrow.T2y, lastrow.T3y, lastrow.T4y] } lastothtimesource.data = { 'x': [lastrow.ULx, lastrow.LLx, lastrow.MIx, lastrow.MMx], 'y': [lastrow.ULy, lastrow.LLy, lastrow.MIy, lastrow.MMy] } # TODO: this is a workaround until we can set x_range, y_range directly # See https://github.com/bokeh/bokeh/issues/4014 def set_limits(xstart, xend): '''Set axis limits.''' ch0.x_range.start = xstart ch0.x_range.end = xend ch0.axis[0].bounds = (xstart, xend) def update_select_widgets(clicked_x=None): '''Update widgets based on current selection. Use the clicked_x param to designate the cursor location if this function is called as the result of a Tap event. If clicked_x is None, then use the existing cursor location to set the center of the selection.''' mode = selmodebtn.labels[selmodebtn.active] if clicked_x is None and cursor.visible: x_loc = cursor.location elif clicked_x is not None: x_loc = clicked_x else: return if mode == '200ms': start = x_loc - 0.100 end = x_loc + 0.100 cursor.location = x_loc else: # 'word' or 'phone' idx = np.abs(source.data['seconds'] - x_loc).argmin() # TODO: clean up the redundancy fld = {'word': 'word', 'phone': 'phone'}[mode] label = source.data[fld][idx] indexes = nonzero_groups(source.data[fld] == label, include_any=idx) secs = source.data['seconds'][indexes] start = secs.min() end = secs.max() cursor.location = secs.mean() playselbtn.start = start playselbtn.end = end selbox.left = start selbox.right = end selbox.visible = True cursor.visible = True def spkr_select_cb(attr, old, new): '''Respond to changes in speaker multiselect.''' try: spkrs = demo[ (demo.sex.isin(sex_select.value) \ & demo.dialect_base_state.isin(state_select.value) \ & (demo.dialect_base_city.isin(city_select.value))) ].subject.unique() new_opts = [''] + [(f.value, f.label) for f in fileoptsdf[ fileoptsdf.speaker.isin(spkrs)].itertuples()] fselect.options = new_opts fselect.value = '' except NameError as e: pass # Values not set yet, so ignore def cursor_cb(e): '''Handle cursor mouse click in the waveform.''' update_select_widgets(clicked_x=e.x) update_trace() update_traj() def x_range_cb(attr, old, new): '''Handle change of x range in waveform/spectrogram.''' if attr == 'start': playvisbtn.start = new elif attr == 'end': playvisbtn.end = new def selection_cb(e): '''Handle data range selection event.''' #! TODO: handle situation in which selection is too short, i.e. len(seldf) <= 1 cursor.location = (e.geometry['x0'] + e.geometry['x1']) / 2 cursor.visible = True playselbtn.start = e.geometry['x0'] playselbtn.end = e.geometry['x1'] selbox.left = e.geometry['x0'] selbox.right = e.geometry['x1'] selbox.visible = True update_trace() update_traj() def selmode_cb(attr, old, new): '''Handle change in click selection value.''' update_select_widgets(clicked_x=None) def anim_cb(attr, old, new): '''Handle change in the animation slider.''' idx = np.argmin(np.abs(timesource.data['sec'] - new)) n = len(timesource.data['color']) active = np.arange(n - idx, n + 1) timesource.data['color'] = np.pad(active, (0, n - len(active)), constant_values=0) anim_cmap = LinearColorMapper(palette=r_Greys256, low=1, high=n + 1, low_color='white') for tag, palette in (('anim_tng', r_Reds9), ('anim_oth', r_Greens9)): for a in find(traj.references(), {'tags': tag}): a.line_color = linear_cmap('color', palette, low=1, high=n + 1, low_color='white') lasttngtimesource.data = { 'x': [ timesource.data[pt][idx][1] for pt in ('T1x', 'T2x', 'T3x', 'T4x') ], 'y': [ timesource.data[pt][idx][1] for pt in ('T1y', 'T2y', 'T3y', 'T4y') ] } lastothtimesource.data = { 'x': [ timesource.data[pt][idx][1] for pt in ('ULx', 'LLx', 'MIx', 'MMx') ], 'y': [ timesource.data[pt][idx][1] for pt in ('ULy', 'LLy', 'MIy', 'MMy') ] } def anim_btn_cb(): '''Handle click of anim_btn animate trajectories of selected audio.''' values = np.linspace(anim_slider.start, anim_slider.end, len(timesource.data['T1x'])) for v in values: anim_slider.value = v def low_thresh_cb(attr, old, new): '''Handle change in threshold slider to fade out low spectrogram values.''' params['low_thresh_power'] = new lt = _low_thresh() spec0cmap.low = lt def _low_thresh(): return sgrams[0].values.min() \ + sgrams[0].values.std()**params['low_thresh_power'] step = None rate = orig_rate = None # dfs = {} xrng = [] yrng = [] width = 1000 height = 200 cutoff = 50 order = 3 tngcolor = 'DarkRed' othcolor = 'Indigo' fselect = Select(options=[], value='') fselect.on_change('value', load_wav_cb) sex_select = MultiSelect(options=[('F', 'female'), ('M', 'male')], value=['F', 'M']) state_select = MultiSelect( options=list(demo.dialect_base_state.cat.categories), value=list(demo.dialect_base_state.cat.categories)) city_select = MultiSelect( options=list(demo.dialect_base_city.cat.categories), value=list(demo.dialect_base_city.cat.categories)) sex_select.on_change('value', spkr_select_cb) state_select.on_change('value', spkr_select_cb) city_select.on_change('value', spkr_select_cb) spkr_select_cb('', '', '') source = ColumnDataSource(data=dict(seconds=[], ch0=[])) channels = ['ch0'] playvisbtn = AudioButton(label='Play visible signal', source=source, channels=channels, width=120, disabled=True) playselbtn = AudioButton(label='Play selected signal', source=source, channels=channels, width=120, disabled=True) selmodebtn = RadioButtonGroup(labels=['200ms', 'word', 'phone'], active=1) selmodebtn.on_change('active', selmode_cb) # Instantiate and share specific select/zoom tools so that # highlighting is synchronized on all plots. boxsel = BoxSelectTool(dimensions='width') spboxsel = BoxSelectTool(dimensions='width') boxzoom = BoxZoomTool(dimensions='width') zoomin = ZoomInTool(dimensions='width') zoomout = ZoomOutTool(dimensions='width') crosshair = CrosshairTool(dimensions='height') shared_tools = [ 'xpan', boxzoom, boxsel, crosshair, zoomin, zoomout, 'reset' ] uttdiv = Div(text='') figargs = dict(tools=shared_tools, ) cursor = Span(dimension='height', line_color='red', line_dash='dashed', line_width=1) wavspec_height = 280 ch0 = figure(name='ch0', tooltips=[('time', '$x{0.0000}'), ('word', '@word'), ('phone', '@phone')], height=wavspec_height, **figargs) ch0.toolbar.logo = None ch0.line(x='seconds', y='ch0', source=source, nonselection_line_alpha=0.6) # Link pan, zoom events for plots with x_range. ch0.x_range.on_change('start', x_range_cb) ch0.x_range.on_change('end', x_range_cb) ch0.on_event(SelectionGeometry, selection_cb) ch0.on_event(Tap, cursor_cb) ch0.add_layout(cursor) wavtab = Panel(child=ch0, title='Waveform') selbox = BoxAnnotation(name='selbox', left=None, right=None, fill_color='green', fill_alpha=0.1, line_color='green', line_width=1.5, line_dash='dashed', visible=False) ch0.add_layout(selbox) sgrams = [np.ones((1, 1))] specsource = ColumnDataSource(data=dict(sgram0=[sgrams[0]])) spec0 = figure( name='spec0', x_range=ch0.x_range, # Keep times synchronized tooltips=[("time", "$x{0.0000}"), ("freq", "$y{0.0000}"), ("value", "@sgram0{0.000000}")], height=wavspec_height, **figargs) spec0.toolbar.logo = None spec0.x_range.on_change('start', x_range_cb) spec0.x_range.on_change('end', x_range_cb) spec0.on_event(SelectionGeometry, selection_cb) spec0.on_event(Tap, cursor_cb) spec0.add_layout(cursor) spec0.x_range.range_padding = spec0.y_range.range_padding = 0 spec0cmap = LogColorMapper(palette=r_Greys256, low_color=params['low_thresh_color']) low_thresh_slider = Slider(start=1.0, end=12.0, step=0.03125, value=params['low_thresh_power'], title='Spectrogram threshold') low_thresh_slider.on_change('value', low_thresh_cb) spec0img = spec0.image(image='sgram0', x=0, y=0, color_mapper=spec0cmap, level='image', source=specsource) spec0.grid.grid_line_width = 0.0 spec0.add_layout(selbox) sgramtab = Panel(child=spec0, title='Spectrogram') tngsource = ColumnDataSource(data={'x': [], 'y': []}) othsource = ColumnDataSource(data={'x': [], 'y': []}) timesource = ColumnDataSource({ 'T1x': [], 'T1y': [], 'T2x': [], 'T2y': [], 'T3x': [], 'T3y': [], 'T4x': [], 'T4y': [], 'ULx': [], 'ULy': [], 'LLx': [], 'LLy': [], 'MIx': [], 'MIy': [], 'MMx': [], 'MMy': [], 'color': [], 'sec': [] }) lasttngtimesource = ColumnDataSource(data={'x': [], 'y': []}) lastothtimesource = ColumnDataSource(data={'x': [], 'y': []}) palsource = ColumnDataSource(pd.DataFrame({'x': [], 'y': []})) phasource = ColumnDataSource(pd.DataFrame({'x': [], 'y': []})) trace = figure(width=500, height=300, title='Static trace', x_range=(-100.0, 25.0), y_range=(-37.650, 37.650), tools=[], tags=['xray', 'static_fig']) trace.toolbar.logo = None trace.circle('x', 'y', source=tngsource, size=3, color=tngcolor, tags=['update_xray']) trace.circle('x', 'y', source=othsource, size=3, color=othcolor, tags=['update_xray']) trace.line('x', 'y', source=tngsource, color=tngcolor, tags=['update_xray']) trace.line('x', 'y', source=palsource, color='black') trace.line('x', 'y', source=phasource, color='black') traj = figure(width=500, height=300, title='Trajectories', x_range=(-100.0, 25.0), y_range=(-37.650, 37.650), tools=[], tags=['xray', 'trajectory_fig']) traj.toolbar.logo = None traj.multi_line('T1x', 'T1y', source=timesource, tags=['anim_tng']) traj.multi_line('T2x', 'T2y', source=timesource, tags=['anim_tng']) traj.multi_line('T3x', 'T3y', source=timesource, tags=['anim_tng']) traj.multi_line('T4x', 'T4y', source=timesource, tags=['anim_tng']) traj.multi_line('ULx', 'ULy', source=timesource, tags=['anim_oth']) traj.multi_line('LLx', 'LLy', source=timesource, tags=['anim_oth']) traj.multi_line('MIx', 'MIy', source=timesource, tags=['anim_oth']) traj.multi_line('MMx', 'MMy', source=timesource, tags=['anim_oth']) traj.circle('x', 'y', source=lasttngtimesource, color=tngcolor) traj.circle('x', 'y', source=lastothtimesource, color=othcolor) traj.line('x', 'y', source=lasttngtimesource, color='lightgray') traj.line('x', 'y', source=palsource, color='black') traj.line('x', 'y', source=phasource, color='black') anim_slider = Slider(start=0, end=100, step=1, value=0, width=240, format='0.000f', title='Selected trajectory', orientation='horizontal', disabled=True) anim_slider.on_change('value', anim_cb) anim_btn = Button(label='Animate', width=120, disabled=True) anim_btn.on_click(anim_btn_cb) audtabs = Tabs(tabs=[wavtab, sgramtab]) mainLayout = column( row(sex_select, state_select, city_select), row(fselect), row( column(uttdiv, audtabs), column( #! row(anim_slider, anim_btn), column(Div(text='Click selection mode:'), selmodebtn, low_thresh_slider), row(playvisbtn, playselbtn))), row(trace, traj), name='mainLayout') doc.add_root(mainLayout) return doc