Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clean up var names in unit tests, avoid MP API access in GitHub workflow #207

Merged
merged 17 commits into from
Sep 29, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions examples/make_assets/structure_viz.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# %%
import os
from typing import cast

import matplotlib.pyplot as plt
Expand All @@ -10,8 +11,6 @@
from pymatviz.enums import ElemColorScheme, Key


struct: Structure # for type hinting

df_steels = load_dataset("matbench_steels")
df_phonons = load_dataset("matbench_phonons")

Expand All @@ -31,11 +30,18 @@


# %% Plot some disordered structures in 2D
if os.environ.get("MP_API_KEY") is None:
DanielYang59 marked this conversation as resolved.
Show resolved Hide resolved
raise RuntimeError("no mp api key, debugging")

disordered_structs = {
mp_id: MPRester().get_structure_by_material_id(mp_id, conventional_unit_cell=True)
mp_id: MPRester(api_key=os.environ.get("MP_API_KEY")).get_structure_by_material_id(
mp_id, conventional_unit_cell=True
)
for mp_id in ["mp-19017", "mp-12712"]
}

struct: Structure # for type hinting

for mp_id, struct in disordered_structs.items():
for site in struct: # disorder structures in-place
if "Fe" in site.species:
Expand Down
14 changes: 7 additions & 7 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
from collections.abc import Generator


# if platform is windows, set matplotlib backend to "Agg" to fix
# _tkinter.TclError: Can't find a usable init.tcl in the following directories
# https://github.com/orgs/community/discussions/26434
# If platform is Windows, set matplotlib backend to "Agg" to fix:
# "_tkinter.TclError: Can't find a usable init.tcl in the following directories"
# See: https://github.com/orgs/community/discussions/26434
if platform.system() == "Windows":
import matplotlib as mpl

Expand Down Expand Up @@ -52,10 +52,10 @@ def df_or_arrays(request: pytest.FixtureRequest) -> DfOrArrays:

@pytest.fixture(autouse=True)
def _run_around_tests() -> Generator[None, None, None]:
"""Ensure matplotlib plots are closed after each test so as not to leak state
between tests."""
"""Ensure matplotlib plots are closed after each test
so as not to leak state between tests.
"""
# runs before each test

yield

# runs after each test
Expand Down Expand Up @@ -121,7 +121,7 @@ def matplotlib_scatter() -> plt.Figure:

@pytest.fixture
def glass_formulas() -> list[str]:
"""First 20 materials in the Matbench glass dataset.
"""First 20 materials in the MatBench glass dataset.

from matminer.datasets import load_dataset

Expand Down
4 changes: 0 additions & 4 deletions tests/test_bar.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

from pymatviz.bar import spacegroup_bar
from pymatviz.utils import BACKENDS, MATPLOTLIB, PLOTLY
from tests.conftest import y_pred, y_true


if TYPE_CHECKING:
Expand All @@ -20,9 +19,6 @@
from pymatviz.utils import Backend


y_std_mock = y_true - y_pred


@pytest.mark.parametrize("backend", BACKENDS)
@pytest.mark.parametrize(
("xticks", "show_counts", "show_empty_bins", "log"),
Expand Down
38 changes: 19 additions & 19 deletions tests/test_scatter.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
from tests.conftest import DfOrArrays


x_col, y_col, *_ = df_regr
df_tips = px.data.tips()
X_COL, Y_COL, *_ = df_regr
DF_TIPS = px.data.tips()


@pytest.mark.parametrize("log_density", [True, False])
Expand Down Expand Up @@ -166,7 +166,7 @@ def test_density_scatter_plotly(


def test_density_scatter_plotly_hover_template() -> None:
fig = density_scatter_plotly(df=df_regr, x=x_col, y=y_col, log_density=True)
fig = density_scatter_plotly(df=df_regr, x=X_COL, y=Y_COL, log_density=True)
hover_template = fig.data[0].hovertemplate
assert "Point Density" in hover_template
assert "color" not in hover_template # Ensure log-count values are not displayed
Expand All @@ -175,18 +175,18 @@ def test_density_scatter_plotly_hover_template() -> None:
@pytest.mark.parametrize("stats", [1, (1,), "foo"])
def test_density_scatter_plotly_raises_on_bad_stats_type(stats: Any) -> None:
with pytest.raises(TypeError, match="stats must be bool or dict"):
density_scatter_plotly(df=df_regr, x=x_col, y=y_col, stats=stats)
density_scatter_plotly(df=df_regr, x=X_COL, y=Y_COL, stats=stats)


def test_density_scatter_plotly_empty_dataframe() -> None:
empty_df = pd.DataFrame({x_col: [], y_col: []})
empty_df = pd.DataFrame({X_COL: [], Y_COL: []})
with pytest.raises(ValueError, match="input should have multiple elements"):
density_scatter_plotly(df=empty_df, x=x_col, y=y_col)
density_scatter_plotly(df=empty_df, x=X_COL, y=Y_COL)


def test_density_scatter_plotly_facet() -> None:
fig = density_scatter_plotly(
df=df_tips, x="total_bill", y="tip", facet_col="smoker"
df=DF_TIPS, x="total_bill", y="tip", facet_col="smoker"
)

assert isinstance(fig, go.Figure)
Expand All @@ -196,7 +196,7 @@ def test_density_scatter_plotly_facet() -> None:

def test_density_scatter_plotly_facet_log_density() -> None:
fig = density_scatter_plotly(
df=df_tips, x="total_bill", y="tip", facet_col="smoker", log_density=True
df=DF_TIPS, x="total_bill", y="tip", facet_col="smoker", log_density=True
)

assert fig.layout.coloraxis.colorbar.ticktext is not None
Expand All @@ -205,7 +205,7 @@ def test_density_scatter_plotly_facet_log_density() -> None:

def test_density_scatter_plotly_facet_stats() -> None:
fig = density_scatter_plotly(
df=df_tips, x="total_bill", y="tip", facet_col="smoker", stats=True
df=DF_TIPS, x="total_bill", y="tip", facet_col="smoker", stats=True
)

# Check there are at least 2 annotations (could be more due to facet labels)
Expand All @@ -217,7 +217,7 @@ def test_density_scatter_plotly_facet_stats() -> None:

def test_density_scatter_plotly_facet_best_fit_line() -> None:
fig = density_scatter_plotly(
df=df_tips, x="total_bill", y="tip", facet_col="smoker", best_fit_line=True
df=DF_TIPS, x="total_bill", y="tip", facet_col="smoker", best_fit_line=True
)

# Check there are at least 4 shapes (2 identity lines, 2 best fit lines)
Expand All @@ -231,18 +231,18 @@ def test_density_scatter_plotly_facet_best_fit_line() -> None:

def test_density_scatter_plotly_facet_custom_bins() -> None:
fig = density_scatter_plotly(
df=df_tips, x="total_bill", y="tip", facet_col="smoker", n_bins=10
df=DF_TIPS, x="total_bill", y="tip", facet_col="smoker", n_bins=10
)

# Check that binning has been applied (number of points should be reduced)
smoker_count = df_tips["smoker"].value_counts()
smoker_count = DF_TIPS["smoker"].value_counts()
assert len(fig.data[0].x) < smoker_count["No"]
assert len(fig.data[1].x) < smoker_count["Yes"]


def test_density_scatter_plotly_facet_custom_color() -> None:
fig = density_scatter_plotly(
df=df_tips,
df=DF_TIPS,
x="total_bill",
y="tip",
facet_col="smoker",
Expand All @@ -260,7 +260,7 @@ def test_density_scatter_plotly_facet_density_methods(
density: Literal["kde", "empirical"],
) -> None:
fig = density_scatter_plotly(
df=df_tips, x="total_bill", y="tip", facet_col="smoker", density=density
df=DF_TIPS, x="total_bill", y="tip", facet_col="smoker", density=density
)

assert isinstance(fig, go.Figure)
Expand All @@ -269,30 +269,30 @@ def test_density_scatter_plotly_facet_density_methods(

def test_density_scatter_plotly_facet_size() -> None:
fig = density_scatter_plotly(
df=df_tips, x="total_bill", y="tip", size="size", facet_col="smoker"
df=DF_TIPS, x="total_bill", y="tip", size="size", facet_col="smoker"
)

assert "marker.size" in fig.data[0]
assert "marker.size" in fig.data[1]


def test_density_scatter_plotly_facet_multiple_categories() -> None:
fig = density_scatter_plotly(df=df_tips, x="total_bill", y="tip", facet_col="day")
fig = density_scatter_plotly(df=DF_TIPS, x="total_bill", y="tip", facet_col="day")

assert len(fig.data) == df_tips["day"].nunique()
assert len(fig.data) == DF_TIPS["day"].nunique()


def test_density_scatter_plotly_facet_identity_line() -> None:
fig = density_scatter_plotly(
df=df_tips, x="total_bill", y="tip", facet_col="smoker", identity_line=True
df=DF_TIPS, x="total_bill", y="tip", facet_col="smoker", identity_line=True
)

assert len(fig.layout.shapes) == 2 # Two identity lines, one for each facet


def test_density_scatter_plotly_facet_hover_template() -> None:
fig = density_scatter_plotly(
df=df_tips, x="total_bill", y="tip", facet_col="smoker"
df=DF_TIPS, x="total_bill", y="tip", facet_col="smoker"
)

for trace in fig.data:
Expand Down
36 changes: 18 additions & 18 deletions tests/test_structure_viz.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
if TYPE_CHECKING:
from collections.abc import Sequence

coords = [[0, 0, 0], [0.5, 0.5, 0.5]]
disordered_struct = Structure(
lattice := np.eye(3) * 5, species=[{"Fe": 0.75, "C": 0.25}, "O"], coords=coords
COORDS = [[0, 0, 0], [0.5, 0.5, 0.5]]
DISORDERED_STRUCT = Structure(
lattice := np.eye(3) * 5, species=[{"Fe": 0.75, "C": 0.25}, "O"], coords=COORDS
)


Expand All @@ -39,7 +39,7 @@ def test_structure_2d(
standardize_struct: bool | None,
) -> None:
ax = pmv.structure_2d(
disordered_struct,
DISORDERED_STRUCT,
atomic_radii=radii,
rotation=rotation,
site_labels=labels,
Expand All @@ -57,15 +57,15 @@ def test_structure_2d(
patch_counts = pd.Series(
[type(patch).__name__ for patch in ax.patches]
).value_counts()
assert patch_counts["Wedge"] == len(disordered_struct.composition)
assert patch_counts["Wedge"] == len(DISORDERED_STRUCT.composition)

min_expected_n_patches = 182
assert patch_counts["PathPatch"] > min_expected_n_patches


@pytest.mark.parametrize("axis", [True, False, "on", "off", "square", "equal"])
def test_structure_2d_axis(axis: str | bool) -> None:
ax = pmv.structure_2d(disordered_struct, axis=axis)
ax = pmv.structure_2d(DISORDERED_STRUCT, axis=axis)
assert isinstance(ax, plt.Axes)
assert ax.axes.axison == (axis not in (False, "off"))

Expand All @@ -77,7 +77,7 @@ def test_structure_2d_axis(axis: str | bool) -> None:
def test_structure_2d_site_labels(
site_labels: bool | str | dict[str, str | float] | Sequence[str],
) -> None:
ax = pmv.structure_2d(disordered_struct, site_labels=site_labels)
ax = pmv.structure_2d(DISORDERED_STRUCT, site_labels=site_labels)
assert isinstance(ax, plt.Axes)
if site_labels is False:
assert not ax.axes.texts
Expand All @@ -88,8 +88,8 @@ def test_structure_2d_site_labels(

def test_structure_2d_warns() -> None:
# for sites with negative fractional coordinates
orig_coords = disordered_struct[0].frac_coords.copy()
disordered_struct[0].frac_coords = [-0.1, 0.1, 0.1]
orig_coords = DISORDERED_STRUCT[0].frac_coords.copy()
DISORDERED_STRUCT[0].frac_coords = [-0.1, 0.1, 0.1]
standardize_struct = False
try:
with pytest.warns(
Expand All @@ -99,24 +99,24 @@ def test_structure_2d_warns() -> None:
f"{standardize_struct=}, you may want to set standardize_struct=True"
),
):
pmv.structure_2d(disordered_struct, standardize_struct=standardize_struct)
pmv.structure_2d(DISORDERED_STRUCT, standardize_struct=standardize_struct)
finally:
disordered_struct[0].frac_coords = orig_coords
DISORDERED_STRUCT[0].frac_coords = orig_coords

# warns when passing subplot_kwargs for a single structure
with pytest.warns(
UserWarning, match="subplot_kwargs are ignored when plotting a single structure"
):
pmv.structure_2d(disordered_struct, subplot_kwargs={"facecolor": "red"})
pmv.structure_2d(DISORDERED_STRUCT, subplot_kwargs={"facecolor": "red"})


struct1 = Structure(lattice, ["Fe", "O"], coords=coords)
struct1 = Structure(lattice, ["Fe", "O"], coords=COORDS)
struct1.properties = {"id": "struct1"}
struct2 = Structure(lattice, ["Co", "O"], coords=coords)
struct2 = Structure(lattice, ["Co", "O"], coords=COORDS)
struct2.properties = {Key.mat_id: "struct2"}
struct3 = Structure(lattice, ["Ni", "O"], coords=coords)
struct3 = Structure(lattice, ["Ni", "O"], coords=COORDS)
struct3.properties = {"ID": "struct3", "name": "nickel oxide"} # extra properties
struct4 = Structure(lattice, ["Cu", "O"], coords=coords)
struct4 = Structure(lattice, ["Cu", "O"], coords=COORDS)


def test_structure_2d_multiple() -> None:
Expand Down Expand Up @@ -167,7 +167,7 @@ def subplot_title(struct: Structure, key: str | int) -> str:
def test_structure_2d_color_warning() -> None:
# Copernicium is not in the default color scheme
elem_symbol = "Cn"
struct = Structure(np.eye(3) * 5, [elem_symbol] * 2, coords=coords)
struct = Structure(np.eye(3) * 5, [elem_symbol] * 2, coords=COORDS)
fallback_color = "gray"

for elem_colors in ElemColorScheme:
Expand All @@ -188,7 +188,7 @@ def test_structure_2d_color_warning() -> None:

# create custom color scheme missing an element
custom_colors = {"Fe": "red"}
struct = Structure(np.eye(3) * 5, ["Fe", "O"], coords=coords)
struct = Structure(np.eye(3) * 5, ["Fe", "O"], coords=COORDS)

with pytest.warns(
UserWarning,
Expand Down
8 changes: 4 additions & 4 deletions tests/test_uncertainty.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@
from numpy.typing import ArrayLike


y_std_mock = y_true - y_pred
Y_STD_MOCK = y_true - y_pred


@pytest.mark.parametrize(
"y_std",
[
y_std_mock,
{"y_std_mock": y_std_mock},
Y_STD_MOCK,
{"y_std_mock": Y_STD_MOCK},
df_regr.columns[0], # single std col
df_regr.columns[:2], # multiple std cols
],
Expand All @@ -39,7 +39,7 @@ def test_error_decay_with_uncert(
df, x, y = df_or_arrays
# override y_std if col name but no df provided, would be nonsensical input
if df is None and isinstance(y_std, str | pd.Index):
y_std = y_std_mock
y_std = Y_STD_MOCK
ax = error_decay_with_uncert(
x, y, y_std, df=df, n_rand=n_rand, percentiles=percentiles
)
Expand Down
Loading
Loading