Beispiel #1
0
    "angle": 0,
    "color": "black",
    "text_align": "left",
    "text_baseline": "middle"
}
x = dodge("group", -0.4, range=p.x_range)
y = dodge("period", 0.3, range=p.y_range)
p.text(x=x,
       y="period",
       text="sym",
       text_font_style="bold",
       text_font_size="16pt",
       **text_props)
p.text(x=x, y=y, text="atomic_number", text_font_size="11pt", **text_props)

color_bar = ColorBar(color_mapper=color_mapper,
                     ticker=BasicTicker(desired_num_ticks=10),
                     border_line_color=None,
                     label_standoff=cbar_standoff,
                     location=(0, 0),
                     orientation="vertical",
                     scale_alpha=alpha,
                     major_label_text_font_size=str(cbar_fontsize) + "pt")

if cbar_height is not None:
    color_bar.height = cbar_height

p.add_layout(color_bar, "right")
p.grid.grid_line_color = None
show(p)
Beispiel #2
0
def plot_ptable_trend(
    data_elements=["Rb", "S", "Se"],
    data_list=[10, 20, 30],
    input_file=None,
    output_html="ptable.html",
    bokeh_palette="Plasma256",
    cmap=plasma,
    log_scale=0,
    width=1050,
    alpha=0.65,
    cbar_height=520,
    cbar_font="14pt",
    save_plot=True,
):
    """
    Generate periodic table chemical trends.

    Either provide a file or list of data_elements, &data_list.
    Note that Bokeh already provided a periodic table.
    This module will take your data to color code them.
    See an example: https://www.nature.com/articles/s41598-019-45028-y
    Fig. 3
    Forked from https://github.com/arosen93/ptable_trends
    """
    output_file(output_html)
    # Define number of and groups
    period_label = ["1", "2", "3", "4", "5", "6", "7"]
    group_range = [str(x) for x in range(1, 19)]
    if input_file is not None:
        data_elements = []
        data_list = []

        f = open(input_file, "r")
        lines = f.read().splitlines()
        f.close()
        for i in lines:
            data_elements.append(i.split()[0])
            data_list.append(i.split()[1])

    data = [float(i) for i in data_list]

    if len(data) != len(data_elements):
        raise ValueError("Unequal number of atomic elements and data points")

    # lanthanides = [x.lower() for x in elements["symbol"][56:70].tolist()]
    # actinides = [x.lower() for x in elements["symbol"][88:102].tolist()]
    period_label.append("blank")
    period_label.append("La")
    period_label.append("Ac")

    count = 0
    for i in range(56, 70):
        elements.period[i] = "La"
        elements.group[i] = str(count + 4)
        count += 1

    count = 0
    for i in range(88, 102):
        elements.period[i] = "Ac"
        elements.group[i] = str(count + 4)
        count += 1

    # Define matplotlib and bokeh color map
    if log_scale == 0:
        color_mapper = LinearColorMapper(palette=bokeh_palette,
                                         low=min(data),
                                         high=max(data))
        norm = Normalize(vmin=min(data), vmax=max(data))
    elif log_scale == 1:
        for i in range(len(data)):
            if data[i] < 0:
                raise ValueError("Entry for element " + data_elements[i] +
                                 " is negative but"
                                 " log-scale is selected")
        color_mapper = LogColorMapper(palette=bokeh_palette,
                                      low=min(data),
                                      high=max(data))
        norm = LogNorm(vmin=min(data), vmax=max(data))
    color_scale = ScalarMappable(norm=norm, cmap=cmap).to_rgba(data,
                                                               alpha=None)

    # Define color for blank entries
    blank_color = "#c4c4c4"
    color_list = []
    for i in range(len(elements)):
        color_list.append(blank_color)

    # Compare elements in dataset with elements in periodic table
    for i in range(len(data)):
        element_entry = elements.symbol[elements.symbol.str.lower() ==
                                        data_elements[i].lower()]
        if not element_entry.empty:
            element_index = element_entry.index[0]
        else:
            print("WARNING: Invalid chemical symbol: " + data_elements[i])
        if color_list[element_index] != blank_color:
            print("WARNING: Multiple entries for element " + data_elements[i])
        color_list[element_index] = to_hex(color_scale[i])

    # Define figure properties for visualizing data
    source = ColumnDataSource(data=dict(
        group=[str(x) for x in elements["group"]],
        period=[str(y) for y in elements["period"]],
        sym=elements["symbol"],
        atomic_number=elements["atomic number"],
        type_color=color_list,
    ))
    # Plot the periodic table
    p = figure(x_range=group_range,
               y_range=list(reversed(period_label)),
               tools="save")
    p.plot_width = width
    p.outline_line_color = None
    p.toolbar_location = "above"
    p.rect(
        "group",
        "period",
        0.9,
        0.9,
        source=source,
        alpha=alpha,
        color="type_color",
    )
    p.axis.visible = False
    text_props = {
        "source": source,
        "angle": 0,
        "color": "black",
        "text_align": "left",
        "text_baseline": "middle",
    }
    x = dodge("group", -0.4, range=p.x_range)
    y = dodge("period", 0.3, range=p.y_range)
    p.text(x=x,
           y="period",
           text="sym",
           text_font_style="bold",
           text_font_size="15pt",
           **text_props)
    p.text(x=x, y=y, text="atomic_number", text_font_size="9pt", **text_props)
    color_bar = ColorBar(
        color_mapper=color_mapper,
        ticker=BasicTicker(desired_num_ticks=10),
        border_line_color=None,
        label_standoff=6,
        major_label_text_font_size=cbar_font,
        location=(0, 0),
        orientation="vertical",
        scale_alpha=alpha,
        width=8,
    )

    if cbar_height is not None:
        color_bar.height = cbar_height

    p.add_layout(color_bar, "right")
    p.grid.grid_line_color = None
    if save_plot:
        save(p)
    else:
        show(p)
    return p
Beispiel #3
0
def scalar_map_2d(cells, values, clim=None, figure=None, delaunay=False,
        colorbar=True, colormap=None, unit=None, clabel=None, colorbar_figure=None,
        xlim=None, ylim=None, **kwargs):
    """
    Plot an interactive 2D scalar map as a colourful image.

    Arguments:

        cells (Partition): spatial description of the cells

        values (pandas.Series or pandas.DataFrame): feature value at each cell/bin,
            encoded into a colour

        clim (2-element sequence): passed to :func:`~matplotlib.cm.ScalarMappable.set_clim`

        figure (bokeh.plotting.figure.Figure): figure handle

        delaunay (bool or dict): overlay the Delaunay graph; if ``dict``, options are passed
            to :func:`~tramway.plot.bokeh.plot_delaunay`

        colorbar (bool or str or dict): add a colour bar; if ``dict``, options are passed to
            :func:`~bokeh.models.ColorBar`

        unit/clabel (str): colorbar label, usually the unit of displayed feature

        colormap (str): colormap name; see also https://matplotlib.org/users/colormaps.html

        xlim (2-element sequence): lower and upper x-axis bounds

        ylim (2-element sequence): lower and upper y-axis bounds

    """
    if isinstance(values, pd.DataFrame):
        feature_name = values.columns[0]
        values = values.iloc[:,0] # to Series
    else:
        feature_name = None

    if figure is None:
        assert False
        figure = plt.figure()

    polygons = []

    xy = cells.tessellation.cell_centers
    if not xlim or not ylim:
        xy_min, _, xy_max, _ = mplt._bounding_box(cells, xy)
        if not xlim:
            xlim = (xy_min[0], xy_max[0])
        if not ylim:
            ylim = (xy_min[1], xy_max[1])
    ix = np.arange(xy.shape[0])
    vertices, cell_vertices, Av = mplt.box_voronoi_2d(cells.tessellation, xlim, ylim)
    try:
        ok = 0 < cells.location_count
    except (KeyboardInterrupt, SystemExit):
        raise
    except:
        print(traceback.format_exc())
        ok = np.ones(ix.size, dtype=bool)
    if cells.tessellation.cell_label is not None:
        ok = np.logical_and(ok, 0 < cells.tessellation.cell_label)
    map_defined = np.zeros_like(ok)
    map_defined[values.index] = True
    ok[np.logical_not(map_defined)] = False
    ok[ok] = np.logical_not(np.isnan(values.loc[ix[ok]].values))
    for i in ix[ok]:
        vs = cell_vertices[i].tolist()
        # order the vertices so that they draw a polygon
        v0 = v = vs[0]
        vs = set(vs)
        _vertices = []
        #vvs = [] # debug
        while True:
            _vertices.append(vertices[v])
            #vvs.append(v)
            vs.remove(v)
            if not vs:
                break
            ws = set(Av.indices[Av.indptr[v]:Av.indptr[v+1]]) & vs
            if not ws:
                ws = set(Av.indices[Av.indptr[v0]:Av.indptr[v0+1]]) & vs
                if ws:
                    _vertices = _vertices[::-1]
                else:
                    #print((v, vs, vvs, [Av.indices[Av.indptr[v]:Av.indptr[v+1]] for v in vs]))
                    warn('cannot find a path that connects all the vertices of a cell', RuntimeWarning)
                    break
            v = ws.pop()
        #
        if _vertices:
            _vertices = np.vstack(_vertices)
            polygons.append((_vertices[:,0], _vertices[:,1]))

    scalar_map = values.loc[ix[ok]].values
    vmin, vmax = scalar_map.min(), scalar_map.max()
    clim = {} if clim is None else dict(vmin=clim[0], vmax=clim[1])
    scalar_map = mpl.colors.Normalize(**clim)(scalar_map)

    if colormap:
        color_map = mpl.cm.get_cmap(colormap)
    else:
        color_map = mpl.cm.viridis
    colors = [
            "#%02x%02x%02x" % (int(r), int(g), int(b)) for r, g, b, _ in 255*color_map(scalar_map)
            ]
    patch_kwargs = dict(fill_color=colors, line_width=0)
    figure.patches(*zip(*polygons), **patch_kwargs)

    if delaunay or isinstance(delaunay, dict):
        if not isinstance(delaunay, dict):
            delaunay = {}
        plot_delaunay(cells, figure=figure, **delaunay)

    figure.x_range = Range1d(*xlim)
    figure.y_range = Range1d(*ylim)

    if colorbar:
        low = clim.get('vmin', vmin)
        high = clim.get('vmax', vmax)
        color_map = 'Viridis256' if colormap is None else colormap
        color_map = LinearColorMapper(palette=color_map, low=low, high=high)
        color_bar = ColorBar(color_mapper=color_map, ticker=BasicTicker(),
                border_line_color=None, margin=0)
        color_bar.background_fill_color = None
        if unit is None:
            unit = clabel
        if colorbar_figure is None:
            if unit is not None:
                color_bar.title = unit
            figure.add_layout(color_bar, place='right')
        else:
            if unit is not None:
                colorbar_figure.title.text = unit
                colorbar_figure.title_location = 'right'
                colorbar_figure.title.align = 'center'
            color_bar.height = colorbar_figure.plot_height
            if isinstance(colorbar_figure.center[-1], ColorBar):
                colorbar_figure.center = colorbar_figure.center[:-1]
            colorbar_figure.add_layout(color_bar, place='center')
Beispiel #4
0
def add_colorbar(figure,
                 colormap=None,
                 low=0,
                 high=1,
                 unit=None,
                 clabel=None,
                 colorbar_figure=None):
    if colormap is None:
        color_map = "Viridis256"
    elif isinstance(colormap, str):
        if colormap.lower() in (
                "greys",
                "inferno",
                "magma",
                "plasma",
                "viridis",
                "cividis",
                "turbo",
        ):
            color_map = colormap[0].upper() + colormap[1:].lower() + "256"
        else:
            color_map = mpl.cm.get_cmap(colormap)
            color_map = [
                "#%02x%02x%02x" % (int(r), int(g), int(b))
                for r, g, b, _ in 255 * color_map(np.linspace(0, 1, 256))
            ]
    else:
        color_map = colormap
    try:
        color_map = LinearColorMapper(palette=color_map,
                                      low=low,
                                      high=high,
                                      name="color_mapper")
    except ValueError as e:
        try:
            import colorcet
        except ImportError:
            raise ValueError(
                "colormap not found; try installing the colorcet package"
            ) from e
        else:
            raise
    color_bar = ColorBar(
        color_mapper=color_map,
        ticker=BasicTicker(name="ticker"),
        border_line_color=None,
        margin=0,
        name="color_bar",
    )
    color_bar.background_fill_color = None
    # glyph_renderers.append(color_bar)
    if unit is None:
        unit = clabel
    if colorbar_figure is None:
        if unit is not None:
            color_bar.title = unit
        figure.add_layout(color_bar, place="right")
    else:
        if unit is not None:
            colorbar_figure.title.text = unit
            colorbar_figure.title_location = "right"
            colorbar_figure.title.align = "center"
        color_bar.height = colorbar_figure.plot_height
        if isinstance(colorbar_figure.center[-1], ColorBar):
            colorbar_figure.center = colorbar_figure.center[:-1]
        colorbar_figure.add_layout(color_bar, place="center")
Beispiel #5
0
def get_periodic_table_plot():
    """Plot the periodic table with colors (returns bokeh figure)"""

    global names

    symbols, atomic_numbers, groups, periods, group_range, period_label = initialize_periodic_table(
    )

    # get ColumnDataSource for values on periodic table
    source_allEF = get_data_on_perdic_table(load_data=True)

    # EF=0 starting values
    source = source_allEF[0]

    # create figure
    plot = bkp.figure(x_range=group_range,
                      y_range=list(reversed(period_label)),
                      tools='pan,wheel_zoom,reset,save',
                      title='Impurities in Sb2Te3 (6QL)')

    # set up hover tool
    hover = HoverTool()
    hover.tooltips = [
        ("Element", "@sym"
         ),  # things displayed by hover tool, needs to be in 'source' dict
        ("# impcalcs", "@num_impcalcs"),
        ("% magnetic", "@percent_mag"),
        ("<spin mom>", "@smom_mean (+/-@smom_std)"),
        ("<orb mom>", "@omom_mean (+/-@omom_std)"),
        ("<charge doping>", "@charge_doping_mean (+/-@charge_doping_std)"),
        ("<DOS in gap>", "@DOSinGap_mean (+/-@DOSinGap_std)"),
    ]

    # add hover tool to plot
    plot.tools.append(hover)

    plot.plot_width = width
    plot.min_width = width
    plot.max_width = width * 2
    plot.sizing_mode = 'scale_both'
    plot.outline_line_color = None
    plot.toolbar_location = 'above'
    # coloured patches for the elements:
    rects = plot.rect('group',
                      'period',
                      0.9,
                      0.9,
                      source=source,
                      alpha=alpha,
                      color='type_color')
    plot.axis.visible = False  # show axis?
    text_props = {
        'source': source,
        'angle': 0,
        'color': 'black',
        'text_align': 'left',
        'text_baseline': 'middle'
    }
    # add text for all pairs of (x,y)=(group,period)
    x = dodge("group", -0.4, range=plot.x_range)
    y = dodge("period", 0.3, range=plot.y_range)
    y2 = dodge("period", -0.3,
               range=plot.y_range)  # to displat 'c_value' entry as well
    # here add the texts inside atom boxes
    plot.text(x=x,
              y='period',
              text='sym',
              text_font_style='bold',
              text_font_size='16pt',
              **text_props)
    plot.text(x=x,
              y=y,
              text='atomic_number',
              text_font_size='11pt',
              **text_props)

    txt = {
        0: 'num_impcalcs',
        1: 'rms_mean',
        2: 'rms_std',
        3: 'smom_mean',
        4: 'smom_std',
        5: 'omom_mean',
        6: 'omom_std',
        7: 'nummag',
        8: 'percent_mag',
        9: 'charge_doping_mean',
        10: 'DOSinGap_mean'
    }[0]
    color_value = plot.text(x=x,
                            y=y2,
                            text=txt,
                            text_font_size='8pt',
                            name='color_value',
                            **text_props)  # uses y2

    # deactivate grid
    plot.grid.grid_line_color = None

    # title of color bar
    names = [
        '# imps', '<rms>', 'rms std', '<spin mom>', 'spin std', '<orb mom>',
        'orbital mom std', '# magnetic', '% magnetic', '<Charge doping>',
        'charge dop std', '<DOS in gap>', 'dos in gap std'
    ]
    title_name = names[0]

    # for log scale use this as ticker
    from bokeh.models import LogTicker, BasicTicker

    ticker = BasicTicker(desired_num_ticks=10)

    # add color bar
    color_bar = ColorBar(color_mapper=color_mapper_all[0],
                         ticker=ticker,
                         border_line_color=None,
                         label_standoff=cbar_standoff,
                         location=(0, 0),
                         orientation='vertical',
                         scale_alpha=alpha,
                         major_label_text_font_size=str(cbar_fontsize) + 'pt',
                         title=title_name,
                         formatter=formatter_int,
                         padding=20)

    if cbar_height is not None:
        color_bar.height = cbar_height

    plot.add_layout(color_bar, 'right')
    """
    color_bar_plot = bk.figure(title="My color bar title", title_location="right", 
                            plot_width=100, min_width=100, sizing_mode='stretch_both',
                            toolbar_location=None)

    color_bar_plot.add_layout(color_bar, 'right')
    color_bar_plot.title.align="center"
    color_bar_plot.title.text_font_size = '12pt'
    """

    return plot, source, source_allEF, color_bar