{ "cells": [ { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "# `widget-periodictable`: A Jupyter Widget to Create Interactive Periodic Table\n", "\n", "**Source code**:[https://github.com/osscar-org/widget-periodictable](https://github.com/osscar-org/widget-periodictable) \n", "\n", "**Introduction**: The periodic table is an important tool for chemistry and physics \n", "education and research. This is a Jupyter widget to create an interactive periodic \n", "table. Users can customize the colors of the elements and group elements by assigning them colors. \n", "The elements are also clickable and trigger custom events.\n", "\n", "```{image} ./images/widget_periodictable.png\n", ":alt: image periodictable\n", ":class: bg-primary mb-1\n", ":width: 500px\n", ":align: center\n", "```\n", "\n", "````{admonition} Installation\n", "```bash\n", "pip install --upgrade widget-periodictable\n", "```\n", "````\n", "\n", "## Try it with Binder\n", "\n", "You can try the interactive periodic table and check the usage through the Binder link:\n", "[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/osscar-org/widget-periodictable/develop?urlpath=%2Fvoila%2Frender%2Fexamples%2Fintroduction.ipynb)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Tutorial\n", "\n", "
\n", "\n", "### **Import the widget**" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "import ipywidgets as widgets\n", "from widget_periodictable import PTableWidget\n", "from ipywidgets import Layout" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### **Initialize and visualize the element grid**\n", "\n", "Here, we initialize the periodic table with three states, which have red, green\n", "and blue color respectively. The selected elements are C, Si and Ge. The carbon\n", "is in the 1st state, which has red color. The elements B, Al and Ga are disabled,\n", "which means they are not clickable. The remaining unselected elements are in pink. The border color of each element is black. The width option is set for\n", "each element." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "c59bf12be17a454c89589d7b154857dc", "version_major": 2, "version_minor": 0 }, "text/plain": [ "PTableWidget(allElements=['H', 'He', 'Li', 'Be', 'B', 'C', 'N', 'O', 'F', 'Ne', 'Na', 'Mg', 'Al', 'Si', 'P', '…" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "widget = PTableWidget(states = 3, selected_elements = {\"C\": 0, \"Si\": 1, \"Ge\": 2}, \n", " selected_colors = ['red', 'green', 'blue'], \n", " disabled_elements = ['B', 'Al', 'Ga'],\n", " unselected_color='pink', border_color = 'black', width = '20px')\n", "\n", "display(widget)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### **Set the states of the elements**\n", "\n", "The periodic table allows users to customize the states of the selected elements. \n", "If one does not specify the selected element's state, it shall default to zero.\n", "One can initialize the selected elements by using a dictionary." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "widget.selected_elements = {\"La\": 0, \"Ce\": 1, \"Pr\": 2}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Change or reset the element's state via the `set_element_state` method.\n", "Note, however, that you cannot use widget.selected_elements[\"Nd\"] = 1 to set the states of the elements for instance." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "widget.set_element_state(\"Nd\",0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Get the elements which are in the same state:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['La', 'Nd']" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "widget.get_elements_by_state(0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### **Get the selected values in python**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Check which elements are currently selected" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "f658caea21644cbba8d8c05a099079d5", "version_major": 2, "version_minor": 0 }, "text/plain": [ "VBox(children=(Button(button_style='success', description='Get the currently selected values', layout=Layout(w…" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "output = widgets.Output()\n", "\n", "def on_get_in_python(event):\n", " output.clear_output()\n", " with output:\n", " print(\n", " \"Currently selected values:\", \n", " widget.selected_elements)\n", "\n", "button2 = widgets.Button(\n", " description=\"Get the currently selected values\", \n", " button_style='success',\n", " layout={'width': '300px'}\n", ")\n", "button2.on_click(on_get_in_python)\n", "vbox = widgets.VBox([button2, output])\n", "vbox" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### **Play with enabling/disabling some elements**" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "1b169901f3fd42b59182d7772e0f0384", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Checkbox(value=False, description='Disable oxygen')" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "toggle_disabled = widgets.Checkbox(\n", " value=\"O\" in widget.disabled_elements,\n", " description='Disable oxygen',\n", " disabled=False\n", ")\n", "\n", "def on_change_disabled(event):\n", " if toggle_disabled.value:\n", " # It's set, meaning we want to disable oxygen\n", " widget.disabled_elements = [\"O\"]\n", " else:\n", " widget.disabled_elements = []\n", "toggle_disabled.observe(on_change_disabled, names='value')\n", "\n", "def on_change(event):\n", " \"\"\"\n", " Update the toggle value if manually changing the disabled_elements list.\n", " \"\"\"\n", " toggle_disabled.value = \"O\" in widget.disabled_elements\n", "widget.observe(on_change, names='disabled_elements', type='change') \n", " \n", "toggle_disabled" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### **Freeze (disable clicking events) the whole periodic table**" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "fc3d79d12d76454a8250a602de665f81", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Checkbox(value=False, description='Freeze periodic table:')" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "toggle_freeze = widgets.Checkbox(\n", " value= False,\n", " description='Freeze periodic table:',\n", " disabled=False\n", ")\n", "\n", "def on_freeze_change(event):\n", " widget.disabled = toggle_freeze.value\n", " \n", "toggle_freeze.observe(on_freeze_change, names='value')\n", "\n", "toggle_freeze" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### **Set the selected values from python**\n", "\n", "Choose the selected values from python" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "f29cb7d4e8fc49ed9aefc9e1ae8761d6", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Button(button_style='success', description='Select only Li and H (from python)', layout=Layout(width='300px'),…" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "def on_set_from_python(event):\n", " # NOTE! If you put an element which does not exist, it will stay forever in the list, but it's ignored\n", " widget.selected_elements = {\"Li\":0, \"H\":0}\n", "\n", "button = widgets.Button(\n", " description=\"Select only Li and H (from python)\", \n", " button_style='success',\n", " layout={'width': '300px'}\n", ")\n", "button.on_click(on_set_from_python)\n", "button" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### **Change the displayed string for some elements**\n", "\n", "Note that you should pass valid HTML strings, as they will not be escaped. On the other hand this allows one to use HTML to change the class, color, ..." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "b61605d0b08345f19f8344d3761b9677", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Button(button_style='success', description='Make noble gases bold', layout=Layout(width='300px'), style=Button…" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "def get_noble_gases_state():\n", " label_deactivate = \"Make noble gases bold\"\n", " label_activate = \"Make noble gases not bold\"\n", " def deactivate_noble_gases(event):\n", " widget.display_names_replacements = {}\n", " def activate_noble_gases(event):\n", " widget.display_names_replacements = {\n", " elem_name: \"{}\".format(elem_name)\n", " for elem_name in ['He', 'Ne', 'Ar', 'Kr', 'Xe', 'Rn', 'Og']\n", " }\n", "\n", " if 'He' in widget.display_names_replacements:\n", " return {\n", " 'is_active': True,\n", " 'toggler_function': deactivate_noble_gases,\n", " 'toggled_label': label_deactivate,\n", " 'current_label': label_activate\n", " }\n", " else:\n", " return {\n", " 'is_active': True,\n", " 'toggler_function': activate_noble_gases,\n", " 'toggled_label': label_activate,\n", " 'current_label': label_deactivate\n", " }\n", "\n", "button_noble = widgets.Button(\n", " description=get_noble_gases_state()['current_label'], \n", " button_style='success',\n", " layout={'width': '300px'}\n", ")\n", " \n", "def on_toggle_noble_gases(event):\n", " \"\"\"Toggle the state of the button and of the .\"\"\"\n", " state = get_noble_gases_state() \n", " # Change the table\n", " state['toggler_function'](event)\n", " # Change the button description\n", " button_noble.description = state['toggled_label']\n", " \n", "button_noble.on_click(on_toggle_noble_gases)\n", "button_noble" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.7" }, "voila": { "authors": "Dou Du, Casper Welzel Andersen and Giovanni Pizzi" } }, "nbformat": 4, "nbformat_minor": 4 }