Skip to content

Instantly share code, notes, and snippets.

@DenisKramer
Last active August 23, 2024 08:46
Show Gist options
  • Select an option

  • Save DenisKramer/d44a1104f93b54f5ce50b0093bb38992 to your computer and use it in GitHub Desktop.

Select an option

Save DenisKramer/d44a1104f93b54f5ce50b0093bb38992 to your computer and use it in GitHub Desktop.
Periodic Table Heatmap widget for Python and Jupyter notebooks using Bokeh and Pandas
def periodic_table_plot(df, title="", element_column_name="element", value_column_name=None, colors="#ddd"):
'''
Create an interactive periodic table with heatmap.
Parameters:
df Pandas Dataframe with relevant data. Has to have at least two columns with element
symbols (e.g., Fe, Ir, H, ...) and a second column with values to display as heat map
title A descriptive string shown as title with the periodic table
element_column_name A string containing the name of the column with the element symbols in the df dataframe
value_column_name A string containing the name of the column with the heat map values in the df dataframe
colors A string or bokeh.palette as colormap to use as heatmap in the periodic table
Usage:
import pandas as pd
from bokeh.plotting import show
from bokeh.transform import linear_cmap
from bokeh.bokeh.palettes import Spectral6
voltages = pd.DataFrame([{"metal": "V", "voltage": 1.0},{"metal": "Ni", "voltage": 3.2}])
pt = periodic_table_plot(voltages, title="Intercalation voltages", element_column_name="metal", value_column_name="voltage", colors=linear_cmap(field_name='voltage', palette=Spectral6, low=0.0, high=2.5))
show(pt)
'''
from bokeh.plotting import figure
from bokeh.sampledata.periodic_table import elements
from bokeh.transform import dodge
periods = ["I", "II", "III", "IV", "V", "VI", "VII"]
groups = [str(x) for x in range(1, 19)]
df = pd.merge(df,elements[['symbol','atomic number','name','group','period']], left_on=element_column_name, right_on='symbol')
df["period"] = [periods[x-1] for x in df.period]
df_missing = elements[~elements['symbol'].isin(df[element_column_name])][['symbol','atomic number','name','group','period']]
df_missing["period"] = [periods[x-1] for x in df_missing.period]
TOOLTIPS = [
("Name", "@name"),
("Atomic number", "@{atomic number}")
]
if value_column_name:
TOOLTIPS.append((value_column_name, f"@{{{value_column_name}}}"))
p = figure(title=f"Periodic Table ({title})", width=1000, height=450,
x_range=groups, y_range=list(reversed(periods)),
tools="hover", toolbar_location=None, tooltips=TOOLTIPS)
r = p.rect("group", "period", 0.95, 0.95, source=df, fill_alpha=0.6,
color=colors)
rm = p.rect("group", "period", 0.95, 0.95, source=df_missing, fill_alpha=0.6,
color="#eee")
# Print elements with values
text_props = dict(source=df, text_align="left", text_baseline="middle")
x = dodge("group", -0.4, range=p.x_range)
p.text(x=x, y="period", text="symbol", text_font_style="bold", **text_props)
p.text(x=x, y=dodge("period", 0.3, range=p.y_range), text="atomic number",
text_font_size="11px", **text_props)
p.text(x=x, y=dodge("period", -0.35, range=p.y_range), text="name",
text_font_size="7px", **text_props)
# # Print elements without values
text_props = dict(source=df_missing, text_align="left", text_baseline="middle", color="#aaa")
p.text(x=x, y="period", text="symbol", text_font_style="bold", **text_props)
p.text(x=x, y=dodge("period", 0.3, range=p.y_range), text="atomic number",
text_font_size="11px", **text_props)
p.text(x=x, y=dodge("period", -0.35, range=p.y_range), text="name",
text_font_size="7px", **text_props)
p.outline_line_color = None
p.grid.grid_line_color = None
p.axis.axis_line_color = None
p.axis.major_tick_line_color = None
p.axis.major_label_standoff = 0
p.hover.renderers = [r] # only hover element boxes
return p
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment