Last active
August 23, 2024 08:46
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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