Skip to content

Commit

Permalink
Plotly Support (#195)
Browse files Browse the repository at this point in the history
* plot fed

* plot fef

* plot fed

* plot fed

* plot fed

* plot fed

* remove uid

* remove uid

* moved phase plot

* moved phase plot

* moved phase plot

* moved phase plot

* moved phase plot

* plot tests

plot tests

plot tests

plot tests

plot tests

* plot tests

* plot tests
  • Loading branch information
jmmshn authored May 21, 2024
1 parent bdd3145 commit 8a44d47
Show file tree
Hide file tree
Showing 9 changed files with 457 additions and 152 deletions.
142 changes: 3 additions & 139 deletions pymatgen/analysis/defects/plotting/phases.py
Original file line number Diff line number Diff line change
@@ -1,142 +1,6 @@
"""Plotting functions for competing phases."""

from __future__ import annotations
# Contents moved to pymatgen.analysis.defects.plotting.thermo
from .thermo import plot_chempot_2d

import logging
from typing import TYPE_CHECKING

from matplotlib import pyplot as plt
from matplotlib.patches import Polygon
from pymatgen.util.string import latexify
from scipy.spatial import ConvexHull

if TYPE_CHECKING:
from matplotlib.axes import Axes
from pymatgen.analysis.defects.thermo import FormationEnergyDiagram
from pymatgen.core import Element

# check if labellines is installed
try:
from labellines import labelLines
except ImportError:

def labelLines(*args, **kwargs) -> None: # noqa: ARG001, ANN002
"""Dummy function if labellines is not installed."""


__author__ = "Jimmy Shen"
__copyright__ = "Copyright 2022, The Materials Project"
__maintainer__ = "Jimmy Shen @jmmshn"
__date__ = "July 2023"

logger = logging.getLogger(__name__)


def plot_chempot_2d(
fed: FormationEnergyDiagram,
x_element: Element,
y_element: Element,
ax: Axes | None = None,
min_mu: float = -5.0,
label_lines: bool = False,
x_vals: list[float] | None = None,
label_fontsize: int = 12,
) -> None:
"""Plot the chemical potential diagram for two elements.
Args:
fed:
The formation energy diagram.
x_element:
The element to use for the x-axis.
y_element:
The element to use for the y-axis.
ax:
The matplotlib axes to plot on. If None, a new figure will be created.
min_mu:
The minimum chemical potential to plot.
label_lines:
Whether to label the lines with the competing phases. Requires Labellines to be installed.
x_vals:
The x position of the line labels. If None, defaults will be used.
label_fontsize:
The fontsize for the line labels.
"""
PLOT_PADDING = 0.1
ax = ax or plt.gca()
hull2d = _convex_hull_2d(
fed.chempot_limits,
x_element=x_element,
y_element=y_element,
competing_phases=fed.competing_phases,
)
x_min = float("inf")
y_min = float("inf")
clip_path = []
for p1, p2, phase in hull2d:
p_txt = ", ".join(map(latexify, phase.keys()))
ax.axline(p1, p2, label=p_txt, color="k")
ax.scatter(p1[0], p1[1], color="k")
x_m_ = p1[0] if p1[0] > min_mu else float("inf")
y_m_ = p1[1] if p1[1] > min_mu else float("inf")
x_min = min(x_min, x_m_)
y_min = min(y_min, y_m_)
clip_path.append(p1)

patch = Polygon(
clip_path,
closed=True,
)
ax.add_patch(patch)

ax.set_xlabel(rf"$\Delta\mu_{{{x_element}}}$ (eV)")
ax.set_ylabel(rf"$\Delta\mu_{{{y_element}}}$ (eV)")
ax.set_xlim(x_min - PLOT_PADDING, 0 + PLOT_PADDING)
ax.set_ylim(y_min - PLOT_PADDING, 0 + PLOT_PADDING)
if label_lines:
labelLines(ax.get_lines(), align=False, xvals=x_vals, fontsize=label_fontsize)


def _convex_hull_2d(
points: list[dict],
x_element: Element,
y_element: Element,
competing_phases: list | None = None,
) -> list:
"""Compute the convex hull of a set of points in 2D.
Args:
points:
A list of dictionaries with keys "x" and "y" and values as floats.
x_element:
The element to use for the x-axis.
y_element:
The element to use for the y-axis.
tol:
The tolerance for determining if two points are the same in the 2D plane.
competing_phases:
A list of competing phases for each point.
Returns:
A list of dictionaries with keys "x" and "y" that form the vertices of the
convex hull.
"""
if competing_phases is None:
competing_phases = [None] * len(points)
xy_points = [(pt[x_element], pt[y_element]) for pt in points]
hull = ConvexHull(xy_points)
xy_hull = [xy_points[i] for i in hull.vertices]

def _get_line_data(i1: int, i2: int) -> tuple:
cp1 = competing_phases[hull.vertices[i1]]
cp2 = competing_phases[hull.vertices[i2]]
shared_keys = cp1.keys() & cp2.keys()
shared_phase = {k: cp1[k] for k in shared_keys}
return xy_hull[i1], xy_hull[i2], shared_phase

# return all pairs of points:
pt_and_phase = [
_get_line_data(itr - 1, itr) for itr in range(1, len(hull.vertices))
]
pt_and_phase.append(_get_line_data(len(hull.vertices) - 1, 0))
return pt_and_phase
__all__ = ["plot_chempot_2d"]
Loading

0 comments on commit 8a44d47

Please sign in to comment.