Spaces:
Running
Running
File size: 5,185 Bytes
d9ed521 3eda6d3 3b3aaa9 3eda6d3 3b3aaa9 3eda6d3 3b3aaa9 3eda6d3 3b3aaa9 3eda6d3 3b3aaa9 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
# NOTE: https://stackoverflow.com/questions/77062368/streamlit-bokeh-event-callback-to-get-clicked-values
# Taptool: https://docs.bokeh.org/en/2.4.2/docs/reference/models/tools.html#taptool
import streamlit as st
from bokeh.plotting import figure
from bokeh.plotting import figure, show
from bokeh.sampledata.periodic_table import elements
from bokeh.transform import dodge, factor_cmap
import streamlit as st
from bokeh.plotting import figure
from bokeh.models import ColumnDataSource, CustomJS, TapTool
from bokeh.sampledata.periodic_table import elements
from bokeh.transform import dodge, factor_cmap
periods = ["I", "II", "III", "IV", "V", "VI", "VII"]
groups = [str(x) for x in range(1, 19)]
df = elements.copy()
df["atomic mass"] = df["atomic mass"].astype(str)
df["group"] = df["group"].astype(str)
df["period"] = [periods[x-1] for x in df.period]
df = df[df.group != "-"]
df = df[df.symbol != "Lr"]
df = df[df.symbol != "Lu"]
cmap = {
"alkali metal" : "#a6cee3",
"alkaline earth metal" : "#1f78b4",
"metal" : "#d93b43",
"halogen" : "#999d9a",
"metalloid" : "#e08d49",
"noble gas" : "#eaeaea",
"nonmetal" : "#f1d4Af",
"transition metal" : "#599d7A",
}
TOOLTIPS = [
("Name", "@name"),
("Atomic number", "@{atomic number}"),
("Atomic mass", "@{atomic mass}"),
("Type", "@metal"),
("CPK color", "$color[hex, swatch]:CPK"),
("Electronic configuration", "@{electronic configuration}"),
]
p = figure(title="Periodic Table (omitting LA and AC Series)", width=1000, height=450,
x_range=groups, y_range=list(reversed(periods)),
tools="hover,tap", toolbar_location=None, tooltips=TOOLTIPS)
# Convert DataFrame to ColumnDataSource
df["selected"] = False
source = ColumnDataSource(df)
r = p.rect("group", "period", 0.95, 0.95, source=source, fill_alpha=0.6,
legend_field="metal",
color=factor_cmap('metal', palette=list(cmap.values()), factors=list(cmap.keys())),
selection_color="firebrick", selection_alpha=0.9)
# r = p.rect("group", "period", 0.95, 0.95, source=df, fill_alpha=0.6, legend_field="metal",
# color=factor_cmap('metal', palette=list(cmap.values()), factors=list(cmap.keys())))
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)
p.text(x=x, y=dodge("period", -0.2, range=p.y_range), text="atomic mass",
text_font_size="7px", **text_props)
p.text(x=["3", "3"], y=["VI", "VII"], text=["LA", "AC"], text_align="center", text_baseline="middle")
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.legend.orientation = "horizontal"
p.legend.location ="top_center"
p.hover.renderers = [r] # only hover element boxes
print(source.dataspecs())
# Create a CustomJS callback
callback = CustomJS(args=dict(source=source), code="""
var data = source.data;
var selected_elements = [];
for (var i = 0; i < data.symbol.length; i++) {
if (data.selected[i]) { // Corrected if statement with braces
selected_elements.push(data.symbol[i]);
}
}
console.log('Selected elements:', selected_elements);
document.dispatchEvent(new CustomEvent("selection_event", {detail: JSON.stringify(selected_elements)}));
""")
# yield j
# st.rerun()
# Add TapTool with the callback
tap_tool = TapTool()
p.add_tools(tap_tool)
p.js_on_event('tap', callback)
st.bokeh_chart(p, use_container_width=True)
# show(p)
selected_info = st.empty()
# Use session state to store selected elements
if 'selected_elements' not in st.session_state:
st.session_state.selected_elements = []
st.markdown("""
<script>
document.addEventListener('selection_event', function(e) {
var selected_elements = JSON.parse(e.detail);
window.parent.postMessage({
type: 'streamlit:set_session_state',
data: {
selected_elements: selected_elements
}
}, '*');
});
</script>
""", unsafe_allow_html=True)
# Display selected elements
if st.session_state.selected_elements:
st.write("Selected Elements:")
for element in st.session_state.selected_elements:
st.write(f"{element['symbol']} ({element['name']}):")
st.write(f" Atomic Number: {element['atomic_number']}")
st.write(f" Atomic Mass: {element['atomic_mass']}")
st.write(f" Type: {element['metal']}")
st.write("---")
else:
st.write("No elements selected. Click on elements in the periodic table to select them.")
# st.rerun()
# Add a button to clear selection
if st.button("Clear Selection"):
st.session_state.selected_elements = []
st.rerun()
|