[READ-ONLY] Mirror of https://github.com/jmrplens/PyOctaveBand. [Python3] Octave-Band and Fractional Octave-Band filter. For signal in time domain. jmrplens.github.io/PyOctaveBand/
acoustics audio filter frequency frequency-analysis frequency-domain octave python3 signal time-domain
0

Configure Feed

Select the types of activity you want to include in your feed.

fix: address the review findings on the plotting batch

- plot_monte_carlo lets callers override density (setdefault instead of
a hardcoded kwarg that collided) (Copilot)
- plot_open_plan imports matplotlib.ticker after the lazy axes creation
so a missing matplotlib still raises the actionable hint (Copilot)
- the exposure plot computes its y-limits from the data instead of
clamping at 0 dB (negative levels no longer clip) (Copilot)
- the sound-power legend also renders when the caller passes label=
(Gemini)
- the insulation plot annotations are quoted for consistency (the file
already had future annotations, so this is style, not a crash fix)
(Gemini)
- the GUM example comment now says honestly that the committed figure
overlays the Gaussian, and the open-plan one-liner snippet gains
plt.show(), on all surfaces (CodeRabbit)

José M. Requena Plens (Jul 10, 2026, 1:16 PM +0200) 52e53f96 49b1a2b0

+29 -12
+2 -1
docs/gum-uncertainty.md
··· 117 117 keep_samples=True) 118 118 k, U = result.expanded(0.95) 119 119 120 - # One line per panel — the budget and the Monte Carlo output distribution: 120 + # One line per panel — the budget bars, and the Monte Carlo histogram with 121 + # its coverage interval (the committed figure also overlays the GUM Gaussian): 121 122 result.plot() 122 123 mc.plot() 123 124 plt.show()
+3
docs/room-acoustics.md
··· 352 352 <summary>Show the code for this figure</summary> 353 353 354 354 ```python 355 + import matplotlib.pyplot as plt 356 + 355 357 # One line: the D2,S regression rebuilt from the result fields, with the 356 358 # rD / rP crossings marked (the figure above adds the measured points and 357 359 # the STI axis on top of it): 358 360 m.plot() 361 + plt.show() 359 362 ``` 360 363 361 364 ```python
+3 -1
site/src/content/docs/es/guides/gum-uncertainty.md
··· 120 120 keep_samples=True) 121 121 k, U = result.expanded(0.95) 122 122 123 - # En una línea por panel — el balance y la distribución de salida de Monte Carlo: 123 + # En una línea por panel — las barras del balance, y el histograma de Monte 124 + # Carlo con su intervalo (la figura del repositorio superpone además la 125 + # gaussiana del GUM): 124 126 result.plot() 125 127 mc.plot() 126 128 plt.show()
+3
site/src/content/docs/es/guides/room-acoustics.md
··· 366 366 <summary>Ver el código de esta figura</summary> 367 367 368 368 ```python 369 + import matplotlib.pyplot as plt 370 + 369 371 # En una línea: la regresión D2,S reconstruida con los campos del resultado, 370 372 # con los cruces rD / rP marcados (la figura superior añade además los puntos 371 373 # medidos y el eje de STI): 372 374 m.plot() 375 + plt.show() 373 376 ``` 374 377 375 378 ```python
+2 -1
site/src/content/docs/guides/gum-uncertainty.md
··· 118 118 keep_samples=True) 119 119 k, U = result.expanded(0.95) 120 120 121 - # One line per panel — the budget and the Monte Carlo output distribution: 121 + # One line per panel — the budget bars, and the Monte Carlo histogram with 122 + # its coverage interval (the committed figure also overlays the GUM Gaussian): 122 123 result.plot() 123 124 mc.plot() 124 125 plt.show()
+3
site/src/content/docs/guides/room-acoustics.md
··· 353 353 <summary>Show the code for this figure</summary> 354 354 355 355 ```python 356 + import matplotlib.pyplot as plt 357 + 356 358 # One line: the D2,S regression rebuilt from the result fields, with the 357 359 # rD / rP crossings marked (the figure above adds the measured points and 358 360 # the STI axis on top of it): 359 361 m.plot() 362 + plt.show() 360 363 ``` 361 364 362 365 ```python
+8 -4
src/phonometry/_plotting.py
··· 1007 1007 ax.set_title(f"{designation} sound power spectrum") 1008 1008 if np.any(neg): 1009 1009 ax.plot([], [], color=_C_MUTED, marker="s", ls="", label="Non-positive band") 1010 + if np.any(neg) or "label" in kwargs: 1010 1011 ax.legend(loc="best", fontsize="small") 1011 1012 ax.grid(True, axis="y", alpha=0.3) 1012 1013 return ax ··· 1882 1883 samples = np.asarray(result.samples, dtype=np.float64) 1883 1884 kwargs.setdefault("color", _C_PRIMARY_LIGHT) 1884 1885 kwargs.setdefault("bins", 120) 1885 - ax.hist(samples, density=True, **kwargs) 1886 + kwargs.setdefault("density", True) 1887 + ax.hist(samples, **kwargs) 1886 1888 low, high = result.interval 1887 1889 ax.axvspan(low, high, color=_C_PRIMARY, alpha=0.12, 1888 1890 label=f"{100.0 * result.coverage:g} % coverage interval") ··· 1921 1923 :raises ValueError: If the spatial-decay regression is undefined 1922 1924 (``d2s`` / ``lp_as_4m`` are NaN). 1923 1925 """ 1924 - import matplotlib.ticker as mticker 1925 - 1926 1926 if not (np.isfinite(result.d2s) and np.isfinite(result.lp_as_4m)): 1927 1927 raise ValueError( 1928 1928 "plot() needs the spatial-decay regression; this result's d2s / " ··· 1930 1930 "range)." 1931 1931 ) 1932 1932 ax = ax if ax is not None else _new_axes() 1933 + import matplotlib.ticker as mticker 1934 + 1933 1935 r_max = 16.0 1934 1936 for marker in (result.rd, result.rp): 1935 1937 if np.isfinite(marker): ··· 2097 2099 label=f"$L_{{EX,8h}}$ = {result.lex_8h:.1f} dB") 2098 2100 ax.axhline(result.upper_limit, color=_C_MUTED, ls=":", 2099 2101 label=f"$L_{{EX,8h}} + U$ = {result.upper_limit:.1f} dB") 2100 - ax.set_ylim(0.0, max(result.upper_limit, max(contributions)) * 1.12) 2102 + top = max(result.upper_limit, max(contributions)) 2103 + bottom = min(0.0, min(contributions)) 2104 + ax.set_ylim(bottom * 1.12 if bottom < 0.0 else 0.0, top * 1.12) 2101 2105 ax.set_ylabel("A-weighted level [dB]") 2102 2106 ax.set_title( 2103 2107 f"ISO 9612 daily noise exposure — $L_{{EX,8h}}$ = "
+5 -5
src/phonometry/insulation.py
··· 191 191 dnt: np.ndarray 192 192 r_prime: np.ndarray | None 193 193 194 - def plot(self, ax: Axes | None = None, **kwargs: Any) -> Axes: 194 + def plot(self, ax: "Axes | None" = None, **kwargs: Any) -> "Axes": 195 195 """Plot the per-band insulation quantities (``DnT``, ``D``, ``R'``). 196 196 197 197 Requires matplotlib (``pip install phonometry[plot]``); returns the ··· 232 232 measured: np.ndarray | None = None 233 233 shifted_reference: np.ndarray | None = None 234 234 235 - def plot(self, ax: Axes | None = None, **kwargs: Any) -> Axes: 235 + def plot(self, ax: "Axes | None" = None, **kwargs: Any) -> "Axes": 236 236 """Plot the measured curve vs the shifted reference (ISO 717-1). 237 237 238 238 Unfavourable deviations (reference above measurement) are shaded and ··· 261 261 l_n_t: np.ndarray 262 262 l_n: np.ndarray | None 263 263 264 - def plot(self, ax: Axes | None = None, **kwargs: Any) -> Axes: 264 + def plot(self, ax: "Axes | None" = None, **kwargs: Any) -> "Axes": 265 265 """Plot the per-band impact levels (``L'nT`` and, if present, ``L'n``). 266 266 267 267 Requires matplotlib (``pip install phonometry[plot]``); returns the ··· 301 301 measured: np.ndarray | None = None 302 302 shifted_reference: np.ndarray | None = None 303 303 304 - def plot(self, ax: Axes | None = None, **kwargs: Any) -> Axes: 304 + def plot(self, ax: "Axes | None" = None, **kwargs: Any) -> "Axes": 305 305 """Plot the measured curve vs the shifted reference (ISO 717-2). 306 306 307 307 Unfavourable deviations (measurement above the reference, the sign ··· 339 339 r_prime: np.ndarray | None 340 340 frequencies: np.ndarray | None = None 341 341 342 - def plot(self, ax: Axes | None = None, **kwargs: Any) -> Axes: 342 + def plot(self, ax: "Axes | None" = None, **kwargs: Any) -> "Axes": 343 343 """Plot the per-band façade insulation profile (ISO 16283-3). 344 344 345 345 Draws the standardized level difference and any other available