Spaces:
Running
Running
| import os | |
| from pymatgen.ext.matproj import MPRester | |
| import crystal_toolkit.components as ctc | |
| from crystal_toolkit.settings import SETTINGS | |
| import dash | |
| from dash import html, dcc | |
| from dash.dependencies import Input, Output, State | |
| # Set your Materials Project API key | |
| MATERIALS_PROJECT_API_KEY = os.getenv('MATERIALS_PROJECT_API_KEY') | |
| # Initialize the Dash app | |
| app = dash.Dash(__name__, assets_folder=SETTINGS.ASSETS_PATH) | |
| server = app.server # Expose the server for deployment | |
| # Define the app layout | |
| layout = html.Div([ | |
| dcc.Markdown("## Interactive Crystal Viewer"), | |
| html.Div([ | |
| html.Div([ | |
| html.Label("Search by Chemical System (e.g., 'Ac-Cd-Ge')"), | |
| dcc.Input( | |
| id='query-input', | |
| type='text', | |
| value='Ac-Cd-Ge', | |
| placeholder='Ac-Cd-Ge', | |
| style={'width': '100%'} | |
| ), | |
| ], style={'width': '70%', 'display': 'inline-block', 'verticalAlign': 'top'}), | |
| html.Div([ | |
| html.Button('Search', id='search-button', n_clicks=0), | |
| ], style={'width': '28%', 'display': 'inline-block', 'paddingLeft': '2%', 'verticalAlign': 'top'}), | |
| ], style={'margin-bottom': '20px'}), | |
| html.Div([ | |
| html.Label("Select Material"), | |
| dcc.Dropdown( | |
| id='material-dropdown', | |
| options=[], # Empty options initially | |
| value=None | |
| ), | |
| ], style={'margin-bottom': '20px'}), | |
| html.Button('Display Material', id='display-button', n_clicks=0), | |
| html.Div([ | |
| html.Div(id='structure-container', style={'width': '48%', 'display': 'inline-block', 'verticalAlign': 'top'}), | |
| html.Div(id='properties-container', | |
| style={'width': '48%', 'display': 'inline-block', 'paddingLeft': '4%', 'verticalAlign': 'top'}), | |
| ], style={'margin-top': '20px'}), | |
| ]) | |
| # Function to search for materials | |
| def search_materials(query): | |
| with MPRester(MATERIALS_PROJECT_API_KEY) as mpr: | |
| results = mpr.summary.search( | |
| chemsys=query, | |
| fields=["material_id", "formula_pretty"] | |
| ) | |
| options = [{'label': f"{res.formula_pretty} ({res.material_id})", 'value': res.material_id} for res in results] | |
| return options | |
| # Callback to update the material dropdown based on search | |
| def update_material_dropdown(n_clicks, query): | |
| if n_clicks is None or not query: | |
| return [], None | |
| options = search_materials(query) | |
| if not options: | |
| return [], None | |
| return options, options[0]['value'] | |
| # Callback to display the selected material | |
| def display_material(n_clicks, material_id): | |
| if n_clicks is None or not material_id: | |
| return '', '' | |
| with MPRester(MATERIALS_PROJECT_API_KEY) as mpr: | |
| material = mpr.get_structure_by_material_id(material_id) | |
| summary = mpr.summary.get_data_by_id(material_id) | |
| # Create the StructureMoleculeComponent | |
| structure_component = ctc.StructureMoleculeComponent(material) | |
| # Extract key properties | |
| properties = { | |
| "Material ID": material_id, | |
| "Formula": summary.formula_pretty, | |
| "Energy Above Hull (eV/atom)": summary.energy_above_hull, | |
| "Space Group": summary.symmetry.symbol, | |
| "Band Gap (eV)": summary.band_gap, | |
| "Formation Energy (eV/atom)": summary.formation_energy_per_atom, | |
| "Magnetic Ordering": summary.ordering, | |
| "Total Magnetization (μB/f.u.)": summary.total_magnetization, | |
| "Is Stable": summary.is_stable, | |
| "Crystal System": summary.symmetry.crystal_system, | |
| "Density (g/cm³)": summary.density, | |
| } | |
| # Format properties as an HTML table | |
| properties_html = html.Table([ | |
| html.Tbody([ | |
| html.Tr([html.Th(key), html.Td(str(value))]) for key, value in properties.items() | |
| ]) | |
| ], style={'border': '1px solid black', 'width': '100%', 'borderCollapse': 'collapse'}) | |
| return structure_component.layout(), properties_html | |
| # Register crystal toolkit with the app | |
| ctc.register_crystal_toolkit(app, layout) | |
| if __name__ == '__main__': | |
| app.run_server(debug=True, port=7860) | |