From fe39d3cf08560ea57ae9e98d7fe3ff03dff4a7f6 Mon Sep 17 00:00:00 2001 From: David BROCHART Date: Tue, 17 Mar 2015 16:24:21 +0100 Subject: [PATCH 01/11] Fix for issue #9671 --- pandas/tools/plotting.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/pandas/tools/plotting.py b/pandas/tools/plotting.py index cf9c890823f8f..fc4530450d629 100644 --- a/pandas/tools/plotting.py +++ b/pandas/tools/plotting.py @@ -871,12 +871,17 @@ def _validate_color_args(self): "simultaneously. Using 'color'") if 'color' in self.kwds and self.style is not None: + if com.is_list_like(self.style): + styles = self.style + else: + styles = [self.style] # need only a single match - if re.match('^[a-z]+?', self.style) is not None: - raise ValueError("Cannot pass 'style' string with a color " - "symbol and 'color' keyword argument. Please" - " use one or the other or pass 'style' " - "without a color symbol") + for s in styles: + if re.match('^[a-z]+?', s) is not None: + raise ValueError("Cannot pass 'style' string with a color " + "symbol and 'color' keyword argument. Please" + " use one or the other or pass 'style' " + "without a color symbol") def _iter_data(self, data=None, keep_index=False, fillna=None): if data is None: From 07fff6788170ea9774f1fddf446b74a4935f6579 Mon Sep 17 00:00:00 2001 From: "David BROCHART (home)" Date: Wed, 18 Mar 2015 15:41:39 +0100 Subject: [PATCH 02/11] Added test for bug fix of issue #9671 --- pandas/tests/test_graphics.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pandas/tests/test_graphics.py b/pandas/tests/test_graphics.py index 1cb11179b2430..731313fcdab72 100644 --- a/pandas/tests/test_graphics.py +++ b/pandas/tests/test_graphics.py @@ -991,6 +991,18 @@ def test_plot(self): df = DataFrame({'x': [1, 2], 'y': [3, 4]}) with tm.assertRaises(TypeError): df.plot(kind='line', blarg=True) + try: + df.plot(color = ['red', 'black'], style = ['-', '--']) + df['x'].plot(color = 'red', style = '-') + except: + self.fail("Calling 'plot()' on a dataframe/series and passing both 'color' and 'style' arguments should be allowed if there is no color symbol in the style string(s)") + try: + df.plot(color = ['red', 'black'], style = ['k-', 'r--']) + df['x'].plot(color = 'red', style = 'k-') + except: + pass + else: + self.fail("Calling 'plot()' on a dataframe/series and passing both 'color' and 'style' arguments should raise an error if there is a color symbol in the style string(s)") df = DataFrame(np.random.rand(10, 3), index=list(string.ascii_letters[:10])) From 72c5bc1ebf81b34f45a3eebf9d116a717945a8d0 Mon Sep 17 00:00:00 2001 From: "David BROCHART (home)" Date: Wed, 18 Mar 2015 23:12:39 +0100 Subject: [PATCH 03/11] Made a separate test called test_color_and_style_arguments, made changes as suggested by TomAugspurger --- pandas/tests/test_graphics.py | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/pandas/tests/test_graphics.py b/pandas/tests/test_graphics.py index 731313fcdab72..9ac1e58a56bbb 100644 --- a/pandas/tests/test_graphics.py +++ b/pandas/tests/test_graphics.py @@ -991,18 +991,6 @@ def test_plot(self): df = DataFrame({'x': [1, 2], 'y': [3, 4]}) with tm.assertRaises(TypeError): df.plot(kind='line', blarg=True) - try: - df.plot(color = ['red', 'black'], style = ['-', '--']) - df['x'].plot(color = 'red', style = '-') - except: - self.fail("Calling 'plot()' on a dataframe/series and passing both 'color' and 'style' arguments should be allowed if there is no color symbol in the style string(s)") - try: - df.plot(color = ['red', 'black'], style = ['k-', 'r--']) - df['x'].plot(color = 'red', style = 'k-') - except: - pass - else: - self.fail("Calling 'plot()' on a dataframe/series and passing both 'color' and 'style' arguments should raise an error if there is a color symbol in the style string(s)") df = DataFrame(np.random.rand(10, 3), index=list(string.ascii_letters[:10])) @@ -1065,6 +1053,22 @@ def test_plot(self): self.assertEqual(len(axes), 1) self.assertIs(ax.get_axes(), axes[0]) + def test_color_and_style_arguments(self): + df = DataFrame({'x': [1, 2], 'y': [3, 4]}) + # passing both 'color' and 'style' arguments should be allowed + # if there is no color symbol in the style strings: + ax = df.plot(color = ['red', 'black'], style = ['-', '--']) + # check that the linestyles are correctly set: + linestyle = [line.get_linestyle() for line in ax.lines] + self.assertEqual(linestyle, ['-', '--']) + # check that the colors are correctly set: + color = [line.get_color() for line in ax.lines] + self.assertEqual(color, ['red', 'black']) + # passing both 'color' and 'style' arguments should not be allowed + # if there is a color symbol in the style strings: + with tm.assertRaises(ValueError): + df.plot(color = ['red', 'black'], style = ['k-', 'r--']) + def test_nonnumeric_exclude(self): df = DataFrame({'A': ["x", "y", "z"], 'B': [1, 2, 3]}) ax = df.plot() From 025de9d4ecd3650807f96a47165ec89eff4878e8 Mon Sep 17 00:00:00 2001 From: Tomaz Berisa Date: Fri, 3 Apr 2015 16:12:44 -0400 Subject: [PATCH 04/11] BUG: Fix for #9764 Values from range [1e-7, 5e-7] (for display.precision=7) not displaying 0 anymore --- pandas/core/format.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/format.py b/pandas/core/format.py index b21ca9050ffd0..7b8a3161b5e05 100644 --- a/pandas/core/format.py +++ b/pandas/core/format.py @@ -1996,7 +1996,7 @@ def _format_strings(self): # this is pretty arbitrary for now has_large_values = (abs_vals > 1e8).any() - has_small_values = ((abs_vals < 10 ** (-self.digits)) & + has_small_values = ((abs_vals < 10 ** (-self.digits+1)) & (abs_vals > 0)).any() if too_long and has_large_values: From e375dd7c32abcb4af4c4c368492a52c468ad1453 Mon Sep 17 00:00:00 2001 From: Tomaz Berisa Date: Fri, 3 Apr 2015 17:29:56 -0400 Subject: [PATCH 05/11] TST: Test for #9764 fix --- pandas/tests/test_format.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/pandas/tests/test_format.py b/pandas/tests/test_format.py index ce32c8af99a73..145fa78b387cd 100644 --- a/pandas/tests/test_format.py +++ b/pandas/tests/test_format.py @@ -2986,6 +2986,20 @@ def test_format(self): self.assertEqual(result[0], " 12") self.assertEqual(result[1], " 0") + def test_output_significant_digits(self): + # relevant to issue #9764 + d=pd.DataFrame({'col1':[9.999e-8, 1e-7, 1.0001e-7, 2e-7, 4.999e-7, 5e-7, 5.0001e-7, 6e-7, 9.999e-7, 1e-6, 1.0001e-6, 2e-6, 4.999e-6, 5e-6, 5.0001e-6, 6e-6]}) + + expected_output={ + (0,6):' col1\n0 9.999000e-08\n1 1.000000e-07\n2 1.000100e-07\n3 2.000000e-07\n4 4.999000e-07\n5 5.000000e-07', + (1,6):' col1\n1 1.000000e-07\n2 1.000100e-07\n3 2.000000e-07\n4 4.999000e-07\n5 5.000000e-07', + (1,8):' col1\n1 1.000000e-07\n2 1.000100e-07\n3 2.000000e-07\n4 4.999000e-07\n5 5.000000e-07\n6 5.000100e-07\n7 6.000000e-07', + (8,16):' col1\n8 9.999000e-07\n9 1.000000e-06\n10 1.000100e-06\n11 2.000000e-06\n12 4.999000e-06\n13 5.000000e-06\n14 5.000100e-06\n15 6.000000e-06', + (9,16):' col1\n9 0.000001\n10 0.000001\n11 0.000002\n12 0.000005\n13 0.000005\n14 0.000005\n15 0.000006' + } + + for k, v in expected_output.items(): + self.assertEqual(d[k[0]:k[1]].__str__(), v) class TestRepr_timedelta64(tm.TestCase): From 86a1404cb41ab1d8bd070fcc16e8c1eafa6909b5 Mon Sep 17 00:00:00 2001 From: Tomaz Berisa Date: Fri, 3 Apr 2015 17:48:38 -0400 Subject: [PATCH 06/11] TST: Test saves and restore context (#9764) --- pandas/tests/test_format.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pandas/tests/test_format.py b/pandas/tests/test_format.py index 145fa78b387cd..e3f458690d5f7 100644 --- a/pandas/tests/test_format.py +++ b/pandas/tests/test_format.py @@ -2987,7 +2987,13 @@ def test_format(self): self.assertEqual(result[1], " 0") def test_output_significant_digits(self): - # relevant to issue #9764 + # Issue #9764 + + # In case default display precision changes: + saved_option=pd.get_option('display.precision') + pd.set_option('display.precision', 7) + + # DataFrame from issue #9764 d=pd.DataFrame({'col1':[9.999e-8, 1e-7, 1.0001e-7, 2e-7, 4.999e-7, 5e-7, 5.0001e-7, 6e-7, 9.999e-7, 1e-6, 1.0001e-6, 2e-6, 4.999e-6, 5e-6, 5.0001e-6, 6e-6]}) expected_output={ @@ -3001,6 +3007,9 @@ def test_output_significant_digits(self): for k, v in expected_output.items(): self.assertEqual(d[k[0]:k[1]].__str__(), v) + # Restore precision + pd.set_option('display.precision', saved_option) + class TestRepr_timedelta64(tm.TestCase): def test_none(self): From 7857c4348d46ea92e2e7dcf5b9d03d91855f8117 Mon Sep 17 00:00:00 2001 From: Tomaz Berisa Date: Sat, 4 Apr 2015 17:39:59 -0400 Subject: [PATCH 07/11] CLN: Test code cleanup (#9764) --- pandas/tests/test_format.py | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/pandas/tests/test_format.py b/pandas/tests/test_format.py index e3f458690d5f7..1dcdbf12a6b59 100644 --- a/pandas/tests/test_format.py +++ b/pandas/tests/test_format.py @@ -2990,25 +2990,21 @@ def test_output_significant_digits(self): # Issue #9764 # In case default display precision changes: - saved_option=pd.get_option('display.precision') - pd.set_option('display.precision', 7) + with pd.option_context('display.precision', 7): + # DataFrame example from issue #9764 + d=pd.DataFrame({'col1':[9.999e-8, 1e-7, 1.0001e-7, 2e-7, 4.999e-7, 5e-7, 5.0001e-7, 6e-7, 9.999e-7, 1e-6, 1.0001e-6, 2e-6, 4.999e-6, 5e-6, 5.0001e-6, 6e-6]}) + + expected_output={ + (0,6):' col1\n0 9.999000e-08\n1 1.000000e-07\n2 1.000100e-07\n3 2.000000e-07\n4 4.999000e-07\n5 5.000000e-07', + (1,6):' col1\n1 1.000000e-07\n2 1.000100e-07\n3 2.000000e-07\n4 4.999000e-07\n5 5.000000e-07', + (1,8):' col1\n1 1.000000e-07\n2 1.000100e-07\n3 2.000000e-07\n4 4.999000e-07\n5 5.000000e-07\n6 5.000100e-07\n7 6.000000e-07', + (8,16):' col1\n8 9.999000e-07\n9 1.000000e-06\n10 1.000100e-06\n11 2.000000e-06\n12 4.999000e-06\n13 5.000000e-06\n14 5.000100e-06\n15 6.000000e-06', + (9,16):' col1\n9 0.000001\n10 0.000001\n11 0.000002\n12 0.000005\n13 0.000005\n14 0.000005\n15 0.000006' + } + + for (start, stop), v in expected_output.items(): + self.assertEqual(str(d[start:stop]), v) - # DataFrame from issue #9764 - d=pd.DataFrame({'col1':[9.999e-8, 1e-7, 1.0001e-7, 2e-7, 4.999e-7, 5e-7, 5.0001e-7, 6e-7, 9.999e-7, 1e-6, 1.0001e-6, 2e-6, 4.999e-6, 5e-6, 5.0001e-6, 6e-6]}) - - expected_output={ - (0,6):' col1\n0 9.999000e-08\n1 1.000000e-07\n2 1.000100e-07\n3 2.000000e-07\n4 4.999000e-07\n5 5.000000e-07', - (1,6):' col1\n1 1.000000e-07\n2 1.000100e-07\n3 2.000000e-07\n4 4.999000e-07\n5 5.000000e-07', - (1,8):' col1\n1 1.000000e-07\n2 1.000100e-07\n3 2.000000e-07\n4 4.999000e-07\n5 5.000000e-07\n6 5.000100e-07\n7 6.000000e-07', - (8,16):' col1\n8 9.999000e-07\n9 1.000000e-06\n10 1.000100e-06\n11 2.000000e-06\n12 4.999000e-06\n13 5.000000e-06\n14 5.000100e-06\n15 6.000000e-06', - (9,16):' col1\n9 0.000001\n10 0.000001\n11 0.000002\n12 0.000005\n13 0.000005\n14 0.000005\n15 0.000006' - } - - for k, v in expected_output.items(): - self.assertEqual(d[k[0]:k[1]].__str__(), v) - - # Restore precision - pd.set_option('display.precision', saved_option) class TestRepr_timedelta64(tm.TestCase): From ce988b417b4ca0c62b08c6ad52c80b813fad3ef4 Mon Sep 17 00:00:00 2001 From: Tomaz Berisa Date: Sat, 4 Apr 2015 17:54:32 -0400 Subject: [PATCH 08/11] DOC: Update whatsnew for 0.16.1 (#9764) --- doc/source/whatsnew/v0.16.1.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v0.16.1.txt b/doc/source/whatsnew/v0.16.1.txt index 8c49e2780ed06..6fc347cfeb273 100644 --- a/doc/source/whatsnew/v0.16.1.txt +++ b/doc/source/whatsnew/v0.16.1.txt @@ -79,3 +79,4 @@ Bug Fixes - Bug in ``Series.quantile`` on empty Series of type ``Datetime`` or ``Timedelta`` (:issue:`9675`) - Bug in ``where`` causing incorrect results when upcasting was required (:issue:`9731`) +- Bug in ``FloatArrayFormatter`` where decision boundary for displaying "small" floats in decimal format is off by one order of magnitude for a given display.precision (:issue:`9764`) From e9179feb290a5da3aafbda0efa882afff4415768 Mon Sep 17 00:00:00 2001 From: dsm054 Date: Sat, 28 Mar 2015 18:35:51 -0400 Subject: [PATCH 09/11] BUG: DataFrame.equals should not care about block order (GH #9330) --- doc/source/whatsnew/v0.16.1.txt | 1 + pandas/core/internals.py | 14 +++++++++++++- pandas/io/tests/test_pytables.py | 18 ++++++++++++++++-- pandas/tests/test_frame.py | 14 ++++++++++++++ pandas/tests/test_internals.py | 25 ++++++++++++++++++++++--- 5 files changed, 66 insertions(+), 6 deletions(-) diff --git a/doc/source/whatsnew/v0.16.1.txt b/doc/source/whatsnew/v0.16.1.txt index 05c762b91b925..4ca0ac88df2c5 100644 --- a/doc/source/whatsnew/v0.16.1.txt +++ b/doc/source/whatsnew/v0.16.1.txt @@ -71,6 +71,7 @@ Bug Fixes - Bug in ``transform`` causing length mismatch when null entries were present and a fast aggregator was being used (:issue:`9697`) +- Bug in ``equals`` causing false negatives when block order differed (:issue:`9330`) - Bug in ``DataFrame`` slicing may not retain metadata (:issue:`9776`) - Bug where ``TimdeltaIndex`` were not properly serialized in fixed ``HDFStore`` (:issue:`9635`) diff --git a/pandas/core/internals.py b/pandas/core/internals.py index 7a16fb2b6b0d7..9b2d366bfb2be 100644 --- a/pandas/core/internals.py +++ b/pandas/core/internals.py @@ -3310,8 +3310,20 @@ def equals(self, other): return False self._consolidate_inplace() other._consolidate_inplace() + if len(self.blocks) != len(other.blocks): + return False + + # canonicalize block order, using a tuple combining the type + # name and then mgr_locs because there might be unconsolidated + # blocks (say, Categorical) which can only be distinguished by + # the iteration order + def canonicalize(block): + return (block.dtype.name, block.mgr_locs.as_array.tolist()) + + self_blocks = sorted(self.blocks, key=canonicalize) + other_blocks = sorted(other.blocks, key=canonicalize) return all(block.equals(oblock) for block, oblock in - zip(self.blocks, other.blocks)) + zip(self_blocks, other_blocks)) class SingleBlockManager(BlockManager): diff --git a/pandas/io/tests/test_pytables.py b/pandas/io/tests/test_pytables.py index acdc991c92efe..03e7a8eae549d 100644 --- a/pandas/io/tests/test_pytables.py +++ b/pandas/io/tests/test_pytables.py @@ -4584,19 +4584,33 @@ def test_duplicate_column_name(self): with ensure_clean_path(self.path) as path: self.assertRaises(ValueError, df.to_hdf, path, 'df', format='fixed') + df.to_hdf(path, 'df', format='table') + other = read_hdf(path, 'df') + + tm.assert_frame_equal(df, other) + self.assertTrue(df.equals(other)) + self.assertTrue(other.equals(df)) + + def test_round_trip_equals(self): + # GH 9330 + df = DataFrame({"B": [1,2], "A": ["x","y"]}) + + with ensure_clean_path(self.path) as path: df.to_hdf(path, 'df', format='table') other = read_hdf(path, 'df') tm.assert_frame_equal(df, other) + self.assertTrue(df.equals(other)) + self.assertTrue(other.equals(df)) def test_preserve_timedeltaindex_type(self): - # GH9635 + # GH9635 # Storing TimedeltaIndexed DataFrames in fixed stores did not preserve # the type of the index. df = DataFrame(np.random.normal(size=(10,5))) df.index = timedelta_range(start='0s',periods=10,freq='1s',name='example') with ensure_clean_store(self.path) as store: - + store['df'] = df assert_frame_equal(store['df'], df) diff --git a/pandas/tests/test_frame.py b/pandas/tests/test_frame.py index cdda087b27613..3e4c16f63035f 100644 --- a/pandas/tests/test_frame.py +++ b/pandas/tests/test_frame.py @@ -5944,6 +5944,20 @@ def test_boolean_comparison(self): self.assertRaises(ValueError, lambda : df == (2,2)) self.assertRaises(ValueError, lambda : df == [2,2]) + def test_equals_different_blocks(self): + # GH 9330 + df0 = pd.DataFrame({"A": ["x","y"], "B": [1,2], + "C": ["w","z"]}) + df1 = df0.reset_index()[["A","B","C"]] + # this assert verifies that the above operations have + # induced a block rearrangement + self.assertTrue(df0._data.blocks[0].dtype != + df1._data.blocks[0].dtype) + # do the real tests + self.assert_frame_equal(df0, df1) + self.assertTrue(df0.equals(df1)) + self.assertTrue(df1.equals(df0)) + def test_to_csv_from_csv(self): pname = '__tmp_to_csv_from_csv__' diff --git a/pandas/tests/test_internals.py b/pandas/tests/test_internals.py index 45f089f5e0a53..36585abd1b98f 100644 --- a/pandas/tests/test_internals.py +++ b/pandas/tests/test_internals.py @@ -68,15 +68,15 @@ def create_block(typestr, placement, item_shape=None, num_offset=0): elif typestr in ('object', 'string', 'O'): values = np.reshape(['A%d' % i for i in mat.ravel() + num_offset], shape) - elif typestr in ('bool'): + elif typestr in ('b','bool',): values = np.ones(shape, dtype=np.bool_) elif typestr in ('datetime', 'dt', 'M8[ns]'): values = (mat * 1e9).astype('M8[ns]') elif typestr in ('timedelta', 'td', 'm8[ns]'): values = (mat * 1).astype('m8[ns]') - elif typestr in ('category'): + elif typestr in ('category',): values = Categorical([1,1,2,2,3,3,3,3,4,4]) - elif typestr in ('category2'): + elif typestr in ('category2',): values = Categorical(['a','a','a','a','b','b','c','c','c','d']) elif typestr in ('sparse', 'sparse_na'): # FIXME: doesn't support num_rows != 10 @@ -751,6 +751,25 @@ def test_equals(self): bm2 = BlockManager(bm1.blocks[::-1], bm1.axes) self.assertTrue(bm1.equals(bm2)) + def test_equals_block_order_different_dtypes(self): + # GH 9330 + + mgr_strings = [ + "a:i8;b:f8", # basic case + "a:i8;b:f8;c:c8;d:b", # many types + "a:i8;e:dt;f:td;g:string", # more types + "a:i8;b:category;c:category2;d:category2", # categories + "c:sparse;d:sparse_na;b:f8", # sparse + ] + + for mgr_string in mgr_strings: + bm = create_mgr(mgr_string) + block_perms = itertools.permutations(bm.blocks) + for bm_perm in block_perms: + bm_this = BlockManager(bm_perm, bm.axes) + self.assertTrue(bm.equals(bm_this)) + self.assertTrue(bm_this.equals(bm)) + def test_single_mgr_ctor(self): mgr = create_single_mgr('f8', num_rows=5) self.assertEqual(mgr.as_matrix().tolist(), [0., 1., 2., 3., 4.]) From 94ec6c3587cda028802825bc4d95c56238513385 Mon Sep 17 00:00:00 2001 From: David BROCHART Date: Tue, 17 Mar 2015 16:24:21 +0100 Subject: [PATCH 10/11] Fixed bug #9671 where 'DataFrame.plot()' raised an error when both 'color' and 'style' keywords were passed and there was no color symbol in the style strings (this should be allowed) --- pandas/tests/test_graphics.py | 16 ++++++++++++++++ pandas/tools/plotting.py | 15 ++++++++++----- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/pandas/tests/test_graphics.py b/pandas/tests/test_graphics.py index 3ce4e150326a2..36c19cd39f76c 100644 --- a/pandas/tests/test_graphics.py +++ b/pandas/tests/test_graphics.py @@ -1154,6 +1154,22 @@ def test_plot(self): self.assertEqual(len(axes), 1) self.assertIs(ax.get_axes(), axes[0]) + def test_color_and_style_arguments(self): + df = DataFrame({'x': [1, 2], 'y': [3, 4]}) + # passing both 'color' and 'style' arguments should be allowed + # if there is no color symbol in the style strings: + ax = df.plot(color = ['red', 'black'], style = ['-', '--']) + # check that the linestyles are correctly set: + linestyle = [line.get_linestyle() for line in ax.lines] + self.assertEqual(linestyle, ['-', '--']) + # check that the colors are correctly set: + color = [line.get_color() for line in ax.lines] + self.assertEqual(color, ['red', 'black']) + # passing both 'color' and 'style' arguments should not be allowed + # if there is a color symbol in the style strings: + with tm.assertRaises(ValueError): + df.plot(color = ['red', 'black'], style = ['k-', 'r--']) + def test_nonnumeric_exclude(self): df = DataFrame({'A': ["x", "y", "z"], 'B': [1, 2, 3]}) ax = df.plot() diff --git a/pandas/tools/plotting.py b/pandas/tools/plotting.py index 0be030d7c2c8e..358c5b0dd5940 100644 --- a/pandas/tools/plotting.py +++ b/pandas/tools/plotting.py @@ -867,12 +867,17 @@ def _validate_color_args(self): "simultaneously. Using 'color'") if 'color' in self.kwds and self.style is not None: + if com.is_list_like(self.style): + styles = self.style + else: + styles = [self.style] # need only a single match - if re.match('^[a-z]+?', self.style) is not None: - raise ValueError("Cannot pass 'style' string with a color " - "symbol and 'color' keyword argument. Please" - " use one or the other or pass 'style' " - "without a color symbol") + for s in styles: + if re.match('^[a-z]+?', s) is not None: + raise ValueError("Cannot pass 'style' string with a color " + "symbol and 'color' keyword argument. Please" + " use one or the other or pass 'style' " + "without a color symbol") def _iter_data(self, data=None, keep_index=False, fillna=None): if data is None: From b00da07c54322d91a5b4c0238d72b50c1d1f7969 Mon Sep 17 00:00:00 2001 From: "David BROCHART (home)" Date: Mon, 6 Apr 2015 09:00:01 +0200 Subject: [PATCH 11/11] DOC: Update whatsnew for 0.16.1 (#9671) --- doc/source/whatsnew/v0.16.1.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/source/whatsnew/v0.16.1.txt b/doc/source/whatsnew/v0.16.1.txt index 9a00008362bc4..806f77ea56122 100644 --- a/doc/source/whatsnew/v0.16.1.txt +++ b/doc/source/whatsnew/v0.16.1.txt @@ -82,3 +82,5 @@ Bug Fixes - Bug in ``Series.quantile`` on empty Series of type ``Datetime`` or ``Timedelta`` (:issue:`9675`) - Bug in ``where`` causing incorrect results when upcasting was required (:issue:`9731`) - Bug in ``FloatArrayFormatter`` where decision boundary for displaying "small" floats in decimal format is off by one order of magnitude for a given display.precision (:issue:`9764`) + +- Fixed bug (:issue:`9671`) where ``DataFrame.plot()`` raised an error when both ``color`` and ``style`` keywords were passed and there was no color symbol in the style strings (this should be allowed).