{"record":{"id":"f0e52bd1d3f48d37","repo":"matplotlib/matplotlib","slug":"bw-method-should-be-scott-silverman-a-scal","errorCode":null,"errorMessage":"`bw_method` should be 'scott', 'silverman', a scalar or a callable","messagePattern":"`bw_method` should be 'scott', 'silverman', a scalar or a callable","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"lib/matplotlib/mlab.py","lineNumber":851,"sourceCode":"        if not np.array(self.dataset).size > 1:\n            raise ValueError(\"`dataset` input should have multiple elements.\")\n\n        self.dim, self.num_dp = np.array(self.dataset).shape\n\n        if bw_method is None:\n            pass\n        elif cbook._str_equal(bw_method, 'scott'):\n            self.covariance_factor = self.scotts_factor\n        elif cbook._str_equal(bw_method, 'silverman'):\n            self.covariance_factor = self.silverman_factor\n        elif isinstance(bw_method, Number):\n            self._bw_method = 'use constant'\n            self.covariance_factor = lambda: bw_method\n        elif callable(bw_method):\n            self._bw_method = bw_method\n            self.covariance_factor = lambda: self._bw_method(self)\n        else:\n            raise ValueError(\"`bw_method` should be 'scott', 'silverman', a \"\n                             \"scalar or a callable\")\n\n        # Computes the covariance matrix for each Gaussian kernel using\n        # covariance_factor().\n\n        self.factor = self.covariance_factor()\n        # Cache covariance and inverse covariance of the data\n        if not hasattr(self, '_data_inv_cov'):\n            self.data_covariance = np.atleast_2d(\n                np.cov(\n                    self.dataset,\n                    rowvar=1,\n                    bias=False))\n            self.data_inv_cov = np.linalg.inv(self.data_covariance)\n\n        self.covariance = self.data_covariance * self.factor ** 2\n        self.inv_cov = self.data_inv_cov / self.factor ** 2\n        self.norm_factor = (np.sqrt(np.linalg.det(2 * np.pi * self.covariance))","sourceCodeStart":833,"sourceCodeEnd":869,"githubUrl":"https://github.com/matplotlib/matplotlib/blob/b379c1b69e012b142c0f496a52bcb30513802d72/lib/matplotlib/mlab.py#L833-L869","documentation":"mlab.GaussianKDE.__init__ accepts bw_method=None (class default), the strings 'scott' or 'silverman' (matched case-insensitively via cbook._str_equal), a numbers.Number used as a constant factor, or a callable receiving the KDE instance. Any other value — a string like 'auto', a list/array, or an object — raises ValueError(\"`bw_method` should be 'scott', 'silverman', a scalar or a callable\").","triggerScenarios":"GaussianKDE(data, bw_method='auto'); bw_method=[0.5] or np.array([0.5]) (arrays are not Number instances); bw_method='Scott' actually passes due to case-insensitive compare, but 'scott factor' or 'cross_validation' fails; passing a method name from another library (e.g. seaborn's bandwidth semantics).","commonSituations":"Exposing a user-facing bandwidth parameter straight into GaussianKDE without validation; porting scipy examples where bw_method can also be a string scalar like '0.5' (it cannot here); config files storing bw_method as a JSON list.","solutions":["Use one of the four accepted forms: None, 'scott', 'silverman', a plain float/int, or a callable like lambda kde: kde.n ** -0.2.","If the value arrives as a 1-element sequence, unwrap it: bw = float(bw[0]).","Validate at the config boundary: reject unknown strings early with your own error message.","For data-driven bandwidths, pass a callable rather than a string identifier."],"exampleFix":"# before\nkde = mlab.GaussianKDE(data, bw_method='auto')\n\n# after\nbw = {'auto': 'scott', 'default': None}.get(cfg_bw, cfg_bw)\nkde = mlab.GaussianKDE(data, bw_method=bw if isinstance(bw, (str, float, int)) or bw is None or callable(bw) else 'scott')","handlingStrategy":"type-guard","validationCode":"from numbers import Number\n\ndef valid_bw(bw):\n    return (bw is None or isinstance(bw, (str, Number)) and not isinstance(bw, bool)\n            or callable(bw)) and not isinstance(bw, (list, tuple, np.ndarray))","typeGuard":"def is_valid_bw_method(bw) -> bool:\n    if bw is None or callable(bw):\n        return True\n    if isinstance(bw, str):\n        return bw.lower() in ('scott', 'silverman')\n    return isinstance(bw, Number) and not isinstance(bw, bool)","tryCatchPattern":"try:\n    kde = mlab.GaussianKDE(data, bw_method=bw)\nexcept ValueError:\n    kde = mlab.GaussianKDE(data, bw_method='scott')  # explicit fallback default","preventionTips":["Whitelist bw_method at the config boundary: None | 'scott' | 'silverman' | float | callable.","Unwrap single-element sequences from configs before passing.","Never forward raw user strings — map them to allowed values first."],"tags":["matplotlib","mlab","kde","bandwidth","parameter-validation"],"backgroundTag":"invalid-parameter-value","analyzedSha":"b379c1b69e012b142c0f496a52bcb30513802d72","analyzedAt":"2026-08-21T23:31:55.468Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}