From 9dcd040285690cd8d90c0d8db747203c2eebce9e Mon Sep 17 00:00:00 2001 From: AndresOrtegaGuerrero Date: Wed, 8 Nov 2023 15:37:36 +0000 Subject: [PATCH] adding raman plot widget --- aiidalab_qe_vibroscopy/utils/raman/result.py | 196 ++++++++++++++++++- aiidalab_qe_vibroscopy/workflows/result.py | 21 +- 2 files changed, 199 insertions(+), 18 deletions(-) diff --git a/aiidalab_qe_vibroscopy/utils/raman/result.py b/aiidalab_qe_vibroscopy/utils/raman/result.py index 1c10505..f5f9f31 100644 --- a/aiidalab_qe_vibroscopy/utils/raman/result.py +++ b/aiidalab_qe_vibroscopy/utils/raman/result.py @@ -7,8 +7,12 @@ from widget_bandsplot import BandsPlotWidget from aiidalab_qe.common.panel import ResultPanel - +import ipywidgets as ipw import numpy as np +from IPython.display import clear_output, display +import base64 +import json + from aiida_vibroscopy.utils.broadenings import multilorentz def plot_powder( @@ -110,6 +114,196 @@ def _update_view(self): g, ] +class SpectrumPlotWidget(ipw.VBox): + """Widget that allows different options for plotting Raman Spectrum.""" + + description = ipw.HTML( + """
+ Select the type of Raman spectrum to plot. +
""" + ) + def __init__(self, node, **kwargs): + self.node = node + #VibriationalData + self.vibro = self.node.outputs.vibronic.iraman.vibrational_data.numerical_accuracy_4 + self._plot_type = ipw.ToggleButtons( + options=[ + ("Powder", "powder"), + ("Single Crystal", "single_crystal"), + ], + value="powder", + description="Spectrum type:", + disabled=False, + style={"description_width": "initial"}, + ) + self.temperature = ipw.FloatText( + value=298.0, + description="Temperature (K):", + disabled=False, + style={"description_width": "initial"}, + ) + self.frequency_laser = ipw.FloatText( + value=532.0, + description="Laser frequency (nm):", + disabled=False, + style={"description_width": "initial"}, + ) + self.pol_incoming = ipw.Text( + value="0 0 1", + description="Incoming polarization:", + disabled=False, + style={"description_width": "initial"}, + ) + self.pol_outgoing = ipw.Text( + value="0 0 1", + description="Outgoing polarization:", + disabled=False, + style={"description_width": "initial"}, + ) + self.plot_button = ipw.Button( + description="Plot", + icon="pencil", + button_style="primary", + disabled=False, + layout=ipw.Layout(width="auto"), + ) + self.download_button = ipw.Button( + description="Download Data", + icon="download", + button_style="primary", + disabled=False, + layout=ipw.Layout(width="auto", visibility="hidden"), + ) + self.wrong_syntax = ipw.HTML( + value=""" wrong syntax""", + layout={"visibility": "hidden"}, + ) + self.spectrum_widget = ipw.Output() + self.frequencies = [] + self.intensities = [] + self.polarization_out = ipw.Output() + + def download_data(_=None): + filename = "spectra.json" + my_dict = {"Frequencies cm-1": self.frequencies.tolist(), "Intensities": self.intensities.tolist()} + json_str = json.dumps(my_dict) + b64_str = base64.b64encode(json_str.encode()).decode() + self._download(payload=b64_str, filename=filename) + + + self._plot_type.observe(self._on_plot_type_change, names="value") + self.plot_button.on_click(self._on_plot_button_clicked) + self.download_button.on_click(download_data) + super().__init__( + children=[ + self.description, + self._plot_type, + self.temperature, + self.frequency_laser, + self.polarization_out, + ipw.HBox([self.plot_button, self.download_button]), + self.wrong_syntax, + self.spectrum_widget, + ] + ) + + @staticmethod + def _download(payload, filename): + from IPython.display import Javascript + + javas = Javascript( + """ + var link = document.createElement('a'); + link.href = 'data:text/json;charset=utf-8;base64,{payload}' + link.download = "{filename}" + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + """.format( + payload=payload, filename=filename + ) + ) + display(javas) + + def _on_plot_type_change(self, change): + if change["new"] == "single_crystal": + with self.polarization_out: + clear_output() + display(self.pol_incoming) + display(self.pol_outgoing) + else: + self.pol_incoming.value = "0 0 1" + self.pol_outgoing.value = "0 0 1" + self.wrong_syntax.layout.visibility = "hidden" + with self.polarization_out: + clear_output() + + def _on_plot_button_clicked(self, change): + if self._plot_type.value == "powder": + # Powder spectrum + polarized_intensities, depolarized_intensities, frequencies, labels = self.vibro.run_powder_raman_intensities(frequencies=self.frequency_laser.value, temperature=self.temperature.value) + total_intensities = polarized_intensities + depolarized_intensities + self.frequencies , self.intensities = plot_powder(frequencies, total_intensities) + self._display_figure() + + + else: + # Single crystal spectrum + dir_incoming, correct_syntax_incoming = self._check_inputs_correct(self.pol_incoming) + dir_outgoing, correct_syntax_outgoing = self._check_inputs_correct(self.pol_outgoing) + if not correct_syntax_incoming or not correct_syntax_outgoing: + self.wrong_syntax.layout.visibility = "visible" + return + else: + self.wrong_syntax.layout.visibility = "hidden" + intensities, frequencies, labels = self.vibro.run_single_crystal_raman_intensities(pol_incoming=dir_incoming, pol_outgoing=dir_incoming, frequencies=self.frequency_laser.value, temperature=self.temperature.value) + self.frequencies , self.intensities = plot_powder(frequencies, intensities) + self._display_figure() + + def _check_inputs_correct(self,polarization): + #Check if the polarization vectors are correct + input_text = polarization.value + input_values = input_text.split() + dir_values = [] + if len(input_values) == 3: + try: + dir_values = [float(i) for i in input_values] + return dir_values, True + except: + return dir_values, False + else: + return dir_values, False + + def _spectrum_widget(self): + import plotly.graph_objects as go + + fig = go.FigureWidget( + layout=go.Layout( + title=dict(text="Raman spectrum"), + barmode="overlay", + ) + ) + fig.layout.xaxis.title = "Wavenumber (cm-1)" + fig.layout.yaxis.title = "Intensity (arb. units)" + fig.layout.xaxis.nticks = 0 + fig.add_scatter(x=self.frequencies,y=self.intensities,name=f"") + fig.update_layout( + height=500, + width=700, + plot_bgcolor="white", + + + ) + return fig + + def _display_figure(self): + with self.spectrum_widget: + clear_output() + display(self._spectrum_widget()) + self.download_button.layout.visibility = "visible" + + + diff --git a/aiidalab_qe_vibroscopy/workflows/result.py b/aiidalab_qe_vibroscopy/workflows/result.py index 64d19d9..90d09d1 100644 --- a/aiidalab_qe_vibroscopy/workflows/result.py +++ b/aiidalab_qe_vibroscopy/workflows/result.py @@ -13,7 +13,7 @@ from ..utils.raman.result import export_iramanworkchain_data from ..utils.harmonic.result import export_phononworkchain_data import ipywidgets as ipw - +from ..utils.raman.result import SpectrumPlotWidget class Result(ResultPanel): title = "Vibrational Structure" @@ -45,27 +45,14 @@ def _update_view(self): table_html += "" active_modes = ipw.VBox([ipw.HTML(value=" Raman Active Modes "),ipw.HTML(value=table_html)]) + + spectrum_widget = SpectrumPlotWidget(self.node) if spectra_data[3] in ["Raman vibrational spectrum","Infrared vibrational spectrum"]: - import plotly.graph_objects as go - - frequencies = spectra_data[1] - total_intensities = spectra_data[0] - g = go.FigureWidget( - layout=go.Layout( - title=dict(text=spectra_data[3]), - barmode="overlay", - ) - ) - g.layout.xaxis.title = "Wavenumber (cm-1)" - g.layout.yaxis.title = "Intensity (arb. units)" - g.layout.xaxis.nticks = 0 - g.add_scatter(x=frequencies,y=total_intensities,name=f"") - self.children=[ - ipw.HBox([active_modes, g]) + ipw.HBox([spectrum_widget, active_modes ]) ] if phonon_data: