Scientific Data Analysis with LabPlot in Python: Signal Processing, Spectral Peak Fitting, Visualization, and Batch Automation

2026年8月24日 03:32
站內 AI 整理稿

In this tutorial, we explore a LabPlot-inspired scientific data analysis workflow in Python while preserving the structure and terminology of LabPlot’s aspect tree, analysis kernels, plotting system, and project model.

We build reusable components to import tabular data, compute descriptive statistics, smooth and differentiate signals, perform Fourier analysis and filtering, detect peaks, integrate curves, reduce data, and fit nonlinear models with detailed statistical diagnostics.

We then apply these tools to a realistic spectroscopy example: removing periodic interference, identifying overlapping peaks, fitting a multi-Gaussian model, inspecting residuals, visualizing results through themed worksheets, exporting figures, and saving project data in LabPlot-compatible .

lml-style files.Finally, we extend the same workflow to batch processing so we can analyze multiple temperature-dependent spectra and fit secondary trends across the resulting measurements.

Copy CodeCopiedUse a different Browserimport os, sys, gzip, bz2, lzma, time, math, textwrap, warnings import xml.etree.ElementTree as ET from dataclasses import dataclass, field from enum import Enum import numpy as np, pandas as pd, matplotlib, matplotlib.pyplot as plt from matplotlib.

ticker import AutoMinorLocator import scipy from scipy import signal, stats, optimize warnings.filterwarnings("ignore", category=RuntimeWarning) np.random.seed(20260815) INCOLAB = "google.colab" in sys.modules OUT = "/content/labplotout" if INCOLAB else os.path.join(os.getcwd(), "labplotout") os.

makedirs(OUT, existok=True) try: from pylabplot import ; HAVESDK = True except Exception: HAVESDK = False banner = lambda t: print("\n" + "=" 76 + f"\n {t}\n" + "=" 76) banner("environment") print(f" numpy {np.version} | scipy {scipy.version} | mpl {matplotlib.

version} | " f"colab={INCOLAB} | pylabplot={'yes' if HAVESDK else 'no -> emulation'}\n -> {OUT}") class PlotDesignation(Enum): NoDesignation = 0; X = 1; Y = 2; Z = 3 XError = 4; XErrorMinus = 5; XErrorPlus = 6 YError = 7; YErrorMinus = 8; YErrorPlus = 9 class ColumnMode(Enum): Double = 0; Text = 1; Integer = 2; BigInt = 3; DateTime = 4 class AbstractAspect: def init(self, name, comment=""): self.

name, self.comment, self.parent, self.children = name, comment, None, [] def name(self): return self.name def addChild(self, a): a.parent = self; self.children.append(a); return a def tree(self, d=0): s = " " d + f"{'|- ' if d else ''}{type(self).name:<20} {self.

name}" if isinstance(self, Column): s += f" [{self.columnMode.name}, {self.rowCount()} rows, {self.plotDesignation.name}]" return "\n".join([s] + [c.tree(d+1) for c in self.children]) class Column(AbstractAspect): """LabPlot's fundamental data source: a typed vector + a plot designation.

""" def init(self, name, values=None, mode=ColumnMode.Double, designation=PlotDesignation.NoDesignation): super().init(name) self.columnMode, self.plotDesignation = mode, designation self.d = np.asarray([] if values is None else values, float) def values(self): return self.

d def rowCount(self): return len(self.d) def clean(self): return self.d[np.isfinite(self.d)] def statistics(self): """The 20 quantities in LabPlot's Column Statistics dialog.""" x = self.clean(); n = x.size if not n: return {} q1, med, q3 = np.

percentile(x, [25, 50, 75]); iqr, pos = q3 - q1, x[x > 0] h = 2 iqr / n(1/3) if iqr > 0 else 0 c, = np.histogram(x, bins=int(np.clip(np.ptp(x)/h, 1, 1000)) if h else 10) p = c[c > 0] / c.sum(); v, k = np.unique(np.round(x, 12), returncounts=True) return {"Count": n, "Minimum": x.min(), "Maximum": x.

max(), "Arithmetic mean": x.mean(), "Geometric mean": stats.gmean(pos) if pos.size else np.nan, "Harmonic mean": stats.hmean(pos) if pos.size else np.nan, "Contraharmonic mean": (x2).sum() / x.sum() if x.sum() else np.nan, "Mode": v[k.argmax()] if k.max() > 1 else np.

nan, "First quartile": q1, "Median": med, "Third quartile": q3, "Interquartile range": iqr, "Trimean": (q1 + 2med + q3) / 4, "Variance": x.var(ddof=1), "Standard deviation": x.std(ddof=1), "Skewness": stats.skew(x), "Mean absolute deviation": np.abs(x - x.mean()).

mean(), "Median absolute deviation": np.median(np.abs(x - med)), "Kurtosis": stats.kurtosis(x, fisher=False), "Entropy": float(-(p np.log2(p)).sum())} def sparkline(self, w=26): """LabPlot 2.11+ draws these in the column header; text version.""" b, x = ".-~^", self.clean() s = x[np.linspace(0, x.

size-1, min(w, x.size)).astype(int)] if x.size > 1 else x return "" if s.size < 2 or np.ptp(s) == 0 else "".join( b[i] for i in ((s - s.min()) / np.ptp(s) 4).round().astype(int)) class Spreadsheet(AbstractAspect): def columns(self): return [c for c in self.

children if isinstance(c, Column)] def column(self, k): cs = self.columns() return cs[k] if isinstance(k, int) else next(c for c in cs if c.name() == k) def columnCount(self): return len(self.columns()) def rowCount(self): return max([c.rowCount() for c in self.

columns()], default=0) def appendColumn(self, n, v, d=PlotDesignation.Y): return self.addChild(Column(n, v, designation=d)) def toDataFrame(self): return pd.DataFrame({c.name(): c.values() for c in self.columns()}) def info(self): print(f" Spreadsheet '{self.name}': {self.rowCount()} rows x {self.

columnCount()} cols") for c in self.columns(): s = c.statistics() print(f" {c.name():<12}{c.plotDesignation.name:<6}min {s['Minimum']:>9.4g} max " f"{s['Maximum']:>9.4g} mean {s['Arithmetic mean']:>9.4g} {c.

sparkline()}") class Project(AbstractAspect): XMLVERSION = 15 def init(self, name="project", author=""): super().init(name); self.author, self.version = author, "2.12.1" def spreadsheets(self): return [c for c in self.

children if isinstance(c, Spreadsheet)] class AsciiFilter: """LabPlot's text import: separator auto-detect, comments, row/col limits.""" def init(self, separator="auto", commentCharacter="#", headerEnabled=True, startRow=1, endRow=-1, startColumn=1, endColumn=-1): self.separator, self.

commentCharacter = separator, commentCharacter self.headerEnabled, self.startRow, self.endRow = headerEnabled, startRow, endRow self.startColumn, self.

endColumn = startColumn, endColumn def readDataFromFile(self, path, dataSource): with open(path, encoding="utf-8", errors="replace") as fh: lines = [l.rstrip("\n") for l in fh if l.strip() and not l.lstrip().startswith(self.commentCharacter)] lines = lines[self.startRow - 1: None if self.

endRow < 0 else self.endRow] if not lines: raise ValueError("AsciiFilter: nothing to import") sep = (next((s for s in (",", ";", "\t", "|") if s in lines[0]), None) if self.separator == "auto" else self.separator) split = lambda l: [p.strip() for p in (l.split(sep) if sep else l.split()) if p.

strip()] header = split(lines[0]) if self.headerEnabled else None rows = [split(l) for l in (lines[1:] if self.headerEnabled else lines)] ncol = max(map(len, rows)) c0, c1 = self.startColumn - 1, ncol if self.endColumn < 0 else self.

endColumn for j in range(c0, min(c1, ncol)): vals = [] for r in rows: try: vals.append(float(r[j])) except (IndexError, ValueError): vals.append(np.nan) dataSource.addChild(Column( header[j] if header and j < len(header) else f"Column {j+1}", vals, designation=PlotDesignation.

X if j == c0 else PlotDesignation.Y)) return dataSource We set up the Python environment, configure reproducibility, and establish the output directory for the tutorial.We recreate LabPlot’s core aspect-tree structure using projects, spreadsheets, columns, plot designations, and column modes.

We also implement the AsciiFilter workflow to import structured text data into our LabPlot-style data model.Copy CodeCopiedUse a different Browserclass nslsmooth: """Analysis -> Smooth (Savitzky-Golay; LabPlot also offers moving average/percentile).

""" @staticmethod def savitzkygolay(y, points=11, order=3, deriv=0): points += points % 2 == 0 return signal.savgol_filter(y, points, min(order, points-1), deriv=deriv, mode="interp") cla

Related

相關文章

抖省省誕生7個月:引流灌溉、重金猛推,日活2000萬後急速降溫

進入9月,抖音本地生活服務(簡稱:抖音生服)開始提速盈利節奏,繼續降補,並大幅提升廣告考核佔比。服務零售部分類目廣告考核佔比提升到80%,GMV考核佔比變小。Ka餐飲類目廣告考核佔比保持20%,商圈廣告考核佔比保持10%。4月調整架構之前,廣告考核還不是硬性指標。過去半年,抖音生服推出獨立APP抖省省,猛砸補貼和引流灌溉,使得抖省省日活快速拉昇,一度被外界視作對美團的又一場奇襲。從QuestMobile獲取的數據顯示,3月到6月抖省省日活從400萬拉昇到2000萬,7月維持在2200萬。

2 天前

OpenAI、Anthropic罕見聯手:砸下1個億,給數學家送錢、送算力

編譯 | 黃菲 編輯 | 江宇 10月16日報道,昨日,OpenAI、Anthropic聯合美國西蒙斯基金會(Simons Foundation),共同投入1500萬美元(約合人民幣1.01億元),支持數學家評估AI輔助產生的研究成果,並幫助研究人員學習和使用AI工具。 其中,OpenAI出資500萬美元(約合人民幣3360萬元),Anthropic的具體出資金額尚未披露。 根據基金會公告,兩家公司還將為獲得資助的研究人員提供AI工具和計算資源,相關資金將由西蒙斯基金會管理和分配。

2 天前

“圳”啟“芯”程 智創未來!2026灣芯展盛大啟幕

10月14日,2026灣區半導體產業生態博覽會(灣芯展WESEMiBAY)在深圳會展中心(福田)盛大啟幕。本屆灣芯展由中國國際工程諮詢有限公司指導,深圳市半導體與集成電路產業聯盟、深圳市重大產業投資集團有限公司主辦。深圳市有關領導同志,市政府有關部門和集成電路發展集聚區有關負責同志,以及國內外半導體與集成電路產業龍頭企業、高校、科研院所及媒體代表等蒞臨現場參觀交流。開展首日,近8萬平方米展館人流如織,深圳再度成為全球半導體產業目光的交匯點。

3 天前
Hugging Face BlogAI工具與產品

Welcome Muse Spark Open: open-weight frontier multimodal mixture-of-experts model from Meta

Back to Articles Welcome Muse Spark Open: open-weight frontier multimodal mixture-of-experts model from Meta Published October 15, 2026 Update on GitHub Upvote 1 Pedro Cuenca pcuenq Follow merve merve Follow ben burtenshaw burtenshaw Follow Guarin Flück guarin Follow Quentin Gallouédec qgallouedec Follow Alvaro Bartolome alvarobartt Follow Serveurperso Serveurperso Follow Jun Kim Jundot Follow Muse Spark Open is an open-weight model from Meta.

3 天前