From f512de6b9493757f3a9c873f7459244185135791 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Fri, 8 Nov 2024 19:35:40 +0800 Subject: [PATCH 01/12] Initial design of Figure.scatter --- pygmt/figure.py | 1 + pygmt/src/__init__.py | 1 + pygmt/src/scatter.py | 48 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100644 pygmt/src/scatter.py diff --git a/pygmt/figure.py b/pygmt/figure.py index 4163ab52eb1..93ec4c5385f 100644 --- a/pygmt/figure.py +++ b/pygmt/figure.py @@ -418,6 +418,7 @@ def _repr_html_(self): plot3d, psconvert, rose, + scatter, set_panel, shift_origin, solar, diff --git a/pygmt/src/__init__.py b/pygmt/src/__init__.py index e4db7321963..aad5f67cd83 100644 --- a/pygmt/src/__init__.py +++ b/pygmt/src/__init__.py @@ -42,6 +42,7 @@ from pygmt.src.project import project from pygmt.src.psconvert import psconvert from pygmt.src.rose import rose +from pygmt.src.scatter import scatter from pygmt.src.select import select from pygmt.src.shift_origin import shift_origin from pygmt.src.solar import solar diff --git a/pygmt/src/scatter.py b/pygmt/src/scatter.py new file mode 100644 index 00000000000..9d3fa631e64 --- /dev/null +++ b/pygmt/src/scatter.py @@ -0,0 +1,48 @@ +""" +scatter - Scatter plot. +""" + +from pygmt.helpers import is_nonstr_iter + + +def _parse_symbol_size(symbol, size): + """ + Parse the symbol and size into a style string. + + >>> _parse_symbol_size("c", 0.2) + 'c0.2' + >>> _parse_symbol_size("c", "0.2c") + 'c0.2c' + >>> _parse_symbol_size("c", [0.2, 0.3]) + 'c' + >>> _parse_symbol_size(["c", "t"], "0.2c") + '0.2c' + >>> _parse_symbol_size(["c", "t"], [0.2, 0.3]) + '' + """ + return "".join(f"{arg}" for arg in [symbol, size] if not is_nonstr_iter(arg)) + + +def scatter(self, x, y, symbol, size, **kwargs): + """ + Plot scatter points on a map. + + Parameters + ---------- + x, y : array-like + The coordinates of the points to plot. + symbol : str or sequence + The symbol to use for the points. + size : float or sequence + The size of the points. + """ + kwargs = self._preprocess(**kwargs) + + # style is a combination of symbol and size, but only if they are string-like + style = _parse_symbol_size(symbol, size) + if not is_nonstr_iter(symbol): + symbol = None + if not is_nonstr_iter(size): + size = None + + self.plot(x=x, y=y, style=style, symbol=symbol, size=size, **kwargs) From 8bd2777d7343716fa09bc1bb3f9230291bbe36f9 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Mon, 11 Nov 2024 13:05:28 +0800 Subject: [PATCH 02/12] Improve docstrings for symbol --- pygmt/src/scatter.py | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/pygmt/src/scatter.py b/pygmt/src/scatter.py index 9d3fa631e64..ec155041c88 100644 --- a/pygmt/src/scatter.py +++ b/pygmt/src/scatter.py @@ -2,6 +2,8 @@ scatter - Scatter plot. """ +from collections.abc import Sequence + from pygmt.helpers import is_nonstr_iter @@ -23,7 +25,14 @@ def _parse_symbol_size(symbol, size): return "".join(f"{arg}" for arg in [symbol, size] if not is_nonstr_iter(arg)) -def scatter(self, x, y, symbol, size, **kwargs): +def scatter( + self, + x, + y, + symbol: str | Sequence[str], + size: float | str | Sequence[float, str], + **kwargs, +): """ Plot scatter points on a map. @@ -31,9 +40,25 @@ def scatter(self, x, y, symbol, size, **kwargs): ---------- x, y : array-like The coordinates of the points to plot. - symbol : str or sequence - The symbol to use for the points. - size : float or sequence + symbol + Symbol to use for the points. Can be a single symbol or a sequence of symbols. + Valid symbols are: + + - ``-``: X-dash (-) + - ``+``: Plus + - ``a``: Star + - ``c``: Circle + - ``d``: Diamond + - ``g``: Octagon + - ``h``: Hexagon + - ``i``: Inverted triangle + - ``n``: Pentagon + - ``p``: Point + - ``s``: Square + - ``t``: Triangle + - ``x``: Cross + - ``y``: Y-dash (|) + size The size of the points. """ kwargs = self._preprocess(**kwargs) From 96c7ed117e1b309c4b9d8c0c664281397396f9df Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Mon, 11 Nov 2024 18:04:59 +0800 Subject: [PATCH 03/12] Fix a typo --- pygmt/src/scatter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/src/scatter.py b/pygmt/src/scatter.py index ec155041c88..53bb795b86f 100644 --- a/pygmt/src/scatter.py +++ b/pygmt/src/scatter.py @@ -30,7 +30,7 @@ def scatter( x, y, symbol: str | Sequence[str], - size: float | str | Sequence[float, str], + size: float | str | Sequence[float | str], **kwargs, ): """ From 5ca92f7a04a7f4bb77a94a805871acf4779aa6a3 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Mon, 11 Nov 2024 18:13:18 +0800 Subject: [PATCH 04/12] Add more parameters --- pygmt/src/scatter.py | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/pygmt/src/scatter.py b/pygmt/src/scatter.py index 53bb795b86f..219d4c0947a 100644 --- a/pygmt/src/scatter.py +++ b/pygmt/src/scatter.py @@ -25,17 +25,25 @@ def _parse_symbol_size(symbol, size): return "".join(f"{arg}" for arg in [symbol, size] if not is_nonstr_iter(arg)) -def scatter( +def scatter( # noqa: PLR0913 self, x, y, symbol: str | Sequence[str], size: float | str | Sequence[float | str], - **kwargs, + fill: str | Sequence[float] | None = None, + intensity: float | Sequence[float] | None = None, + transparency: float | Sequence[float] | None = None, + cmap: str | None = None, + no_clip: bool = False, + perspective=None, ): """ Plot scatter points on a map. + This function can plot points with different symbols, sizes, and colors. + + Parameters ---------- x, y : array-like @@ -60,8 +68,18 @@ def scatter( - ``y``: Y-dash (|) size The size of the points. + intensity + The intensity of the points. + transparency + The transparency of the points. + cmap + The colormap to use for the points. + no_clip + If True, do not clip the points to the viewport. + perspective + The perspective of the points. """ - kwargs = self._preprocess(**kwargs) + self._preprocess() # style is a combination of symbol and size, but only if they are string-like style = _parse_symbol_size(symbol, size) @@ -70,4 +88,16 @@ def scatter( if not is_nonstr_iter(size): size = None - self.plot(x=x, y=y, style=style, symbol=symbol, size=size, **kwargs) + self.plot( + x=x, + y=y, + style=style, + symbol=symbol, + size=size, + fill=fill, + intensity=intensity, + transparency=transparency, + cmap=cmap, + no_clip=no_clip, + perspective=perspective, + ) From 20254f6d47bcc4f70d15c0dcf06d323360aa9011 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Mon, 11 Nov 2024 18:15:19 +0800 Subject: [PATCH 05/12] Add to doc API page --- doc/api/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/api/index.rst b/doc/api/index.rst index 01fac7d7a89..704938a483e 100644 --- a/doc/api/index.rst +++ b/doc/api/index.rst @@ -48,6 +48,7 @@ Plotting tabular data Figure.plot Figure.plot3d Figure.rose + Figure.scatter Figure.ternary Figure.velo Figure.wiggle From a83319423a77d85507ebe385eaa2c84cafbf3ed3 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Mon, 11 Nov 2024 19:16:28 +0800 Subject: [PATCH 06/12] Improve docstrings --- pygmt/src/scatter.py | 44 +++++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/pygmt/src/scatter.py b/pygmt/src/scatter.py index 219d4c0947a..465e02968cf 100644 --- a/pygmt/src/scatter.py +++ b/pygmt/src/scatter.py @@ -4,7 +4,7 @@ from collections.abc import Sequence -from pygmt.helpers import is_nonstr_iter +from pygmt.helpers import fmt_docstring, is_nonstr_iter def _parse_symbol_size(symbol, size): @@ -25,6 +25,7 @@ def _parse_symbol_size(symbol, size): return "".join(f"{arg}" for arg in [symbol, size] if not is_nonstr_iter(arg)) +@fmt_docstring def scatter( # noqa: PLR0913 self, x, @@ -39,17 +40,26 @@ def scatter( # noqa: PLR0913 perspective=None, ): """ - Plot scatter points on a map. + Plot scatter points. - This function can plot points with different symbols, sizes, and colors. + It can plot data points with constant or varying symbols, sizes, colors, and + transparencies, and intensities. + The parameters ``symbol``, ``size``, ``fill``, ``intensity``, and + ``transparency`` can be a single scalar value or a sequence of values with the + same length as the number of data points. If a single value is given, it is + used for all data points. If a sequence is given, different values are used + for different data points. Parameters ---------- - x, y : array-like - The coordinates of the points to plot. + x, y + The data coordinates. symbol - Symbol to use for the points. Can be a single symbol or a sequence of symbols. + The symbol(s) to use. It can be a single symbol string to use the same + symbol for all data points or a sequence of symbol strings to have + different symbols for different data points. + Valid symbols are: - ``-``: X-dash (-) @@ -67,17 +77,25 @@ def scatter( # noqa: PLR0913 - ``x``: Cross - ``y``: Y-dash (|) size - The size of the points. + The size(s) of the points. intensity - The intensity of the points. + The intensity(ies) of the points. transparency - The transparency of the points. + The transparency(ies) of the points. cmap - The colormap to use for the points. + The colormap to map scalar values in ``fill`` to colors. In this case, + ``fill`` must be a sequence of numbers. no_clip - If True, do not clip the points to the viewport. - perspective - The perspective of the points. + If True, do not clip the points that fall outside the frame boundaries. + {perspective} + + Examples + -------- + >>> import pygmt + >>> fig = pygmt.Figure() + >>> fig.basemap(region=[0, 3, 0, 3], projection="X10c/5c", frame=True) + >>> fig.scatter(x=[0, 1, 2], y=[0, 1, 2], symbol="c", size=0.5) + >>> fig.show() """ self._preprocess() From 8d7f7449a320f970a1badda8c59927bada886f42 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Mon, 11 Nov 2024 19:26:25 +0800 Subject: [PATCH 07/12] Add parameter for pen --- pygmt/src/scatter.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/pygmt/src/scatter.py b/pygmt/src/scatter.py index 465e02968cf..e5eb00b71d3 100644 --- a/pygmt/src/scatter.py +++ b/pygmt/src/scatter.py @@ -36,6 +36,7 @@ def scatter( # noqa: PLR0913 intensity: float | Sequence[float] | None = None, transparency: float | Sequence[float] | None = None, cmap: str | None = None, + pen: str | float | None = None, no_clip: bool = False, perspective=None, ): @@ -85,16 +86,35 @@ def scatter( # noqa: PLR0913 cmap The colormap to map scalar values in ``fill`` to colors. In this case, ``fill`` must be a sequence of numbers. + pen + The pen property of the symbol outline. no_clip If True, do not clip the points that fall outside the frame boundaries. {perspective} Examples -------- + + Plot three points with the same symbol and size. + >>> import pygmt >>> fig = pygmt.Figure() >>> fig.basemap(region=[0, 3, 0, 3], projection="X10c/5c", frame=True) - >>> fig.scatter(x=[0, 1, 2], y=[0, 1, 2], symbol="c", size=0.5) + >>> fig.scatter(x=[0, 1, 2], y=[0, 1, 2], symbol="c", size=0.3, fill="red") + >>> fig.show() + + Plot three points with different sizes and transparencies. + + >>> fig = pygmt.Figure() + >>> fig.basemap(region=[0, 3, 0, 3], projection="X10c/5c", frame=True) + >>> fig.scatter( + ... x=[0, 1, 2], + ... y=[0, 1, 2], + ... symbol="c", + ... size=[0.5, 0.3, 0.2], + ... fill="blue", + ... transparency=[50, 70, 90], + ... ) >>> fig.show() """ self._preprocess() @@ -116,6 +136,7 @@ def scatter( # noqa: PLR0913 intensity=intensity, transparency=transparency, cmap=cmap, + pen=pen, no_clip=no_clip, perspective=perspective, ) From 84c3c6118fdc5c020340c9736cf5a0bc67729e9b Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 18 Dec 2024 11:27:30 +0800 Subject: [PATCH 08/12] Improve Figure.scatter --- pygmt/src/scatter.py | 54 ++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/pygmt/src/scatter.py b/pygmt/src/scatter.py index e5eb00b71d3..25294685a6d 100644 --- a/pygmt/src/scatter.py +++ b/pygmt/src/scatter.py @@ -1,5 +1,5 @@ """ -scatter - Scatter plot. +scatter - Plot scatter points. """ from collections.abc import Sequence @@ -7,10 +7,14 @@ from pygmt.helpers import fmt_docstring, is_nonstr_iter -def _parse_symbol_size(symbol, size): +def _parse_symbol_size( + symbol: str | Sequence[str], size: float | str | Sequence[float | str] +) -> str: """ - Parse the symbol and size into a style string. + Parse the 'symbol' and 'size' parameter into GMT's style string. + Examples + -------- >>> _parse_symbol_size("c", 0.2) 'c0.2' >>> _parse_symbol_size("c", "0.2c") @@ -43,25 +47,19 @@ def scatter( # noqa: PLR0913 """ Plot scatter points. - It can plot data points with constant or varying symbols, sizes, colors, and - transparencies, and intensities. - - The parameters ``symbol``, ``size``, ``fill``, ``intensity``, and - ``transparency`` can be a single scalar value or a sequence of values with the - same length as the number of data points. If a single value is given, it is - used for all data points. If a sequence is given, different values are used - for different data points. + It can plot data points with constant or varying symbols, sizes, colors, + transparencies, and intensities. The parameters ``symbol``, ``size``, ``fill``, + ``intensity``, and ``transparency`` can be a single scalar value or a sequence of + values with the same length as the number of data points. If a single value is + given, it is used for all data points. If a sequence is given, different values are + used for different data points. Parameters ---------- x, y The data coordinates. symbol - The symbol(s) to use. It can be a single symbol string to use the same - symbol for all data points or a sequence of symbol strings to have - different symbols for different data points. - - Valid symbols are: + The symbol(s) to use. Valid symbols are: - ``-``: X-dash (-) - ``+``: Plus @@ -79,13 +77,16 @@ def scatter( # noqa: PLR0913 - ``y``: Y-dash (|) size The size(s) of the points. + fill + Set color or pattern for filling symbols [Default is no fill]. If ``cmap`` is + used, ``fill`` must be a sequence of values. intensity The intensity(ies) of the points. transparency The transparency(ies) of the points. cmap - The colormap to map scalar values in ``fill`` to colors. In this case, - ``fill`` must be a sequence of numbers. + The colormap to map scalar values in ``fill`` to colors. In this case, ``fill`` + must be a sequence of values. pen The pen property of the symbol outline. no_clip @@ -119,19 +120,18 @@ def scatter( # noqa: PLR0913 """ self._preprocess() - # style is a combination of symbol and size, but only if they are string-like - style = _parse_symbol_size(symbol, size) - if not is_nonstr_iter(symbol): - symbol = None - if not is_nonstr_iter(size): - size = None + # Create GMT plot's "style" from "symbol" and "size". + _style = _parse_symbol_size(symbol, size) + # Set "symbol" and "size" to None if they're not sequences. + _symbol = symbol if is_nonstr_iter(symbol) else None + _size = size if is_nonstr_iter(size) else None self.plot( x=x, y=y, - style=style, - symbol=symbol, - size=size, + style=_style, + symbol=_symbol, + size=_size, fill=fill, intensity=intensity, transparency=transparency, From ce3f03ec02feaf78a6b70c387af25314dc8d3a93 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Thu, 19 Dec 2024 20:40:14 +0800 Subject: [PATCH 09/12] Need to set 'cmap' if 'fill' is a sequence --- pygmt/src/scatter.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pygmt/src/scatter.py b/pygmt/src/scatter.py index 25294685a6d..308927e9bfd 100644 --- a/pygmt/src/scatter.py +++ b/pygmt/src/scatter.py @@ -126,6 +126,10 @@ def scatter( # noqa: PLR0913 _symbol = symbol if is_nonstr_iter(symbol) else None _size = size if is_nonstr_iter(size) else None + # Set "cmap" to True if "fill" is a sequence of values. + if is_nonstr_iter(fill) and cmap is None: + cmap = True + self.plot( x=x, y=y, From 66cb558f3e042dd5b5b68581974b250a9b911416 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Thu, 19 Dec 2024 20:49:49 +0800 Subject: [PATCH 10/12] Remove point as a valid symbol --- pygmt/src/scatter.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pygmt/src/scatter.py b/pygmt/src/scatter.py index 308927e9bfd..8c8d30967a4 100644 --- a/pygmt/src/scatter.py +++ b/pygmt/src/scatter.py @@ -70,7 +70,6 @@ def scatter( # noqa: PLR0913 - ``h``: Hexagon - ``i``: Inverted triangle - ``n``: Pentagon - - ``p``: Point - ``s``: Square - ``t``: Triangle - ``x``: Cross From 3ec751c53110d454ff98bde3d6a5e93d68a8c69a Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Thu, 19 Dec 2024 21:12:24 +0800 Subject: [PATCH 11/12] Improve docstrings for cmap --- pygmt/src/scatter.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pygmt/src/scatter.py b/pygmt/src/scatter.py index 8c8d30967a4..967ebd2a8dd 100644 --- a/pygmt/src/scatter.py +++ b/pygmt/src/scatter.py @@ -39,7 +39,7 @@ def scatter( # noqa: PLR0913 fill: str | Sequence[float] | None = None, intensity: float | Sequence[float] | None = None, transparency: float | Sequence[float] | None = None, - cmap: str | None = None, + cmap: str | bool | None = None, pen: str | float | None = None, no_clip: bool = False, perspective=None, @@ -77,8 +77,8 @@ def scatter( # noqa: PLR0913 size The size(s) of the points. fill - Set color or pattern for filling symbols [Default is no fill]. If ``cmap`` is - used, ``fill`` must be a sequence of values. + Set color or pattern for filling symbols [Default is no fill]. If a sequence of + values is given, ``cmap`` must be specified. intensity The intensity(ies) of the points. transparency From af90220a0c7aae32944e98859ad1c081077b2686 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Thu, 19 Dec 2024 21:12:44 +0800 Subject: [PATCH 12/12] Add tests for Figure.scatter --- pygmt/tests/baseline/test_scatter.png.dvc | 5 + .../tests/baseline/test_scatter_fills.png.dvc | 5 + .../baseline/test_scatter_intensity.png.dvc | 5 + .../tests/baseline/test_scatter_sizes.png.dvc | 5 + .../baseline/test_scatter_sizes_fills.png.dvc | 5 + ...scatter_sizes_fills_transparencies.png.dvc | 5 + ...zes_fills_transparencies_intensity.png.dvc | 5 + .../baseline/test_scatter_symbols.png.dvc | 5 + .../test_scatter_symbols_sizes.png.dvc | 5 + ...zes_fills_transparencies_intensity.png.dvc | 5 + .../test_scatter_transparencies.png.dvc | 5 + .../test_scatter_valid_symbols.png.dvc | 5 + pygmt/tests/test_scatter.py | 247 ++++++++++++++++++ 13 files changed, 307 insertions(+) create mode 100644 pygmt/tests/baseline/test_scatter.png.dvc create mode 100644 pygmt/tests/baseline/test_scatter_fills.png.dvc create mode 100644 pygmt/tests/baseline/test_scatter_intensity.png.dvc create mode 100644 pygmt/tests/baseline/test_scatter_sizes.png.dvc create mode 100644 pygmt/tests/baseline/test_scatter_sizes_fills.png.dvc create mode 100644 pygmt/tests/baseline/test_scatter_sizes_fills_transparencies.png.dvc create mode 100644 pygmt/tests/baseline/test_scatter_sizes_fills_transparencies_intensity.png.dvc create mode 100644 pygmt/tests/baseline/test_scatter_symbols.png.dvc create mode 100644 pygmt/tests/baseline/test_scatter_symbols_sizes.png.dvc create mode 100644 pygmt/tests/baseline/test_scatter_symbols_sizes_fills_transparencies_intensity.png.dvc create mode 100644 pygmt/tests/baseline/test_scatter_transparencies.png.dvc create mode 100644 pygmt/tests/baseline/test_scatter_valid_symbols.png.dvc create mode 100644 pygmt/tests/test_scatter.py diff --git a/pygmt/tests/baseline/test_scatter.png.dvc b/pygmt/tests/baseline/test_scatter.png.dvc new file mode 100644 index 00000000000..84acf08cf75 --- /dev/null +++ b/pygmt/tests/baseline/test_scatter.png.dvc @@ -0,0 +1,5 @@ +outs: +- md5: 5705688b5f45ec842980b94bec239b02 + size: 20703 + hash: md5 + path: test_scatter.png diff --git a/pygmt/tests/baseline/test_scatter_fills.png.dvc b/pygmt/tests/baseline/test_scatter_fills.png.dvc new file mode 100644 index 00000000000..edc28e369db --- /dev/null +++ b/pygmt/tests/baseline/test_scatter_fills.png.dvc @@ -0,0 +1,5 @@ +outs: +- md5: f4bc6e6818d9889f6c729993dbfa8cfe + size: 22012 + hash: md5 + path: test_scatter_fills.png diff --git a/pygmt/tests/baseline/test_scatter_intensity.png.dvc b/pygmt/tests/baseline/test_scatter_intensity.png.dvc new file mode 100644 index 00000000000..e28d11f0119 --- /dev/null +++ b/pygmt/tests/baseline/test_scatter_intensity.png.dvc @@ -0,0 +1,5 @@ +outs: +- md5: ff2b09d8983b015ea7229c6def8ef7de + size: 21670 + hash: md5 + path: test_scatter_intensity.png diff --git a/pygmt/tests/baseline/test_scatter_sizes.png.dvc b/pygmt/tests/baseline/test_scatter_sizes.png.dvc new file mode 100644 index 00000000000..68b4f0c9a75 --- /dev/null +++ b/pygmt/tests/baseline/test_scatter_sizes.png.dvc @@ -0,0 +1,5 @@ +outs: +- md5: 4b85b972171fa9a5cfcc20fab7e81fb5 + size: 22315 + hash: md5 + path: test_scatter_sizes.png diff --git a/pygmt/tests/baseline/test_scatter_sizes_fills.png.dvc b/pygmt/tests/baseline/test_scatter_sizes_fills.png.dvc new file mode 100644 index 00000000000..d759a6c5aeb --- /dev/null +++ b/pygmt/tests/baseline/test_scatter_sizes_fills.png.dvc @@ -0,0 +1,5 @@ +outs: +- md5: 457480111a3d08e16aca82e8464809db + size: 22049 + hash: md5 + path: test_scatter_sizes_fills.png diff --git a/pygmt/tests/baseline/test_scatter_sizes_fills_transparencies.png.dvc b/pygmt/tests/baseline/test_scatter_sizes_fills_transparencies.png.dvc new file mode 100644 index 00000000000..1c704cc029a --- /dev/null +++ b/pygmt/tests/baseline/test_scatter_sizes_fills_transparencies.png.dvc @@ -0,0 +1,5 @@ +outs: +- md5: 2b85221c5c451cefeb0cd81e033724b2 + size: 21152 + hash: md5 + path: test_scatter_sizes_fills_transparencies.png diff --git a/pygmt/tests/baseline/test_scatter_sizes_fills_transparencies_intensity.png.dvc b/pygmt/tests/baseline/test_scatter_sizes_fills_transparencies_intensity.png.dvc new file mode 100644 index 00000000000..086ed902e84 --- /dev/null +++ b/pygmt/tests/baseline/test_scatter_sizes_fills_transparencies_intensity.png.dvc @@ -0,0 +1,5 @@ +outs: +- md5: f0282431c7ef8d95c870e1c3b6bcdfbd + size: 21231 + hash: md5 + path: test_scatter_sizes_fills_transparencies_intensity.png diff --git a/pygmt/tests/baseline/test_scatter_symbols.png.dvc b/pygmt/tests/baseline/test_scatter_symbols.png.dvc new file mode 100644 index 00000000000..18ad6449807 --- /dev/null +++ b/pygmt/tests/baseline/test_scatter_symbols.png.dvc @@ -0,0 +1,5 @@ +outs: +- md5: 4f5f9fc44bc8f5f32de388bc75a2d474 + size: 20479 + hash: md5 + path: test_scatter_symbols.png diff --git a/pygmt/tests/baseline/test_scatter_symbols_sizes.png.dvc b/pygmt/tests/baseline/test_scatter_symbols_sizes.png.dvc new file mode 100644 index 00000000000..eafe78a736a --- /dev/null +++ b/pygmt/tests/baseline/test_scatter_symbols_sizes.png.dvc @@ -0,0 +1,5 @@ +outs: +- md5: 8d23bb9dd39f1b1151412f8a43f6c12c + size: 21815 + hash: md5 + path: test_scatter_symbols_sizes.png diff --git a/pygmt/tests/baseline/test_scatter_symbols_sizes_fills_transparencies_intensity.png.dvc b/pygmt/tests/baseline/test_scatter_symbols_sizes_fills_transparencies_intensity.png.dvc new file mode 100644 index 00000000000..3afffde12ac --- /dev/null +++ b/pygmt/tests/baseline/test_scatter_symbols_sizes_fills_transparencies_intensity.png.dvc @@ -0,0 +1,5 @@ +outs: +- md5: 488eec9d3ef156993a82cc2a66125a67 + size: 20879 + hash: md5 + path: test_scatter_symbols_sizes_fills_transparencies_intensity.png diff --git a/pygmt/tests/baseline/test_scatter_transparencies.png.dvc b/pygmt/tests/baseline/test_scatter_transparencies.png.dvc new file mode 100644 index 00000000000..8f1dc493dcf --- /dev/null +++ b/pygmt/tests/baseline/test_scatter_transparencies.png.dvc @@ -0,0 +1,5 @@ +outs: +- md5: 4943894ddcff5d0f486246e106839158 + size: 20679 + hash: md5 + path: test_scatter_transparencies.png diff --git a/pygmt/tests/baseline/test_scatter_valid_symbols.png.dvc b/pygmt/tests/baseline/test_scatter_valid_symbols.png.dvc new file mode 100644 index 00000000000..e7fb0a73dc0 --- /dev/null +++ b/pygmt/tests/baseline/test_scatter_valid_symbols.png.dvc @@ -0,0 +1,5 @@ +outs: +- md5: 6d4e6acdd44006be6e384f425c302932 + size: 24570 + hash: md5 + path: test_scatter_valid_symbols.png diff --git a/pygmt/tests/test_scatter.py b/pygmt/tests/test_scatter.py new file mode 100644 index 00000000000..7305b09d532 --- /dev/null +++ b/pygmt/tests/test_scatter.py @@ -0,0 +1,247 @@ +""" +Test Figure.scatter. +""" + +import numpy as np +import pytest +from pygmt import Figure, makecpt + + +# +# Fixtures that are used in tests. +# +@pytest.fixture(scope="module", name="region") +def fixture_region(): + """ + The region of sample data. + """ + return [0, 5, 5, 10] + + +@pytest.fixture(scope="module", name="x") +def fixture_x(): + """ + The x coordinates of sample data. + """ + return [1, 2, 3, 4] + + +@pytest.fixture(scope="module", name="y") +def fixture_y(): + """ + The y coordinates of sample data. + """ + return [6, 7, 8, 9] + + +@pytest.fixture(scope="module", name="size") +def fixture_size(): + """ + The size of sample data. + """ + return [0.2, 0.4, 0.6, 0.8] + + +@pytest.fixture(scope="module", name="symbol") +def fixture_symbol(): + """ + The symbol of sample data. + """ + return ["a", "c", "i", "t"] + + +@pytest.fixture(scope="module", name="fill") +def fixture_fill(): + """ + The z value of sample data for fill. + """ + return [1, 2, 3, 4] + + +@pytest.fixture(scope="module", name="transparency") +def fixture_transparency(): + """ + The transparency of sample data. + """ + return [20, 40, 60, 80] + + +@pytest.fixture(scope="module", name="intensity") +def fixture_intensity(): + """ + The intensity of sample data. + """ + return [-0.8, -0.3, 0.3, 0.8] + + +# +# Tests for the simplest scatter plot with constant size and symbol. +# +@pytest.mark.mpl_image_compare +def test_scatter(region, x, y): + """ + Test the simplest scatter plot with constant size and symbol. + """ + fig = Figure() + fig.basemap(region=region, frame=True) + fig.scatter(x=x, y=y, symbol="c", size=0.2) + return fig + + +# +# Tests for scatter plots with one parameter given as a sequence. +# +@pytest.mark.mpl_image_compare +def test_scatter_sizes(region, x, y, size): + """ + Test the scatter plot with different sizes. + """ + fig = Figure() + fig.basemap(region=region, frame=True) + fig.scatter(x=x, y=y, symbol="c", size=size) + return fig + + +@pytest.mark.mpl_image_compare +def test_scatter_symbols(region, x, y, symbol): + """ + Test the scatter plot with different symbols. + """ + fig = Figure() + fig.basemap(region=region, frame=True) + fig.scatter(x=x, y=y, symbol=symbol, size=0.2) + return fig + + +@pytest.mark.mpl_image_compare +def test_scatter_fills(region, x, y, fill): + """ + Test the scatter plot with different colors. + """ + fig = Figure() + fig.basemap(region=region, frame=True) + makecpt(cmap="viridis", series=[0, 5]) + fig.scatter(x=x, y=y, symbol="c", size=0.5, fill=fill) + return fig + + +@pytest.mark.mpl_image_compare +def test_scatter_transparencies(region, x, y, transparency): + """ + Test the scatter plot with different transparency. + """ + fig = Figure() + fig.basemap(region=region, frame=True) + makecpt(cmap="viridis", series=[1, 4]) + fig.scatter(x=x, y=y, symbol="c", size=0.5, fill="red", transparency=transparency) + return fig + + +@pytest.mark.mpl_image_compare +def test_scatter_intensity(region, x, y, intensity): + """ + Test the scatter plot with different intensity. + """ + fig = Figure() + fig.basemap(region=region, frame=True) + fig.scatter(x=x, y=y, symbol="c", size=0.5, fill="red", intensity=intensity) + return fig + + +# +# Tests for scatter plots with multiple parameters given as sequences. +# +@pytest.mark.mpl_image_compare +def test_scatter_symbols_sizes(region, x, y, symbol, size): + """ + Test the scatter plot with different symbols and sizes. + """ + fig = Figure() + fig.basemap(region=region, frame=True) + fig.scatter(x=x, y=y, symbol=symbol, size=size) + return fig + + +@pytest.mark.mpl_image_compare +def test_scatter_sizes_fills(region, x, y, size, fill): + """ + Test the scatter plot with different sizes and colors. + """ + fig = Figure() + fig.basemap(region=region, frame=True) + makecpt(cmap="viridis", series=[0, 5]) + fig.scatter(x=x, y=y, symbol="c", size=size, fill=fill) + return fig + + +@pytest.mark.mpl_image_compare +def test_scatter_sizes_fills_transparencies(region, x, y, size, fill, transparency): + """ + Test the scatter plot with different sizes and colors. + """ + fig = Figure() + fig.basemap(region=region, frame=True) + makecpt(cmap="viridis", series=[0, 5]) + fig.scatter(x=x, y=y, symbol="c", size=size, fill=fill, transparency=transparency) + return fig + + +@pytest.mark.mpl_image_compare +def test_scatter_sizes_fills_transparencies_intensity( + region, x, y, size, fill, transparency, intensity +): + """ + Test the scatter plot with different sizes and colors. + """ + fig = Figure() + fig.basemap(region=region, frame=True) + makecpt(cmap="viridis", series=[0, 5]) + fig.scatter( + x=x, + y=y, + symbol="c", + size=size, + fill=fill, + transparency=transparency, + intensity=intensity, + ) + return fig + + +@pytest.mark.mpl_image_compare +def test_scatter_symbols_sizes_fills_transparencies_intensity( + region, x, y, symbol, size, fill, transparency, intensity +): + """ + Test the scatter plot with different sizes and colors. + """ + fig = Figure() + fig.basemap(region=region, frame=True) + makecpt(cmap="viridis", series=[0, 5]) + fig.scatter( + x=x, + y=y, + symbol=symbol, + size=size, + fill=fill, + transparency=transparency, + intensity=intensity, + ) + return fig + + +# +# Other tests for scatter plots. +# +@pytest.mark.mpl_image_compare +def test_scatter_valid_symbols(): + """ + Test the scatter plot with data. + """ + symbols = ["-", "+", "a", "c", "d", "g", "h", "i", "n", "s", "t", "x", "y"] + x = np.arange(len(symbols)) + y = [1.0] * len(symbols) + fig = Figure() + fig.basemap(region=[-1, len(symbols), 0, 2], frame=True) + fig.scatter(x=x, y=y, symbol=symbols, size=0.5, pen="1p,black") + return fig