From 935063494753bb4ab4ed84280a917bef05da5da8 Mon Sep 17 00:00:00 2001 From: nkorinek Date: Thu, 27 Feb 2020 12:23:00 -0700 Subject: [PATCH 01/12] Add a get and assert function for bin midpoints, as well as tests for those functions --- matplotcheck/base.py | 55 +++++++++++++++++++- matplotcheck/tests/test_base_data.py | 75 ++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+), 1 deletion(-) diff --git a/matplotcheck/base.py b/matplotcheck/base.py index fe828643..fad0577b 100644 --- a/matplotcheck/base.py +++ b/matplotcheck/base.py @@ -1195,10 +1195,22 @@ def get_bin_values(self): Int : The number of bins in the histogram""" - bin_values = self.get_xy(xtime=False)["y"].tolist() + bin_values = self.get_xy()["y"].tolist() return bin_values + def get_bin_midpoints(self): + """Returns the middle value of each bin in a histogram + + Returns + ------- + Int : + The number of bins in the histogram""" + + bin_midpoints = self.get_xy()["x"].tolist() + + return bin_midpoints + def assert_bin_values( self, bin_values, @@ -1261,3 +1273,44 @@ def assert_bin_values( ) except AssertionError: raise AssertionError(message) + + def assert_bin_midpoints( + self, + bin_midpoints, + message="Did not find expected bin midpoints in plot", + ): + """ + Asserts that the middle values of histogram bins match `bin_midpoints`. + + Parameters + ---------- + bin_midpoints : list + A list of numbers representing the expected middles of bin values + covered by each consecutive bin (i.e. the midpoint of the bars in + the histogram). + message : string + The error message to be displayed if the bin mid point values do not + match `bin_midpoints` + + Raises + ------ + AssertionError + if the Values of histogram bins do not match `bin_midpoints` + """ + + plot_bin_midpoints = self.get_bin_midpoints() + + if not isinstance(bin_midpoints, list): + raise ValueError( + "Need to submit a list for expected bin midpoints." + ) + + if len(plot_bin_midpoints) != len(bin_midpoints): + raise ValueError("Bin midpoints lists lengths do no match.") + + try: + np.testing.assert_array_max_ulp( + np.array(plot_bin_midpoints), np.array(bin_midpoints) + ) + except AssertionError: + raise AssertionError(message) diff --git a/matplotcheck/tests/test_base_data.py b/matplotcheck/tests/test_base_data.py index fee04b3f..1e9fd0b4 100644 --- a/matplotcheck/tests/test_base_data.py +++ b/matplotcheck/tests/test_base_data.py @@ -369,3 +369,78 @@ def test_assert_bin_values_tolerance_fails(pt_hist_overlapping): pt_hist_overlapping.assert_bin_values(bin_values, tolerance=0.09) plt.close() + + +def test_assert_bin_midpoints_pass(pt_hist): + """Test that bin midpoints are correct""" + bins = [2.5, 3.5, 4.5, 5.5, 6.5, 7.5] + pt_hist.assert_bin_midpoints(bins) + + plt.close() + + +def test_assert_bin_midpoints_fail(pt_hist): + """Test that bin midpoints fail when incorrect""" + bins = [2, 3, 4, 5, 6, 7] + with pytest.raises(AssertionError, match="Did not find expected bin midp"): + pt_hist.assert_bin_midpoints(bins) + + plt.close() + + +def test_assert_bin_midpoints_fails_wrong_type(pt_hist): + """Test that bin midpoints fails when not handed a list""" + bins = (2.5, 3.5, 4.5, 5.5, 6.5, 7.5) + with pytest.raises(ValueError, match="Need to submit a list for expected"): + pt_hist.assert_bin_midpoints(bins) + + plt.close() + + +def test_assert_bin_midpoints_fails_wrong_length(pt_hist): + """Test that bin midpoints fails when not handed a list""" + bins = [2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8] + with pytest.raises(ValueError, match="Bin midpoints lists lengths do no "): + pt_hist.assert_bin_midpoints(bins) + + plt.close() + + +def test_assert_bin_midpoints_fail_custom_message(pt_hist): + """Test that bin midpoints fail when incorrect""" + bins = [2, 3, 4, 5, 6, 7] + message = "Test Message" + with pytest.raises(AssertionError, match="Test Message"): + pt_hist.assert_bin_midpoints(bins, message="Test Message") + + plt.close() + + +def test_assert_bin_midpoints_overlap_pass(pt_hist_overlapping): + """Test that bin midpoints are correct""" + bins = [2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5] + pt_hist_overlapping.assert_bin_midpoints(bins) + + plt.close() + + +def test_assert_bin_midpoints_overlap_fail(pt_hist_overlapping): + """Test that bin midpoints fail when incorrect""" + bins = [2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7] + with pytest.raises( + AssertionError, match="Did not find expected bin midpo" + ): + pt_hist_overlapping.assert_bin_midpoints(bins) + + plt.close() + + +def test_assert_bin_midpoints_overlap_length_fail(pt_hist_overlapping): + """Test that bin midpoints are correct""" + bins = [2.5, 3.5, 4.5, 5.5, 6.5, 7.5] + with pytest.raises( + ValueError, match="Bin midpoints lists lengths do no matc" + ): + pt_hist_overlapping.assert_bin_midpoints(bins) + + plt.close() From ef8db01d8b718bba57a18f6d8e76b7f13f974b3d Mon Sep 17 00:00:00 2001 From: nkorinek Date: Thu, 27 Feb 2020 12:25:18 -0700 Subject: [PATCH 02/12] Updated docstrings --- matplotcheck/tests/test_base_data.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/matplotcheck/tests/test_base_data.py b/matplotcheck/tests/test_base_data.py index 1e9fd0b4..51795a5c 100644 --- a/matplotcheck/tests/test_base_data.py +++ b/matplotcheck/tests/test_base_data.py @@ -398,7 +398,8 @@ def test_assert_bin_midpoints_fails_wrong_type(pt_hist): def test_assert_bin_midpoints_fails_wrong_length(pt_hist): - """Test that bin midpoints fails when not handed a list""" + """Test that bin midpoints fails when not handed a list with the wrong + length""" bins = [2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8] with pytest.raises(ValueError, match="Bin midpoints lists lengths do no "): pt_hist.assert_bin_midpoints(bins) @@ -407,7 +408,7 @@ def test_assert_bin_midpoints_fails_wrong_length(pt_hist): def test_assert_bin_midpoints_fail_custom_message(pt_hist): - """Test that bin midpoints fail when incorrect""" + """Test that correct error message is thrown when bin midpoints fail""" bins = [2, 3, 4, 5, 6, 7] message = "Test Message" with pytest.raises(AssertionError, match="Test Message"): @@ -417,7 +418,7 @@ def test_assert_bin_midpoints_fail_custom_message(pt_hist): def test_assert_bin_midpoints_overlap_pass(pt_hist_overlapping): - """Test that bin midpoints are correct""" + """Test that bin midpoints are correct with overlapping histograms""" bins = [2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5] pt_hist_overlapping.assert_bin_midpoints(bins) @@ -425,7 +426,8 @@ def test_assert_bin_midpoints_overlap_pass(pt_hist_overlapping): def test_assert_bin_midpoints_overlap_fail(pt_hist_overlapping): - """Test that bin midpoints fail when incorrect""" + """Test that bin midpoints fail with overlapping histograms when + incorrect""" bins = [2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7] with pytest.raises( AssertionError, match="Did not find expected bin midpo" @@ -436,7 +438,8 @@ def test_assert_bin_midpoints_overlap_fail(pt_hist_overlapping): def test_assert_bin_midpoints_overlap_length_fail(pt_hist_overlapping): - """Test that bin midpoints are correct""" + """Test that bin midpoints fail with overlapping histograms when + incorrect length""" bins = [2.5, 3.5, 4.5, 5.5, 6.5, 7.5] with pytest.raises( ValueError, match="Bin midpoints lists lengths do no matc" From e850b8c7a158599b811d454d8ca8a82bf595ea6c Mon Sep 17 00:00:00 2001 From: nkorinek Date: Thu, 27 Feb 2020 12:39:24 -0700 Subject: [PATCH 03/12] Added changelog changes and fixed minor formatting issue --- CHANGELOG.md | 1 + matplotcheck/tests/test_base_data.py | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index de1bc962..ed7bd577 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +* Added arguments to get and assert the midpoint values of bins in a histogram (@nkorinek, #184) ## [0.1.2] * Created a vignette covering the testing of histograms (@ryla5068, #149) diff --git a/matplotcheck/tests/test_base_data.py b/matplotcheck/tests/test_base_data.py index 51795a5c..1306171a 100644 --- a/matplotcheck/tests/test_base_data.py +++ b/matplotcheck/tests/test_base_data.py @@ -410,7 +410,6 @@ def test_assert_bin_midpoints_fails_wrong_length(pt_hist): def test_assert_bin_midpoints_fail_custom_message(pt_hist): """Test that correct error message is thrown when bin midpoints fail""" bins = [2, 3, 4, 5, 6, 7] - message = "Test Message" with pytest.raises(AssertionError, match="Test Message"): pt_hist.assert_bin_midpoints(bins, message="Test Message") From 8c7a91accefdbaab91331fdfdfee915389884480 Mon Sep 17 00:00:00 2001 From: nkorinek Date: Tue, 3 Mar 2020 10:14:14 -0700 Subject: [PATCH 04/12] small flake8 fix --- matplotcheck/base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/matplotcheck/base.py b/matplotcheck/base.py index da7e8aa1..81cffa0e 100644 --- a/matplotcheck/base.py +++ b/matplotcheck/base.py @@ -1298,8 +1298,8 @@ def assert_bin_midpoints( covered by each consecutive bin (i.e. the midpoint of the bars in the histogram). message : string - The error message to be displayed if the bin mid point values do not - match `bin_midpoints` + The error message to be displayed if the bin mid point values do + not match `bin_midpoints` Raises ------ From 230a1732c16ad14224dbc04bb7193c7e3cefc686 Mon Sep 17 00:00:00 2001 From: nkorinek Date: Tue, 3 Mar 2020 11:41:03 -0700 Subject: [PATCH 05/12] Added midpoints functionatlity to the vignette for histogram testing --- examples/plot_histogram_testing.py | 53 ++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/examples/plot_histogram_testing.py b/examples/plot_histogram_testing.py index 454e406a..180d0f64 100644 --- a/examples/plot_histogram_testing.py +++ b/examples/plot_histogram_testing.py @@ -196,3 +196,56 @@ # When using tolerances, the ``tolerance`` argument is taken as a relative # tolerance. For more information, see the documentation for the # ``base.assert_bin_heights()`` method. + +################################################################################ +# Testing the Histogram Midpoints +# ------------------------------- +# So far, we have tested the histogram values as well as the number of bins +# the histogram has. It may also be useful to test that the data bins cover +# the range of values that they were expected to. In order to do this, we can +# test the midpoints of each bin to ensure that the data covered by each +# bin is as expected. This is tested very similarly to the bins values. +# Simply provide ``assert_bin_midpoints()`` with a list of the expected +# midpoints, and it will assert if they are accurate or not. In order to obtain +# the midpoints in a PlotTester object, you can use ``get_bin_midpoints()``, +# much like ``get_bin_values()``. +# +# For this example, we will create a plot tester object from a histogram plot, +# the same way we did for the bin values example. + +fig, ax = plt.subplots() +ax.hist(testing_data, bins=8, color="gold") + +midpoints_plot_hold = nb.convert_axes(plt, which_axes="current") +plot_tester_expected_3 = mpc.PlotTester(midpoints_plot_hold) +print(plot_tester_expected_3.get_bin_midpoints()) + +################################################################################ +# We got the values from the plot tester object! As you can see, the values +# that were collected are the midpoints for the values each histogram bin +# covers. Now we can test that they are asserted indeed correct with an +# assertion test. + +try: + plot_tester_expected_3.assert_bin_midpoints( + [-0.875, -0.625, -0.375, -0.125, 0.125, 0.375, 0.625, 0.875] + ) +except AssertionError as message: + print("AssertionError:", message) + +################################################################################ +# Here we can see that this will fail when given incorrect values. + +try: + plot_tester_expected_3.assert_bin_midpoints( + [-0.75, -0.5, -0.25, -0, 0.25, 0.5, 0.75, 1] + ) +except AssertionError as message: + print("AssertionError:", message) + +############################################################################### +# +# .. note:: +# Keep in mind this test is for the midpoints of the range that each bin +# covers. So if a bin covers all data that's in between 0 and 1, than the +# value given for that bin will be .5, not 0 or 1. From 8b3594eaf489101d59f5a0b8cf081f2e135b67d5 Mon Sep 17 00:00:00 2001 From: nkorinek Date: Thu, 19 Mar 2020 16:39:37 -0600 Subject: [PATCH 06/12] Adding in changes suggested on GitHub1 --- examples/plot_histogram_testing.py | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/examples/plot_histogram_testing.py b/examples/plot_histogram_testing.py index 180d0f64..ff0efe72 100644 --- a/examples/plot_histogram_testing.py +++ b/examples/plot_histogram_testing.py @@ -28,7 +28,7 @@ ################################################################################ # Testing the Histogram # --------------------- -# Now you can make a PlotTester object and test the histogram. We'll test both +# Now you can make a PlotTester object and test the histogram. You'll test both # the number of bins and the values of those bins. ############################################################################### @@ -47,7 +47,7 @@ expected_bin_values = [341, 68, 40, 28, 23] plot_tester_1.assert_bin_values(expected_bin_values) ################################################################################ -# And we can also run some tests that will fail. +# And you can also run some tests that will fail. # try: plot_tester_1.assert_num_bins(6) @@ -200,9 +200,9 @@ ################################################################################ # Testing the Histogram Midpoints # ------------------------------- -# So far, we have tested the histogram values as well as the number of bins +# So far, you have tested the histogram values as well as the number of bins # the histogram has. It may also be useful to test that the data bins cover -# the range of values that they were expected to. In order to do this, we can +# the range of values that they were expected to. In order to do this, you can # test the midpoints of each bin to ensure that the data covered by each # bin is as expected. This is tested very similarly to the bins values. # Simply provide ``assert_bin_midpoints()`` with a list of the expected @@ -210,20 +210,25 @@ # the midpoints in a PlotTester object, you can use ``get_bin_midpoints()``, # much like ``get_bin_values()``. # -# For this example, we will create a plot tester object from a histogram plot, -# the same way we did for the bin values example. +# For this example, you will create a plot tester object from a histogram plot, +# the same way you did for the bin values example. fig, ax = plt.subplots() ax.hist(testing_data, bins=8, color="gold") -midpoints_plot_hold = nb.convert_axes(plt, which_axes="current") -plot_tester_expected_3 = mpc.PlotTester(midpoints_plot_hold) +# If you were running this in a notebook, the commented out line below would +# store the matplotlib object. However, in this example, you can just grab the +# axes object directly. + +# midpoints_plot_hold = nb.convert_axes(plt, which_axes="current") + +plot_tester_expected_3 = mpc.PlotTester(ax) print(plot_tester_expected_3.get_bin_midpoints()) ################################################################################ -# We got the values from the plot tester object! As you can see, the values +# You got the values from the plot tester object! As you can see, the values # that were collected are the midpoints for the values each histogram bin -# covers. Now we can test that they are asserted indeed correct with an +# covers. Now you can test that they are asserted indeed correct with an # assertion test. try: @@ -234,7 +239,7 @@ print("AssertionError:", message) ################################################################################ -# Here we can see that this will fail when given incorrect values. +# Here you can see that this will fail when given incorrect values. try: plot_tester_expected_3.assert_bin_midpoints( From faeed03e45c48aa966ab599b2f73e76c36a9ad11 Mon Sep 17 00:00:00 2001 From: nkorinek Date: Thu, 19 Mar 2020 16:42:04 -0600 Subject: [PATCH 07/12] Fixed function description --- matplotcheck/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matplotcheck/base.py b/matplotcheck/base.py index 98ce403f..6bdcc12c 100644 --- a/matplotcheck/base.py +++ b/matplotcheck/base.py @@ -1211,7 +1211,7 @@ def get_bin_values(self): return bin_values def get_bin_midpoints(self): - """Returns the middle value of each bin in a histogram + """Returns the mid point value of each bin in a histogram Returns ------- From ee2cfa760961e36e8b682563b820af7022db9a50 Mon Sep 17 00:00:00 2001 From: nkorinek Date: Fri, 20 Mar 2020 12:10:58 -0600 Subject: [PATCH 08/12] Took out all instances of in example --- examples/plot_histogram_testing.py | 38 ++++++++++++------------------ 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/examples/plot_histogram_testing.py b/examples/plot_histogram_testing.py index ff0efe72..8be95362 100644 --- a/examples/plot_histogram_testing.py +++ b/examples/plot_histogram_testing.py @@ -14,7 +14,6 @@ import matplotlib.pyplot as plt import matplotcheck.base as mpc -import matplotcheck.notebook as nb import numpy as np @@ -23,12 +22,16 @@ fig, ax = plt.subplots() ax.hist(data, bins=5, color="gold") -plot_1_hold = nb.convert_axes(plt, which_axes="current") +# If you were running this in a notebook, the commented out line below would +# store the matplotlib object. However, in this example, you can just grab the +# axes object directly. + +# plot_1_hold = nb.convert_axes(plt, which_axes="current") ################################################################################ # Testing the Histogram # --------------------- -# Now you can make a PlotTester object and test the histogram. You'll test both +# Now you can make a ``PlotTester`` object and test the histogram. You'll test both # the number of bins and the values of those bins. ############################################################################### @@ -40,7 +43,7 @@ # the value of the first bin in the above histogram is 341. Note that the # height of the first bar is also 341. -plot_tester_1 = mpc.PlotTester(plot_1_hold) +plot_tester_1 = mpc.PlotTester(ax) plot_tester_1.assert_num_bins(5) @@ -85,8 +88,7 @@ fig, ax = plt.subplots() ax.hist(expected_data, bins=8, color="gold") -expected_plot_hold = nb.convert_axes(plt, which_axes="current") -plot_tester_expected = mpc.PlotTester(expected_plot_hold) +plot_tester_expected = mpc.PlotTester(ax) print(plot_tester_expected.get_bin_values()) ################################################################################ @@ -101,10 +103,9 @@ testing_data = np.sin(np.arange(2 * np.pi, 4 * np.pi, np.pi / 50)) fig, ax = plt.subplots() ax.hist(testing_data, bins=8, color="orange") -testing_plot_hold = nb.convert_axes(plt, which_axes="current") # Testing the histogram against the expected bin values -plot_tester_testing = mpc.PlotTester(testing_plot_hold) +plot_tester_testing = mpc.PlotTester(ax) plot_tester_testing.assert_bin_values( [23.0, 10.0, 8.0, 9.0, 9.0, 8.0, 10.0, 23.0] ) @@ -132,8 +133,7 @@ # the ``assert_bin_values()`` method. # # You will start by making two histograms with slightly different data and -# storing the plots with ``nb.convert_axes()``. The gold plot will serve as the -# expected plot, and the orange plot will serve as the testing plot. +# converting the plots to ``PlotTester`` objects. expected_data = 0.1 * np.power(np.arange(0, 10, 0.1), 2) bins = np.arange(0, 10, 1) @@ -141,7 +141,7 @@ fig1, ax2 = plt.subplots() ax2.hist(expected_data, color="gold", bins=bins) -expected_plot_2_hold = nb.convert_axes(plt, which_axes="current") +plot_tester_expected_2 = mpc.PlotTester(ax2) ################################################################################ @@ -150,17 +150,15 @@ fig2, ax2 = plt.subplots() ax2.hist(test_data, color="orange", bins=bins) -testing_plot_2_hold = nb.convert_axes(plt, which_axes="current") +plot_tester_testing_2 = mpc.PlotTester(ax2) ################################################################################ -# Now you will create a `PlotTester` object for each plot. This allows you to -# extract the expected bin values from the expected plot and allows you to -# test the testing plot. +# With the ``PlotTester`` objects you created from the axes, you can now +# extract the expected bin values from the expected plot and test the testing +# plot. -plot_tester_expected_2 = mpc.PlotTester(expected_plot_2_hold) bins_expected_2 = plot_tester_expected_2.get_bin_values() -plot_tester_testing_2 = mpc.PlotTester(testing_plot_2_hold) ################################################################################ # You'll notice that the test (orange) plot differs somewhat from the @@ -216,12 +214,6 @@ fig, ax = plt.subplots() ax.hist(testing_data, bins=8, color="gold") -# If you were running this in a notebook, the commented out line below would -# store the matplotlib object. However, in this example, you can just grab the -# axes object directly. - -# midpoints_plot_hold = nb.convert_axes(plt, which_axes="current") - plot_tester_expected_3 = mpc.PlotTester(ax) print(plot_tester_expected_3.get_bin_midpoints()) From ff27823ef8bc890e45e12cb40d3461753477af69 Mon Sep 17 00:00:00 2001 From: Leah Wasser Date: Fri, 20 Mar 2020 14:49:54 -0600 Subject: [PATCH 09/12] update docs --- ...gram_testing.py => plot_test_histogram.py} | 192 ++++++++++-------- 1 file changed, 102 insertions(+), 90 deletions(-) rename examples/{plot_histogram_testing.py => plot_test_histogram.py} (59%) diff --git a/examples/plot_histogram_testing.py b/examples/plot_test_histogram.py similarity index 59% rename from examples/plot_histogram_testing.py rename to examples/plot_test_histogram.py index 8be95362..9719c763 100644 --- a/examples/plot_histogram_testing.py +++ b/examples/plot_test_histogram.py @@ -1,16 +1,19 @@ """ -Testing Histograms -================== +Test Histogram Plots with Matplotcheck +====================================== -These are some examples of using the basic functionality of MatPlotCheck -to test histogram plots in Python. +Below you will find some examples of how to use MatPlotCheck +to test histogram plots created with Matplotlib in Python. """ -################################################################################ +############################################################################### # Setup # ----- # You will start by importing the required packages and plotting a histogram. +# Once you have created your plot, you will created a Matplotcheck +# ``PlotTester`` object by providing the Matplotlib axis object to +# ``PlotTester``. import matplotlib.pyplot as plt import matplotcheck.base as mpc @@ -22,34 +25,33 @@ fig, ax = plt.subplots() ax.hist(data, bins=5, color="gold") -# If you were running this in a notebook, the commented out line below would -# store the matplotlib object. However, in this example, you can just grab the -# axes object directly. - -# plot_1_hold = nb.convert_axes(plt, which_axes="current") +# Create a Matplotcheck PlotTester object +plot_tester_1 = mpc.PlotTester(ax) -################################################################################ -# Testing the Histogram +############################################################################### +# Test a Histogram Plot # --------------------- -# Now you can make a ``PlotTester`` object and test the histogram. You'll test both -# the number of bins and the values of those bins. +# Once you have created a PlotTester object, you are ready to test various +# parts of your plot. Below, you test both +# the number of bins and the values associated with those bins. ############################################################################### # # .. note:: # Throughout this vignette, the term `bin value` is used to describe the # number of datapoints that fall within a bin. In other words, a bin's value -# is equal to the height of the bar correspondign to that bin. For example, +# is equal to the height of the bar corresponding to that bin. For example, # the value of the first bin in the above histogram is 341. Note that the # height of the first bar is also 341. -plot_tester_1 = mpc.PlotTester(ax) - +# Test that the histogram plot has 5 bins plot_tester_1.assert_num_bins(5) +# Test that the histogram bin values (the height of each bin) is as expected expected_bin_values = [341, 68, 40, 28, 23] plot_tester_1.assert_bin_values(expected_bin_values) -################################################################################ + +############################################################################### # And you can also run some tests that will fail. # try: @@ -62,105 +64,102 @@ except AssertionError as message: print("AssertionError:", message) -################################################################################ +############################################################################### # Determining Expected Values # --------------------------- -# With a histogram, you may not know the values you expect to find for each bin -# before you begin testing. (More simply, you probably know how you expect a -# histogram to look and how you expect it to be made. But you might not know -# the exact height of each bar in that histogram.) In this case, matplotcheck -# provides a method for extracting the bin values from an existing histogram: -# ``get_bin_values()``. +# You can use the MatPlotCheck ``get_bin_values()`` method to extract the bin +# values that are expected for a plot. This is helpful if you are using a tool +# like nbgrader to create the the expected plot outcomes in a homework +# assignment. # -# To use this, you can create a histogram however you think it should be created -# (this will be called the expected histogram) and use it as a reference. Then -# you can extract the bin values from it (called the expected values). These -# expected values can be used to test whether another histogram (e.g. a -# student's histogram) also contains the expected values. +# To extract bin values from an expected plot you first create the expected +# histogram plot that you will use to grade your assignment (or htat you expect +# as an outcome from a test). Next, you create a PlotTester object from that +# plot. Finally, you call the ``get_bin_values()`` method to grab the expected +# bin values from that plot. # -# For this example, you will start by creating a histogram that will serve as -# your expected histogram, and then extracting the expected values from it. To -# do this, you need to create a `PlotTester` object from it and use the -# ``get_bin_values()`` method. +# The steps outlined above are implemented below. expected_data = np.sin(np.arange(0, 2 * np.pi, np.pi / 50)) +# Create the expected plot fig, ax = plt.subplots() ax.hist(expected_data, bins=8, color="gold") +# Create a Matplotcheck PlotTester object from the axis object plot_tester_expected = mpc.PlotTester(ax) +# Get bin values from the expected plot print(plot_tester_expected.get_bin_values()) -################################################################################ -# Great! Now you know the bin values that you expect to see when you test a -# plot. -# -# Now you can create another histogram (our testing histogram) and check -# whether it matches the expected histogram (i.e. check wether its bin values -# match the expected bin values). - -# Create and plot the testing histogram -testing_data = np.sin(np.arange(2 * np.pi, 4 * np.pi, np.pi / 50)) +############################################################################### +# This example assumes that you are creating tests for a student +# assignment. Once you have created the PlotTester object for the expected +# plot (this is the answer to the assignment that you expect the student to +# come to), +# you can then test the student plot to see if it matches expected bin values. +# Below another plot is created that represents the student submitted plot. + +# Create and plot the student submitted histogram +data = np.sin(np.arange(2 * np.pi, 4 * np.pi, np.pi / 50)) fig, ax = plt.subplots() -ax.hist(testing_data, bins=8, color="orange") +ax.hist(data, bins=8, color="orange") -# Testing the histogram against the expected bin values +# Test the student submitted histogram bin values against the expected +# bin values (the correct answer to the assigned plot) plot_tester_testing = mpc.PlotTester(ax) plot_tester_testing.assert_bin_values( [23.0, 10.0, 8.0, 9.0, 9.0, 8.0, 10.0, 23.0] ) -################################################################################ -# Since ``assert_bin_values()`` did not raise an ``AssertionError``, you know -# that the test passed. This means the testing histogram had the same bin values -# as the expected histogram. - +############################################################################### +# +# Above, ``assert_bin_values()`` did not raise an ``AssertionError``. This +# means that the test passed and the student submitted plot has the correct +# histogram bins. +# ############################################################################### # # .. note:: -# In this example, you have created the expected histogram and the testing -# histogram in the same file. Normally you would create the expected histogram -# in one location, extract the expected bin values from it, and use those to -# test the testing histogram in another location (e.g. within a student's -# homework assignment.) - - -################################################################################ +# In this example, you created the expected histogram (the homework answer) +# and the student submitted histogram in the same file. +# +############################################################################### # Testing with Tolerances # ----------------------- # In some cases, you might want to run a test that doesn't require the bin -# values to match exactly. For this, you can use the ``tolerance`` argument of -# the ``assert_bin_values()`` method. +# values to match exactly. For example, it might be ok if the values are +# a few tenths off. To allow for some "wiggle room" in the expected answer, +# you can use the ``tolerance`` parameter of the ``assert_bin_values()`` +# method. # # You will start by making two histograms with slightly different data and -# converting the plots to ``PlotTester`` objects. +# storing the plots with ``nb.convert_axes()``. The gold plot will serve as the +# expected plot, and the orange plot will serve as the testing plot. +# +# You will then create a `PlotTester` object for each plot. This allows you to +# extract the expected bin values from the expected plot and use those value to +# test the testing plot. expected_data = 0.1 * np.power(np.arange(0, 10, 0.1), 2) bins = np.arange(0, 10, 1) -fig1, ax2 = plt.subplots() -ax2.hist(expected_data, color="gold", bins=bins) +fig1, ax1 = plt.subplots() +ax1.hist(expected_data, color="gold", bins=bins) -plot_tester_expected_2 = mpc.PlotTester(ax2) +# Create plot tester object +plot_tester_expected_1 = mpc.PlotTester(ax1) +# Get expected bin values +bins_expected_1 = plot_tester_expected_1.get_bin_values() -################################################################################ +############################################################################### test_data = 0.1995 * np.power(np.arange(0, 10, 0.1), 1.7) - fig2, ax2 = plt.subplots() ax2.hist(test_data, color="orange", bins=bins) - +# Create plot tester object plot_tester_testing_2 = mpc.PlotTester(ax2) -################################################################################ -# With the ``PlotTester`` objects you created from the axes, you can now -# extract the expected bin values from the expected plot and test the testing -# plot. - -bins_expected_2 = plot_tester_expected_2.get_bin_values() - - -################################################################################ +############################################################################### # You'll notice that the test (orange) plot differs somewhat from the # expected (gold) plot, but still has a similar shape and similar bin # values. @@ -168,23 +167,23 @@ # If you test it without the ``tolerance`` argument, the assertion will fail. try: - plot_tester_testing_2.assert_bin_values(bins_expected_2) + plot_tester_testing_2.assert_bin_values(bins_expected_1) except AssertionError as message: print("AssertionError:", message) -################################################################################ -# However, if you set a tolerance, the assertion can pass. Here you will test it -# with ``tolerance=0.2``. +############################################################################### +# However, if you set a tolerance, the assertion can pass. Here you will test +# it with ``tolerance=0.2``. -plot_tester_testing_2.assert_bin_values(bins_expected_2, tolerance=0.2) +plot_tester_testing_2.assert_bin_values(bins_expected_1, tolerance=0.2) -################################################################################ +############################################################################### # Because no ``AssertionError`` is raised, you know that the test passed with # a tolerance of 0.2. However, the test will not pass with a tolerance that is # too small; the test will fail with ``tolerance=0.1``. try: - plot_tester_testing_2.assert_bin_values(bins_expected_2, tolerance=0.1) + plot_tester_testing_2.assert_bin_values(bins_expected_1, tolerance=0.1) except AssertionError as message: print("AssertionError:", message) @@ -195,9 +194,9 @@ # tolerance. For more information, see the documentation for the # ``base.assert_bin_heights()`` method. -################################################################################ -# Testing the Histogram Midpoints -# ------------------------------- +############################################################################### +# Test Histogram Midpoints +# ------------------------ # So far, you have tested the histogram values as well as the number of bins # the histogram has. It may also be useful to test that the data bins cover # the range of values that they were expected to. In order to do this, you can @@ -212,12 +211,18 @@ # the same way you did for the bin values example. fig, ax = plt.subplots() -ax.hist(testing_data, bins=8, color="gold") +ax.hist(test_data, bins=8, color="gold") + +# If you were running this in a notebook, the commented out line below would +# store the matplotlib object. However, in this example, you can just grab the +# axes object directly. + +# midpoints_plot_hold = nb.convert_axes(plt, which_axes="current") plot_tester_expected_3 = mpc.PlotTester(ax) print(plot_tester_expected_3.get_bin_midpoints()) -################################################################################ +############################################################################### # You got the values from the plot tester object! As you can see, the values # that were collected are the midpoints for the values each histogram bin # covers. Now you can test that they are asserted indeed correct with an @@ -230,7 +235,7 @@ except AssertionError as message: print("AssertionError:", message) -################################################################################ +############################################################################### # Here you can see that this will fail when given incorrect values. try: @@ -246,3 +251,10 @@ # Keep in mind this test is for the midpoints of the range that each bin # covers. So if a bin covers all data that's in between 0 and 1, than the # value given for that bin will be .5, not 0 or 1. + + +# .. note:: +# If you are working on tests for jupyter notebooks, you can call the +# line below to capture the student cell in a notebook. Then you can +# Use that object for testing. +# testing_plot_2_hold = nb.convert_axes(plt, which_axes="current"). From bdad6e1821b3e00d87519a516ba72b66b5167e09 Mon Sep 17 00:00:00 2001 From: nkorinek Date: Fri, 20 Mar 2020 15:03:45 -0600 Subject: [PATCH 10/12] Fixed small bug with section titles --- examples/plot_test_histogram.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/plot_test_histogram.py b/examples/plot_test_histogram.py index 9719c763..5db81094 100644 --- a/examples/plot_test_histogram.py +++ b/examples/plot_test_histogram.py @@ -112,17 +112,18 @@ ) ############################################################################### -# # Above, ``assert_bin_values()`` did not raise an ``AssertionError``. This # means that the test passed and the student submitted plot has the correct # histogram bins. # + ############################################################################### # # .. note:: # In this example, you created the expected histogram (the homework answer) # and the student submitted histogram in the same file. # + ############################################################################### # Testing with Tolerances # ----------------------- From 00408089e1f7661cee72d55185a2403e15c1b927 Mon Sep 17 00:00:00 2001 From: Leah Wasser Date: Mon, 23 Mar 2020 11:02:53 -0600 Subject: [PATCH 11/12] Update matplotcheck/tests/test_base_data.py --- matplotcheck/tests/test_base_data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matplotcheck/tests/test_base_data.py b/matplotcheck/tests/test_base_data.py index 57372591..001986c2 100644 --- a/matplotcheck/tests/test_base_data.py +++ b/matplotcheck/tests/test_base_data.py @@ -442,7 +442,7 @@ def test_assert_bin_midpoints_overlap_length_fail(pt_hist_overlapping): incorrect length""" bins = [2.5, 3.5, 4.5, 5.5, 6.5, 7.5] with pytest.raises( - ValueError, match="Bin midpoints lists lengths do no matc" + ValueError, match="Bin midpoints lists lengths do no match" ): pt_hist_overlapping.assert_bin_midpoints(bins) From 6f9f0579f173a43dd851d216a9d1f0fede0caed1 Mon Sep 17 00:00:00 2001 From: nkorinek Date: Mon, 23 Mar 2020 15:29:44 -0600 Subject: [PATCH 12/12] reworded changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5200a075..ae8af8c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] -* Added arguments to get and assert the midpoint values of bins in a histogram (@nkorinek, #184) +* Added functions to get and assert the midpoint values of bins in a histogram (@nkorinek, #184) * Created tests for the vector module (@nkorinek, #209) * Created functions to test point geometries in VectorTester (@nkorinek, #176) * made `assert_string_contains()` accept correct strings with spaces in them (@nkorinek, #182)