Close Menu
NCIJ Network NCIJ Network
    What's Hot

    ‘It’s like a death sentence’ says British widow facing deportation from Sweden | Brexit

    September 9, 2026

    Labour picks former child refugee to stand in byelection for Starmer’s seat | Byelections

    September 9, 2026

    LIV races to re-sign golfers to clinch $300mn bankruptcy rescue

    September 9, 2026
    Facebook X (Twitter) Instagram
    Trending
    • ‘It’s like a death sentence’ says British widow facing deportation from Sweden | Brexit
    • Labour picks former child refugee to stand in byelection for Starmer’s seat | Byelections
    • LIV races to re-sign golfers to clinch $300mn bankruptcy rescue
    • OpenAI adds a prominent AI doomer to its board of directors
    • HelmGuard Raises $7.3 Million for Agentic GRC and Security
    • Block Is Latest Bitcoin-Focused Company To Apply For Charter
    • Solana’s 300ms speed boost to outrun trading bots might come with a hidden cost
    • Interstellar comet 3I/ATLAS is bursting with methanol
    • About
      • Our Team
      • Editorial Policy
      • Editorial Independence
      • International Support
    • Trust & Standards
      • AI Usage Policy
      • Conflict of Interest Policy
      • Corrections Policy
      • Ethics Policy
      • Fact-Checking Policy
      • Source Protection
    • Get Involved
      • Guide for Sources
      • Support Independent Journalism
    • Legal
      • Cookie Policy
      • Privacy Policy
      • Terms of Use
    Facebook X (Twitter) Instagram
    NCIJ Network NCIJ Network
    Wednesday, September 9
    • Home
    • World
    • Ai
    • Business
    • Politics
    • Health
    • Crypto
    • Science
    • Technology
    • Cybersecurity
    • Defense & Security
    • Economy
    • Energy
    • Europe
    • More
      • Fact Check
      • Investigations
      • Opinion & Analysis
      • Environment
    NCIJ Network NCIJ Network
    Home»Artificial Intelligence

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

    NCIJ NETWNCIJ NETWORKBy NCIJ NETWNCIJ NETWORKAugust 24, 2026 Artificial Intelligence No Comments6 Mins Read
    Share
    Facebook Twitter LinkedIn Pinterest Email

    THEMES = {
    "BlackOnWhite": dict(bg="#ffffff", fg="#000000", grid="#c8c8c8",
      cycle=["#3465a4", "#cc0000", "#4e9a06", "#f57900", "#75507b", "#06989a"]),
    "Dracula": dict(bg="#282a36", fg="#f8f8f2", grid="#44475a",
      cycle=["#8be9fd", "#ff79c6", "#50fa7b", "#ffb86c", "#bd93f9", "#f1fa8c"]),
    "SolarizedDark": dict(bg="#002b36", fg="#93a1a1", grid="#0f4b57",
      cycle=["#268bd2", "#dc322f", "#859900", "#b58900", "#6c71c4", "#2aa198"])}
    class XYCurve(AbstractAspect):
       def __init__(self, name, x=None, y=None, lineStyle="-", lineWidth=1.6,
                    symbolStyle=None, symbolSize=4., color=None, alpha=1., zorder=2):
           super().__init__(name)
           self.xColumn, self.yColumn, self.color, self.alpha = x, y, color, alpha
           self.lineStyle, self.lineWidth = lineStyle, lineWidth
           self.symbolStyle, self.symbolSize, self.zorder = symbolStyle, symbolSize, zorder
           self.yErrorColumn = self.fillBetween = None
       def setXColumn(self, c): self.xColumn = c; return self
       def setYColumn(self, c): self.yColumn = c; return self
       @staticmethod
       def _v(c): return c.values() if isinstance(c, Column) else np.asarray(c, float)
       def draw(self, ax, color):
           c = self.color or color; X, Y = self._v(self.xColumn), self._v(self.yColumn)
           if self.fillBetween is not None:
               ax.fill_between(X, *self.fillBetween, color=c, alpha=.2, lw=0, zorder=self.zorder-1)
           if self.yErrorColumn is not None:
               ax.errorbar(X, Y, yerr=self._v(self.yErrorColumn), fmt="none", ecolor=c,
                           elinewidth=.8, capsize=2, alpha=.7, zorder=self.zorder)
           ax.plot(X, Y, linestyle=self.lineStyle or "none", marker=self.symbolStyle or "none",
                   markersize=self.symbolSize, linewidth=self.lineWidth, color=c, alpha=self.alpha,
                   label=self._name, zorder=self.zorder, markeredgewidth=0)
    class Histogram(AbstractAspect):
       """normalization: 'Count' | 'Probability' | 'CountDensity' | 'ProbabilityDensity'."""
       def __init__(self, name, dataColumn=None, bins="auto", normalization="ProbabilityDensity"):
           super().__init__(name)
           self.dataColumn, self.bins, self.normalization = dataColumn, bins, normalization
       def draw(self, ax, color):
           d = (self.dataColumn.clean() if isinstance(self.dataColumn, Column)
                else np.asarray(self.dataColumn, float))
           ax.hist(d, bins=self.bins, color=color, alpha=.55, edgecolor=color, lw=.8,
                   label=self._name, zorder=1, density="Density" in self.normalization
                   or self.normalization == "Probability")
    class CartesianPlot(AbstractAspect):
       class Type(Enum):
           FourAxes = 0; TwoAxes = 1
       def __init__(self, name, title=None, xLabel="x", yLabel="y", logX=False, logY=False):
           super().__init__(name); self.type = CartesianPlot.Type.FourAxes
           self.title, self.xLabel, self.yLabel = title or name, xLabel, yLabel
           self.logX, self.logY, self.legend = logX, logY, None
           self.xRange, self.yRange, self.labels = None, None, []
       def setType(self, t): self.type = t; return self
       def addLegend(self, loc="best"): self.legend = loc; return self
       def setRange(self, x=None, y=None): self.xRange, self.yRange = x, y; return self
       def addTextLabel(self, txt, x, y): self.labels.append((txt, x, y)); return self
       def _render(self, ax, th):
           ax.set_facecolor(th["bg"])
           for i, ch in enumerate(self.children): ch.draw(ax, th["cycle"][i % len(th["cycle"])])
           ax.set_title(self.title, color=th["fg"], fontsize=10.5, pad=7)
           ax.set_xlabel(self.xLabel, color=th["fg"], fontsize=9.5)
           ax.set_ylabel(self.yLabel, color=th["fg"], fontsize=9.5)
           for lg, sc, axis in ((self.logX, ax.set_xscale, ax.xaxis), (self.logY, ax.set_yscale, ax.yaxis)):
               sc("log") if lg else axis.set_minor_locator(AutoMinorLocator(2))
           if self.xRange: ax.set_xlim(*self.xRange)
           if self.yRange: ax.set_ylim(*self.yRange)
           four = self.type is CartesianPlot.Type.FourAxes
           for s in ("top", "right"): ax.spines[s].set_visible(four)
           for s in ax.spines.values(): s.set_color(th["fg"]); s.set_linewidth(.9)
           ax.tick_params(which="both", direction="in", colors=th["fg"], top=four,
                          right=four, labelsize=8.5)
           ax.grid(True, color=th["grid"], lw=.6, alpha=.7, zorder=0)
           for t, x, y in self.labels:
               ax.annotate(t, (x, y), color=th["fg"], fontsize=7.5, ha="center")
           if self.legend:
               for t in ax.legend(loc=self.legend, fontsize=8, framealpha=.85, facecolor=th["bg"],
                                  edgecolor=th["grid"]).get_texts(): t.set_color(th["fg"])
    class Worksheet(AbstractAspect):
       class ExportFormat(Enum):
           PDF = 0; SVG = 1; PNG = 2
       def __init__(self, name, cols=None, figsize=(15, 8.5), dpi=110):
           super().__init__(name); self.themeName = "BlackOnWhite"
           self.cols, self.figsize, self.dpi, self._fig = cols, figsize, dpi, None
       def setTheme(self, n):
           if n not in THEMES: raise KeyError(f"themes: {list(THEMES)}")
           self.themeName = n; return self
       def render(self):
           th = THEMES[self.themeName]
           ps = [c for c in self.children if isinstance(c, CartesianPlot)]
           cols = self.cols or min(len(ps), 2)
           fig, axes = plt.subplots(math.ceil(len(ps)/cols), cols, figsize=self.figsize, dpi=self.dpi)
           fig.patch.set_facecolor(th["bg"]); axes = np.atleast_1d(axes).ravel()
           for ax, p in zip(axes, ps): p._render(ax, th)
           for ax in axes[len(ps):]: ax.axis("off")
           fig.suptitle(self._name, color=th["fg"], fontsize=13, y=.995)
           fig.tight_layout(rect=(0, 0, 1, .98)); self._fig = fig; return fig
       def show(self):
           (self.render() if self._fig is None else None); plt.show()
       def exportToFile(self, path, format=None):
           if self._fig is None: self.render()
           fmt = (format.name.lower() if isinstance(format, Worksheet.ExportFormat)
                  else format or os.path.splitext(path)[1].lstrip("."))
           self._fig.savefig(path, format=fmt, dpi=self.dpi, bbox_inches="tight",
                             facecolor=self._fig.get_facecolor()); return path
    def _reduce(x, y, tolerance=None):
       i = nsl_geom.douglas_peucker(x, y, tolerance if tolerance is not None else .02*np.ptp(y))
       return x[i], y[i], {"in": len(x), "out": len(i), "compression": 1 - len(i)/len(x)}
    class XYAnalysisCurve(XYCurve):
       OPS = {
        "smooth": lambda x, y, points=11, order=3:
           (x, nsl_smooth.savitzky_golay(y, points, order), {}),
        "differentiate": lambda x, y, derivOrder=1, smoothPoints=0:
           (x, nsl_diff.derive(x, y, derivOrder, smoothPoints), {}),
        "integrate": lambda x, y, method="trapezoid", absolute=False:
           (lambda c: (x, c, {"total": float(c[-1])}))(nsl_int.integrate(x, y, method, absolute)),
        "dft": lambda x, y, output="amplitude", window="rectangular":
           nsl_dft.transform(x, y, output, window) + ({},),
        "filter": lambda x, y, type="lowpass", form="butterworth", cutoff=.1, cutoff2=.3, order=3:
           (x, nsl_filter.apply(x, y, type, form, cutoff, cutoff2, order), {}),
        "hilbert": lambda x, y, output="envelope": (x, nsl_hilbert.transform(y, output), {}),
        "reduce": _reduce}
       def __init__(self, name, xData, yData, op, style=None, **opts):
           super().__init__(name, **(style or {}))
           self._xin, self._yin = XYCurve._v(xData), XYCurve._v(yData)
           self.op, self.opts, self.result = op, opts, None
           self.recalculate()
       def recalculate(self):
           self.xColumn, self.yColumn, self.result = 
               XYAnalysisCurve.OPS[self.op](self._xin, self._yin, **self.opts)
           return self
    _mk = lambda op: (lambda name, x, y, style=None, **kw: XYAnalysisCurve(name, x, y, op, style, **kw))
    XYSmoothCurve, XYDifferentiationCurve = _mk("smooth"), _mk("differentiate")
    XYIntegrationCurve = _mk("integrate")
    XYFourierTransformCurve, XYFourierFilterCurve = _mk("dft"), _mk("filter")
    XYHilbertTransformCurve, XYDataReductionCurve = _mk("hilbert"), _mk("reduce")
    class XYFitCurve(XYCurve):
       """LabPlot's centrepiece: non-linear fitting with the full statistics table."""
       def __init__(self, name, xData, yData, model, p0, paramNames=None, yerr=None,
                    bounds=None, npoints=800, **kw):
           super().__init__(name, **kw)
           self._xin, self._yin = XYCurve._v(xData), XYCurve._v(yData)
           self.model, self.p0, self.paramNames = model, p0, paramNames
           self.yerr, self.bounds, self.npoints, self.fitResult = yerr, bounds, npoints, None
       def recalculate(self, conf=.95, showConfidenceInterval=True):
           self.fitResult = nsl_fit.fit(self.model, self._xin, self._yin, self.p0,
                                        self.yerr, self.bounds, self.paramNames, conf)
           xf = np.linspace(self._xin.min(), self._xin.max(), self.npoints)
           yf = self.model(xf, *self.fitResult.values); self.xColumn, self.yColumn = xf, yf
           if showConfidenceInterval:
               d = nsl_fit.confidenceBand(self.model, xf, self.fitResult, conf)
               self.fillBetween = (yf - d, yf + d)
           return self
    class ProjectFile:
       MAGIC = ((b"x1fx8b", gzip.decompress, "gzip"), (b"BZh", bz2.decompress, "bzip2"),
                (b"xfd7zXZx00", lzma.decompress, "xz"))
       @staticmethod
       def load(path):
           blob = open(path, "rb").read(); kind = "plain"
           for magic, dec, nm in ProjectFile.MAGIC:
               if blob.startswith(magic): blob, kind = dec(blob), nm; break
           root = ET.fromstring(blob.decode("utf-8", "replace"))
           root = root if root.tag == "project" else root.find(".//project")
           if root is None: raise ValueError("no project element found")
           prj = Project(os.path.basename(path), root.get("author", ""))
           prj.version = root.get("version", "?")
           print(f"  loaded .lml: compression={kind} version={prj.version} xmlVersion="
                 f"{root.get('xmlVersion','?')}")
           parents = {c: p for p in root.iter() for c in p}
           def sheet_of(n):
               n = parents.get(n)
               while n is not None and n.tag != "spreadsheet": n = parents.get(n)
               return n
           buckets = {}
           for col in root.iter("column"):
               buckets.setdefault(id(sheet_of(col)), (sheet_of(col), []))[1].append(col)
           for el, cols in buckets.values():
               sp = Spreadsheet(el.get("name", "spreadsheet") if el is not None else "sheet")
               for c in cols: sp.addChild(ProjectFile._column(c))
               prj.addChild(sp)
           return prj
       @staticmethod
       def _column(el):
           name = el.get("name") or next(
               (el.find(t).get("name") for t in ("general", "comment")
                if el.find(t) is not None and el.find(t).get("name")), "Column")
           rows = el.findall("row")
           if rows:
               raw = [r.text for r in sorted(rows, key=lambda r: int(r.get("index", 0)))]
           else:
               node = next((el.find(t) for t in ("values", "data", "double")
                            if el.find(t) is not None and el.find(t).text), None)
               raw = (node.text if node is not None else el.text or "").split()
           vals = []
           for v in raw:
               try: vals.append(float(v))
               except (TypeError, ValueError): vals.append(np.nan)
           try: des = PlotDesignation(int(el.get("designation", 0)))
           except (ValueError, TypeError): des = PlotDesignation.NoDesignation
           return Column(name, vals, designation=des)
       @staticmethod
       def save(project, path, compression="gzip"):
           root = ET.Element("project", {
               "version": project.version, "xmlVersion": str(Project.XML_VERSION),
               "fileName": os.path.basename(path), "author": project.author,
               "modificationTime": time.strftime("%Y-%m-%d %H:%M:%S")})
           ET.SubElement(root, "comment").text = project.comment
           for sp in project.spreadsheets():
               e = ET.SubElement(root, "spreadsheet", {"name": sp.name()})
               ET.SubElement(e, "general", {"rowCount": str(sp.rowCount()),
                                            "columnCount": str(sp.columnCount())})
               for col in sp.columns():
                   c = ET.SubElement(e, "column", {
                       "name": col.name(), "rows": str(col.rowCount()),
                       "designation": str(col.plotDesignation.value), "mode": str(col.columnMode.value)})
                   for i, v in enumerate(col.values()):
                       ET.SubElement(c, "row", {"index": str(i)}).text = repr(float(v))
           xml = (b'nn'
                  + ET.tostring(root, encoding="utf-8"))
           open(path, "wb").write({"gzip": gzip.compress, "bzip2": bz2.compress,
                                   "xz": lzma.compress, "none": lambda b: b}[compression](xml))
           return path
    
    Analysis Automation Batch data Fitting LabPlot Peak processing Python scientific signal Spectral Visualization
    NCIJ NETWNCIJ NETWORK
    • Website

    Keep Reading

    Veradigm warns of patient data breach after ransomware gang claims attack

    New analysis maps mercury threat to 951 Amazon communities in three countries

    CloudNC aims to accelerate AI supply chain machining

    Bitcoin just hit a decade-low S&P 500 correlation, but the daily data tells a different story

    Samsung taps Mistral AI models for semiconductor manufacturing

    Gradium Launches Voice Design: Write a Prompt, Get a Brand New Synthetic Voice in Seconds

    Add A Comment
    Leave A Reply Cancel Reply

    Editors Picks

    ‘It’s like a death sentence’ says British widow facing deportation from Sweden | Brexit

    September 9, 2026

    Labour picks former child refugee to stand in byelection for Starmer’s seat | Byelections

    September 9, 2026

    LIV races to re-sign golfers to clinch $300mn bankruptcy rescue

    September 9, 2026

    OpenAI adds a prominent AI doomer to its board of directors

    September 9, 2026
    Latest Posts

    Justice Dept. Subpoenas Times Freelancer in Effort to Identify Sources

    August 1, 2026

    Michigan joins Minnesota in reporting cyberattacks, with FBI investigating | Cybercrime News

    August 1, 2026

    Tiny aerosol particles could supercharge tropical storm clouds

    August 1, 2026

    Subscribe to News

    Get the latest sports news from NewsSite about world, sports and politics.

    NCIJ Network is an independent digital news platform delivering trusted investigative journalism, European and global news, in-depth analysis, and fact-based reporting with accuracy, transparency, and integrity.

    Facebook X (Twitter) Instagram Pinterest YouTube

    ‘It’s like a death sentence’ says British widow facing deportation from Sweden | Brexit

    September 9, 2026

    Labour picks former child refugee to stand in byelection for Starmer’s seat | Byelections

    September 9, 2026

    LIV races to re-sign golfers to clinch $300mn bankruptcy rescue

    September 9, 2026

    Subscribe to Updates

    Get the latest creative news from FooBar about art, design and business.

    Type above and press Enter to search. Press Esc to cancel.