def test_CategoricalColorMapper(): mapper = CategoricalColorMapper() check_properties_existence(mapper, [ "factors", "palette", "nan_color"], )
def get_color_mapper(column, df, palette='Viridis256'): ''' Return a color mapper instace for a given category or continuous properties Args: column : str name of the color that should be color mapped df : pandas.DataFrame data frame ''' cmaps = { 'block': 'Set1_4', 'period': 'Dark2_7', 'name_series': 'Spectral10', 'group_name': viridis(18), 'is_radioactive': d3['Category10'][4][2:], 'is_monoisotopic': d3['Category10'][4][2:], 'goldschmidt_class': 'Set2_4', 'geochemical_class': d3['Category10'][10], } if column in cmaps.keys(): factors = list(df[column].unique()) if any(x is None for x in factors): factors = sorted([x for x in factors if x is not None]) + [None] elif column == 'group_name': factors = [ str(x) for x in sorted(int(s) for s in factors if s != 'f block') ] + ['f block'] else: factors = sorted(factors) ccm = CategoricalColorMapper(palette=cmaps[column], factors=factors, nan_color='#ffffff') elif column == 'value': if df[column].skew() > SKEW_THRS: ccm = LogColorMapper(palette=palette, low=df[column].min(), high=df[column].max(), nan_color='#ffffff') else: ccm = LinearColorMapper(palette=palette, low=df[column].min(), high=df[column].max(), nan_color='#ffffff') else: ccm = None return ccm
def test_categorical_color_mapper_with_pandas_index(pd): fruits = ['Apples', 'Pears', 'Nectarines', 'Plums', 'Grapes', 'Strawberries'] years = ['2015', '2016', '2017'] data = {'2015' : [2, 1, 4, 3, 2, 4], '2016' : [5, 3, 3, 2, 4, 6], '2017' : [3, 2, 4, 4, 5, 3]} df = pd.DataFrame(data, index=fruits) fruits = df.index years = df.columns m = CategoricalColorMapper(palette=Spectral6, factors=years, start=1, end=2) assert list(m.factors) == list(years) assert isinstance(m.factors, pd.Index)
def build_viz_withparam(df, filterBird='LIAK11EG12'): #print(filterState) gps = getArtox_gps_data() ## filter the dataset to keep only ports of the given state if (filterBird!='LIAK11EG12') : if (filterBird=='Unknown') : df = df[df.bird_id.isnull() ] else : df = df[df.bird_id.eq(filterBird) ] ## Build the map p = figure(x_range=(-9587947, 1113194), y_range=(3503549, 13195489), x_axis_type="mercator", y_axis_type="mercator") tile_provider = get_provider(CARTODBPOSITRON) p.add_tile(tile_provider) msource = ColumnDataSource(df) # https://docs.bokeh.org/en/latest/docs/reference/palettes.html color_mapper = CategoricalColorMapper(palette=["blue", "pink"], factors=["M", "F"]) ## Filter GPS data with the choosen bird gpsnumber = df.loc[df['bird_id']==filterBird, 'clean_glsid'].values[0] gpsnumber #'148' msourceGPS = ColumnDataSource(gps.loc[gps['id']==gpsnumber,]) #process the time dimension thisbirdtimes = gps.loc[gps['id']==gpsnumber, 'timestampgps'].values thisbirdtimes = pd.to_datetime(thisbirdtimes) #transform string into datetime type #First solution for points color : time on a continuous scale t = np.array([xi.timestamp() for xi in thisbirdtimes]) #transform datetime into float type msourceGPS.add(t, 'timeasreal') point_mapper = linear_cmap(field_name='timeasreal', palette=GnBu[9], low=min(t), high=max(t)) #OK for time on a continuous scale, you can also use the palette PiYG11 ## Afficher les coordonnées GPS de cet oiseau #https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.loc.html #p.line(df.iloc[3, 2], df.iloc[3, 3], color='red', line_width=2) p.line(df.loc[df['bird_id']==filterBird, 'x_path_coordinates'].values[0], df.loc[df['bird_id']==filterBird, 'y_path_coordinates'].values[0], color='red', line_width=1) p.circle(x='x', y='y', size=7, source=msourceGPS, fill_color=point_mapper, fill_alpha=1, line_alpha=0) return p
def make_barplot(species, xaxis, dic_yaxis, dic_yaxis_pvalues, what, x_range, width, end_title): colors = ["#75968f", "#dfccce", "#550b1d"] #colors=brewer['RdYlBu'][3] title = '{} on {} {}'.format(what, species, end_title) pvalues_factor = copy.deepcopy(dic_yaxis_pvalues[species]) # Transform pvalues in categorical data for color range for i in range(0, len(dic_yaxis_pvalues[species])): if dic_yaxis_pvalues[species][i] < 0.025: pvalues_factor[i] = 'lower' elif dic_yaxis_pvalues[species][i] > 0.975: pvalues_factor[i] = 'higher' else: pvalues_factor[i] = 'unsignificant' # Color range mapper mapper = CategoricalColorMapper( palette=colors, factors=['lower', 'unsignificant', 'higher']) p = figure(x_range=x_range[end_title], plot_width=width, plot_height=350, toolbar_location=None, title=title) if end_title == 'codons': p.xaxis.major_label_orientation = pi / 3 source = ColumnDataSource( data=dict(what=xaxis, counts=dic_yaxis[species], label=pvalues_factor)) r1 = p.vbar(x='what', top='counts', width=0.9, source=source, line_color='white', color={ 'field': 'label', 'transform': mapper }, legend='label') p.legend.orientation = 'horizontal' p.legend.location = 'top_right' export_png(p, filename='{}.png'.format(title.replace(" ", "_")))
def get_color_mapper(column, df, palette="Viridis256"): """ Return a color mapper instace for a given category or continuous properties Args: column : str name of the color that should be color mapped df : pandas.DataFrame data frame """ cmaps = { "block": "Set1_4", "period": "Dark2_7", "name_series": "Spectral10", "group_name": viridis(18), "is_radioactive": d3["Category10"][4][2:], "is_monoisotopic": d3["Category10"][4][2:], "goldschmidt_class": "Set2_4", "geochemical_class": d3["Category10"][10], } if column in cmaps.keys(): factors = list(df[column].unique()) if any(x is None for x in factors): factors = sorted([x for x in factors if x is not None]) + [None] elif column == "group_name": factors = [str(x) for x in sorted(int(s) for s in factors if s != "f block")] + ["f block"] else: factors = sorted(factors) ccm = CategoricalColorMapper(palette=cmaps[column], factors=factors, nan_color="#ffffff") elif column == "value": if df[column].skew() > SKEW_THRS: ccm = LogColorMapper(palette=palette, low=df[column].min(), high=df[column].max(), nan_color="#ffffff") else: ccm = LinearColorMapper(palette=palette, low=df[column].min(), high=df[column].max(), nan_color="#ffffff") else: ccm = None return ccm
def _create_mapper(adata, key): """ Helper function to create CategoricalColorMapper from annotated data. Params -------- adata: AnnData annotated data object key: str key in `adata.obs.obs_keys()` or `adata.var_names`, for which we want the colors; if no colors for given column are found in `adata.uns[key_colors]`, use `viridis` palette Returns -------- mapper: bokeh.models.mappers.CategoricalColorMapper mapper which maps valuems from `adata.obs[key]` to colors """ if not key in adata.obs_keys(): assert key in adata.var_names, f'`{key}` not found in `adata.obs_keys()` or `adata.var_names`' ix = np.where(adata.var_names == key)[0][0] vals = list(adata.X[:, ix]) palette = cm.get_cmap('viridis', adata.n_obs) mapper = dict(zip(vals, range(len(vals)))) palette = to_hex_palette(palette([mapper[v] for v in vals])) return LinearColorMapper(palette=palette, low=np.min(vals), high=np.max(vals)) is_categorical = adata.obs[key].dtype.name == 'category' default_palette = cm.get_cmap('viridis', adata.n_obs if not is_categorical else len(adata.obs[key].unique())) palette = adata.uns.get(f'{key}_colors', default_palette) if palette is default_palette: vals = adata.obs[key].unique() if is_categorical else adata.obs[key] mapper = dict(zip(vals, range(len(vals)))) palette = palette([mapper[v] for v in vals]) palette = to_hex_palette(palette) if is_categorical: return CategoricalColorMapper(palette=palette, factors=list(map(str, adata.obs[key].cat.categories))) return LinearColorMapper(palette=palette, low=np.min(adata.obs[key]), high=np.max(adata.obs[key]))
def _create_mapper(adata, key): """ Helper function to create CategoricalColorMapper from annotated data. Params -------- adata: AnnData annotated data object key: str key in `adata.obs.obs_keys()`, for which we want the colors; if no colors for given column are found in `adata.uns[key_colors]`, use Viridis palette Returns -------- mapper: bokeh.models.mappers.CategoricalColorMapper mapper which maps valuems from `adata.obs[key]` to colors """ # TODO: # plate colors return float palette = adata.uns.get(f'{key}_colors', viridis(len(adata.obs[key].unique()))) key_col = adata.obs[key].astype('category') if adata.obs[key].dtype.name != 'category' else adata.obs[key] return CategoricalColorMapper(palette=palette, factors=list(map(str, key_col.cat.categories)))
def factor_cmap(field_name, palette, factors, start=0, end=None, nan_color="gray"): ''' Create a ``DataSpec`` dict to apply a client-side ``CategoricalColorMapper`` transformation to a ``ColumnDataSource`` column. Args: field_name (str) : a field name to configure ``DataSpec`` with palette (seq[color]) : a list of colors to use for colormapping factors (seq) : a sequences of categorical factors corresponding to the palette start (int, optional) : a start slice index to apply when the column data has factors with multiple levels. (default: 0) end (int, optional) : an end slice index to apply when the column data has factors with multiple levels. (default: None) nan_color (color, optional) : a default color to use when mapping data from a column does not succeed (default: "gray") Returns: dict ''' return field( field_name, CategoricalColorMapper(palette=palette, factors=factors, start=start, end=end, nan_color=nan_color))
def test_no_warning_if_categorical_color_mapper_with_long_palette(recwarn): CategoricalColorMapper(factors=["a", "b", "c"], palette=["red", "green", "orange", "blue"]) assert len(recwarn) == 0
def test_warning_if_categorical_color_mapper_with_short_palette(recwarn): CategoricalColorMapper(factors=["a", "b", "c"], palette=["red", "green"]) assert len(recwarn) == 1
map_options=map_options, sizing_mode='stretch_both', tools=[hover, tap, zoom, pan]) plot.title.text = "VirtualDive" plot.title.text_font_size = "25px" plot.title_location = "right" plot.title.align = "right" plot.api_key = "AIzaSyAX0RhQ5JTdQAjveEADHzBXbxkVLYCiPps" #color_mapper = CategoricalColorMapper(factors=['hi', 'lo'], palette=[RdBu3[2], RdBu3[0]]) #color_mapper = LogColorMapper(palette="Viridis5", low=min_median_house_value, high=max_median_house_value) paletteinvert = palette[::-1] color_mapper = CategoricalColorMapper(palette=["magenta", "cyan"], factors=['No', 'Yes']) color_mapper2 = LogColorMapper(palette=fire) protectedannulus = Annulus(x="lon", y="lat", inner_radius=4000, outer_radius=7000, fill_color="cyan", fill_alpha=0.3, line_color=None) unprotectedannulus = Annulus(x="lon", y="lat", inner_radius=4000, outer_radius=7000, fill_color={
# Ranges matches this bbox in long/lat (-86.13, 30) (10, 75.6) # select st_setsrid(st_transform(st_setsrid(st_makebox2d(st_point(-86.13, 30), st_point(10, 75.6)), 4326), 3857), 3857) # expected an element of either String or List(Tuple(String, String)) # range bounds supplied in Web mercator coordinates p = figure(x_range=(-9587947, 1113194), y_range=(3503549, 13195489), x_axis_type="mercator", y_axis_type="mercator") tile_provider = get_provider(CARTODBPOSITRON) p.add_tile(tile_provider) msource = ColumnDataSource(df) color_mapper = CategoricalColorMapper(palette=["blue", "pink"], factors=["M", "F"]) #p.multi_line(df.iloc[0:1, 2], df.iloc[0:1, 3], color='blue', line_width=1) p.multi_line('x_path_coordinates', 'y_path_coordinates', source=msource, color={ 'field': 'sex', 'transform': color_mapper }, line_width=1) #p.line(df.iloc[3, 2], df.iloc[3, 3], color='red', line_width=2) p.line(df.loc[df['bird_id'] == 'LIAK11EG12', 'x_path_coordinates'].values[0], df.loc[df['bird_id'] == 'LIAK11EG12', 'y_path_coordinates'].values[0], color='red',
def thresholding_hist(adata, key, categories, basis=['umap'], components=[1, 2], bins='auto', palette=None, legend_loc='top_right', plot_width=None, plot_height=None, save=None): """Histogram with the option to highlight categories based on thresholding binned values. Params -------- adata: AnnData object annotated data object key: str key in `adata.obs_keys()` where the data is stored categories: dict dictionary with keys corresponding to group names and values to starting boundaries `[min, max]` basis: list, optional (default: `['umap']`) basis in `adata.obsm_keys()` to visualize components: list(int); list(list(int)), optional (default: `[1, 2]`) components to use for each basis bins: int; str, optional (default: `auto`) number of bins used for initial binning or a string key used in from numpy.histogram palette: list(str), optional (default: `None`) palette to use for coloring categories legend_loc: str, default(`'top_right'`) position of the legend plot_width: int, optional (default: `None`) width of the plot plot_height: int, optional (default: `None`) height of the plot save: Union[os.PathLike, Str, NoneType], optional (default: `None`) path where to save the plot Returns -------- None """ if not isinstance(components[0], list): components = [components] if len(components) != len(basis): assert len(basis) % len(components) == 0 and len(basis) >= len(components) components = components * (len(basis) // len(components)) if not isinstance(components, np.ndarray): components = np.asarray(components) if not isinstance(basis, list): basis = [basis] palette = Set1[9] + Set2[8] + Set3[12] if palette is None else palette hist_fig = figure() _set_plot_wh(hist_fig, plot_width, plot_height) hist_fig.xaxis.axis_label = key hist_fig.yaxis.axis_label = 'normalized frequency' hist, edges = np.histogram(adata.obs[key], density=True, bins=bins) source = ColumnDataSource(data=dict(hist=hist, l_edges=edges[:-1], r_edges=edges[1:], category=['default'] * len(hist), indices=[[]] * len(hist))) df = pd.concat([pd.DataFrame(adata.obsm[f'X_{bs}'][:, comp - (bs != 'diffmap')], columns=[f'x_{bs}', f'y_{bs}']) for bs, comp in zip(basis, components)], axis=1) df['values'] = list(adata.obs[key]) df['category'] = 'default' df['visible_category'] = 'default' df['cat_stack'] = [['default']] * len(df) orig = ColumnDataSource(df) color = dict(field='category', transform=CategoricalColorMapper(palette=palette, factors=list(categories.keys()))) hist_fig.quad(source=source, top='hist', bottom=0, left='l_edges', right='r_edges', color=color, line_color="#555555", legend_group='category') if legend_loc is not None: hist_fig.legend.location = legend_loc emb_figs = [] for bs, comp in zip(basis, components): fig = figure(title=bs) fig.xaxis.axis_label = f'{bs}_{comp[0]}' fig.yaxis.axis_label = f'{bs}_{comp[1]}' _set_plot_wh(fig, plot_width, plot_height) fig.scatter(f'x_{bs}', f'y_{bs}', source=orig, size=10, color=color, legend_group='category') if legend_loc is not None: fig.legend.location = legend_loc emb_figs.append(fig) inputs, category_cbs = [], [] code_start, code_mid, code_thresh = [], [], [] args = {'source': source, 'orig': orig} for col, cat_item in zip(palette, categories.items()): cat, (start, end) = cat_item inp_min = TextInput(name='test', value=f'{start}', title=f'{cat}/min') inp_max = TextInput(name='test', value=f'{end}', title=f'{cat}/max') code_start.append(f''' var min_{cat} = parseFloat(inp_min_{cat}.value); var max_{cat} = parseFloat(inp_max_{cat}.value); ''') code_mid.append(f''' var mid_{cat} = (source.data['r_edges'][i] - source.data['l_edges'][i]) / 2; ''') code_thresh.append(f''' if (source.data['l_edges'][i] + mid_{cat} >= min_{cat} && source.data['r_edges'][i] - mid_{cat} <= max_{cat}) {{ source.data['category'][i] = '{cat}'; for (var j = 0; j < source.data['indices'][i].length; j++) {{ var ix = source.data['indices'][i][j]; orig.data['category'][ix] = '{cat}'; }} }} ''') args[f'inp_min_{cat}'] = inp_min args[f'inp_max_{cat}'] = inp_max min_ds = ColumnDataSource(dict(xs=[start] * 2)) max_ds = ColumnDataSource(dict(xs=[end] * 2)) inputs.extend([inp_min, inp_max]) code_thresh.append( ''' { source.data['category'][i] = 'default'; for (var j = 0; j < source.data['indices'][i].length; j++) { var ix = source.data['indices'][i][j]; orig.data['category'][ix] = 'default'; } } ''') callback = CustomJS(args=args, code=f''' {';'.join(code_start)} for (var i = 0; i < source.data['hist'].length; i++) {{ {';'.join(code_mid)} {' else '.join(code_thresh)} }} orig.change.emit(); source.change.emit(); ''') for input in inputs: input.js_on_change('value', callback) slider = Slider(start=1, end=100, value=len(hist), title='Bins') interactive_hist_cb = CustomJS(args={'source': source, 'orig': orig, 'bins': slider}, code=_inter_hist_js_code) slider.js_on_change('value', interactive_hist_cb, callback) plot = column(row(hist_fig, column(slider, *inputs)), *emb_figs) if save is not None: save = save if str(save).endswith('.html') else str(save) + '.html' bokeh_save(plot, save) else: show(plot)
HoverTool(tooltips=[('Employee Email:', '@Emails')], show_arrow=True, renderers=[p.select('stationary')[0]])) # create a reference circle p.circle(x=[0], y=[0], radius=circle_radius, fill_alpha=0.0, line_alpha=1.0, color='black') # create the arrows and hovertool layout ontop of multiline cat10_palette = bokeh.palettes.Category10[10] arrow_line_palette = [cat10_palette[3], cat10_palette[2]] # red and green arrow_mapper = CategoricalColorMapper(palette=arrow_line_palette, factors=['neg', 'pos']) p.add_layout( Arrow(end=VeeHead(size=10, fill_alpha=0.50, line_alpha=0.50, fill_color=cat10_palette[7]), source=source_arrows, x_start='x_from', y_start='y_from', x_end='x_to', y_end='y_to', line_alpha=0.50, line_color={ 'field': 'Sentiment', 'transform': arrow_mapper }))
def visualise(): # plot for mouse over view - "Images" button is off if toggle_val == False: # mouseover tool containing image and attribute hover = HoverTool(tooltips=""" <div> <div> <img src="@thumbs" alt="thumbs" style="float: left; marsquaregin: 0px 50px 15px 0px;" border="2" ></img> </div> <div> <span style="font-size: 12px; color: #966;">Index: $index</span> </div> <div> <span style="font-size: 12px; font-weight: bold;">@{imgs}</span> </div> <div> <span style="font-size: 12px; font-weight: bold;">ID: @{Patient ID}</span> </div> </div> """) # create figure with mouse over, lasso, tap, pan, and zoom tools tools = [ hover, 'box_zoom', 'pan', 'zoom_out', 'zoom_in', 'reset', 'tap', lasso ] p = figure(logo=None, tools=tools, title=PLOT_TITLE) # only run lasso tool callback after loop drawn p.select(LassoSelectTool).select_every_mousemove = False # map color based on col_cat selected cat_set = list(set(source.data[color_cat])) # group by value mapper = CategoricalColorMapper(palette=COLORS, factors=cat_set) # add circle plot with selected values p.circle(x=x_axis, y=y_axis, size=5, source=source, color={ 'field': color_cat, 'transform': mapper }) # if plot selection changex, run selection_callback() to update table source.on_change('selected', selection_callback) # plot for image glyph view - "Images" button is on else: # create figure with mouse over, lasso, tap, pan, and zoom tools tools = [ 'box_zoom', 'pan', 'zoom_out', 'zoom_in', 'reset', 'tap', lasso ] p = figure(logo=None, tools=tools, title=PLOT_TITLE) # add square - needed for tap tool callbacks p.square(x=x_axis, y=y_axis, size=25, source=source) # add image glyphs based using original image size p.image_url(x=x_axis, y=y_axis, url=THUMBS, h=None, w=None, source=source, anchor="center") # url = "http://127.0.0.1:5000/explore/00000013_005.png" url = "http://127.0.0.1:5000/explore/" + "default/" + "@{Image Index}" # create tap tool and connect to plot taptool = p.select(type=TapTool) # on click open new page with full-sized image taptool.callback = OpenURL(url=url) # return the complete plot with all tools p.plot_width = 1500 p.plot_height = 800 return p
#Create list of datasets to call sources = {} for x in range(2010, 2018): newdf = df_annual[df_annual['year'] <= x] sources['_{0}'.format(x)] = ColumnDataSource( data=dict(lat=newdf.lat.tolist(), lon=newdf.lon.tolist(), size=newdf.docks.tolist(), rate=newdf.year.tolist(), name=newdf.commonName.tolist())) #Map circle colors to years color_mapper = CategoricalColorMapper( factors=[2017, 2016, 2015, 2014, 2013, 2012, 2011, 2010], palette=[ '#08306b', '#08519c', '#2171b5', '#4292c6', '#6baed6', '#9ecae1', '#c6dbef', '#deebf7' ]) circle = Circle(x="lon", y="lat", size="size", fill_color=dict(field='rate', transform=color_mapper), fill_alpha=0.8, line_color=None) plot.add_glyph(sources['_2010'], circle) #Add tools hover = HoverTool(tooltips=[("station", "@name"), ("docks",
plot.title.offset = -20 plot.title.text_font_size = "40px" #Set api key plot.api_key = API_KEY #Create column data source source = ColumnDataSource(data=dict(lat=stations.lat.tolist(), lon=stations.lon.tolist(), size=stations.docks.tolist(), color=stations.installed_year.tolist(), name=stations.station.tolist())) color_mapper = CategoricalColorMapper( factors=[2017, 2016, 2015, 2014, 2013, 2012, 2011, 2010], palette=brewer['Blues'][8]) circle = Circle(x="lon", y="lat", size="size", fill_color=dict(field='color', transform=color_mapper), fill_alpha=0.8, line_color=None) plot.add_glyph(source, circle) #Add tools hover = HoverTool(tooltips=[("station", "@name"), ("docks", "@size"), ("year added", "@color")]) plot.add_tools(PanTool(), WheelZoomTool(), hover)
def main(fname, ignore_files, n_largest): sections = parseSections(open(fname, 'r')) if sections is None: print( 'start of memory config not found, did you invoke the compiler/linker with LANG=C?' ) return sectionWhitelist = {'.text', '.data', '.bss', '.rodata'} plots = [] whitelistedSections = list( filter(lambda x: x.section in sectionWhitelist, sections)) allObjects = list(chain(*map(lambda x: x.children, whitelistedSections))) allFiles = list(set(map(lambda x: x.basepath, allObjects))) for s in whitelistedSections: objects = s.children groupsize = {} for k, g in groupby(sorted(objects, key=lambda x: x.basepath), lambda x: x.basepath): size = sum(map(lambda x: x.size, g)) groupsize[k] = size #objects.sort (reverse=True, key=lambda x: x.size) grouped_obj = [ GroupedObj(k, size) for k, size in groupsize.items() if k not in ignore_files ] grouped_obj.sort(reverse=True, key=lambda x: x.size) for i in range(0, n_largest): o = grouped_obj[i] print(f'{o.size:>8} {o.path}') values = list(map(lambda x: x.size, grouped_obj)) totalsize = sum(values) x = 0 y = 0 width = 1000 height = 1000 values = squarify.normalize_sizes(values, width, height) padded_rects = squarify.padded_squarify(values, x, y, width, height) # plot with bokeh output_file('linkermap.html', title='Linker map') left = list(map(lambda x: x['x'], padded_rects)) top = list(map(lambda x: x['y'], padded_rects)) rectx = list(map(lambda x: x['x'] + x['dx'] / 2, padded_rects)) recty = list(map(lambda x: x['y'] + x['dy'] / 2, padded_rects)) rectw = list(map(lambda x: x['dx'], padded_rects)) recth = list(map(lambda x: x['dy'], padded_rects)) files = list(map(lambda x: x.path, grouped_obj)) size = list(map(lambda x: x.size, grouped_obj)) #children = list (map (lambda x: ','.join (map (lambda x: x[1], x.children)) if x.children else x.section, grouped_obj)) legend = list( map(lambda x: '{} ({})'.format(x.path, x.size), grouped_obj)) source = ColumnDataSource(data=dict( left=left, top=top, x=rectx, y=recty, width=rectw, height=recth, file=files, size=size, # children=children, legend=legend, )) hover = HoverTool(tooltips=[ ("size", "@size"), ("file", "@file"), # ("symbol", "@children"), ]) p = figure(title='Linker map for section {} ({} bytes)'.format( s.section, totalsize), plot_width=width, plot_height=height, tools=[hover, 'pan', 'wheel_zoom', 'box_zoom', 'reset'], x_range=(0, width), y_range=(0, height)) p.xaxis.visible = False p.xgrid.visible = False p.yaxis.visible = False p.ygrid.visible = False palette = inferno(len(grouped_obj)) mapper = CategoricalColorMapper(palette=palette, factors=allFiles) p.rect(x='x', y='y', width='width', height='height', source=source, color={ 'field': 'file', 'transform': mapper }, legend='legend') # set up legend, must be done after plotting p.legend.location = "top_left" p.legend.orientation = "horizontal" plots.append(p) show(column(*plots, sizing_mode="scale_width"))