pymatgen icon indicating copy to clipboard operation
pymatgen copied to clipboard

Highlight selected points in plotly PDPlotter

Open CompRhys opened this issue 2 years ago • 6 comments

Sometimes I want to plot a phase diagram and highlight points that are not on the convex hull. It would be nice to be able to give a list of entry names that would then be highlighted in a separate list to "stable" and "above hull".

@mattmcdermott Is this something that seems reasonable to be able to add?

CompRhys avatar Jan 30 '22 19:01 CompRhys

Would also be nice to be able to pass in additional information for the hover labels i.e. a DOI for the entry etc

CompRhys avatar Jan 30 '22 19:01 CompRhys

Additionally if using PDEntry entry_id = getattr(entry, "entry_id", "no ID") doesn't grab the name as PDEntry calls the identifier name

CompRhys avatar Jan 30 '22 20:01 CompRhys

Sometimes I want to plot a phase diagram and highlight points that are not on the convex hull. It would be nice to be able to give a list of entry names that would then be highlighted in a separate list to "stable" and "above hull".

This should be doable, but I don't yet know a clean way to do it in Plotly. The most straightforward approach would be to define a new trace that would correspond to "Highlighted" points, but because the stable and unstable entries are already split into two traces, you would need to create four separate traces now: 1) Highlighted - Stable, 2) Highlighted - Unstable, 3) Unhighlighted - Stable, 4) Unhighlighted - Unstable. Since this is kind of gross I'd rather not do it that way. However, if you think this would be okay (or even preferred?) let me know.

I think the better way is probably to add a Button in plotly, so that you can restyle the phase diagram. The issue with that is there doesn't seem to be way to hide specific points without leaving some weird stuff behind. I tried setting their opacity to zero, but it leaves behind some artifacts that look kind of gross. (See picture where I try to hide all but one stable point and one unstable point). For the stable points, it seems to leave behind gray lines that I can't get rid of, and the legend labels also get messed up.

Would also be nice to be able to pass in additional information for the hover labels i.e. a DOI for the entry etc

Additionally if using PDEntry entry_id = getattr(entry, "entry_id", "no ID") doesn't grab the name as PDEntry calls the identifier name

^ I should be able to address these!

Screen Shot 2022-01-31 at 1 44 09 PM

mattmcdermott avatar Jan 31 '22 21:01 mattmcdermott

@janosh does the stuff you were doing with groups for the frontier plot offer any nice solutions for highlighting here?

CompRhys avatar Feb 01 '22 01:02 CompRhys

@CompRhys I don't see how without changes to PDPlotter which might turn into a mess.

But since PDPlotter returns a Plotly figure object, you can just apply changes to any of its traces as you see fit:

Screen Shot 2022-02-01 at 08 50 36

from pymatgen.analysis.phase_diagram import PDPlotter, PhaseDiagram
from pymatgen.ext.matproj import MPRester

entries = MPRester().get_entries("Fe-O")
entries += MPRester().get_entries("Fe")
entries += MPRester().get_entries("O")

pd = PhaseDiagram(entries)

fig = PDPlotter(pd).get_plot()

unstable = [trace for trace in fig.data if trace.name == "Above Hull"][0]

unstable["marker"]["size"] = [10] * (len(unstable["x"]) - 1) + [40]

janosh avatar Feb 01 '22 08:02 janosh

The issue with that is there doesn't seem to be way to hide specific points without leaving some weird stuff behind.

@mattmcdermott I assume you could zip over the x, y and hovertext attributes of a trace and populate new lists with the existing points based on conditions, then overwrite the existing attributes with the new lists. Something like:

trace = [trace for trace in fig.data if trace.name == "Above Hull"][0]

new_x, new_y, new_hover = [], [], []
for x, y, h in zip(trace.x, trace.y, trace.hovertext):
    if (x < 0.5) and (y > 1):
        new_x.append(x)
        new_y.append(y)
        new_hover.append(h)

trace.x = new_x
trace.y = new_y
trace.hovertext = new_hover

Haven't tried it though. And it's a lot of work too.

janosh avatar Feb 01 '22 09:02 janosh

@CompRhys FYI, I finally added this feature in https://github.com/materialsproject/pymatgen/pull/3032.

mattmcdermott avatar Jun 02 '23 23:06 mattmcdermott