Density of States (DOS)
The Dos component visualizes electronic and phonon density of states from canonical data keyed by series label.
Basic Usage
Pass a record to doses. Each entry declares type: "phonon" with frequencies in THz, or type: "electronic" with energies in eV, plus densities.
Interactive example
svelte<script lang="ts">
import { Dos } from 'matterviz'
import { phonon_dos } from '#site/phonons/index.js'
</script>
<Dos doses={{ '': phonon_dos['mp-2758-Sr4Se4-pbe'] }} />Electronic DOS with Spin Polarization
Convert pymatgen CompleteDos and LobsterCompleteDos objects with normalize_dos at the input boundary. Spin-polarized data (stored as {1: [...], -1: [...]}) is automatically extracted and drawn according to spin_mode: mirror (default, spin-down below zero), overlay, up_only or down_only. Use shift_to_fermi() to center energies at E_F = 0:
Interactive example
svelte<script lang="ts">
import { Dos } from 'matterviz'
import { shift_to_fermi, normalize_dos, extract_pdos } from '#lib/spectral/helpers.js'
import { dos_spin_polarization } from '#site/electronic/dos/index.js'
const total_dos = normalize_dos(shift_to_fermi(dos_spin_polarization))
if (!total_dos) throw new Error('Invalid DOS fixture')
</script>
{#if total_dos}<Dos doses={{ '': total_dos }} />{/if}Projected DOS (pDOS)
Extract atom-resolved or orbital-resolved projections from CompleteDos using extract_pdos(raw, type):
Interactive example
svelte<script lang="ts">
import { Dos } from 'matterviz'
import { shift_to_fermi, normalize_dos, extract_pdos } from '#lib/spectral/helpers.js'
import { dos_spin_polarization } from '#site/electronic/dos/index.js'
let pdos_type = $state<'atom' | 'orbital'>('atom')
const projected = $derived(extract_pdos(shift_to_fermi(dos_spin_polarization), pdos_type))
</script>
<label style="display: block; margin-bottom: 0.5em">
Projection:
<select bind:value={pdos_type}>
<option value="atom">Atom-resolved (Ta, Zn, Co)</option>
<option value="orbital">Orbital-resolved (s, p, d)</option>
</select>
</label>
{#if projected}<Dos doses={projected} stack spin_mode="up_only" />{/if}Stacking and Smearing
Use stack for filled areas, sigma for Gaussian smearing and normalize (max, sum, integral). Phonon DOS also accepts units (THz, eV, meV, Ha, cm^-1).
Interactive example
svelte<script lang="ts">
import { Dos } from 'matterviz'
import { phonon_dos } from '#site/phonons/index.js'
const dos = phonon_dos['mp-2758-Sr4Se4-pbe']
const doses = {
'Mode A': { ...dos, densities: dos.densities.map((density) => density * 0.45) },
'Mode B': { ...dos, densities: dos.densities.map((density) => density * 0.35) },
'Mode C': { ...dos, densities: dos.densities.map((density) => density * 0.2) },
}
</script>
<Dos {doses} normalize="max" sigma={0.1} stack />Thermal Properties
thermal_properties(dos, temperatures, unit) integrates the Bose–Einstein occupation over a phonon DOS to give the harmonic free energy F, internal energy U, entropy S and heat capacity Cv (eV and eV/K per whatever the DOS integrates to, 3N modes per cell here). PhononThermalPlot draws them against temperature, in phonopy’s kJ/mol and J/(K·mol) by default, with F and U on the left axis and S and Cv on the right. For this simulated Sr4Se4 DOS (2 atoms in the primitive cell) Cv tends to the classical limit of 6 kB ≈ 49.9 J/(K·mol), reaching 49.5 by 500 K:
Interactive example
svelte<script lang="ts">
import { PhononThermalPlot, format_num, thermal_properties } from 'matterviz'
import { phonon_dos } from '#site/phonons/index.js'
let energy_unit = $state<'kJ/mol' | 'eV'>(`kJ/mol`)
const dos = phonon_dos['mp-2758-Sr4Se4-pbe']
const temperatures = Array.from({ length: 81 }, (_, idx) => 10 * idx)
const { zero_point_energy } = thermal_properties(dos, temperatures)
</script>
<label style="display: block; margin-bottom: 1ex">
Units
<select bind:value={energy_unit}>
<option value="kJ/mol">kJ/mol, J/(K·mol)</option>
<option value="eV">eV, meV/K</option>
</select>
· zero-point energy {format_num(zero_point_energy, `.4f`)} eV/cell
</label>
<PhononThermalPlot {dos} {temperatures} {energy_unit} />Interactive Explorer
Browse all available DOS files. Click to load, use controls to adjust visualization:
Interactive example
svelte<script lang="ts">
import { Dos, FilePicker } from 'matterviz'
import { shift_to_fermi, normalize_dos, extract_pdos } from '#lib/spectral/helpers.js'
import { dos_spin_polarization, get_dos } from '#site/electronic/dos/index.js'
import { phonon_dos } from '#site/phonons/index.js'
const files = [
{
name: 'mp-865805 (Ta-Zn-Co)',
data: shift_to_fermi(dos_spin_polarization),
category: 'Electronic',
category_icon: '⚡',
},
{
name: 'KF Lobster',
data: get_dos('lobster'),
category: 'Electronic',
category_icon: '⚡',
},
...Object.entries(phonon_dos).map(([key, data]) => ({
name: key.replace('mp-', '').replace(/-/g, ' '),
data,
category: 'Phonon',
category_icon: '🔊',
})),
]
let active_file = $state(files[0].name)
let pdos_type = $state<'atom' | 'orbital' | null>(null)
const current_dos = $derived(files.find((file) => file.name === active_file)?.data)
const doses = $derived.by(() => {
if (pdos_type) {
const projected = extract_pdos(current_dos, pdos_type)
if (!projected) throw new Error(`No ${pdos_type} projected DOS in ${active_file}`)
return projected
}
const total = normalize_dos(current_dos)
if (!total) throw new Error(`Invalid DOS in ${active_file}`)
return { '': total }
})
const is_electronic = $derived(
files.find((file) => file.name === active_file)?.category === 'Electronic',
)
</script>
<div
style="display: flex; gap: 1em; margin-bottom: 0.5em; align-items: center; flex-wrap: wrap"
>
<FilePicker
files={files.map((file) => ({
name: file.name,
category: file.category,
category_icon: file.category_icon,
}))}
active_files={[active_file]}
show_category_filters
on_click={(file) => ([active_file, pdos_type] = [file.name, null])}
/>
{#if is_electronic}
<select bind:value={pdos_type} style="padding: 4px">
<option value={null}>Total DOS</option>
<option value="atom">Atom pDOS</option>
<option value="orbital">Orbital pDOS</option>
</select>
{/if}
</div>
<Dos
{doses}
stack={pdos_type !== null}
show_normalize_control
show_units_control={!is_electronic}
/>