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

Interactive plotter #81

Merged
merged 60 commits into from
Aug 1, 2023
Merged
Show file tree
Hide file tree
Changes from 51 commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
436e118
First draft of InteractiveCohpPlotter
kaueltzen Nov 15, 2022
bf77096
Fixed layout_dict import, color scheme
kaueltzen Nov 16, 2022
fa554ab
fixed relevant bonds iter. error, added x axis rangeslider
kaueltzen Nov 24, 2022
5b4eedd
Merge branch 'interactive_plotter' of github.com:ahtakkatha/LobsterPy…
kaueltzen Nov 24, 2022
6946097
Fixed merging error
kaueltzen Nov 29, 2022
7eaf71b
Added plot_interactive_cohps() to description class (summed COHPs)
kaueltzen Dec 4, 2022
9df8c4c
Fixed plot_interactive_cohps() to plot COHPs in same plot
kaueltzen Dec 4, 2022
9bec1b3
Made rangeslider optional, fixed legend display, added different inte…
kaueltzen Dec 16, 2022
ae21a80
Merge branch 'JaGeo:main' into interactive_plotter
kaueltzen Dec 19, 2022
79eb6b5
Removed integration options that were recently moved to another branc…
kaueltzen Apr 27, 2023
e22744b
Merge branch 'main' into interactive_plotter
kaueltzen Apr 27, 2023
376b009
Removed redundant COHPCAR reading (significantly faster), modified pl…
kaueltzen Apr 27, 2023
6d42115
Fixed importation error.
kaueltzen Apr 27, 2023
e8ba02e
Merge branch 'JaGeo:main' into interactive_plotter
naik-aakash May 5, 2023
52bd8a9
add dropdown to interactive plotter layout, add option to plot direct…
naik-aakash May 15, 2023
7ea3f94
Merge branch 'JaGeo:main' into interactive_plotter
naik-aakash May 15, 2023
cd80e13
Merge branch 'JaGeo:main' into interactive_plotter
naik-aakash May 16, 2023
5a7bda3
update plotter
naik-aakash May 16, 2023
773ef9b
adapt plot_interactive_cohps of describe method
naik-aakash May 16, 2023
2ca4f13
Fix linting issues
naik-aakash May 16, 2023
3c7bdb7
add preliminary tests for interactive plotter
naik-aakash May 17, 2023
c58b9c6
attempt to fix failing 3.9 and 3.10 tests
naik-aakash May 18, 2023
caf2d01
fix interactive plot test
naik-aakash May 18, 2023
cc230ff
Fix interactive plotlyfigure object data checking
naik-aakash May 18, 2023
4343ac4
remove unused import
naik-aakash May 18, 2023
807c44c
add test for interactive plotter from describe method
naik-aakash May 18, 2023
d33c63f
update test_plotting.py
naik-aakash May 18, 2023
3c3bd40
fix pylint error for describe.py
naik-aakash May 18, 2023
6fa68ef
update test_plotting.py
naik-aakash May 18, 2023
c2bb10a
make interactive plot labels consistent to analyze output, add test f…
naik-aakash May 22, 2023
84df95a
clean up interactive plotter code,fix handle duplicate label with lab…
naik-aakash May 23, 2023
af242ed
more cleanup: remove redundant dropdown from interactive plotter, upd…
naik-aakash May 23, 2023
447f287
remove redundant _update_cohps_data method, simplify code logic
naik-aakash May 23, 2023
7de1cf3
Fix visibility inconsitency for "All" key in dropdown menu
naik-aakash May 24, 2023
7df457d
Merge branch 'JaGeo:main' into interactive_plotter
naik-aakash May 31, 2023
afd32e3
update bond labels in label resolved, add more tests to increase cove…
naik-aakash Jun 1, 2023
0594cdf
Merge branch 'interactive_plotter' of github.com:kaueltzen/LobsterPy …
naik-aakash Jun 1, 2023
8f6918e
Merge branch 'JaGeo:main' into interactive_plotter
naik-aakash Jun 5, 2023
71240bc
Merge branch 'main' of github.com:JaGeo/LobsterPy into interactive_pl…
JaGeo Jun 20, 2023
aa80966
Change set to seq
JaGeo Jun 20, 2023
b43b74c
fix bug and reformat
JaGeo Jun 20, 2023
655e638
Fix hide
JaGeo Jun 20, 2023
a667a72
Fix cation anion
JaGeo Jun 20, 2023
5165ba3
Fix documentation
JaGeo Jun 20, 2023
a6b54f1
Fix cation anion
JaGeo Jun 20, 2023
bccacde
code reformatting based on review
naik-aakash Jun 30, 2023
99e2671
remove unused import
naik-aakash Jun 30, 2023
32a5dfd
fix doc string
naik-aakash Jun 30, 2023
20cd3bd
fix exception text
naik-aakash Jun 30, 2023
36f0de9
add docstring to private _insert_number_of_bonds_in_label
naik-aakash Jun 30, 2023
545e6c5
fix doc-string linting error, improve code readability
naik-aakash Jun 30, 2023
2bac25b
imporve code formatting
naik-aakash Jul 24, 2023
0896844
add color arg to get_plot, refactor add_all_relevant_cohps method, ad…
naik-aakash Jul 24, 2023
abcb119
run black
naik-aakash Jul 24, 2023
1eed7f8
removed __future__ import
naik-aakash Jul 24, 2023
250d236
attempt to fix python3.8 linitng error
naik-aakash Jul 24, 2023
d012563
remove unnecessary variable assignment
naik-aakash Jul 24, 2023
f5f6a8d
update tests for custom colors, update tutorial for interactiveplotte…
naik-aakash Jul 25, 2023
79d5749
update tutorial files
naik-aakash Jul 25, 2023
3924374
update doc generation conf.py file to exclude plotter test
naik-aakash Jul 25, 2023
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

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions lobsterpy/TestData/interactive_plotter_ref/fig_mp8818.json

Large diffs are not rendered by default.

Binary file not shown.
2 changes: 1 addition & 1 deletion lobsterpy/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@ def run(args):
filename=args.save_plot,
title=args.title,
sigma=sigma,
skip_show=args.hideplot,
hide=args.hideplot,
)

if args.action == "plot":
Expand Down
88 changes: 43 additions & 45 deletions lobsterpy/cohp/analyze.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,12 @@ class Analysis:
path_to_icohplist: str that describes the path to ICOHPLIST.lobster
path_to_poscar: str that describes path to POSCAR
path_to_madelung: str that describes path to POSCAR
set_cohps: list of cohps
set_coordination_ions: list of coodination environment strings for each cation
seq_cohps: list of cohps
seq_coord_ions: list of coodination environment strings for each cation
set_equivalent_sites: set of inequivalent sites
set_inequivalent_ions: set of inequivalent cations/sites in the structure
set_infos_bonds: information on cation anion bonds
seq_ineq_ions: set of inequivalent cations/sites in the structure
seq_infos_bonds (list): information on cation anion bonds (lists
of pymatgen.io.lobster.lobsterenv.ICOHPNeighborsInfo)
spg: space group information
structure: Structure object
type_charge: which charges are considered here
Expand Down Expand Up @@ -141,7 +142,7 @@ def setup_env(self):
if (
str(err) == "min() arg is an empty sequence"
or str(err)
== "All valences are equal to 0, additional_conditions 1 and 3 and 5 and 6 will not work"
== "All valences are equal to 0, additional_conditions 1, 3, 5 and 6 will not work"
):
raise ValueError(
"Consider switching to an analysis of all bonds and not only cation-anion bonds."
Expand Down Expand Up @@ -220,25 +221,24 @@ def get_information_all_bonds(self, summed_spins=True):
"""
if self.whichbonds == "cation-anion":
# this will only analyze cation anion bonds which simplifies the analysis
self.set_inequivalent_ions = []
self.set_coordination_ions = []
self.set_infos_bonds = []
self.set_labels_cohps = []
self.set_cohps = []
self.seq_ineq_ions = []
self.seq_coord_ions = []
self.seq_infos_bonds = []
self.seq_labels_cohps = []
self.seq_cohps = []
# only_bonds_to

self.anion_types = self.chemenv.get_anion_types()
for ice, ce in enumerate(self.lse.coordination_environments):
# only look at inequivalent sites (use of symmetry to speed everything up!)!
# only look at those cations that have cation-anion bonds
if ice in self.set_equivalent_sites and ce[0]["ce_symbol"] is not None:
self.set_inequivalent_ions.append(ice)
ce = ce[0]["ce_symbol"]
self.set_coordination_ions.append(ce)
cation_anion_infos = self.chemenv.get_info_icohps_to_neighbors(
[ice]
self.seq_ineq_ions.append(ice)

self.seq_coord_ions.append(ce[0]["ce_symbol"])
self.seq_infos_bonds.append(
self.chemenv.get_info_icohps_to_neighbors([ice])
)
self.set_infos_bonds.append(cation_anion_infos)

aniontype_labels = []
aniontype_cohps = []
Expand All @@ -257,29 +257,29 @@ def get_information_all_bonds(self, summed_spins=True):
aniontype_labels.append(labels)
aniontype_cohps.append(summedcohps)

self.set_labels_cohps.append(aniontype_labels)
self.set_cohps.append(aniontype_cohps)
self.seq_labels_cohps.append(aniontype_labels)
self.seq_cohps.append(aniontype_cohps)

elif self.whichbonds == "all":
# this will only analyze all bonds

self.set_inequivalent_ions = []
self.set_coordination_ions = []
self.set_infos_bonds = []
self.set_labels_cohps = []
self.set_cohps = []
self.seq_ineq_ions = []
self.seq_coord_ions = []
self.seq_infos_bonds = []
self.seq_labels_cohps = []
self.seq_cohps = []
# only_bonds_to
self.elements = self.structure.composition.elements
# self.anion_types = self.chemenv.get_anion_types()
for ice, ce in enumerate(self.lse.coordination_environments):
# only look at inequivalent sites (use of symmetry to speed everything up!)!
# only look at those cations that have cation-anion bonds
if ice in self.set_equivalent_sites and ce[0]["ce_symbol"] is not None:
self.set_inequivalent_ions.append(ice)
ce = ce[0]["ce_symbol"]
self.set_coordination_ions.append(ce)
bonds_infos = self.chemenv.get_info_icohps_to_neighbors([ice])
self.set_infos_bonds.append(bonds_infos)
self.seq_ineq_ions.append(ice)
self.seq_coord_ions.append(ce[0]["ce_symbol"])
self.seq_infos_bonds.append(
self.chemenv.get_info_icohps_to_neighbors([ice])
)

type_labels = []
type_cohps = []
Expand All @@ -298,8 +298,8 @@ def get_information_all_bonds(self, summed_spins=True):
type_labels.append(labels)
type_cohps.append(summedcohps)

self.set_labels_cohps.append(type_labels)
self.set_cohps.append(type_cohps)
self.seq_labels_cohps.append(type_labels)
self.seq_cohps.append(type_cohps)

@staticmethod
def _get_strenghts_for_each_bond(pairs, strengths, nameion=None):
Expand Down Expand Up @@ -648,9 +648,9 @@ def set_condensed_bonding_analysis(self):

# how many inequivalent cations are in the structure
if self.whichbonds == "cation-anion":
number_considered_ions = len(self.set_inequivalent_ions)
number_considered_ions = len(self.seq_ineq_ions)
elif self.whichbonds == "all":
number_considered_ions = len(self.set_inequivalent_ions)
number_considered_ions = len(self.seq_ineq_ions)

# what was the maximum bond lengths that was considered
max_bond_lengths = max(self.chemenv.Icohpcollection._list_length)
Expand All @@ -662,11 +662,11 @@ def set_condensed_bonding_analysis(self):
site_dict = {}
if self.whichbonds == "cation-anion":
for ication, ce, cation_anion_infos, labels, cohps in zip(
self.set_inequivalent_ions,
self.set_coordination_ions,
self.set_infos_bonds,
self.set_labels_cohps,
self.set_cohps,
self.seq_ineq_ions,
self.seq_coord_ions,
self.seq_infos_bonds,
self.seq_labels_cohps,
self.seq_cohps,
):
namecation = str(self.structure[ication].specie)

Expand Down Expand Up @@ -702,11 +702,11 @@ def set_condensed_bonding_analysis(self):
}
elif self.whichbonds == "all":
for iion, ce, bond_infos, labels, cohps in zip(
self.set_inequivalent_ions,
self.set_coordination_ions,
self.set_infos_bonds,
self.set_labels_cohps,
self.set_cohps,
self.seq_ineq_ions,
self.seq_coord_ions,
self.seq_infos_bonds,
self.seq_labels_cohps,
self.seq_cohps,
):
nameion = str(self.structure[iion].specie)

Expand Down Expand Up @@ -810,9 +810,7 @@ def set_summary_dicts(self):

"""
relevant_ion_ids = [
isite
for isite in self.list_equivalent_sites
if isite in self.set_inequivalent_ions
isite for isite in self.list_equivalent_sites if isite in self.seq_ineq_ions
]

# formula_units = self.structure.composition.num_atoms /
Expand Down
80 changes: 69 additions & 11 deletions lobsterpy/cohp/describe.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from pathlib import Path

from lobsterpy.plotting import PlainCohpPlotter
from lobsterpy.plotting import InteractiveCohpPlotter


class Description:
Expand Down Expand Up @@ -45,7 +46,7 @@ def set_description(self):
[
str(site.specie) + str(isite + 1)
for isite, site in enumerate(self.analysis_object.structure)
if isite in self.analysis_object.set_inequivalent_ions
if isite in self.analysis_object.seq_ineq_ions
]
)
self.text = []
Expand Down Expand Up @@ -119,7 +120,7 @@ def set_description(self):
[
str(site.specie) + str(isite + 1)
for isite, site in enumerate(self.analysis_object.structure)
if isite in self.analysis_object.set_inequivalent_ions
if isite in self.analysis_object.seq_ineq_ions
]
)
self.text = []
Expand Down Expand Up @@ -210,7 +211,7 @@ def plot_cohps(
integrated=False,
title="",
sigma=None,
skip_show=False,
hide=False,
):
"""
Will automatically generate plots of the most relevant COHP
Expand All @@ -223,22 +224,23 @@ def plot_cohps(
integrated (bool): if True, integrated COHPs will be shown
sigma: Standard deviation of Gaussian broadening applied to
population data. If None, no broadening will be added.
skip_show (bool): if True, the plot will not be shown.
title: sets the title of figure generated
hide (bool): if True, the plot will not be shown.

Returns:
A matplotlib object.

"""
set_cohps = self.analysis_object.set_cohps
seq_cohps = self.analysis_object.seq_cohps
if self.analysis_object.whichbonds == "cation-anion":
set_inequivalent_cations = self.analysis_object.set_inequivalent_ions
seq_ineq_cations = self.analysis_object.seq_ineq_ions
elif self.analysis_object.whichbonds == "all":
set_inequivalent_cations = self.analysis_object.set_inequivalent_ions
set_labels_cohps = self.analysis_object.set_labels_cohps
seq_ineq_cations = self.analysis_object.seq_ineq_ions
seq_labels = self.analysis_object.seq_labels_cohps
structure = self.analysis_object.structure

for iplot, (ication, labels, cohps) in enumerate(
zip(set_inequivalent_cations, set_labels_cohps, set_cohps)
zip(seq_ineq_cations, seq_labels, seq_cohps)
):
namecation = str(structure[ication].specie)

Expand All @@ -253,7 +255,7 @@ def plot_cohps(

plot.title(title)
if save:
if len(set_inequivalent_cations) > 1:
if len(seq_ineq_cations) > 1:
if isinstance(filename, str):
filename = Path(filename)
filename_new = (
Expand All @@ -262,12 +264,68 @@ def plot_cohps(
else:
filename_new = filename
plot.savefig(filename_new)
if not skip_show:
if not hide:
plot.show()
else:
if not save:
plot.close()

def plot_interactive_cohps(
self,
save_as_html=False,
filename=None,
ylim=None,
xlim=None,
integrated=False,
title="",
sigma=None,
skip_show=False,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't show=True be a more natural way of expressing this? (I appreciate this also applies to plot_cohps...)

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right. It's like this in the normal plotter classes as well as I wanted to quickly provide a fix for one project and did not fully think it through ... 😅.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will replace it with "hide" as we would otherwise also need to adapt the atomate2 workflows and schema.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand, how would using "show" break a workflow but using "hide" not break it? The default behaviour can be the same either way. (i.e. show=True is equivalent to skip_show=False.)

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, you are correct. We have to update it in any case as I changed the argument name...🙈

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@naik-aakash , maybe we can fix this here and the snake case issue of "whichbonds" as well... As we will break the atomate2 workflow in any case.

Copy link
Collaborator

@ajjackson ajjackson Jun 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might make sense to invert the logic at the CLI with something like
add_argument('--hide', action='store_false', dest='show', ...)

):
"""
Will automatically generate interactive plots of the most relevant COHP

Args:
save_as_html (bool): will save the plot to a html file
filename (str/Path):
ylim (list of float): energy scale that is shown in plot (eV)
xlim (list of float): energy range for COHPs in eV
integrated (bool): if True, integrated COHPs will be shown
sigma: Standard deviation of Gaussian broadening applied to
population data. If None, no broadening will be added.
title : Title of the interactive plot
skip_show (bool): if True, the plot will not be shown.

Returns:
A plotly.graph_objects.Figure object.

"""
cba_cohp_plot_data = {} # Initialize dict to store plot data

set_cohps = self.analysis_object.seq_cohps
set_labels_cohps = self.analysis_object.seq_labels_cohps
set_inequivalent_cations = self.analysis_object.seq_ineq_ions
structure = self.analysis_object.structure

for _iplot, (ication, labels, cohps) in enumerate(
zip(set_inequivalent_cations, set_labels_cohps, set_cohps)
):
label_str = f"{str(structure[ication].specie)}{str(ication + 1)}: "
for label, cohp in zip(labels, cohps):
if label is not None:
cba_cohp_plot_data[label_str + label] = cohp

ia = InteractiveCohpPlotter()
ia.add_cohps_from_plot_data(plot_data_dict=cba_cohp_plot_data)
plot = ia.get_plot(integrated=integrated, xlim=xlim, ylim=ylim, sigma=sigma)

plot.update_layout(title_text=title)
if save_as_html:
plot.write_html(filename, include_mathjax="cdn")
if not skip_show:
return plot.show()

return plot

@staticmethod
def _coordination_environment_to_text(ce):
"""
Expand Down
2 changes: 1 addition & 1 deletion lobsterpy/cohp/test/test_describe.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ def test_plot(self):
self.assertFalse(Path(filename_test).exists())
self.assertTrue(Path(filename_test_1).exists())

def test_write_descritoin(self):
def test_write_description(self):
self.describe_NaCl.write_description()
self.describe_NaSi_madelung_all.write_description()
self.describe_NaSbF6.write_description()
Expand Down
Loading