From a22e8dcb64c7136bc346e638d1f6923c60cbbaf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Serge-=C3=89tienne=20Parent?= Date: Mon, 26 Feb 2018 14:00:15 -0500 Subject: [PATCH 01/26] Create deviation_ellipses.py example showing bivariate deviation ellipses of petal length and width of three iris species --- .../deviation_ellipses.py | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 tests/examples_arguments_syntax/deviation_ellipses.py diff --git a/tests/examples_arguments_syntax/deviation_ellipses.py b/tests/examples_arguments_syntax/deviation_ellipses.py new file mode 100644 index 0000000000..e1e2ea20ea --- /dev/null +++ b/tests/examples_arguments_syntax/deviation_ellipses.py @@ -0,0 +1,63 @@ +""" +Deviation ellipse +----------------------- +This example shows bivariate deviation ellipses of petal length and width of three iris species. +""" + +import numpy as np +import pandas as pd +from scipy.stats import f as ssf +import altair as alt +from vega_datasets import data + +iris = data.iris() + +def ellipse(X, level=0.95, method='deviation', npoints=100): + """ + X: data, 2D numpy array with 2 columns + level: confidence level + method: either 'deviation' (swarning data) or 'error (swarning the mean)' + npoints: number of points describing the ellipse + """ + cov_mat = np.cov(X.T) + dfd = X.shape[0]-1 + dfn = 2 + center = np.apply_along_axis(np.mean, arr=X, axis=0) # np.mean(X, axis=0) + if method == 'deviation': + radius = np.sqrt(2 * ssf.ppf(q=level, dfn=dfn, dfd=dfd)) + elif method == 'error': + radius = np.sqrt(2 * ssf.ppf(q=level, dfn=dfn, dfd=dfd)) / np.sqrt(X.shape[0]) + else: + raise ValueError("Method should be either 'deviation' or 'error'.") + angles = (np.arange(0,npoints+1)) * 2 * np.pi/npoints + circle = np.vstack((np.cos(angles), np.sin(angles))).T + ellipse = center + (radius * np.dot(circle, np.linalg.cholesky(cov_mat).T).T).T + return ellipse + +columns = ['petalLength', 'petalWidth'] +petal_ellipse = [] +for species in iris.species.unique(): + ell_df = pd.DataFrame(ellipse(X=iris.loc[iris.species == species, columns].as_matrix()), + columns = columns) + ell_df['species'] = species + petal_ellipse.append(ell_df) + +petal_ellipse = pd.concat(petal_ellipse, axis=0).reset_index() + +chart_deviation = alt.Chart(petal_ellipse).mark_line().\ + encode( + x=alt.X('petalLength', scale=alt.Scale(zero=False)), + y=alt.Y('petalWidth', scale=alt.Scale(zero=False)), + color='species', + order='index') +# works only if chart_deviation is printed here +# chart_deviation + +chart_points = alt.Chart(iris).mark_point().\ + encode( + x=alt.X('petalLength', scale=alt.Scale(zero=False)), + y=alt.Y('petalWidth', scale=alt.Scale(zero=False)), + color='species') + +chart = chart_points + chart_deviation +chart From 1983ede5160d5f71d374066f3f59645261545e18 Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Sat, 4 Jan 2025 17:35:52 +0000 Subject: [PATCH 02/26] docs: Initial rewrite of (#514) Happy with the end result, but not comfortable merging so much complexity I don't understand yet #3715 --- .../deviation_ellipses.py | 112 +++++++++++------- 1 file changed, 69 insertions(+), 43 deletions(-) diff --git a/tests/examples_arguments_syntax/deviation_ellipses.py b/tests/examples_arguments_syntax/deviation_ellipses.py index e1e2ea20ea..859c71cfd3 100644 --- a/tests/examples_arguments_syntax/deviation_ellipses.py +++ b/tests/examples_arguments_syntax/deviation_ellipses.py @@ -1,63 +1,89 @@ +from __future__ import annotations + """ Deviation ellipse ----------------------- This example shows bivariate deviation ellipses of petal length and width of three iris species. """ +from typing import Literal + import numpy as np import pandas as pd from scipy.stats import f as ssf + import altair as alt from vega_datasets import data -iris = data.iris() -def ellipse(X, level=0.95, method='deviation', npoints=100): +def np_ellipse( + arr: np.ndarray[tuple[int, int], np.dtype[np.float64]], + conf_level: float = 0.95, + method: Literal["deviation", "error"] = "deviation", + segments: int = 100, +): """ - X: data, 2D numpy array with 2 columns - level: confidence level - method: either 'deviation' (swarning data) or 'error (swarning the mean)' - npoints: number of points describing the ellipse - """ - cov_mat = np.cov(X.T) - dfd = X.shape[0]-1 + Arguments: + arr: 2D numpy array with 2 columns + level: confidence level + method: either 'deviation' (swarning data) or 'error (swarning the mean)' + segments: number of points describing the ellipse. + """ # noqa: D205 + n_elements = len(arr) + # TODO: + # - dfn? + # - dfd? + # - ssf.ppf? + # - Percent point function (inverse of `cdf`) at q of the given RV. dfn = 2 - center = np.apply_along_axis(np.mean, arr=X, axis=0) # np.mean(X, axis=0) - if method == 'deviation': - radius = np.sqrt(2 * ssf.ppf(q=level, dfn=dfn, dfd=dfd)) - elif method == 'error': - radius = np.sqrt(2 * ssf.ppf(q=level, dfn=dfn, dfd=dfd)) / np.sqrt(X.shape[0]) + dfd = n_elements - 1 + deviation = np.sqrt(2 * ssf.ppf(conf_level, dfn=dfn, dfd=dfd)) + if method == "deviation": + radius = deviation + elif method == "error": + radius = deviation / np.sqrt(n_elements) else: - raise ValueError("Method should be either 'deviation' or 'error'.") - angles = (np.arange(0,npoints+1)) * 2 * np.pi/npoints + msg = "Method should be either 'deviation' or 'error'." + raise ValueError(msg) + angles = (np.arange(0, segments + 1)) * 2 * np.pi / segments circle = np.vstack((np.cos(angles), np.sin(angles))).T + center = np.mean(arr, axis=0) + cov_mat = np.cov(arr.T) + # TODO: Figure out why so many transpositions ellipse = center + (radius * np.dot(circle, np.linalg.cholesky(cov_mat).T).T).T return ellipse -columns = ['petalLength', 'petalWidth'] -petal_ellipse = [] -for species in iris.species.unique(): - ell_df = pd.DataFrame(ellipse(X=iris.loc[iris.species == species, columns].as_matrix()), - columns = columns) - ell_df['species'] = species - petal_ellipse.append(ell_df) - -petal_ellipse = pd.concat(petal_ellipse, axis=0).reset_index() - -chart_deviation = alt.Chart(petal_ellipse).mark_line().\ - encode( - x=alt.X('petalLength', scale=alt.Scale(zero=False)), - y=alt.Y('petalWidth', scale=alt.Scale(zero=False)), - color='species', - order='index') -# works only if chart_deviation is printed here -# chart_deviation - -chart_points = alt.Chart(iris).mark_point().\ - encode( - x=alt.X('petalLength', scale=alt.Scale(zero=False)), - y=alt.Y('petalWidth', scale=alt.Scale(zero=False)), - color='species') - -chart = chart_points + chart_deviation -chart + +def pd_ellipse( + df: pd.DataFrame, col_x: str, col_y: str, col_group: str +) -> pd.DataFrame: + cols = col_x, col_y + groups = [] + # TODO: Rewrite in a more readable way + categories = df[col_group].unique() + for category in categories: + sliced = df.loc[df[col_group] == category, cols] + ell_df = pd.DataFrame(np_ellipse(sliced.to_numpy()), columns=cols) + ell_df[col_group] = category + groups.append(ell_df) + return pd.concat(groups).reset_index() + + +col_x = "petalLength" +col_y = "petalWidth" +col_group = "species" +x = alt.X(col_x, scale=alt.Scale(zero=False)) +y = alt.Y(col_y, scale=alt.Scale(zero=False)) +color = alt.Color(col_group) + +source = data.iris() +ellipse = pd_ellipse(source, col_x=col_x, col_y=col_y, col_group=col_group) +points = alt.Chart(source).mark_circle().encode(x, y, color) +lines = ( + alt.Chart(ellipse) + .mark_line(filled=True, fillOpacity=0.2) + .encode(x, y, color, order="index") +) + +chart = lines + points +chart \ No newline at end of file From dc7639d4a41baf3a476403238c1d970927ba352f Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Sat, 4 Jan 2025 17:39:52 +0000 Subject: [PATCH 03/26] ci(typing): Adds `scipy-stubs` to `altair[doc]` `scipy` is only used for one example in the user guide, but this will be the second https://docs.scipy.org/doc/scipy/release/1.15.0-notes.html#other-changes --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 3b555aa43c..84af61627c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -96,7 +96,7 @@ doc = [ "myst-parser", "sphinx_copybutton", "sphinx-design", - "scipy", + "scipy-stubs[scipy]", ] [tool.hatch.version] From a296b8248d7375069eb8e9c680778c8abe2ccddb Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Sat, 4 Jan 2025 17:46:36 +0000 Subject: [PATCH 04/26] fix: Only install `scipy-stubs` on `>=3.10` --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 84af61627c..2c5c1f04e7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -96,7 +96,8 @@ doc = [ "myst-parser", "sphinx_copybutton", "sphinx-design", - "scipy-stubs[scipy]", + "scipy", + "scipy-stubs; python_version>=\"3.10\"", ] [tool.hatch.version] From eb2587180f76f6b5d5dcd12ad344062cc2718f93 Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Sat, 4 Jan 2025 17:58:54 +0000 Subject: [PATCH 05/26] chore(typing): Ignore incorrect `pandas` stubs --- tests/examples_arguments_syntax/deviation_ellipses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/examples_arguments_syntax/deviation_ellipses.py b/tests/examples_arguments_syntax/deviation_ellipses.py index 859c71cfd3..59e9cd3407 100644 --- a/tests/examples_arguments_syntax/deviation_ellipses.py +++ b/tests/examples_arguments_syntax/deviation_ellipses.py @@ -63,7 +63,7 @@ def pd_ellipse( categories = df[col_group].unique() for category in categories: sliced = df.loc[df[col_group] == category, cols] - ell_df = pd.DataFrame(np_ellipse(sliced.to_numpy()), columns=cols) + ell_df = pd.DataFrame(np_ellipse(sliced.to_numpy()), columns=cols) # type: ignore ell_df[col_group] = category groups.append(ell_df) return pd.concat(groups).reset_index() From 279fca5b6da8afc73c70b6cc576df809cfbf8f77 Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Sat, 4 Jan 2025 18:08:30 +0000 Subject: [PATCH 06/26] ci(typing): ignore `scipy` on `3.9` https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-library-stubs-or-py-typed-marker https://github.com/vega/altair/actions/runs/12612565960/job/35149436953?pr=3747 --- pyproject.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 2c5c1f04e7..71c486cfad 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -452,8 +452,10 @@ module = [ "ipykernel.*", "ibis.*", "vegafusion.*", + "scipy.*" ] ignore_missing_imports = true +disable_error_code = ["import-untyped"] [tool.pyright] enableExperimentalFeatures=true From 4944b80d2ed26be6831f28a00410314107c51ff9 Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Sat, 4 Jan 2025 18:57:51 +0000 Subject: [PATCH 07/26] docs: Add missing category --- tests/examples_arguments_syntax/deviation_ellipses.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/examples_arguments_syntax/deviation_ellipses.py b/tests/examples_arguments_syntax/deviation_ellipses.py index 59e9cd3407..93800c4060 100644 --- a/tests/examples_arguments_syntax/deviation_ellipses.py +++ b/tests/examples_arguments_syntax/deviation_ellipses.py @@ -2,10 +2,10 @@ """ Deviation ellipse ------------------------ +----------------- This example shows bivariate deviation ellipses of petal length and width of three iris species. """ - +# category: distributions from typing import Literal import numpy as np From 7cd2a775566891d5be861252ac0f87b351ac6351 Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Sat, 4 Jan 2025 19:02:05 +0000 Subject: [PATCH 08/26] fix: Add missing support for `from __future__ import annotations` Fixes https://github.com/vega/altair/actions/runs/12612637008/job/35149593128?pr=3747#step:6:25 --- sphinxext/utils.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/sphinxext/utils.py b/sphinxext/utils.py index 743cf09132..ee2ca85e0f 100644 --- a/sphinxext/utils.py +++ b/sphinxext/utils.py @@ -58,7 +58,7 @@ def create_generic_image( """ -def _parse_source_file(filename: str) -> tuple[ast.Module | None, str]: +def _parse_source_file(filename: str | Path) -> tuple[ast.Module | None, str]: """ Parse source file into AST node. @@ -88,7 +88,7 @@ def _parse_source_file(filename: str) -> tuple[ast.Module | None, str]: return node, content -def get_docstring_and_rest(filename: str) -> tuple[str, str | None, str, int]: +def get_docstring_and_rest(filename: str | Path) -> tuple[str, str | None, str, int]: # noqa: C901 """ Separate ``filename`` content between docstring and the rest. @@ -115,6 +115,7 @@ def get_docstring_and_rest(filename: str) -> tuple[str, str | None, str, int]: This function adapted from the sphinx-gallery project; license: BSD-3 https://github.com/sphinx-gallery/sphinx-gallery/ """ + FUTURE_STATEMENT = "from __future__ import annotations" node, content = _parse_source_file(filename) # Find the category comment @@ -157,10 +158,16 @@ def get_docstring_and_rest(filename: str) -> tuple[str, str | None, str, int]: except AttributeError: # this block can be removed when python 3.6 support is dropped + if ( + isinstance(node.body[0], ast.ImportFrom) + and node.body[0].module == "__future__" + ): + node.body.pop(0) + content = content.replace(FUTURE_STATEMENT, "").lstrip("\n") if ( node.body and isinstance(node.body[0], ast.Expr) - and isinstance(node.body[0].value, (ast.Str, ast.Constant)) + and isinstance(node.body[0].value, ast.Constant) ): docstring_node = node.body[0] docstring = docstring_node.value.s # pyright: ignore[reportAttributeAccessIssue] From be087d25cb46d3a0ea459ab5ee69c5b78add4d40 Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Sat, 4 Jan 2025 19:15:29 +0000 Subject: [PATCH 09/26] test: skip example when `scipy` not installed Temporary fix for https://github.com/vega/altair/actions/runs/12612997919/job/35150338097?pr=3747 --- tests/__init__.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/__init__.py b/tests/__init__.py index 617cfca80b..4cd8206316 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -95,6 +95,10 @@ def windows_has_tzdata() -> bool: https://github.com/vega/vegafusion """ +skip_requires_scipy: pytest.MarkDecorator = pytest.mark.skipif( + find_spec("scipy") is None, reason="`scipy` not installed." +) + def skip_requires_pyarrow( fn: Callable[..., Any] | None = None, /, *, requires_tzdata: bool = False @@ -229,6 +233,7 @@ def _distributed_examples( "wind_vector_map": slow, r"\.point_map\.py": slow, "line_chart_with_color_datum": slow, + "deviation_ellipses": skip_requires_scipy, }, ) ), From 16236295c36e9cc4f5883802a04688060cfedaa9 Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Sat, 4 Jan 2025 22:19:08 +0000 Subject: [PATCH 10/26] docs: reduce segments `100` -> `50` Observed no visible reduction in quality. Slightly visible at `<=40` --- tests/examples_arguments_syntax/deviation_ellipses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/examples_arguments_syntax/deviation_ellipses.py b/tests/examples_arguments_syntax/deviation_ellipses.py index 93800c4060..a4abdf73fe 100644 --- a/tests/examples_arguments_syntax/deviation_ellipses.py +++ b/tests/examples_arguments_syntax/deviation_ellipses.py @@ -20,7 +20,7 @@ def np_ellipse( arr: np.ndarray[tuple[int, int], np.dtype[np.float64]], conf_level: float = 0.95, method: Literal["deviation", "error"] = "deviation", - segments: int = 100, + segments: int = 50 ): """ Arguments: From a357668fc863a1f47a21025f4f0e1fb0720f8b54 Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Sat, 4 Jan 2025 22:32:13 +0000 Subject: [PATCH 11/26] docs: Clean up `numpy`, `scipy` docs/comments --- .../deviation_ellipses.py | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/tests/examples_arguments_syntax/deviation_ellipses.py b/tests/examples_arguments_syntax/deviation_ellipses.py index a4abdf73fe..742297f49c 100644 --- a/tests/examples_arguments_syntax/deviation_ellipses.py +++ b/tests/examples_arguments_syntax/deviation_ellipses.py @@ -10,7 +10,7 @@ import numpy as np import pandas as pd -from scipy.stats import f as ssf +from scipy.stats import f as F import altair as alt from vega_datasets import data @@ -20,24 +20,30 @@ def np_ellipse( arr: np.ndarray[tuple[int, int], np.dtype[np.float64]], conf_level: float = 0.95, method: Literal["deviation", "error"] = "deviation", - segments: int = 50 + segments: int = 50, ): """ - Arguments: - arr: 2D numpy array with 2 columns - level: confidence level - method: either 'deviation' (swarning data) or 'error (swarning the mean)' - segments: number of points describing the ellipse. - """ # noqa: D205 + Calculate confidence interval ellipse. + + Parameters + ---------- + arr + numpy array with 2 columns + conf_level + lower tail probability + method + either 'deviation' (swarning data) or 'error (swarning the mean)' + segments + number of points describing the ellipse. + """ n_elements = len(arr) - # TODO: - # - dfn? - # - dfd? - # - ssf.ppf? - # - Percent point function (inverse of `cdf`) at q of the given RV. + # Degrees of freedom of the chi-squared distribution in the **numerator** dfn = 2 + # Degrees of freedom of the chi-squared distribution in the **denominator** dfd = n_elements - 1 - deviation = np.sqrt(2 * ssf.ppf(conf_level, dfn=dfn, dfd=dfd)) + # Percent point function at `conf_level` of an F continuous random variable + quantile = F.ppf(conf_level, dfn=dfn, dfd=dfd) + deviation = np.sqrt(2 * quantile) if method == "deviation": radius = deviation elif method == "error": From ac34139848cbada90252b2623223ff40a39dbbaf Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Sat, 4 Jan 2025 22:56:32 +0000 Subject: [PATCH 12/26] refactor: Simplify `numpy` transforms --- tests/examples_arguments_syntax/deviation_ellipses.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/examples_arguments_syntax/deviation_ellipses.py b/tests/examples_arguments_syntax/deviation_ellipses.py index 742297f49c..7cb4ee4f49 100644 --- a/tests/examples_arguments_syntax/deviation_ellipses.py +++ b/tests/examples_arguments_syntax/deviation_ellipses.py @@ -52,12 +52,10 @@ def np_ellipse( msg = "Method should be either 'deviation' or 'error'." raise ValueError(msg) angles = (np.arange(0, segments + 1)) * 2 * np.pi / segments - circle = np.vstack((np.cos(angles), np.sin(angles))).T + circle = np.column_stack((np.cos(angles), np.sin(angles))) center = np.mean(arr, axis=0) - cov_mat = np.cov(arr.T) - # TODO: Figure out why so many transpositions - ellipse = center + (radius * np.dot(circle, np.linalg.cholesky(cov_mat).T).T).T - return ellipse + cov_mat = np.cov(arr, rowvar=False) + return center + radius * (circle @ np.linalg.cholesky(cov_mat).T) def pd_ellipse( From e0e276bcf8a36bafe3fcfe6cc89f13d7cd1b7186 Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Sat, 4 Jan 2025 23:09:04 +0000 Subject: [PATCH 13/26] docs: add tooltip, increase size --- tests/examples_arguments_syntax/deviation_ellipses.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/examples_arguments_syntax/deviation_ellipses.py b/tests/examples_arguments_syntax/deviation_ellipses.py index 7cb4ee4f49..cccfdbd82c 100644 --- a/tests/examples_arguments_syntax/deviation_ellipses.py +++ b/tests/examples_arguments_syntax/deviation_ellipses.py @@ -82,12 +82,12 @@ def pd_ellipse( source = data.iris() ellipse = pd_ellipse(source, col_x=col_x, col_y=col_y, col_group=col_group) -points = alt.Chart(source).mark_circle().encode(x, y, color) +points = alt.Chart(source).mark_circle(size=50, tooltip=True).encode(x, y, color) lines = ( alt.Chart(ellipse) .mark_line(filled=True, fillOpacity=0.2) .encode(x, y, color, order="index") ) -chart = lines + points +chart = (lines + points).properties(height=500, width=500) chart \ No newline at end of file From dc0ae5279711cbc7b1b3a7b719d6422f876e2aea Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Sun, 5 Jan 2025 14:28:24 +0000 Subject: [PATCH 14/26] fix: Remove incorrect range stop Previously returned `segments+1` rows, but this isn't specified in `ggplot2 https://github.com/tidyverse/ggplot2/blob/efc53cc000e7d86e3db22e1f43089d366fe24f2e/R/stat-ellipse.R#L122 --- tests/examples_arguments_syntax/deviation_ellipses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/examples_arguments_syntax/deviation_ellipses.py b/tests/examples_arguments_syntax/deviation_ellipses.py index cccfdbd82c..9d446f5366 100644 --- a/tests/examples_arguments_syntax/deviation_ellipses.py +++ b/tests/examples_arguments_syntax/deviation_ellipses.py @@ -51,7 +51,7 @@ def np_ellipse( else: msg = "Method should be either 'deviation' or 'error'." raise ValueError(msg) - angles = (np.arange(0, segments + 1)) * 2 * np.pi / segments + angles = np.arange(0, segments) * 2 * np.pi / segments circle = np.column_stack((np.cos(angles), np.sin(angles))) center = np.mean(arr, axis=0) cov_mat = np.cov(arr, rowvar=False) From 4969a98078ec68aece5add1febec005b4ea1838d Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Sun, 5 Jan 2025 16:50:46 +0000 Subject: [PATCH 15/26] refactor: Remove special casing `__future__` import I forgot that the only requirement was that the import is the **first statement**. Partially reverts (https://github.com/vega/altair/pull/3747/commits/7cd2a775566891d5be861252ac0f87b351ac6351) --- sphinxext/utils.py | 9 +-------- tests/examples_arguments_syntax/deviation_ellipses.py | 5 +++-- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/sphinxext/utils.py b/sphinxext/utils.py index ee2ca85e0f..5f59f0d81e 100644 --- a/sphinxext/utils.py +++ b/sphinxext/utils.py @@ -88,7 +88,7 @@ def _parse_source_file(filename: str | Path) -> tuple[ast.Module | None, str]: return node, content -def get_docstring_and_rest(filename: str | Path) -> tuple[str, str | None, str, int]: # noqa: C901 +def get_docstring_and_rest(filename: str | Path) -> tuple[str, str | None, str, int]: """ Separate ``filename`` content between docstring and the rest. @@ -115,7 +115,6 @@ def get_docstring_and_rest(filename: str | Path) -> tuple[str, str | None, str, This function adapted from the sphinx-gallery project; license: BSD-3 https://github.com/sphinx-gallery/sphinx-gallery/ """ - FUTURE_STATEMENT = "from __future__ import annotations" node, content = _parse_source_file(filename) # Find the category comment @@ -158,12 +157,6 @@ def get_docstring_and_rest(filename: str | Path) -> tuple[str, str | None, str, except AttributeError: # this block can be removed when python 3.6 support is dropped - if ( - isinstance(node.body[0], ast.ImportFrom) - and node.body[0].module == "__future__" - ): - node.body.pop(0) - content = content.replace(FUTURE_STATEMENT, "").lstrip("\n") if ( node.body and isinstance(node.body[0], ast.Expr) diff --git a/tests/examples_arguments_syntax/deviation_ellipses.py b/tests/examples_arguments_syntax/deviation_ellipses.py index 9d446f5366..5971ef9eb8 100644 --- a/tests/examples_arguments_syntax/deviation_ellipses.py +++ b/tests/examples_arguments_syntax/deviation_ellipses.py @@ -1,11 +1,12 @@ -from __future__ import annotations - """ Deviation ellipse ----------------- This example shows bivariate deviation ellipses of petal length and width of three iris species. """ + # category: distributions +from __future__ import annotations + from typing import Literal import numpy as np From dcb9fa565adb28a06938a3d8fe6be9810d90ffb3 Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Sun, 5 Jan 2025 16:58:04 +0000 Subject: [PATCH 16/26] docs: Remove unused `method` code Also resolves https://github.com/vega/altair/pull/3747#discussion_r1903159487 --- .../deviation_ellipses.py | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/tests/examples_arguments_syntax/deviation_ellipses.py b/tests/examples_arguments_syntax/deviation_ellipses.py index 5971ef9eb8..dffc84f75d 100644 --- a/tests/examples_arguments_syntax/deviation_ellipses.py +++ b/tests/examples_arguments_syntax/deviation_ellipses.py @@ -7,8 +7,6 @@ # category: distributions from __future__ import annotations -from typing import Literal - import numpy as np import pandas as pd from scipy.stats import f as F @@ -20,7 +18,6 @@ def np_ellipse( arr: np.ndarray[tuple[int, int], np.dtype[np.float64]], conf_level: float = 0.95, - method: Literal["deviation", "error"] = "deviation", segments: int = 50, ): """ @@ -32,8 +29,6 @@ def np_ellipse( numpy array with 2 columns conf_level lower tail probability - method - either 'deviation' (swarning data) or 'error (swarning the mean)' segments number of points describing the ellipse. """ @@ -44,14 +39,7 @@ def np_ellipse( dfd = n_elements - 1 # Percent point function at `conf_level` of an F continuous random variable quantile = F.ppf(conf_level, dfn=dfn, dfd=dfd) - deviation = np.sqrt(2 * quantile) - if method == "deviation": - radius = deviation - elif method == "error": - radius = deviation / np.sqrt(n_elements) - else: - msg = "Method should be either 'deviation' or 'error'." - raise ValueError(msg) + radius = np.sqrt(2 * quantile) angles = np.arange(0, segments) * 2 * np.pi / segments circle = np.column_stack((np.cos(angles), np.sin(angles))) center = np.mean(arr, axis=0) @@ -91,4 +79,4 @@ def pd_ellipse( ) chart = (lines + points).properties(height=500, width=500) -chart \ No newline at end of file +chart From bd4e30f42dfafe35c79e16698832e13bb65f5899 Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Sun, 5 Jan 2025 17:18:46 +0000 Subject: [PATCH 17/26] docs: rename to 'Confidence Interval Ellipses' --- tests/examples_arguments_syntax/deviation_ellipses.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/examples_arguments_syntax/deviation_ellipses.py b/tests/examples_arguments_syntax/deviation_ellipses.py index dffc84f75d..e40bb3e509 100644 --- a/tests/examples_arguments_syntax/deviation_ellipses.py +++ b/tests/examples_arguments_syntax/deviation_ellipses.py @@ -1,6 +1,6 @@ """ -Deviation ellipse ------------------ +Confidence Interval Ellipses +---------------------------- This example shows bivariate deviation ellipses of petal length and width of three iris species. """ From 62927af736569f7ad906a5106a976ce110c86983 Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Sun, 5 Jan 2025 17:20:15 +0000 Subject: [PATCH 18/26] docs: add references to description --- tests/examples_arguments_syntax/deviation_ellipses.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/examples_arguments_syntax/deviation_ellipses.py b/tests/examples_arguments_syntax/deviation_ellipses.py index e40bb3e509..38db880042 100644 --- a/tests/examples_arguments_syntax/deviation_ellipses.py +++ b/tests/examples_arguments_syntax/deviation_ellipses.py @@ -2,6 +2,15 @@ Confidence Interval Ellipses ---------------------------- This example shows bivariate deviation ellipses of petal length and width of three iris species. + +Inspired by `ggplot2.stat_ellipse`_ and directly based on `Deviation ellipses example`_ by `@essicolo`_ + +.. _ggplot2.stat_ellipse: + https://ggplot2.tidyverse.org/reference/stat_ellipse.html#ref-examples +.. _Deviation ellipses example: + https://github.com/vega/altair/pull/514 +.. _@essicolo: + https://github.com/essicolo """ # category: distributions From 182baeaf459e4792ba4d6a7986aa5595c3c8d020 Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Fri, 10 Jan 2025 14:35:11 +0000 Subject: [PATCH 19/26] docs: Adds methods syntax version Includes comment removal suggestion in (https://github.com/vega/altair/pull/3747#discussion_r1904633378) --- .../deviation_ellipses.py | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 tests/examples_methods_syntax/deviation_ellipses.py diff --git a/tests/examples_methods_syntax/deviation_ellipses.py b/tests/examples_methods_syntax/deviation_ellipses.py new file mode 100644 index 0000000000..b7e98d200f --- /dev/null +++ b/tests/examples_methods_syntax/deviation_ellipses.py @@ -0,0 +1,90 @@ +""" +Confidence Interval Ellipses +---------------------------- +This example shows bivariate deviation ellipses of petal length and width of three iris species. + +Inspired by `ggplot2.stat_ellipse`_ and directly based on `Deviation ellipses example`_ by `@essicolo`_ + +.. _ggplot2.stat_ellipse: + https://ggplot2.tidyverse.org/reference/stat_ellipse.html#ref-examples +.. _Deviation ellipses example: + https://github.com/vega/altair/pull/514 +.. _@essicolo: + https://github.com/essicolo +""" + +# category: distributions +from __future__ import annotations + +import numpy as np +import pandas as pd +from scipy.stats import f as F + +import altair as alt +from vega_datasets import data + + +def np_ellipse( + arr: np.ndarray[tuple[int, int], np.dtype[np.float64]], + conf_level: float = 0.95, + segments: int = 50, +): + """ + Calculate confidence interval ellipse. + + Parameters + ---------- + arr + numpy array with 2 columns + conf_level + lower tail probability + segments + number of points describing the ellipse. + """ + n_elements = len(arr) + # Degrees of freedom of the chi-squared distribution in the **numerator** + dfn = 2 + # Degrees of freedom of the chi-squared distribution in the **denominator** + dfd = n_elements - 1 + # Percent point function at `conf_level` of an F continuous random variable + quantile = F.ppf(conf_level, dfn=dfn, dfd=dfd) + radius = np.sqrt(2 * quantile) + angles = np.arange(0, segments) * 2 * np.pi / segments + circle = np.column_stack((np.cos(angles), np.sin(angles))) + center = np.mean(arr, axis=0) + cov_mat = np.cov(arr, rowvar=False) + return center + radius * (circle @ np.linalg.cholesky(cov_mat).T) + + +def pd_ellipse( + df: pd.DataFrame, col_x: str, col_y: str, col_group: str +) -> pd.DataFrame: + cols = col_x, col_y + groups = [] + categories = df[col_group].unique() + for category in categories: + sliced = df.loc[df[col_group] == category, cols] + ell_df = pd.DataFrame(np_ellipse(sliced.to_numpy()), columns=cols) # type: ignore + ell_df[col_group] = category + groups.append(ell_df) + return pd.concat(groups).reset_index() + + +col_x = "petalLength" +col_y = "petalWidth" +col_group = "species" +x = alt.X(col_x).scale(zero=False) +y = alt.Y(col_y).scale(zero=False) +color = alt.Color(col_group) + +source = data.iris() +ellipse = pd_ellipse(source, col_x=col_x, col_y=col_y, col_group=col_group) +points = alt.Chart(source).mark_circle(size=50, tooltip=True).encode(x, y, color) +lines = ( + alt.Chart(ellipse) + .mark_line(filled=True, fillOpacity=0.2) + .encode(x, y, color, order="index") +) + +chart = (lines + points).properties(height=500, width=500) +chart From fa280f1fc8d71a6e12fa891ab1d0907143075866 Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Fri, 10 Jan 2025 16:37:33 +0000 Subject: [PATCH 20/26] refactor: Rewrite `pd_ellipse` - Fixed a type ignore (causes by incomplete stubs) - Renamed variables - Make replace the implicit `"index"` column with naming it `"order"` https://github.com/vega/altair/pull/3747#discussion_r1903144682 --- .../deviation_ellipses.py | 21 +++++++++---------- .../deviation_ellipses.py | 20 +++++++++--------- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/tests/examples_arguments_syntax/deviation_ellipses.py b/tests/examples_arguments_syntax/deviation_ellipses.py index 38db880042..a6257a072f 100644 --- a/tests/examples_arguments_syntax/deviation_ellipses.py +++ b/tests/examples_arguments_syntax/deviation_ellipses.py @@ -59,16 +59,15 @@ def np_ellipse( def pd_ellipse( df: pd.DataFrame, col_x: str, col_y: str, col_group: str ) -> pd.DataFrame: - cols = col_x, col_y - groups = [] - # TODO: Rewrite in a more readable way - categories = df[col_group].unique() - for category in categories: - sliced = df.loc[df[col_group] == category, cols] - ell_df = pd.DataFrame(np_ellipse(sliced.to_numpy()), columns=cols) # type: ignore - ell_df[col_group] = category - groups.append(ell_df) - return pd.concat(groups).reset_index() + cols = [col_x, col_y] + ellipses = [] + ser: pd.Series[float] = df[col_group] + for group in ser.drop_duplicates(): + arr = df.loc[ser == group, cols].to_numpy() + ellipse = pd.DataFrame(np_ellipse(arr), columns=cols) + ellipse[col_group] = group + ellipses.append(ellipse) + return pd.concat(ellipses).reset_index(names="order") col_x = "petalLength" @@ -84,7 +83,7 @@ def pd_ellipse( lines = ( alt.Chart(ellipse) .mark_line(filled=True, fillOpacity=0.2) - .encode(x, y, color, order="index") + .encode(x, y, color, order="order") ) chart = (lines + points).properties(height=500, width=500) diff --git a/tests/examples_methods_syntax/deviation_ellipses.py b/tests/examples_methods_syntax/deviation_ellipses.py index b7e98d200f..36e7b4097b 100644 --- a/tests/examples_methods_syntax/deviation_ellipses.py +++ b/tests/examples_methods_syntax/deviation_ellipses.py @@ -59,15 +59,15 @@ def np_ellipse( def pd_ellipse( df: pd.DataFrame, col_x: str, col_y: str, col_group: str ) -> pd.DataFrame: - cols = col_x, col_y - groups = [] - categories = df[col_group].unique() - for category in categories: - sliced = df.loc[df[col_group] == category, cols] - ell_df = pd.DataFrame(np_ellipse(sliced.to_numpy()), columns=cols) # type: ignore - ell_df[col_group] = category - groups.append(ell_df) - return pd.concat(groups).reset_index() + cols = [col_x, col_y] + ellipses = [] + ser: pd.Series[float] = df[col_group] + for group in ser.drop_duplicates(): + arr = df.loc[ser == group, cols].to_numpy() + ellipse = pd.DataFrame(np_ellipse(arr), columns=cols) + ellipse[col_group] = group + ellipses.append(ellipse) + return pd.concat(ellipses).reset_index(names="order") col_x = "petalLength" @@ -83,7 +83,7 @@ def pd_ellipse( lines = ( alt.Chart(ellipse) .mark_line(filled=True, fillOpacity=0.2) - .encode(x, y, color, order="index") + .encode(x, y, color, order="order") ) chart = (lines + points).properties(height=500, width=500) From f72da5af7de83a4cef719f943148fe699e2b3b69 Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Fri, 17 Jan 2025 13:07:16 +0000 Subject: [PATCH 21/26] ci(uv): sync `scipy-stubs` https://github.com/vega/altair/pull/3747/commits/dc7639d4a41baf3a476403238c1d970927ba352f https://github.com/vega/altair/pull/3747/commits/a296b8248d7375069eb8e9c680778c8abe2ccddb --- uv.lock | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/uv.lock b/uv.lock index d6a2a3a935..6ca37e0b08 100644 --- a/uv.lock +++ b/uv.lock @@ -101,6 +101,7 @@ doc = [ { name = "pydata-sphinx-theme" }, { name = "scipy", version = "1.13.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, { name = "scipy", version = "1.15.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "scipy-stubs", marker = "python_full_version >= '3.10'" }, { name = "sphinx", version = "7.4.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, { name = "sphinx-copybutton" }, @@ -143,6 +144,7 @@ requires-dist = [ { name = "pytest-xdist", extras = ["psutil"], marker = "extra == 'dev'", specifier = "~=3.5" }, { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.8.4" }, { name = "scipy", marker = "extra == 'doc'" }, + { name = "scipy-stubs", marker = "python_full_version >= '3.10' and extra == 'doc'" }, { name = "sphinx", marker = "extra == 'doc'" }, { name = "sphinx-copybutton", marker = "extra == 'doc'" }, { name = "sphinx-design", marker = "extra == 'doc'" }, @@ -1583,6 +1585,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6c/45/56d99ba9366476cd8548527667f01869279cedb9e66b28eb4dfb27701679/numpydoc-1.8.0-py3-none-any.whl", hash = "sha256:72024c7fd5e17375dec3608a27c03303e8ad00c81292667955c6fea7a3ccf541", size = 64003 }, ] +[[package]] +name = "optype" +version = "0.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version >= '3.10' and python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/89/42/543e02c72aba7ebe78adb76bbfbed1bc1314eba633ad453984948e5a5f46/optype-0.8.0.tar.gz", hash = "sha256:8cbfd452d6f06c7c70502048f38a0d5451bc601054d3a577dd09c7d6363950e1", size = 85295 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/86/ff/604be975eb0e9fd02358cdacf496f4411db97bffc27279ce260e8f50aba4/optype-0.8.0-py3-none-any.whl", hash = "sha256:90a7760177f2e7feae379a60445fceec37b932b75a00c3d96067497573c5e84d", size = 74228 }, +] + [[package]] name = "packaging" version = "24.2" @@ -2627,6 +2641,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e4/1f/5d46a8d94e9f6d2c913cbb109e57e7eed914de38ea99e2c4d69a9fc93140/scipy-1.15.1-cp313-cp313t-win_amd64.whl", hash = "sha256:bc7136626261ac1ed988dca56cfc4ab5180f75e0ee52e58f1e6aa74b5f3eacd5", size = 43181730 }, ] +[[package]] +name = "scipy-stubs" +version = "1.15.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "optype", marker = "python_full_version >= '3.10'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a7/89/a809e2240f679d75cdee1a4b58b8b52caa1c5e2bf2e703cf9d6c16fc9fe0/scipy_stubs-1.15.1.0.tar.gz", hash = "sha256:25756486635594025ed3249b6fb659c29dc5874c7b55565ad248b13a4ff4fa1c", size = 270415 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/71/1f/f1db21491a40923251244ee8de4f71ce95dee2ed83c2b49ad479c2ea5189/scipy_stubs-1.15.1.0-py3-none-any.whl", hash = "sha256:f6e8f8dfd2aaa343705c46ac1fdc69556ea8a0a9b0645cb3af4dd652665a452f", size = 454057 }, +] + [[package]] name = "secretstorage" version = "3.3.3" From 3debf11b68577a76e7a95321cbab90b3ecffc6c1 Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Fri, 17 Jan 2025 13:32:03 +0000 Subject: [PATCH 22/26] refactor(typing): Try removing `from __future__ import annotations` https://github.com/vega/altair/pull/3747#issuecomment-2596884190, https://github.com/vega/altair/pull/3747#issuecomment-2597901908 --- tests/examples_arguments_syntax/deviation_ellipses.py | 2 -- tests/examples_methods_syntax/deviation_ellipses.py | 2 -- 2 files changed, 4 deletions(-) diff --git a/tests/examples_arguments_syntax/deviation_ellipses.py b/tests/examples_arguments_syntax/deviation_ellipses.py index a6257a072f..1f4c7c47b5 100644 --- a/tests/examples_arguments_syntax/deviation_ellipses.py +++ b/tests/examples_arguments_syntax/deviation_ellipses.py @@ -14,8 +14,6 @@ """ # category: distributions -from __future__ import annotations - import numpy as np import pandas as pd from scipy.stats import f as F diff --git a/tests/examples_methods_syntax/deviation_ellipses.py b/tests/examples_methods_syntax/deviation_ellipses.py index 36e7b4097b..21af602d98 100644 --- a/tests/examples_methods_syntax/deviation_ellipses.py +++ b/tests/examples_methods_syntax/deviation_ellipses.py @@ -14,8 +14,6 @@ """ # category: distributions -from __future__ import annotations - import numpy as np import pandas as pd from scipy.stats import f as F From e6c9c5f637b21beff2e4352493d84bad35444fc0 Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Fri, 17 Jan 2025 13:47:15 +0000 Subject: [PATCH 23/26] refactor: rename `np_ellipse` -> `confidence_region_2d` https://github.com/vega/altair/pull/3747#issuecomment-2596884190 --- tests/examples_arguments_syntax/deviation_ellipses.py | 4 ++-- tests/examples_methods_syntax/deviation_ellipses.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/examples_arguments_syntax/deviation_ellipses.py b/tests/examples_arguments_syntax/deviation_ellipses.py index 1f4c7c47b5..6c6e08f817 100644 --- a/tests/examples_arguments_syntax/deviation_ellipses.py +++ b/tests/examples_arguments_syntax/deviation_ellipses.py @@ -22,7 +22,7 @@ from vega_datasets import data -def np_ellipse( +def confidence_region_2d( arr: np.ndarray[tuple[int, int], np.dtype[np.float64]], conf_level: float = 0.95, segments: int = 50, @@ -62,7 +62,7 @@ def pd_ellipse( ser: pd.Series[float] = df[col_group] for group in ser.drop_duplicates(): arr = df.loc[ser == group, cols].to_numpy() - ellipse = pd.DataFrame(np_ellipse(arr), columns=cols) + ellipse = pd.DataFrame(confidence_region_2d(arr), columns=cols) ellipse[col_group] = group ellipses.append(ellipse) return pd.concat(ellipses).reset_index(names="order") diff --git a/tests/examples_methods_syntax/deviation_ellipses.py b/tests/examples_methods_syntax/deviation_ellipses.py index 21af602d98..1b20a6fb6c 100644 --- a/tests/examples_methods_syntax/deviation_ellipses.py +++ b/tests/examples_methods_syntax/deviation_ellipses.py @@ -22,7 +22,7 @@ from vega_datasets import data -def np_ellipse( +def confidence_region_2d( arr: np.ndarray[tuple[int, int], np.dtype[np.float64]], conf_level: float = 0.95, segments: int = 50, @@ -62,7 +62,7 @@ def pd_ellipse( ser: pd.Series[float] = df[col_group] for group in ser.drop_duplicates(): arr = df.loc[ser == group, cols].to_numpy() - ellipse = pd.DataFrame(np_ellipse(arr), columns=cols) + ellipse = pd.DataFrame(confidence_region_2d(arr), columns=cols) ellipse[col_group] = group ellipses.append(ellipse) return pd.concat(ellipses).reset_index(names="order") From 7401a08c080f444d067cac1abc24a6ea5b1c0f90 Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Fri, 17 Jan 2025 13:49:40 +0000 Subject: [PATCH 24/26] refactor: rename `pd_ellipse` -> `grouped_confidence_regions` https://github.com/vega/altair/pull/3747#issuecomment-2596884190 --- tests/examples_arguments_syntax/deviation_ellipses.py | 4 ++-- tests/examples_methods_syntax/deviation_ellipses.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/examples_arguments_syntax/deviation_ellipses.py b/tests/examples_arguments_syntax/deviation_ellipses.py index 6c6e08f817..d631aa826a 100644 --- a/tests/examples_arguments_syntax/deviation_ellipses.py +++ b/tests/examples_arguments_syntax/deviation_ellipses.py @@ -54,7 +54,7 @@ def confidence_region_2d( return center + radius * (circle @ np.linalg.cholesky(cov_mat).T) -def pd_ellipse( +def grouped_confidence_regions( df: pd.DataFrame, col_x: str, col_y: str, col_group: str ) -> pd.DataFrame: cols = [col_x, col_y] @@ -76,7 +76,7 @@ def pd_ellipse( color = alt.Color(col_group) source = data.iris() -ellipse = pd_ellipse(source, col_x=col_x, col_y=col_y, col_group=col_group) +ellipse = grouped_confidence_regions(source, col_x=col_x, col_y=col_y, col_group=col_group) points = alt.Chart(source).mark_circle(size=50, tooltip=True).encode(x, y, color) lines = ( alt.Chart(ellipse) diff --git a/tests/examples_methods_syntax/deviation_ellipses.py b/tests/examples_methods_syntax/deviation_ellipses.py index 1b20a6fb6c..94d042c3e7 100644 --- a/tests/examples_methods_syntax/deviation_ellipses.py +++ b/tests/examples_methods_syntax/deviation_ellipses.py @@ -54,7 +54,7 @@ def confidence_region_2d( return center + radius * (circle @ np.linalg.cholesky(cov_mat).T) -def pd_ellipse( +def grouped_confidence_regions( df: pd.DataFrame, col_x: str, col_y: str, col_group: str ) -> pd.DataFrame: cols = [col_x, col_y] @@ -76,7 +76,7 @@ def pd_ellipse( color = alt.Color(col_group) source = data.iris() -ellipse = pd_ellipse(source, col_x=col_x, col_y=col_y, col_group=col_group) +ellipse = grouped_confidence_regions(source, col_x=col_x, col_y=col_y, col_group=col_group) points = alt.Chart(source).mark_circle(size=50, tooltip=True).encode(x, y, color) lines = ( alt.Chart(ellipse) From 66c4f81004b50d2b3861866f4a9536e492d9ca0c Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Fri, 17 Jan 2025 13:51:06 +0000 Subject: [PATCH 25/26] docs: change category to `"case studies"` https://github.com/vega/altair/pull/3747#issuecomment-2596884190 --- tests/examples_arguments_syntax/deviation_ellipses.py | 2 +- tests/examples_methods_syntax/deviation_ellipses.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/examples_arguments_syntax/deviation_ellipses.py b/tests/examples_arguments_syntax/deviation_ellipses.py index d631aa826a..87594e45fc 100644 --- a/tests/examples_arguments_syntax/deviation_ellipses.py +++ b/tests/examples_arguments_syntax/deviation_ellipses.py @@ -13,7 +13,7 @@ https://github.com/essicolo """ -# category: distributions +# category: case studies import numpy as np import pandas as pd from scipy.stats import f as F diff --git a/tests/examples_methods_syntax/deviation_ellipses.py b/tests/examples_methods_syntax/deviation_ellipses.py index 94d042c3e7..ba98d971f4 100644 --- a/tests/examples_methods_syntax/deviation_ellipses.py +++ b/tests/examples_methods_syntax/deviation_ellipses.py @@ -13,7 +13,7 @@ https://github.com/essicolo """ -# category: distributions +# category: case studies import numpy as np import pandas as pd from scipy.stats import f as F From 1d01fa047638d879c0c93c1d8023a8e547824945 Mon Sep 17 00:00:00 2001 From: Mattijn van Hoek Date: Sat, 18 Jan 2025 12:50:25 +0100 Subject: [PATCH 26/26] styling --- .../deviation_ellipses.py | 26 +++++++++---------- .../deviation_ellipses.py | 26 +++++++++---------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/tests/examples_arguments_syntax/deviation_ellipses.py b/tests/examples_arguments_syntax/deviation_ellipses.py index 87594e45fc..0cc45d3171 100644 --- a/tests/examples_arguments_syntax/deviation_ellipses.py +++ b/tests/examples_arguments_syntax/deviation_ellipses.py @@ -22,11 +22,7 @@ from vega_datasets import data -def confidence_region_2d( - arr: np.ndarray[tuple[int, int], np.dtype[np.float64]], - conf_level: float = 0.95, - segments: int = 50, -): +def confidence_region_2d(arr, conf_level=0.95, segments=50): """ Calculate confidence interval ellipse. @@ -54,9 +50,7 @@ def confidence_region_2d( return center + radius * (circle @ np.linalg.cholesky(cov_mat).T) -def grouped_confidence_regions( - df: pd.DataFrame, col_x: str, col_y: str, col_group: str -) -> pd.DataFrame: +def grouped_confidence_regions(df, col_x, col_y, col_group): cols = [col_x, col_y] ellipses = [] ser: pd.Series[float] = df[col_group] @@ -71,17 +65,23 @@ def grouped_confidence_regions( col_x = "petalLength" col_y = "petalWidth" col_group = "species" + x = alt.X(col_x, scale=alt.Scale(zero=False)) y = alt.Y(col_y, scale=alt.Scale(zero=False)) color = alt.Color(col_group) source = data.iris() ellipse = grouped_confidence_regions(source, col_x=col_x, col_y=col_y, col_group=col_group) -points = alt.Chart(source).mark_circle(size=50, tooltip=True).encode(x, y, color) -lines = ( - alt.Chart(ellipse) - .mark_line(filled=True, fillOpacity=0.2) - .encode(x, y, color, order="order") +points = alt.Chart(source).mark_circle(size=50, tooltip=True).encode( + x=x, + y=y, + color=color +) +lines = alt.Chart(ellipse).mark_line(filled=True, fillOpacity=0.2).encode( + x=x, + y=y, + color=color, + order="order" ) chart = (lines + points).properties(height=500, width=500) diff --git a/tests/examples_methods_syntax/deviation_ellipses.py b/tests/examples_methods_syntax/deviation_ellipses.py index ba98d971f4..e33af72038 100644 --- a/tests/examples_methods_syntax/deviation_ellipses.py +++ b/tests/examples_methods_syntax/deviation_ellipses.py @@ -22,11 +22,7 @@ from vega_datasets import data -def confidence_region_2d( - arr: np.ndarray[tuple[int, int], np.dtype[np.float64]], - conf_level: float = 0.95, - segments: int = 50, -): +def confidence_region_2d(arr, conf_level=0.95, segments=50): """ Calculate confidence interval ellipse. @@ -54,9 +50,7 @@ def confidence_region_2d( return center + radius * (circle @ np.linalg.cholesky(cov_mat).T) -def grouped_confidence_regions( - df: pd.DataFrame, col_x: str, col_y: str, col_group: str -) -> pd.DataFrame: +def grouped_confidence_regions(df, col_x, col_y, col_group): cols = [col_x, col_y] ellipses = [] ser: pd.Series[float] = df[col_group] @@ -71,17 +65,23 @@ def grouped_confidence_regions( col_x = "petalLength" col_y = "petalWidth" col_group = "species" + x = alt.X(col_x).scale(zero=False) y = alt.Y(col_y).scale(zero=False) color = alt.Color(col_group) source = data.iris() ellipse = grouped_confidence_regions(source, col_x=col_x, col_y=col_y, col_group=col_group) -points = alt.Chart(source).mark_circle(size=50, tooltip=True).encode(x, y, color) -lines = ( - alt.Chart(ellipse) - .mark_line(filled=True, fillOpacity=0.2) - .encode(x, y, color, order="order") +points = alt.Chart(source).mark_circle(size=50, tooltip=True).encode( + x=x, + y=y, + color=color +) +lines = alt.Chart(ellipse).mark_line(filled=True, fillOpacity=0.2).encode( + x=x, + y=y, + color=color, + order="order" ) chart = (lines + points).properties(height=500, width=500)