Vishwas1 commited on
Commit
bf0d06f
·
verified ·
1 Parent(s): 306c771

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -250
app.py DELETED
@@ -1,250 +0,0 @@
1
-
2
- import math
3
- from typing import Dict, List, Optional
4
-
5
- import gradio as gr
6
- import pandas as pd
7
- import plotly.express as px
8
- from periodictable import elements
9
-
10
- NUMERIC_PROPS = [
11
- ("mass", "Atomic mass (u)"),
12
- ("density", "Density (g/cm^3)"),
13
- ("electronegativity", "Pauling electronegativity"),
14
- ("boiling_point", "Boiling point (K)"),
15
- ("melting_point", "Melting point (K)"),
16
- ("vdw_radius", "van der Waals radius (pm)"),
17
- ("covalent_radius", "Covalent radius (pm)"),
18
- ]
19
-
20
- CURATED_FACTS: Dict[str, List[str]] = {
21
- "H": ["Lightest element; ~74% of the visible universe by mass is hydrogen in stars."],
22
- "He": ["Inert, used in cryogenics and balloons; second lightest element."],
23
- "Li": ["Batteries MVP: lithium-ion cells power phones and EVs."],
24
- "C": ["Backbone of life; diamond and graphite are pure carbon with wildly different properties."],
25
- "N": ["~78% of Earth's atmosphere is nitrogen (mostly N₂)."],
26
- "O": ["Essential for respiration; ~21% of Earth's atmosphere."],
27
- "Na": ["Sodium metal reacts violently with water—handle only under oil or inert gas."],
28
- "Mg": ["Burns with a bright white flame; used in flares and fireworks."],
29
- "Al": ["Light and strong; forms a protective oxide layer that resists corrosion."],
30
- "Si": ["Silicon is the basis of modern electronics—hello, semiconductors."],
31
- "Cl": ["Powerful disinfectant; elemental chlorine is toxic, compounds are widely useful."],
32
- "Ar": ["Argon is used to provide inert atmospheres for welding and 3D printing."],
33
- "Fe": ["Core of steel; iron is essential in hemoglobin for oxygen transport."],
34
- "Cu": ["Excellent electrical conductor; iconic blue-green patina (verdigris)."],
35
- "Ag": ["Highest electrical conductivity of all metals; historically used as currency."],
36
- "Au": ["Very unreactive ('noble'); prized for electronics and jewelry."],
37
- "Hg": ["Only metal that's liquid at room temperature; toxic—use with care."],
38
- "Pb": ["Dense and malleable; toxicity led to phase-out from gasoline and paints."],
39
- "U": ["Radioactive; used as nuclear reactor fuel (U-235)."],
40
- "Pu": ["Man-made in quantity; key in certain nuclear technologies."],
41
- "F": ["Most electronegative element; extremely reactive."],
42
- "Ne": ["Neon glows striking red-orange in discharge tubes—classic signs."],
43
- "Xe": ["Xenon makes bright camera flashes and high-intensity lamps."],
44
- }
45
-
46
- GROUP_FACTS = {
47
- "alkali": "Alkali metal: very reactive soft metal; forms +1 cations and reacts with water.",
48
- "alkaline-earth": "Alkaline earth metal: reactive (less than Group 1); forms +2 cations.",
49
- "transition": "Transition metal: often good catalysts, colorful compounds, multiple oxidation states.",
50
- "post-transition": "Post-transition metal: softer metals with lower melting points than transition metals.",
51
- "metalloid": "Metalloid: properties between metals and nonmetals; often semiconductors.",
52
- "nonmetal": "Nonmetal: tends to form covalent compounds; wide range of roles in biology and materials.",
53
- "halogen": "Halogen: very reactive nonmetals; form salts with metals and −1 oxidation state.",
54
- "noble-gas": "Noble gas: chemically inert under most conditions; monatomic gases.",
55
- "lanthanide": "Lanthanide: f-block rare earths; notable for magnets, lasers, and phosphors.",
56
- "actinide": "Actinide: radioactive f-block; includes nuclear fuel materials.",
57
- }
58
-
59
- def classify_category(el) -> str:
60
- try:
61
- if el.block == "s" and el.group == 1 and el.number != 1:
62
- return "alkali"
63
- if el.block == "s" and el.group == 2:
64
- return "alkaline-earth"
65
- if el.block == "p" and el.group in (13, 14, 15, 16) and el.metallic:
66
- return "post-transition"
67
- if el.block == "d":
68
- return "transition"
69
- if el.block == "p" and el.group == 17:
70
- return "halogen"
71
- if el.block == "p" and el.group == 18:
72
- return "noble-gas"
73
- if el.block == "p" and not el.metallic:
74
- return "nonmetal"
75
- if el.block == "f" and 57 <= el.number <= 71:
76
- return "lanthanide"
77
- if el.block == "f" and 89 <= el.number <= 103:
78
- return "actinide"
79
- except Exception:
80
- pass
81
- return "nonmetal" if not getattr(el, "metallic", False) else "post-transition"
82
-
83
- def build_elements_df() -> pd.DataFrame:
84
- rows = []
85
- for Z in range(1, 119):
86
- el = elements[Z]
87
- if el is None:
88
- continue
89
- data = {
90
- "Z": el.number,
91
- "symbol": el.symbol,
92
- "name": el.name.title(),
93
- "period": getattr(el, "period", None),
94
- "group": getattr(el, "group", None),
95
- "block": getattr(el, "block", None),
96
- "mass": getattr(el, "mass", None),
97
- "density": getattr(el, "density", None),
98
- "electronegativity": getattr(el, "electronegativity", None),
99
- "boiling_point": getattr(el, "boiling_point", None),
100
- "melting_point": getattr(el, "melting_point", None),
101
- "vdw_radius": getattr(el, "vdw_radius", None),
102
- "covalent_radius": getattr(el, "covalent_radius", None),
103
- "category": classify_category(el),
104
- "is_radioactive": bool(getattr(el, "radioactive", False)),
105
- }
106
- rows.append(data)
107
- df = pd.DataFrame(rows).sort_values("Z").reset_index(drop=True)
108
- return df
109
-
110
- DF = build_elements_df()
111
- MAX_GROUP = 18
112
- MAX_PERIOD = 7
113
-
114
- GRID: List[List[Optional[int]]] = [[None for _ in range(MAX_GROUP)] for _ in range(MAX_PERIOD)]
115
- for _, row in DF.iterrows():
116
- period, group, Z = int(row["period"]), row["group"], int(row["Z"])
117
- if group is None:
118
- continue
119
- GRID[period-1][group-1] = Z
120
-
121
- LAN = [z for z in DF["Z"] if 57 <= z <= 71]
122
- ACT = [z for z in DF["Z"] if 89 <= z <= 103]
123
-
124
- def element_info(z_or_symbol: str):
125
- try:
126
- if z_or_symbol.isdigit():
127
- Z = int(z_or_symbol)
128
- el = elements[Z]
129
- else:
130
- el = elements.symbol(z_or_symbol)
131
- Z = el.number
132
- except Exception:
133
- return f"Unknown element: {z_or_symbol}", None, None
134
-
135
- row = DF.loc[DF['Z'] == Z].iloc[0].to_dict()
136
- symbol = row['symbol']
137
-
138
- facts = []
139
- facts.extend(CURATED_FACTS.get(symbol, []))
140
- facts.append(GROUP_FACTS.get(row['category'], None))
141
- facts = [f for f in facts if f]
142
-
143
- props_lines = [
144
- f"{row['name']} ({symbol}), Z = {Z}",
145
- f"Period {int(row['period'])}, Group {row['group']}, Block {row['block']} | Category: {row['category'].replace('-', ' ').title()}",
146
- f"Atomic mass: {row['mass'] if row['mass'] else '—'} u",
147
- f"Density: {row['density'] if row['density'] else '—'} g/cm³",
148
- f"Electronegativity: {row['electronegativity'] if row['electronegativity'] else '—'} (Pauling)",
149
- f"Melting point: {row['melting_point'] if row['melting_point'] else '—'} K | Boiling point: {row['boiling_point'] if row['boiling_point'] else '—'} K",
150
- f"vdW radius: {row['vdw_radius'] if row['vdw_radius'] else '—'} pm | Covalent radius: {row['covalent_radius'] if row['covalent_radius'] else '—'} pm",
151
- f"Radioactive: {'Yes' if row['is_radioactive'] else 'No'}",
152
- ]
153
- info_text = "\n".join(props_lines)
154
- facts_text = "\n• ".join(["Interesting facts:"] + facts) if facts else "No fact on file—still cool though!"
155
-
156
- prop_key = 'electronegativity' if not pd.isna(row['electronegativity']) else 'mass'
157
- label = dict(NUMERIC_PROPS)[prop_key]
158
- trend_df = DF[['Z', 'symbol', prop_key]].dropna()
159
- fig = px.scatter(
160
- trend_df, x='Z', y=prop_key, hover_name='symbol', title=f'{label} across the periodic table',
161
- )
162
- fig.add_scatter(x=[Z], y=[row[prop_key]] if row[prop_key] else [None],
163
- mode='markers+text', text=[symbol], textposition='top center')
164
-
165
- return info_text, facts_text, fig
166
-
167
- def handle_button_click(z: int):
168
- return element_info(str(z))
169
-
170
- def search_element(query: str):
171
- query = (query or '').strip()
172
- if not query:
173
- return gr.update(), gr.update(), gr.update()
174
- return element_info(query)
175
-
176
- def heatmap(property_key: str):
177
- prop_label = dict(NUMERIC_PROPS)[property_key]
178
- import numpy as np
179
- grid_vals = np.full((MAX_PERIOD, MAX_GROUP), None, dtype=object)
180
- for r in range(MAX_PERIOD):
181
- for c in range(MAX_GROUP):
182
- z = GRID[r][c]
183
- if z is None:
184
- continue
185
- val = DF.loc[DF['Z'] == z, property_key].values[0]
186
- grid_vals[r, c] = val if not pd.isna(val) else None
187
-
188
- fig = px.imshow(
189
- grid_vals.astype(float),
190
- origin='upper',
191
- labels=dict(color=prop_label, x='Group', y='Period'),
192
- x=list(range(1, MAX_GROUP+1)),
193
- y=list(range(1, MAX_PERIOD+1)),
194
- title=f'Periodic heatmap: {prop_label}',
195
- aspect='auto',
196
- color_continuous_scale='Viridis'
197
- )
198
- return fig
199
-
200
- with gr.Blocks(title="Interactive Periodic Table") as demo:
201
- gr.Markdown("# 🧪 Interactive Periodic Table\nClick an element or search by symbol/name/atomic number.")
202
-
203
- with gr.Row():
204
- with gr.Column(scale=2):
205
- gr.Markdown("### Main Table")
206
- with gr.Row():
207
- for g in range(1, 19):
208
- gr.Markdown(f"**{g}**")
209
- for r in range(MAX_PERIOD):
210
- with gr.Row():
211
- for c in range(MAX_GROUP):
212
- z = GRID[r][c]
213
- if z is None:
214
- gr.Button("", interactive=False)
215
- else:
216
- sym = DF.loc[DF['Z'] == z, 'symbol'].values[0]
217
- btn = gr.Button(sym)
218
- btn.click(handle_button_click, inputs=[gr.Number(z, visible=False)], outputs=[
219
- gr.Textbox(interactive=False), gr.Markdown(), gr.Plot()])
220
-
221
- gr.Markdown("### f-block (lanthanides & actinides)")
222
- with gr.Row():
223
- for z in LAN:
224
- sym = DF.loc[DF['Z'] == z, 'symbol'].values[0]
225
- btn = gr.Button(sym)
226
- btn.click(handle_button_click, inputs=[gr.Number(z, visible=False)], outputs=[
227
- gr.Textbox(interactive=False), gr.Markdown(), gr.Plot()])
228
- with gr.Row():
229
- for z in ACT:
230
- sym = DF.loc[DF['Z'] == z, 'symbol'].values[0]
231
- btn = gr.Button(sym)
232
- btn.click(handle_button_click, inputs=[gr.Number(z, visible=False)], outputs=[
233
- gr.Textbox(interactive=False), gr.Markdown(), gr.Plot()])
234
-
235
- with gr.Column(scale=1):
236
- search = gr.Textbox(label="Search (symbol/name/Z)", placeholder="e.g., C, Iron, 79")
237
- info = gr.Textbox(label="Properties", lines=10, interactive=False)
238
- facts = gr.Markdown("Select an element to see fun facts.")
239
- trend = gr.Plot()
240
-
241
- search.submit(search_element, inputs=[search], outputs=[info, facts, trend])
242
-
243
- gr.Markdown("### Trend heatmap")
244
- prop = gr.Dropdown(choices=[k for k, _ in NUMERIC_PROPS], value="electronegativity", label="Property")
245
- heat = gr.Plot()
246
- prop.change(heatmap, inputs=[prop], outputs=[heat])
247
- heat.update(heatmap("electronegativity"))
248
-
249
- if __name__ == "__main__":
250
- demo.launch()