From 2087bead022752568a8f0422cfd6f021d75b822f Mon Sep 17 00:00:00 2001 From: SangGyu An Date: Wed, 9 Aug 2023 08:39:45 -0700 Subject: [PATCH 1/3] Add_binwidth_to_histogram fix fix fix test functions fix fix fix fix testing errors add integration tests fix fix fix fix fix --- CHANGELOG.md | 2 +- doc/api/magic-plot.md | 18 ++- src/sql/ggplot/geom/geom_histogram.py | 9 +- src/sql/magic_plot.py | 15 ++- src/sql/plot.py | 84 ++++++++++-- .../histogram_binwidth_facet_wrap.png | Bin 0 -> 9507 bytes .../histogram_binwidth_with_multiple_cols.png | Bin 0 -> 11379 bytes .../histogram_stacked_with_binwidth.png | Bin 0 -> 12738 bytes .../test_ggplot/histogram_with_binwidth.png | Bin 0 -> 8856 bytes .../histogram_with_narrow_binwidth.png | Bin 0 -> 8897 bytes .../test_magic_plot/hist_binwidth.png | Bin 0 -> 8856 bytes .../histogram_binwidth_with_multiple_cols.png | Bin 0 -> 11367 bytes .../histogram_stacked_with_binwidth.png | Bin 0 -> 12716 bytes .../test_questDB/histogram_with_binwidth.png | Bin 0 -> 8805 bytes .../histogram_with_narrow_binwidth.png | Bin 0 -> 8885 bytes .../integration/test_generic_db_operations.py | 5 + src/tests/integration/test_questDB.py | 56 ++++++++ src/tests/test_ggplot.py | 120 +++++++++++++++++- src/tests/test_magic_plot.py | 53 +++++++- 19 files changed, 339 insertions(+), 23 deletions(-) create mode 100644 src/tests/baseline_images/test_ggplot/histogram_binwidth_facet_wrap.png create mode 100644 src/tests/baseline_images/test_ggplot/histogram_binwidth_with_multiple_cols.png create mode 100644 src/tests/baseline_images/test_ggplot/histogram_stacked_with_binwidth.png create mode 100644 src/tests/baseline_images/test_ggplot/histogram_with_binwidth.png create mode 100644 src/tests/baseline_images/test_ggplot/histogram_with_narrow_binwidth.png create mode 100644 src/tests/baseline_images/test_magic_plot/hist_binwidth.png create mode 100644 src/tests/integration/baseline_images/test_questDB/histogram_binwidth_with_multiple_cols.png create mode 100644 src/tests/integration/baseline_images/test_questDB/histogram_stacked_with_binwidth.png create mode 100644 src/tests/integration/baseline_images/test_questDB/histogram_with_binwidth.png create mode 100644 src/tests/integration/baseline_images/test_questDB/histogram_with_narrow_binwidth.png diff --git a/CHANGELOG.md b/CHANGELOG.md index db04b474b..1a2ebe24b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## 0.9.2dev +* [Feature] Add Add `--binwidth/-W` to ggplot histogram for specifying binwidth (#784) * [Fix] Fix a bug that caused a cell with a CTE to fail if it referenced a table/view with the same name as an existing snippet (#753) ## 0.9.1 (2023-08-10) @@ -12,7 +13,6 @@ * [Fix] Fix error when using SQL Server with pyodbc that caused queries to fail due to multiple open result sets * [Fix] Improves performance when converting DuckDB results to `pandas.DataFrame` * [Fix] Fixes a bug when converting a CTE stored with `--save` into a `pandas.DataFrame` via `.DataFrame()` -* [Doc] Add Redshift tutorial ## 0.9.0 (2023-08-01) diff --git a/doc/api/magic-plot.md b/doc/api/magic-plot.md index 7305d7331..9e3ed7b00 100644 --- a/doc/api/magic-plot.md +++ b/doc/api/magic-plot.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.14.7 + jupytext_version: 1.15.0 kernelspec: display_name: Python 3 (ipykernel) language: python @@ -128,8 +128,14 @@ Shortcut: `%sqlplot hist` `-B`/`--breaks` Custom bin intervals +`-W`/`--binwidth` Width of each bin + `-w`/`--with` Use a previously saved query as input data +```{note} +When using -b/--bins, -B/--breaks, or -W/--binwidth, you can only specify one of them. If none of them is specified, the default value for -b/--bins will be used. +``` + +++ Histogram supports NULL values by skipping them. Now we can @@ -155,12 +161,20 @@ When plotting a histogram, it divides a range with the number of bins - 1 to cal ### Specifying breaks -Breaks allow you to set custom intervals for a histogram. You can specify breaks by passing desired each end and break points separated by whitespace after `-B/--breaks`. Since those break points define a range of data points to plot, bar width, and number of bars in a histogram, make sure to pass more than 1 point that is strictly increasing and includes at least one data point. Note that using both `-b/--bins` and `-B/--breaks` isn't allowed. +Breaks allow you to set custom intervals for a histogram. You can specify breaks by passing desired each end and break points separated by whitespace after `-B/--breaks`. Since those break points define a range of data points to plot, bar width, and number of bars in a histogram, make sure to pass more than 1 point that is strictly increasing and includes at least one data point. ```{code-cell} ipython3 %sqlplot histogram --table penguins.csv --column body_mass_g --breaks 3200 3400 3600 3800 4000 4200 4400 4600 4800 ``` +### Specifying binwidth + +Binwidth allows you to set the width of bins in a histogram. To specify the binwidth, pass a desired width after `-W/--binwidth`. Since the binwidth determines details of distribution, make sure to pass a suitable positive numeric value based on your data. + +```{code-cell} ipython3 +%sqlplot histogram --table penguins.csv --column body_mass_g --binwidth 150 +``` + ### Multiple columns ```{code-cell} ipython3 diff --git a/src/sql/ggplot/geom/geom_histogram.py b/src/sql/ggplot/geom/geom_histogram.py index f52a0470b..34d0e8293 100644 --- a/src/sql/ggplot/geom/geom_histogram.py +++ b/src/sql/ggplot/geom/geom_histogram.py @@ -21,13 +21,19 @@ class geom_histogram(geom): breaks : list Divide bins with custom intervals + + binwidth : int or float + Width of each bin """ - def __init__(self, bins=None, fill=None, cmap=None, breaks=None, **kwargs): + def __init__( + self, bins=None, fill=None, cmap=None, breaks=None, binwidth=None, **kwargs + ): self.bins = bins self.fill = fill self.cmap = cmap self.breaks = breaks + self.binwidth = binwidth super().__init__(**kwargs) @telemetry.log_call("ggplot-histogram") @@ -45,5 +51,6 @@ def draw(self, gg, ax=None, facet=None): facet=facet, ax=ax or gg.axs[0], breaks=self.breaks, + binwidth=self.binwidth, ) return gg diff --git a/src/sql/magic_plot.py b/src/sql/magic_plot.py index 74d051f53..5c9ba07b8 100644 --- a/src/sql/magic_plot.py +++ b/src/sql/magic_plot.py @@ -66,6 +66,12 @@ class SqlPlotMagic(Magics, Configurable): nargs="+", help="Histogram breaks", ) + @argument( + "-W", + "--binwidth", + type=float, + help="Histogram binwidth", + ) @modify_exceptions def execute(self, line="", cell="", local_ns=None): """ @@ -110,13 +116,13 @@ def execute(self, line="", cell="", local_ns=None): conn=None, ) elif cmd.args.line[0] in {"hist", "histogram"}: - # to avoid passing bins default value when breaks are given by a user + # to avoid passing bins default value when breaks or binwidth is specified bin_specified = " --bins " in line or " -b " in line breaks_specified = " --breaks " in line or " -B " in line - if breaks_specified and not bin_specified: + binwidth_specified = " --binwidth " in line or " -W " in line + bins = cmd.args.bins + if not bin_specified and any([breaks_specified, binwidth_specified]): bins = None - else: - bins = cmd.args.bins return plot.histogram( table=table, @@ -125,6 +131,7 @@ def execute(self, line="", cell="", local_ns=None): with_=with_, conn=None, breaks=cmd.args.breaks, + binwidth=cmd.args.binwidth, ) elif cmd.args.line[0] in {"bar"}: return plot.bar( diff --git a/src/sql/plot.py b/src/sql/plot.py index 5b87daf17..e13d36483 100644 --- a/src/sql/plot.py +++ b/src/sql/plot.py @@ -8,6 +8,7 @@ from sql import exceptions, display from sql.stats import _summary_stats +from sql.util import pretty_print try: import matplotlib.pyplot as plt @@ -268,7 +269,7 @@ def _are_numeric_values(*values): return all([isinstance(value, (int, float)) for value in values]) -def _get_bar_width(ax, bins, bin_size): +def _get_bar_width(ax, bins, bin_size, binwidth): """ Return a single bar width based on number of bins or a list of bar widths if `breaks` is given. @@ -286,6 +287,9 @@ def _get_bar_width(ax, bins, bin_size): Calculated bin_size from the _histogram function or from consecutive differences in `breaks` + binwidth : int or float or None + Specified binwidth from a user + Returns ------- width : float @@ -293,6 +297,8 @@ def _get_bar_width(ax, bins, bin_size): """ if _are_numeric_values(bin_size) or isinstance(bin_size, list): width = bin_size + elif _are_numeric_values(binwidth): + width = binwidth else: fig = plt.gcf() bbox = ax.get_window_extent() @@ -318,6 +324,7 @@ def histogram( ax=None, facet=None, breaks=None, + binwidth=None, ): """Plot histogram @@ -371,10 +378,34 @@ def histogram( f"Breaks given : {breaks}. When using breaks, please ensure that " "breaks are strictly increasing." ) - if bins: + + if _are_numeric_values(binwidth): + if binwidth <= 0: raise exceptions.ValueError( - "Both bins and breaks are specified. Must specify only one of them." + f"Binwidth given : {binwidth}. When using binwidth, please ensure to " + "pass a positive value." ) + binwidth = float(binwidth) + elif binwidth is None: + pass + else: + raise exceptions.ValueError( + f"Binwidth given : {binwidth}. When using binwidth, please ensure to " + "pass a numeric value." + ) + + specified_args = [ + args + for args, specified in zip( + ["bins", "breaks", "binwidth"], [bins, breaks, binwidth] + ) + if specified + ] + if len(specified_args) > 1: + raise exceptions.ValueError( + f"{pretty_print(specified_args)} are specified. " + "You can only specify one of them." + ) ax = ax or plt.gca() payload["connection_info"] = conn._get_database_information() @@ -393,9 +424,15 @@ def histogram( raise ValueError("Column name has not been specified") bin_, height, bin_size = _histogram( - table, column, bins, with_=with_, conn=conn, breaks=breaks + table, + column, + bins, + with_=with_, + conn=conn, + breaks=breaks, + binwidth=binwidth, ) - width = _get_bar_width(ax, bin_, bin_size) + width = _get_bar_width(ax, bin_, bin_size, binwidth) data = _histogram_stacked( table, column, @@ -406,6 +443,7 @@ def histogram( conn=conn, facet=facet, breaks=breaks, + binwidth=binwidth, ) cmap = plt.get_cmap(cmap or "viridis") norm = Normalize(vmin=0, vmax=len(data)) @@ -449,9 +487,16 @@ def histogram( ax.legend(handles[::-1], labels[::-1]) elif isinstance(column, str): bin_, height, bin_size = _histogram( - table, column, bins, with_=with_, conn=conn, facet=facet, breaks=breaks + table, + column, + bins, + with_=with_, + conn=conn, + facet=facet, + breaks=breaks, + binwidth=binwidth, ) - width = _get_bar_width(ax, bin_, bin_size) + width = _get_bar_width(ax, bin_, bin_size, binwidth) ax.bar( bin_, @@ -472,9 +517,16 @@ def histogram( ) for i, col in enumerate(column): bin_, height, bin_size = _histogram( - table, col, bins, with_=with_, conn=conn, facet=facet, breaks=breaks + table, + col, + bins, + with_=with_, + conn=conn, + facet=facet, + breaks=breaks, + binwidth=binwidth, ) - width = _get_bar_width(ax, bin_, bin_size) + width = _get_bar_width(ax, bin_, bin_size, binwidth) if isinstance(color, list): color_ = color[i] @@ -505,7 +557,9 @@ def histogram( @modify_exceptions -def _histogram(table, column, bins, with_=None, conn=None, facet=None, breaks=None): +def _histogram( + table, column, bins, with_=None, conn=None, facet=None, breaks=None, binwidth=None +): """Compute bins and heights""" if not conn: conn = sql.connection.ConnectionManager.current @@ -576,7 +630,7 @@ def _histogram(table, column, bins, with_=None, conn=None, facet=None, breaks=No query = template.render( table=table, column=column, filter_query=filter_query ) - elif not isinstance(bins, int): + elif not binwidth and not isinstance(bins, int): raise ValueError( f"bins are '{bins}'. Please specify a valid number of bins." ) @@ -584,7 +638,10 @@ def _histogram(table, column, bins, with_=None, conn=None, facet=None, breaks=No # Use bins - 1 instead of bins and round half down instead of floor # to mimic right-closed histogram intervals in R ggplot range_ = max_ - min_ - bin_size = range_ / (bins - 1) + if binwidth: + bin_size = binwidth + else: + bin_size = range_ / (bins - 1) template_ = """ select ceiling("{{column}}"/{{bin_size}} - 0.5)*{{bin_size}} as bin, @@ -638,6 +695,7 @@ def _histogram_stacked( conn=None, facet=None, breaks=None, + binwidth=None, ): """Compute the corresponding heights of each bin based on the category""" if not conn: @@ -654,6 +712,8 @@ def _histogram_stacked( cases.append(case) cases[0] = cases[0].replace(">", ">=", 1) else: + if binwidth: + bin_size = binwidth tolerance = bin_size / 1000 # Use to avoid floating point error for bin in bins: # Use round half down instead of floor to mimic diff --git a/src/tests/baseline_images/test_ggplot/histogram_binwidth_facet_wrap.png b/src/tests/baseline_images/test_ggplot/histogram_binwidth_facet_wrap.png new file mode 100644 index 0000000000000000000000000000000000000000..588831221b6ce9774ad621d74b6211f94720c670 GIT binary patch literal 9507 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 literal 0 HcmV?d00001 diff --git a/src/tests/baseline_images/test_ggplot/histogram_binwidth_with_multiple_cols.png b/src/tests/baseline_images/test_ggplot/histogram_binwidth_with_multiple_cols.png new file mode 100644 index 0000000000000000000000000000000000000000..be068e91daa684aea71eb18da86296632d9e8bce GIT binary patch literal 11379 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 z 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 OPN`|DW*$F(?SBCSEHHQg literal 0 HcmV?d00001 diff --git a/src/tests/baseline_images/test_ggplot/histogram_stacked_with_binwidth.png b/src/tests/baseline_images/test_ggplot/histogram_stacked_with_binwidth.png new file mode 100644 index 0000000000000000000000000000000000000000..5c704a37a6f6b5566d117a0d0431d67ceb19311f GIT binary patch literal 12738 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 literal 0 HcmV?d00001 diff --git a/src/tests/baseline_images/test_ggplot/histogram_with_binwidth.png b/src/tests/baseline_images/test_ggplot/histogram_with_binwidth.png new file mode 100644 index 0000000000000000000000000000000000000000..f3565b727df2f880c67a7ec10148fce487f87714 GIT binary patch literal 8856 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 literal 0 HcmV?d00001 diff --git a/src/tests/baseline_images/test_ggplot/histogram_with_narrow_binwidth.png b/src/tests/baseline_images/test_ggplot/histogram_with_narrow_binwidth.png new file mode 100644 index 0000000000000000000000000000000000000000..8b4d69e16be5c15b5d7a9b99aed9e63a060a0971 GIT binary patch literal 8897 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 literal 0 HcmV?d00001 diff --git a/src/tests/integration/baseline_images/test_questDB/histogram_binwidth_with_multiple_cols.png b/src/tests/integration/baseline_images/test_questDB/histogram_binwidth_with_multiple_cols.png new file mode 100644 index 0000000000000000000000000000000000000000..0770980ac4ebd38b551d28a44a16d6b7bccde7ff GIT binary patch literal 11367 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 literal 0 HcmV?d00001 diff --git a/src/tests/integration/baseline_images/test_questDB/histogram_stacked_with_binwidth.png b/src/tests/integration/baseline_images/test_questDB/histogram_stacked_with_binwidth.png new file mode 100644 index 0000000000000000000000000000000000000000..f6a27e24417545d36e4a6afbb91a457ec4b423a8 GIT binary patch literal 12716 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 Date: Mon, 14 Aug 2023 17:41:19 -0700 Subject: [PATCH 2/3] fix --- CHANGELOG.md | 3 ++- doc/api/magic-plot.md | 8 ++++--- src/sql/plot.py | 31 ++++++++++---------------- src/sql/util.py | 13 +++++++++++ src/tests/test_magic_plot.py | 42 ++++++++++++++++++++++++++++++++++-- 5 files changed, 71 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7872b8e9b..ae0c63f4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## 0.10.0dev -* [Feature] Add Add `--binwidth/-W` to ggplot histogram for specifying binwidth (#784) +* [Feature] Add `--binwidth/-W` to ggplot histogram for specifying binwidth (#784) * [Fix] Perform `ROLLBACK` when SQLAlchemy raises `PendingRollbackError` * [Fix] Perform `ROLLBACK` when `psycopg2` raises `current transaction is aborted, commands ignored until end of transaction block` * [Fix] Perform `ROLLBACK` when `psycopg2` raises `server closed the connection unexpectedly` (#677) @@ -21,6 +21,7 @@ * [Fix] Fix error when using SQL Server with pyodbc that caused queries to fail due to multiple open result sets * [Fix] Improves performance when converting DuckDB results to `pandas.DataFrame` * [Fix] Fixes a bug when converting a CTE stored with `--save` into a `pandas.DataFrame` via `.DataFrame()` +* [Doc] Add Redshift tutorial ## 0.9.0 (2023-08-01) diff --git a/doc/api/magic-plot.md b/doc/api/magic-plot.md index 9e3ed7b00..63d9e0f95 100644 --- a/doc/api/magic-plot.md +++ b/doc/api/magic-plot.md @@ -153,7 +153,9 @@ When plotting a histogram, it divides a range with the number of bins - 1 to cal +++ -### Number of bins +### Specifying bins + +Bins allow you to set the number of bins in a histogram, and it's useful when you are interested in the overall distribution. ```{code-cell} ipython3 %sqlplot histogram --table penguins.csv --column body_mass_g --bins 100 @@ -161,7 +163,7 @@ When plotting a histogram, it divides a range with the number of bins - 1 to cal ### Specifying breaks -Breaks allow you to set custom intervals for a histogram. You can specify breaks by passing desired each end and break points separated by whitespace after `-B/--breaks`. Since those break points define a range of data points to plot, bar width, and number of bars in a histogram, make sure to pass more than 1 point that is strictly increasing and includes at least one data point. +Breaks allow you to set custom intervals for a histogram. It is useful when you want to view distribution within a specific range. You can specify breaks by passing desired each end and break points separated by whitespace after `-B/--breaks`. Since those break points define a range of data points to plot, bar width, and number of bars in a histogram, make sure to pass more than 1 point that is strictly increasing and includes at least one data point. ```{code-cell} ipython3 %sqlplot histogram --table penguins.csv --column body_mass_g --breaks 3200 3400 3600 3800 4000 4200 4400 4600 4800 @@ -169,7 +171,7 @@ Breaks allow you to set custom intervals for a histogram. You can specify breaks ### Specifying binwidth -Binwidth allows you to set the width of bins in a histogram. To specify the binwidth, pass a desired width after `-W/--binwidth`. Since the binwidth determines details of distribution, make sure to pass a suitable positive numeric value based on your data. +Binwidth allows you to set the width of bins in a histogram. It is useful when you directly aim to adjust the granularity of the histogram. To specify the binwidth, pass a desired width after `-W/--binwidth`. Since the binwidth determines details of distribution, make sure to pass a suitable positive numeric value based on your data. ```{code-cell} ipython3 %sqlplot histogram --table penguins.csv --column body_mass_g --binwidth 150 diff --git a/src/sql/plot.py b/src/sql/plot.py index e13d36483..1cd94bf0a 100644 --- a/src/sql/plot.py +++ b/src/sql/plot.py @@ -8,7 +8,8 @@ from sql import exceptions, display from sql.stats import _summary_stats -from sql.util import pretty_print +from sql.util import _are_numeric_values, validate_mutually_exclusive_args +from sql.display import message try: import matplotlib.pyplot as plt @@ -265,10 +266,6 @@ def _min_max(con, table, column, with_=None, use_backticks=False): return min_, max_ -def _are_numeric_values(*values): - return all([isinstance(value, (int, float)) for value in values]) - - def _get_bar_width(ax, bins, bin_size, binwidth): """ Return a single bar width based on number of bins @@ -386,26 +383,15 @@ def histogram( "pass a positive value." ) binwidth = float(binwidth) - elif binwidth is None: - pass - else: + elif binwidth is not None: raise exceptions.ValueError( f"Binwidth given : {binwidth}. When using binwidth, please ensure to " "pass a numeric value." ) - specified_args = [ - args - for args, specified in zip( - ["bins", "breaks", "binwidth"], [bins, breaks, binwidth] - ) - if specified - ] - if len(specified_args) > 1: - raise exceptions.ValueError( - f"{pretty_print(specified_args)} are specified. " - "You can only specify one of them." - ) + validate_mutually_exclusive_args( + ["bins", "breaks", "binwidth"], [bins, breaks, binwidth] + ) ax = ax or plt.gca() payload["connection_info"] = conn._get_database_information() @@ -640,6 +626,11 @@ def _histogram( range_ = max_ - min_ if binwidth: bin_size = binwidth + if binwidth > range_: + message( + f"Specified binwidth {binwidth} is larger than " + f"the range {range_}. Please choose a smaller binwidth." + ) else: bin_size = range_ / (bins - 1) template_ = """ diff --git a/src/sql/util.py b/src/sql/util.py index 424852ba8..938612f36 100644 --- a/src/sql/util.py +++ b/src/sql/util.py @@ -494,3 +494,16 @@ def get_default_configs(sql): del default_configs["parent"] del default_configs["config"] return default_configs + + +def _are_numeric_values(*values): + return all([isinstance(value, (int, float)) for value in values]) + + +def validate_mutually_exclusive_args(arg_names, args): + specified_args = [arg_name for arg_name, arg in zip(arg_names, args) if arg] + if len(specified_args) > 1: + raise exceptions.ValueError( + f"{pretty_print(specified_args)} are specified. " + "You can only specify one of them." + ) diff --git a/src/tests/test_magic_plot.py b/src/tests/test_magic_plot.py index 54533c60b..354b5a4c0 100644 --- a/src/tests/test_magic_plot.py +++ b/src/tests/test_magic_plot.py @@ -156,6 +156,16 @@ def test_validate_breaks_arguments(load_penguin, ip, cell, error_message): "please ensure to pass a positive value." ), ], + [ + ( + "%sqlplot histogram --table penguins.csv --column body_mass_g " + "--binwidth -10" + ), + ( + "Binwidth given : -10.0. When using binwidth, " + "please ensure to pass a positive value." + ), + ], ], ) def test_validate_binwidth_arguments(load_penguin, ip, cell, error_message): @@ -166,6 +176,27 @@ def test_validate_binwidth_arguments(load_penguin, ip, cell, error_message): assert excinfo.value.error_type == "ValueError" +def test_validate_binwidth_text_argument(tmp_empty, ip): + with pytest.raises(UsageError) as excinfo: + ip.run_cell( + "%sqlplot histogram --table penguins.csv " + "--column body_mass_g --binwidth test" + ) + + assert "argument -W/--binwidth: invalid float value: 'test'" == str(excinfo.value) + + +def test_binwidth_larger_than_range(load_penguin, ip, capsys): + ip.run_cell( + "%sqlplot histogram --table penguins.csv --column body_mass_g --binwidth 3601" + ) + out, _ = capsys.readouterr() + assert ( + "Specified binwidth 3601.0 is larger than the range 3600. " + "Please choose a smaller binwidth." + ) in out + + @_cleanup_cm() @pytest.mark.parametrize( "cell", @@ -530,13 +561,20 @@ def test_hist_breaks(load_penguin, ip): ) +@pytest.mark.parametrize( + "binwidth", + [ + "--binwidth", + "-W", + ], +) @_cleanup_cm() @image_comparison( baseline_images=["hist_binwidth"], extensions=["png"], remove_text=True ) -def test_hist_binwidth(load_penguin, ip): +def test_hist_binwidth(load_penguin, ip, binwidth): ip.run_cell( - "%sqlplot histogram --table penguins.csv --column body_mass_g --binwidth 150" + f"%sqlplot histogram --table penguins.csv --column body_mass_g {binwidth} 150" ) From 28157dd8a8a81bc78b44ba91b168617bca37bacc Mon Sep 17 00:00:00 2001 From: SangGyu An Date: Tue, 15 Aug 2023 17:04:27 -0700 Subject: [PATCH 3/3] fix --- src/sql/util.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/sql/util.py b/src/sql/util.py index 938612f36..a8d91efcc 100644 --- a/src/sql/util.py +++ b/src/sql/util.py @@ -501,6 +501,17 @@ def _are_numeric_values(*values): def validate_mutually_exclusive_args(arg_names, args): + """ + Raises ValueError if a list of values from arg_names filtered by + args' boolean representations is longer than one. + + Parameters + ---------- + arg_names : list + args' names in string + args : list + args values + """ specified_args = [arg_name for arg_name, arg in zip(arg_names, args) if arg] if len(specified_args) > 1: raise exceptions.ValueError(