|
1 |
| -import base64 |
2 |
| -import io |
3 |
| -import os |
4 | 1 | import random
|
5 |
| -import zipfile |
6 | 2 | from typing import Any, Callable, Dict, Optional, Sequence
|
7 | 3 |
|
8 |
| -import bokeh.embed |
9 |
| -import pandas as pd |
10 | 4 | from bson import ObjectId
|
11 |
| -from PIL import Image |
12 | 5 |
|
13 |
| -from pydatalab import nmr_utils |
14 |
| -from pydatalab.bokeh_plots import mytheme, selectable_axes_plot |
15 |
| -from pydatalab.file_utils import get_file_info_by_id |
16 | 6 | from pydatalab.logger import LOGGER
|
17 | 7 |
|
18 | 8 | __all__ = ("generate_random_id", "DataBlock")
|
@@ -170,138 +160,3 @@ def update_from_web(self, data):
|
170 | 160 | self.data.update(data)
|
171 | 161 |
|
172 | 162 | return self
|
173 |
| - |
174 |
| - |
175 |
| -class NotSupportedBlock(DataBlock): |
176 |
| - blocktype = "notsupported" |
177 |
| - description = "Block not supported" |
178 |
| - _supports_collections = True |
179 |
| - |
180 |
| - |
181 |
| -class CommentBlock(DataBlock): |
182 |
| - blocktype = "comment" |
183 |
| - description = "Comment" |
184 |
| - _supports_collections = True |
185 |
| - |
186 |
| - |
187 |
| -class MediaBlock(DataBlock): |
188 |
| - blocktype = "media" |
189 |
| - description = "Media" |
190 |
| - accepted_file_extensions = (".png", ".jpeg", ".jpg", ".tif", ".tiff", ".mp4", ".mov", ".webm") |
191 |
| - _supports_collections = False |
192 |
| - |
193 |
| - @property |
194 |
| - def plot_functions(self): |
195 |
| - return (self.encode_tiff,) |
196 |
| - |
197 |
| - def encode_tiff(self): |
198 |
| - if "file_id" not in self.data: |
199 |
| - LOGGER.warning("ImageBlock.encode_tiff(): No file set in the DataBlock") |
200 |
| - return |
201 |
| - if "b64_encoded_image" not in self.data: |
202 |
| - self.data["b64_encoded_image"] = {} |
203 |
| - file_info = get_file_info_by_id(self.data["file_id"], update_if_live=True) |
204 |
| - if file_info["name"].endswith(".tif") or file_info["name"].endswith(".tiff"): |
205 |
| - im = Image.open(file_info["location"]) |
206 |
| - LOGGER.warning("Making base64 encoding of tif") |
207 |
| - with io.BytesIO() as f: |
208 |
| - im.save(f, format="PNG") |
209 |
| - f.seek(0) |
210 |
| - self.data["b64_encoded_image"][self.data["file_id"]] = base64.b64encode( |
211 |
| - f.getvalue() |
212 |
| - ).decode() |
213 |
| - |
214 |
| - |
215 |
| -class NMRBlock(DataBlock): |
216 |
| - blocktype = "nmr" |
217 |
| - description = "Simple NMR Block" |
218 |
| - accepted_file_extensions = ".zip" |
219 |
| - defaults = {"process number": 1} |
220 |
| - _supports_collections = False |
221 |
| - |
222 |
| - @property |
223 |
| - def plot_functions(self): |
224 |
| - return (self.generate_nmr_plot,) |
225 |
| - |
226 |
| - def read_bruker_nmr_data(self): |
227 |
| - if "file_id" not in self.data: |
228 |
| - LOGGER.warning("NMRPlot.read_bruker_nmr_data(): No file set in the DataBlock") |
229 |
| - return |
230 |
| - |
231 |
| - zip_file_info = get_file_info_by_id(self.data["file_id"], update_if_live=True) |
232 |
| - filename = zip_file_info["name"] |
233 |
| - |
234 |
| - name, ext = os.path.splitext(filename) |
235 |
| - if ext.lower() not in self.accepted_file_extensions: |
236 |
| - LOGGER.warning( |
237 |
| - "NMRBlock.read_bruker_nmr_data(): Unsupported file extension (must be .zip)" |
238 |
| - ) |
239 |
| - return |
240 |
| - |
241 |
| - # unzip: |
242 |
| - directory_location = zip_file_info["location"] + ".extracted" |
243 |
| - LOGGER.debug(f"Directory location is: {directory_location}") |
244 |
| - with zipfile.ZipFile(zip_file_info["location"], "r") as zip_ref: |
245 |
| - zip_ref.extractall(directory_location) |
246 |
| - |
247 |
| - extracted_directory_name = os.path.join(directory_location, name) |
248 |
| - available_processes = os.listdir(os.path.join(extracted_directory_name, "pdata")) |
249 |
| - |
250 |
| - if self.data.get("selected_process") not in available_processes: |
251 |
| - self.data["selected_process"] = available_processes[0] |
252 |
| - |
253 |
| - try: |
254 |
| - df, a_dic, topspin_title, processed_data_shape = nmr_utils.read_bruker_1d( |
255 |
| - os.path.join(directory_location, name), |
256 |
| - process_number=self.data["selected_process"], |
257 |
| - verbose=False, |
258 |
| - ) |
259 |
| - except Exception as error: |
260 |
| - LOGGER.critical(f"Unable to parse {name} as Bruker project. {error}") |
261 |
| - return |
262 |
| - |
263 |
| - serialized_df = df.to_dict() if (df is not None) else None |
264 |
| - |
265 |
| - # all data sorted in a fairly raw way |
266 |
| - self.data["processed_data"] = serialized_df |
267 |
| - self.data["acquisition_parameters"] = a_dic["acqus"] |
268 |
| - self.data["processing_parameters"] = a_dic["procs"] |
269 |
| - self.data["pulse_program"] = a_dic["pprog"] |
270 |
| - |
271 |
| - # specific things that we might want to pull out for the UI: |
272 |
| - self.data["available_processes"] = available_processes |
273 |
| - self.data["nucleus"] = a_dic["acqus"]["NUC1"] |
274 |
| - self.data["carrier_frequency_MHz"] = a_dic["acqus"]["SFO1"] |
275 |
| - self.data["carrier_offset_Hz"] = a_dic["acqus"]["O1"] |
276 |
| - self.data["recycle_delay"] = a_dic["acqus"]["D"][1] |
277 |
| - self.data["nscans"] = a_dic["acqus"]["NS"] |
278 |
| - self.data["CNST31"] = a_dic["acqus"]["CNST"][31] |
279 |
| - self.data["processed_data_shape"] = processed_data_shape |
280 |
| - |
281 |
| - self.data["probe_name"] = a_dic["acqus"]["PROBHD"] |
282 |
| - self.data["pulse_program_name"] = a_dic["acqus"]["PULPROG"] |
283 |
| - self.data["topspin_title"] = topspin_title |
284 |
| - |
285 |
| - def generate_nmr_plot(self): |
286 |
| - self.read_bruker_nmr_data() # currently calls every time plotting happens, but it should only happen if the file was updated |
287 |
| - if "processed_data" not in self.data or not self.data["processed_data"]: |
288 |
| - self.data["bokeh_plot_data"] = None |
289 |
| - return |
290 |
| - |
291 |
| - df = pd.DataFrame(self.data["processed_data"]) |
292 |
| - df["normalized intensity"] = df.intensity / df.intensity.max() |
293 |
| - |
294 |
| - bokeh_layout = selectable_axes_plot( |
295 |
| - df, |
296 |
| - x_options=["ppm", "hz"], |
297 |
| - y_options=[ |
298 |
| - "intensity", |
299 |
| - "intensity_per_scan", |
300 |
| - "normalized intensity", |
301 |
| - ], |
302 |
| - plot_line=True, |
303 |
| - point_size=3, |
304 |
| - ) |
305 |
| - bokeh_layout.children[0].x_range.flipped = True # flip x axis, per NMR convention |
306 |
| - |
307 |
| - self.data["bokeh_plot_data"] = bokeh.embed.json_item(bokeh_layout, theme=mytheme) |
0 commit comments