Skip to content

Commit 5f751d1

Browse files
DanielYang59janosh
andauthored
Split make_assets scripts by plot functions (#247)
* migrate some changes * put under dir first * split coordination * split histogram * split phonon * splig rdf * splig scatter * splig structure_viz and scatter * split the rest * split ptable * copy random data generator * rename powerups plotly * remove plotly example from ptable mpl * move assets/(asset_makers->scripts) * mv assets/*.svg assets/svg/*.svg * change save_and_compress_svg default output directory to assets/svg/ * restore examples/ ruff per-file-ignores * rm assets/scripts/(scatter|uncertainty)/_random_regression_data.py unused, left from bad merge conflict resolve * revert ptable_heatmap_splits * add tests/data/regression.py * fix with_marginal_hist creating two nested coordinated axes in density_hexbin_(hex_)with_hist * make dummy data generator modular a bit * add config_matplotlib * remove np_rng * enhance description of dummy data with GPT * migrate ptable * migrate phonons * relocate ptable dash app * migrate the rest * mv pymatviz/test/data.py to pymatviz/data/__init__.py mv tests/test/test_data.py to tests/test_data.py * fix test.yml find-scripts looking in wrong folder * merge pymatviz/test/config.py into pymatviz/utils.py and rename config_matplotlib to apply_matplotlib_template add unit test for apply_matplotlib_template() remove unneeded plotly templates from matplotlib asset scripts * fix asset scripts failing in CI, delete duplicate assets/scripts/powerups/powerups.py remove unused pmv.set_plotly_template --------- Co-authored-by: Janosh Riebesell <[email protected]>
1 parent d47c39f commit 5f751d1

File tree

128 files changed

+1046
-653
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

128 files changed

+1046
-653
lines changed

.github/workflows/test.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ on:
1010
workflow_dispatch:
1111
workflow_call:
1212

13+
env:
14+
MPLBACKEND: Agg # non-interactive backend for matplotlib
15+
1316
jobs:
1417
tests:
1518
strategy:
@@ -36,7 +39,7 @@ jobs:
3639
- name: Find Python scripts
3740
id: set-matrix
3841
run: |
39-
SCRIPTS=$(find examples/make_assets -name "*.py" | jq -R -s -c 'split("\n")[:-1]')
42+
SCRIPTS=$(find assets/scripts -name "*.py" | jq -R -s -c 'split("\n")[:-1]')
4043
echo "script_list=$SCRIPTS" >> $GITHUB_OUTPUT
4144
4245
test-scripts:

assets/density-scatter-with-hist.svg

Lines changed: 0 additions & 1 deletion
This file was deleted.

examples/make_assets/coordination.py renamed to assets/scripts/coordination/coordination_hist.py

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
import pymatviz as pmv
1010
from pymatviz.coordination import CnSplitMode
11-
from pymatviz.enums import Key
1211
from pymatviz.utils import TEST_FILES
1312

1413

@@ -190,44 +189,3 @@
190189
)
191190
fig.show()
192191
pmv.io.save_and_compress_svg(fig, "coordination-hist-all-combined-side-by-side")
193-
194-
195-
# %% Coordination vs Cutoff example for a single structure
196-
fig = pmv.coordination_vs_cutoff_line(structures[key1])
197-
fig.layout.title = dict(text=f"Coordination vs Cutoff: {key1}", x=0.5, y=0.98)
198-
fig.layout.margin.t = 50
199-
fig.show()
200-
pmv.io.save_and_compress_svg(fig, "coordination-vs-cutoff-single")
201-
202-
203-
# %% Coordination vs Cutoff example for multiple structures
204-
fig = pmv.coordination_vs_cutoff_line(
205-
{key1: structures[key1], key2: structures[key2], key3: structures[key3]},
206-
strategy=(1.0, 6.0),
207-
num_points=100,
208-
)
209-
fig.layout.title = dict(
210-
text="Coordination vs Cutoff: Multiple Structures", x=0.5, y=0.98
211-
)
212-
fig.layout.legend.update(x=0, y=1, bgcolor="rgba(0,0,0,0)")
213-
fig.layout.margin.t = 50
214-
fig.show()
215-
pmv.io.save_and_compress_svg(fig, "coordination-vs-cutoff-multiple")
216-
217-
218-
# %% Coordination vs Cutoff example with custom color scheme
219-
custom_colors = {"Pd": "red", "Zr": "blue"}
220-
fig = pmv.coordination_vs_cutoff_line(
221-
structures[key1], element_color_scheme=custom_colors
222-
)
223-
fig.layout.margin.t = 25
224-
fig.layout.legend.update(x=0, y=1)
225-
fig.show()
226-
pmv.io.save_and_compress_svg(fig, "coordination-vs-cutoff-custom-colors")
227-
228-
229-
# %% plot first 10 structures
230-
fig = pmv.coordination_vs_cutoff_line(df_phonon[Key.structure][:4].tolist())
231-
fig.layout.margin.t = 25
232-
fig.layout.legend.update(x=0, y=1)
233-
fig.show()
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# %%
2+
from glob import glob
3+
4+
from matminer.datasets import load_dataset
5+
from pymatgen.core import Structure
6+
from pymatgen.symmetry.analyzer import SpacegroupAnalyzer
7+
8+
import pymatviz as pmv
9+
from pymatviz.enums import Key
10+
from pymatviz.utils import TEST_FILES
11+
12+
13+
pmv.set_plotly_template("pymatviz_white")
14+
15+
df_phonon = load_dataset(data_name := "matbench_phonons")
16+
17+
18+
# %%
19+
formula_spg_str = (
20+
lambda struct: f"{struct.formula} ({struct.get_space_group_info()[1]})"
21+
)
22+
structures = {
23+
formula_spg_str(struct := Structure.from_file(file)): struct
24+
for file in (
25+
glob(f"{TEST_FILES}/structures/*.json.gz") + glob(f"{TEST_FILES}/xrd/*.cif")
26+
)
27+
}
28+
key1, key2, key3, *_ = structures
29+
30+
for struct in structures.values():
31+
spga = SpacegroupAnalyzer(struct)
32+
sym_struct = spga.get_symmetrized_structure()
33+
# add wyckoff symbols to each site
34+
struct.add_oxidation_state_by_guess()
35+
wyckoff_symbols = ["n/a"] * len(struct)
36+
for indices, symbol in zip(
37+
sym_struct.equivalent_indices, sym_struct.wyckoff_symbols, strict=True
38+
):
39+
for index in indices:
40+
wyckoff_symbols[index] = symbol
41+
if any(sym == "n/a" for sym in wyckoff_symbols):
42+
raise ValueError(f"{struct.formula} has n/a {wyckoff_symbols=}")
43+
44+
struct.add_site_property("wyckoff", wyckoff_symbols)
45+
46+
47+
# %% Coordination vs Cutoff example for a single structure
48+
fig = pmv.coordination_vs_cutoff_line(structures[key1])
49+
fig.layout.title = dict(text=f"Coordination vs Cutoff: {key1}", x=0.5, y=0.98)
50+
fig.layout.margin.t = 50
51+
fig.show()
52+
pmv.io.save_and_compress_svg(fig, "coordination-vs-cutoff-single")
53+
54+
55+
# %% Coordination vs Cutoff example for multiple structures
56+
fig = pmv.coordination_vs_cutoff_line(
57+
{key1: structures[key1], key2: structures[key2], key3: structures[key3]},
58+
strategy=(1.0, 6.0),
59+
num_points=100,
60+
)
61+
fig.layout.title = dict(
62+
text="Coordination vs Cutoff: Multiple Structures", x=0.5, y=0.98
63+
)
64+
fig.layout.legend.update(x=0, y=1, bgcolor="rgba(0,0,0,0)")
65+
fig.layout.margin.t = 50
66+
fig.show()
67+
pmv.io.save_and_compress_svg(fig, "coordination-vs-cutoff-multiple")
68+
69+
70+
# %% Coordination vs Cutoff example with custom color scheme
71+
custom_colors = {"Pd": "red", "Zr": "blue"}
72+
fig = pmv.coordination_vs_cutoff_line(
73+
structures[key1], element_color_scheme=custom_colors
74+
)
75+
fig.layout.margin.t = 25
76+
fig.layout.legend.update(x=0, y=1)
77+
fig.show()
78+
pmv.io.save_and_compress_svg(fig, "coordination-vs-cutoff-custom-colors")
79+
80+
81+
# %% plot first 10 structures
82+
fig = pmv.coordination_vs_cutoff_line(df_phonon[Key.structure][:4].tolist())
83+
fig.layout.margin.t = 25
84+
fig.layout.legend.update(x=0, y=1)
85+
fig.show()
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# %%
2+
from matminer.datasets import load_dataset
3+
4+
import pymatviz as pmv
5+
from pymatviz.enums import Key
6+
7+
8+
# %% Histogram Plots
9+
df_expt_gap = load_dataset("matbench_expt_gap")
10+
11+
ax = pmv.elements_hist(
12+
df_expt_gap[Key.composition], keep_top=15, v_offset=200, rotation=0, fontsize=12
13+
)
14+
pmv.io.save_and_compress_svg(ax, "elements-hist")

assets/scripts/histogram/histogram.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# %%
2+
import numpy as np
3+
4+
import pymatviz as pmv
5+
6+
7+
pmv.set_plotly_template("pymatviz_white")
8+
9+
10+
# %% plot 2 Gaussians and their cumulative distribution functions
11+
rand_regression_size = 500
12+
np_rng = np.random.default_rng(seed=0)
13+
gauss1 = np_rng.normal(5, 4, rand_regression_size)
14+
gauss2 = np_rng.normal(10, 2, rand_regression_size)
15+
16+
fig = pmv.histogram({"Gaussian 1": gauss1, "Gaussian 2": gauss2}, bins=100)
17+
for idx in range(len(fig.data)):
18+
pmv.powerups.add_ecdf_line(fig, trace_idx=idx)
19+
fig.show()
20+
21+
pmv.io.save_and_compress_svg(fig, "histogram-ecdf")
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# %%
2+
from matminer.datasets import load_dataset
3+
from tqdm import tqdm
4+
5+
import pymatviz as pmv
6+
from pymatviz.enums import Key
7+
8+
9+
pmv.set_plotly_template("pymatviz_white")
10+
11+
12+
# %%
13+
df_phonons = load_dataset("matbench_phonons")
14+
15+
df_phonons[[Key.spg_symbol, Key.spg_num]] = [
16+
struct.get_space_group_info()
17+
for struct in tqdm(df_phonons[Key.structure], desc="Getting spacegroups")
18+
]
19+
20+
21+
# %% Spacegroup histograms
22+
for backend in pmv.BACKENDS:
23+
fig = pmv.spacegroup_bar(df_phonons[Key.spg_num], backend=backend)
24+
pmv.io.save_and_compress_svg(fig, f"spg-num-hist-{backend}")
25+
26+
fig = pmv.spacegroup_bar(df_phonons[Key.spg_symbol], backend=backend)
27+
pmv.io.save_and_compress_svg(fig, f"spg-symbol-hist-{backend}")
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# %%
2+
import json
3+
from glob import glob
4+
5+
from monty.io import zopen
6+
from monty.json import MontyDecoder
7+
from pymatgen.phonon.bandstructure import PhononBandStructureSymmLine as PhononBands
8+
9+
import pymatviz as pmv
10+
from pymatviz.enums import Key
11+
12+
13+
# TODO: ffonons not working properly (see #195)
14+
try:
15+
import ffonons # noqa: F401
16+
except ImportError:
17+
raise SystemExit(0) from None # install ffonons to run this script
18+
19+
20+
# %% Plot phonon bands and DOS
21+
for mp_id, formula in (
22+
("mp-2758", "Sr4Se4"),
23+
("mp-23907", "H2"),
24+
):
25+
docs = {}
26+
for path in glob(f"{pmv.utils.TEST_FILES}/phonons/{mp_id}-{formula}-*.json.lzma"):
27+
key = path.split("-")[-1].split(".")[0]
28+
with zopen(path) as file:
29+
docs[key] = json.loads(file.read(), cls=MontyDecoder)
30+
31+
ph_bands: dict[str, PhononBands] = {
32+
key: getattr(doc, Key.ph_band_structure) for key, doc in docs.items()
33+
}
34+
35+
fig = pmv.phonon_bands(ph_bands)
36+
fig.layout.title = dict(text=f"Phonon Bands of {formula} ({mp_id})", x=0.5, y=0.98)
37+
fig.layout.margin = dict(l=0, r=0, b=0, t=40)
38+
pmv.io.save_and_compress_svg(fig, f"phonon-bands-{mp_id}")

examples/make_assets/phonons.py renamed to assets/scripts/phonons/phonon_bands_and_dos.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,6 @@
3636
key: getattr(doc, Key.ph_dos) for key, doc in docs.items()
3737
}
3838

39-
fig = pmv.phonon_bands(ph_bands)
40-
fig.layout.title = dict(text=f"Phonon Bands of {formula} ({mp_id})", x=0.5, y=0.98)
41-
fig.layout.margin = dict(l=0, r=0, b=0, t=40)
42-
pmv.io.save_and_compress_svg(fig, f"phonon-bands-{mp_id}")
43-
44-
fig = pmv.phonon_dos(ph_doses)
45-
fig.layout.title = dict(text=f"Phonon DOS of {formula} ({mp_id})", x=0.5, y=0.98)
46-
fig.layout.margin = dict(l=0, r=0, b=0, t=40)
47-
pmv.io.save_and_compress_svg(fig, f"phonon-dos-{mp_id}")
48-
4939
fig = pmv.phonon_bands_and_dos(ph_bands, ph_doses)
5040
fig.layout.title = dict(
5141
text=f"Phonon Bands and DOS of {formula} ({mp_id})", x=0.5, y=0.98

assets/scripts/phonons/phonon_dos.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# %%
2+
import json
3+
from glob import glob
4+
5+
from monty.io import zopen
6+
from monty.json import MontyDecoder
7+
from pymatgen.phonon.dos import PhononDos
8+
9+
import pymatviz as pmv
10+
from pymatviz.enums import Key
11+
12+
13+
# TODO: ffonons not working properly (see #195)
14+
try:
15+
import ffonons # noqa: F401
16+
except ImportError:
17+
raise SystemExit(0) from None # install ffonons to run this script
18+
19+
20+
# %% Plot phonon bands and DOS
21+
for mp_id, formula in (
22+
("mp-2758", "Sr4Se4"),
23+
("mp-23907", "H2"),
24+
):
25+
docs = {}
26+
for path in glob(f"{pmv.utils.TEST_FILES}/phonons/{mp_id}-{formula}-*.json.lzma"):
27+
key = path.split("-")[-1].split(".")[0]
28+
with zopen(path) as file:
29+
docs[key] = json.loads(file.read(), cls=MontyDecoder)
30+
31+
ph_doses: dict[str, PhononDos] = {
32+
key: getattr(doc, Key.ph_dos) for key, doc in docs.items()
33+
}
34+
35+
fig = pmv.phonon_dos(ph_doses)
36+
fig.layout.title = dict(text=f"Phonon DOS of {formula} ({mp_id})", x=0.5, y=0.98)
37+
fig.layout.margin = dict(l=0, r=0, b=0, t=40)
38+
pmv.io.save_and_compress_svg(fig, f"phonon-dos-{mp_id}")
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# %%
2+
from matminer.datasets import load_dataset
3+
4+
import pymatviz as pmv
5+
from pymatviz.enums import Key
6+
7+
8+
# %%
9+
df_expt_gap = load_dataset("matbench_expt_gap")
10+
11+
12+
# %% Elemental Plots
13+
ax = pmv.ptable_heatmap(
14+
pmv.count_elements(df_expt_gap[Key.composition]),
15+
log=True,
16+
return_type="axes", # TODO: change to return Figure after 2025-07-01
17+
)
18+
title = (
19+
f"Elements in Matbench Experimental Band Gap ({len(df_expt_gap):,} compositions)"
20+
)
21+
ax.set_title(title, x=0.75, y=2.5, fontsize=18, fontweight="bold")
22+
pmv.io.save_and_compress_svg(ax, "ptable-heatmap")
23+
24+
25+
# %%
26+
fig = pmv.ptable_heatmap(pmv.df_ptable[Key.atomic_mass], return_type="figure")
27+
fig.suptitle("Atomic Mass Heatmap", y=0.96, fontsize=20, fontweight="bold")
28+
pmv.io.save_and_compress_svg(fig, "ptable-heatmap-atomic-mass")
29+
30+
31+
# %%
32+
# Filter out near-zero entries
33+
ptable_data = pmv.count_elements(df_expt_gap[Key.composition])
34+
ptable_data = ptable_data[ptable_data > 0.01]
35+
36+
fig = pmv.ptable_heatmap(
37+
ptable_data,
38+
value_show_mode="percent",
39+
exclude_elements=["O"],
40+
return_type="figure",
41+
)
42+
title = "Elements in Matbench Experimental Band Gap (percent)"
43+
fig.suptitle(title, y=0.96, fontsize=20, fontweight="bold")
44+
pmv.io.save_and_compress_svg(fig, "ptable-heatmap-percent")
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# %%
2+
from matminer.datasets import load_dataset
3+
4+
import pymatviz as pmv
5+
from pymatviz.enums import Key
6+
7+
8+
# %%
9+
df_expt_gap = load_dataset("matbench_expt_gap")
10+
df_steels = load_dataset("matbench_steels")
11+
12+
13+
# %%
14+
fig = pmv.ptable_heatmap_ratio(
15+
df_expt_gap[Key.composition], df_steels[Key.composition], log=True, value_fmt=".4g"
16+
)
17+
title = "Element ratios in Matbench Experimental Band Gap vs Matbench Steel"
18+
fig.suptitle(title, y=0.96, fontsize=16, fontweight="bold")
19+
pmv.io.save_and_compress_svg(fig, "ptable-heatmap-ratio")

0 commit comments

Comments
 (0)