Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
15 changes: 15 additions & 0 deletions pydatalab/src/pydatalab/apps/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,21 @@ def load_app_blocks():
except ImportError as e:
_check_error(e)

try:
from pydatalab.apps.gpc_sec import GPCBlock

app_blocks.append(GPCBlock)
except ImportError as e:
_check_error(e)

try:
from pydatalab.apps.dsc import DSCBlock

app_blocks.append(DSCBlock)
except ImportError as e:
_check_error(e)


return app_blocks


Expand Down
68 changes: 57 additions & 11 deletions pydatalab/src/pydatalab/apps/ftir/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@
import pandas as pd
from bokeh.models import HoverTool, LogColorMapper

import codecs

from pydatalab.blocks.base import DataBlock
from pydatalab.bokeh_plots import DATALAB_BOKEH_THEME, selectable_axes_plot
from pydatalab.file_utils import get_file_info_by_id
from pydatalab.logger import LOGGER


class FTIRBlock(DataBlock):
accepted_file_extensions: tuple[str, ...] = (".asp",)
accepted_file_extensions: tuple[str, ...] = (".asp",".txt")
blocktype = "ftir"
name = "FTIR"
description = (
Expand All @@ -36,7 +38,7 @@ def parse_ftir_asp(cls, filename: Path) -> pd.DataFrame:
filename: Path to the .asp file

Returns:
FTIR dataframe with columns "Wavenumber" and "Absorbance"" with the wavenumber in cm^-1
FTIR dataframe with columns "Wavenumber" and "Absorbance"" with the wavenumber in cm^-1 and string 'default' for the x and y units
"""

ftir = pd.read_csv(filename, header=None)
Expand All @@ -46,10 +48,37 @@ def parse_ftir_asp(cls, filename: Path) -> pd.DataFrame:
x_range = np.linspace(start_wavenumber, end_wavenumber, number_of_points)
y = ftir[0].iloc[-number_of_points:]
ftir = pd.DataFrame.from_dict({"Wavenumber": x_range, "Absorbance": y})
return ftir
return ftir, 'default', 'default'

@classmethod
def parse_ftir_txt(cls, filename: Path) -> pd.DataFrame:
"""Parses .txt FTIR data generated by a Shimadzu IR Tracer-100 FT-IR spectrophotometer

The file consists of a header with metadata: a title, data type, x units and y units,
and then the IR data
This function reads the file and extracts the data as a pandas DataFrame, and the x units and y units as strings.
This function does not read the original .ispd file generated by the spectrometer

Args:
filename: Path to the .txt file

Returns:
FTIR dataframe with columns "Wavenumber" and "Absorbance", and strings giving the x and y units
"""
with open(filename,'r') as f:
alldata = f.readlines()
title = alldata[0].split('=')[1]
dtype = alldata[1].split('=')[1]
xunits = alldata[2].split('=')[1]
yunits = alldata[3].split('=')[1]
data = alldata[4:]
x = [float(line.split()[0]) for line in data]
y = [float(line.split()[1]) for line in data]
ftir = pd.DataFrame.from_dict({'Wavenumber':x, 'Absorbance':y})
return ftir, xunits, yunits

@classmethod
def _format_ftir_plot(self, ftir_data: pd.DataFrame) -> bokeh.layouts.layout:
def _format_ftir_plot(self, ftir_data: pd.DataFrame,xunits:str,yunits:str) -> bokeh.layouts.layout:
"""Formats FTIR data for plotting in Bokeh, inverted x-axis with a buffer of 50 cm^-1 on either side

Args:
Expand All @@ -58,6 +87,14 @@ def _format_ftir_plot(self, ftir_data: pd.DataFrame) -> bokeh.layouts.layout:
Returns:
bokeh.layouts.layout: Bokeh layout with FTIR data plotted
"""
if xunits == 'default':
toollabsx = "Wavenumber / cm⁻¹"
else:
toollabsx = "Wavenumber /{0}".format(xunits)
Copy link
Contributor

Choose a reason for hiding this comment

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

Added a space between the / and the unit. This is just to keep it consistent with other datalab blocks.

Suggested change
toollabsx = "Wavenumber /{0}".format(xunits)
toollabsx = "Wavenumber / {0}".format(xunits)

if yunits == 'default':
toollabsy = "Absorbance"
else:
Copy link
Contributor

Choose a reason for hiding this comment

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

Changed the unit to display a superscript like in the other format

Suggested change
else:
elif xunits == "1/CM\n":
toollabsx = "Wavenumber / cm⁻¹"
else:

toollabsy = yunits
layout = selectable_axes_plot(
ftir_data,
x_options=["Wavenumber"],
Expand All @@ -69,16 +106,22 @@ def _format_ftir_plot(self, ftir_data: pd.DataFrame) -> bokeh.layouts.layout:
plot_line=True,
tools=HoverTool(
tooltips=[
("Wavenumber / cm⁻¹", "@Wavenumber{0.00}"),
("Absorbance", "@Absorbance{0.0000}"),
(toollabsx, "@Wavenumber{0.00}"),
(toollabsy, "@Absorbance{0.0000}"),
], # Display x and y values to specified decimal places
mode="vline", # Ensures hover follows the x-axis
),
)
# Adding cm^-1 to the x-axis label using unicode characters - might be a more logical way
layout.children[1].xaxis.axis_label = "Wavenumber / cm⁻¹"
if xunits == 'default':
# Adding cm^-1 to the x-axis label using unicode characters - might be a more logical way
layout.children[1].xaxis.axis_label = "Wavenumber / cm⁻¹"
else:
Copy link
Contributor

Choose a reason for hiding this comment

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

I just made this change so that the label appears the same with a superscript as in the other mode.

Suggested change
else:
elif xunits == "1/CM\n":
layout.children[1].xaxis.axis_label = "Wavenumber / cm⁻¹"
else:

layout.children[1].xaxis.axis_label = "Wavenumber /{0}".format(xunits)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
layout.children[1].xaxis.axis_label = "Wavenumber /{0}".format(xunits)
layout.children[1].xaxis.axis_label = "Wavenumber / {0}".format(xunits)

if yunits != 'default':
layout.children[1].yaxis.axis_label = yunits
return layout


def generate_ftir_plot(self):
file_info = None
# all_files = None
Expand All @@ -97,9 +140,12 @@ def generate_ftir_plot(self):
ext,
)
return
elif ext == '.asp':
ftir_data,xunits,yunits = self.parse_ftir_asp(Path(file_info["location"]))
elif ext == '.txt':
ftir_data,xunits,yunits = self.parse_ftir_txt(Path(file_info["location"]))

ftir_data = self.parse_ftir_asp(Path(file_info["location"]))

print(ftir_data)
if ftir_data is not None:
layout = self._format_ftir_plot(ftir_data)
layout = self._format_ftir_plot(ftir_data,xunits,yunits)
self.data["bokeh_plot_data"] = bokeh.embed.json_item(layout, theme=DATALAB_BOKEH_THEME)
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think we want to include this in the PR, I think the gitignore should've caught it but I can remove it from the other branch.

Binary file not shown.
Loading