Periodic table
<html> TODO: - print total number of PDB entries (footnote or next to Select elements…) - periodic table
- better (gradual) coloring of elements
- elements D and X
- examples:
- list of extra element in each example
- link titles with the PDB title
–> <html lang=en> <meta charset=UTF-8/> <meta name=viewport content=width=device-width, user-scalable=no> <meta name=theme-color content=#ee7711> <title>PDB search with periodic table</title> <script src=data.js></script> <style type=text/css> html { width: 100%; font-family: sans-serif; background-color: #fdfdfd; } @media (max-width: 600px) { html { width: 600px; } } @media (max-width: 800px) { body { margin: 0; } } h1 { font-size: 24px; text-align: center; color: #444; margin-bottom: -10px; } h2 { font-size: 16px; text-align: center; color: #444; margin-bottom: 2px; } h2 span { cursor: pointer; border-style: outset; color: #444;
border-width: 2px; padding: 2px; font-weight: normal; }
h2 span.on { border-style: inset; text-shadow: 1px 1px 0 #444; } #detour { font-size: 11px; line-height: 3; text-align: center; color: #333; } #footnote { font-size: 10px; text-align: center; color: #333; } #periodic { margin: 0 auto; border-spacing: 3px; } @media (min-width: 701px) and (max-width: 800px)
{ #periodic { border-spacing: 2px; } }
@media (max-width: 700px) { #periodic { border-spacing: 1px; } } #periodic tr td { background-color: #f8f8f8; width: 32px; height: 32px;
cursor: pointer; border-style: outset; border-width: 3px; }
@media (max-width: 700px) { #periodic tr td { border-width: 2px; } } #periodic tr td.empty { background-color: transparent; cursor: auto;
border: none; text-align: left; }
#periodic tr.spacer td { height: 10px; } #periodic tr td sup { font-size: 11px; display: block; text-align: center; } #periodic tr td { font-size: 15px; text-align: center; position: relative; } #periodic tr td.sel { border-style: inset; text-shadow: 1px 1px 1px #222; } #periodic tr td.sel sup::before { content: '\25CF'; color: #0f0; font-size: 8px;
position: absolute; top: -1px; left: 1px; }
#desc { padding: 0 30px; color: #555; } #examples { margin: 0 auto; } #examples tr td { background-color: #fff; width: 167px; height: 167px;
font-size: 48px; color: #aaa; text-align: center; background-size: cover; background-repeat: no-repeat; background-position: center center; }
#examples tr td a { display: block; width: 100%; height: 100%;
text-align: left; vertical-align: top; font-size: 16px; color: #888; text-decoration: none; }
table.hide_optional tr.optional { display: none; } </style> <h1>Protein Data Bank entries by elements</h1>
<h2>
<span id="show5" class="on">5</span> <span id="show15">15</span> examples <span id="showPics" class="on">with pics</span>
</h2>
See other <a href="https://project-gemmi.github.io/pdb-stats/">GEMMI visualizations</a>.
© 2017 Global Phasing Ltd. License: MPL 2.0. Images are from RCSB. Last update: 2017-12-01, 135519 PDB entries. <a href="https://github.com/project-gemmi/periodic-table">Source code & info...</a>
<script>
global data defined in data.js var elem_count; a list of 118+2 numbers var ids_by_elems; {C_N_O_S_Zn: [n, '1pdb', '2pdb', …]}, length >2500 window.onload = (function () { 'use strict'; other globals var desc; var example_tds; var show_pics = true; var show15 = false; var state = []; 1-based for (var i_ = 0; i_ < 118+2; i_++) state.push(false); var elements = ['H', 'He', 'Li', 'Be', 'B', 'C', 'N', 'O', 'F', 'Ne', 'Na', 'Mg', 'Al', 'Si', 'P', 'S', 'Cl', 'Ar', 'K', 'Ca', 'Sc', 'Ti', 'V', 'Cr', 'Mn', 'Fe', 'Co', 'Ni', 'Cu', 'Zn', 'Ga', 'Ge', 'As', 'Se', 'Br', 'Kr', 'Rb', 'Sr', 'Y', 'Zr', 'Nb', 'Mo', 'Tc', 'Ru', 'Rh', 'Pd', 'Ag', 'Cd', 'In', 'Sn', 'Sb', 'Te', 'I', 'Xe', 'Cs', 'Ba', 'La', 'Ce', 'Pr', 'Nd', 'Pm', 'Sm', 'Eu', 'Gd', 'Tb', 'Dy', 'Ho', 'Er', 'Tm', 'Yb', 'Lu', 'Hf', 'Ta', 'W', 'Re', 'Os', 'Ir', 'Pt', 'Au', 'Hg', 'Tl', 'Pb', 'Bi', 'Po', 'At', 'Rn', 'Fr', 'Ra', 'Ac', 'Th', 'Pa', 'U', 'Np', 'Pu', 'Am', 'Cm', 'Bk', 'Cf', 'Es', 'Fm', 'Md', 'No', 'Lr', 'Rf', 'Db', 'Sg', 'Bh', 'Hs', 'Mt', 'Ds', 'Rg', 'Cn', 'Nh', 'Fl', 'Mc', 'Lv', 'Ts', 'Og', 'D', 'X']; var PDB_LINK = 'https://www.ebi.ac.uk/pdbe/entry/pdb/'; var PDB_LINK = 'https://www.rcsb.org/pdb/explore/explore.do?structureId='; function image_link(pdb_id) {
return 'https://www.rcsb.org/pdb/images/' + pdb_id + '_bio_r_250.jpg';
}
function contains(key, names) {
for (var i = 0; i < names.length; i++) { if (key.indexOf(names[i]) === -1) return false; } return true;
}
function toggle_elem(td) {
var n = elements.indexOf(td.id); var sel = state[n]; state[n] = !sel; td.className = sel ? '' : 'sel'; update();
};
function update() {
var NE = 15; // number of examples var names = []; var padded_names = []; var indices = []; for (var i = 0; i < elements.length; i++) { var element = elements[i]; if (state[i]) { names.push(element); indices.push(i); padded_names.push(element.length == 1 ? element + '_' : element); } } var exact_key = padded_names.join(''); if (names.length === 0) { desc.innerHTML = 'Select elements...'; for (var i = 0; i < example_tds.length; i++) { setup_example(example_tds[i], null); } return; } var exact_match = ids_by_elems[exact_key]; var only_count = exact_match ? exact_match[0] : 0; var example_codes = only_count > 0 ? exact_match.slice(1) : []; var incl_count = 0; for (var k in ids_by_elems) { if (contains(k, padded_names)) { incl_count += ids_by_elems[k][0]; if (example_codes.length < NE && k !== exact_key) { Array.prototype.push.apply(example_codes, ids_by_elems[k].slice(1, NE+1)); } } } desc.innerHTML = 'selected: ' + names.join(', ') + '<br/>entries with it: ' + incl_count + '<br/>entries with only it: ' + only_count; for (var i = 0; i < example_tds.length; i++) { setup_example(example_tds[i], example_codes[i]); }
}
function setup_example(td, code) {
if (code != null) { td.innerHTML = '<a href="' + PDB_LINK + code + '">' + code + '</a>'; td.style.backgroundImage = show_pics ? 'url(' + image_link(code) + ')' : ''; } else { td.innerHTML = '×'; td.style.backgroundImage = ''; }
}
function color_for_count(cnt) {
if (cnt < 1) return '#f8f8f8'; if (cnt < 10) return '#fdfde4'; if (cnt < 25) return '#fdfdd0'; if (cnt < 100) return '#fdfdbb'; if (cnt < 250) return '#fff8a0'; if (cnt < 1000) return '#fe8'; if (cnt < 5000) return '#fc5'; if (cnt < 10000) return '#f93'; if (cnt < 30000) return '#e71'; if (cnt < 100000) return '#d61'; return '#c41';
}
function init_cell(cell) {
cell.onclick = function () { toggle_elem(cell); }; var cnt = elem_count[elements.indexOf(cell.id)]; cell.style.backgroundColor = color_for_count(cnt);
}
function update_5_15() {
document.getElementById('show5').className = show15 ? '' : 'on'; document.getElementById('show15').className = show15 ? 'on' : ''; document.getElementById('examples').className = show15 ? '' : 'hide_optional';
}
return function () { initialization desc = document.getElementById('desc'); desc.innerHTML = 'Select elements…'; example_tds = document.getElementById('examples').getElementsByTagName('td'); var cells = document.getElementById('periodic').getElementsByTagName('td'); for (var i = 0; i < cells.length; i++) { if (cells[i].className !== 'empty') init_cell(cells[i]); } document.getElementById('show5').onclick = function () { show15 = false; update_5_15(); } document.getElementById('show15').onclick = function () { show15 = true; update_5_15(); } document.getElementById('showPics').onclick = function () { show_pics = !show_pics; document.getElementById('showPics').className = show_pics ? 'on' : ''; update(); } }; })(); </script> </html>
Discussion