demo + utils venv
This commit is contained in:
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,544 @@
|
||||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
import os
|
||||
import warnings
|
||||
|
||||
import numpy as np
|
||||
from numpy import random
|
||||
import pytest
|
||||
|
||||
from pandas.compat import iteritems, zip
|
||||
from pandas.util._decorators import cache_readonly
|
||||
import pandas.util._test_decorators as td
|
||||
|
||||
from pandas.core.dtypes.api import is_list_like
|
||||
|
||||
from pandas import DataFrame, Series
|
||||
import pandas.util.testing as tm
|
||||
from pandas.util.testing import (
|
||||
assert_is_valid_plot_return_object, ensure_clean)
|
||||
|
||||
import pandas.plotting as plotting
|
||||
from pandas.plotting._tools import _flatten
|
||||
|
||||
|
||||
"""
|
||||
This is a common base class used for various plotting tests
|
||||
"""
|
||||
|
||||
|
||||
def _skip_if_no_scipy_gaussian_kde():
|
||||
try:
|
||||
from scipy.stats import gaussian_kde # noqa
|
||||
except ImportError:
|
||||
pytest.skip("scipy version doesn't support gaussian_kde")
|
||||
|
||||
|
||||
def _ok_for_gaussian_kde(kind):
|
||||
if kind in ['kde', 'density']:
|
||||
try:
|
||||
from scipy.stats import gaussian_kde # noqa
|
||||
except ImportError:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
@td.skip_if_no_mpl
|
||||
class TestPlotBase(object):
|
||||
|
||||
def setup_method(self, method):
|
||||
|
||||
import matplotlib as mpl
|
||||
mpl.rcdefaults()
|
||||
|
||||
self.mpl_ge_2_0_1 = plotting._compat._mpl_ge_2_0_1()
|
||||
self.mpl_ge_2_1_0 = plotting._compat._mpl_ge_2_1_0()
|
||||
self.mpl_ge_2_2_0 = plotting._compat._mpl_ge_2_2_0()
|
||||
self.mpl_ge_2_2_2 = plotting._compat._mpl_ge_2_2_2()
|
||||
self.mpl_ge_3_0_0 = plotting._compat._mpl_ge_3_0_0()
|
||||
|
||||
self.bp_n_objects = 7
|
||||
self.polycollection_factor = 2
|
||||
self.default_figsize = (6.4, 4.8)
|
||||
self.default_tick_position = 'left'
|
||||
|
||||
n = 100
|
||||
with tm.RNGContext(42):
|
||||
gender = np.random.choice(['Male', 'Female'], size=n)
|
||||
classroom = np.random.choice(['A', 'B', 'C'], size=n)
|
||||
|
||||
self.hist_df = DataFrame({'gender': gender,
|
||||
'classroom': classroom,
|
||||
'height': random.normal(66, 4, size=n),
|
||||
'weight': random.normal(161, 32, size=n),
|
||||
'category': random.randint(4, size=n)})
|
||||
|
||||
self.tdf = tm.makeTimeDataFrame()
|
||||
self.hexbin_df = DataFrame({"A": np.random.uniform(size=20),
|
||||
"B": np.random.uniform(size=20),
|
||||
"C": np.arange(20) + np.random.uniform(
|
||||
size=20)})
|
||||
|
||||
def teardown_method(self, method):
|
||||
tm.close()
|
||||
|
||||
@cache_readonly
|
||||
def plt(self):
|
||||
import matplotlib.pyplot as plt
|
||||
return plt
|
||||
|
||||
@cache_readonly
|
||||
def colorconverter(self):
|
||||
import matplotlib.colors as colors
|
||||
return colors.colorConverter
|
||||
|
||||
def _check_legend_labels(self, axes, labels=None, visible=True):
|
||||
"""
|
||||
Check each axes has expected legend labels
|
||||
|
||||
Parameters
|
||||
----------
|
||||
axes : matplotlib Axes object, or its list-like
|
||||
labels : list-like
|
||||
expected legend labels
|
||||
visible : bool
|
||||
expected legend visibility. labels are checked only when visible is
|
||||
True
|
||||
"""
|
||||
|
||||
if visible and (labels is None):
|
||||
raise ValueError('labels must be specified when visible is True')
|
||||
axes = self._flatten_visible(axes)
|
||||
for ax in axes:
|
||||
if visible:
|
||||
assert ax.get_legend() is not None
|
||||
self._check_text_labels(ax.get_legend().get_texts(), labels)
|
||||
else:
|
||||
assert ax.get_legend() is None
|
||||
|
||||
def _check_data(self, xp, rs):
|
||||
"""
|
||||
Check each axes has identical lines
|
||||
|
||||
Parameters
|
||||
----------
|
||||
xp : matplotlib Axes object
|
||||
rs : matplotlib Axes object
|
||||
"""
|
||||
xp_lines = xp.get_lines()
|
||||
rs_lines = rs.get_lines()
|
||||
|
||||
def check_line(xpl, rsl):
|
||||
xpdata = xpl.get_xydata()
|
||||
rsdata = rsl.get_xydata()
|
||||
tm.assert_almost_equal(xpdata, rsdata)
|
||||
|
||||
assert len(xp_lines) == len(rs_lines)
|
||||
[check_line(xpl, rsl) for xpl, rsl in zip(xp_lines, rs_lines)]
|
||||
tm.close()
|
||||
|
||||
def _check_visible(self, collections, visible=True):
|
||||
"""
|
||||
Check each artist is visible or not
|
||||
|
||||
Parameters
|
||||
----------
|
||||
collections : matplotlib Artist or its list-like
|
||||
target Artist or its list or collection
|
||||
visible : bool
|
||||
expected visibility
|
||||
"""
|
||||
from matplotlib.collections import Collection
|
||||
if not isinstance(collections,
|
||||
Collection) and not is_list_like(collections):
|
||||
collections = [collections]
|
||||
|
||||
for patch in collections:
|
||||
assert patch.get_visible() == visible
|
||||
|
||||
def _get_colors_mapped(self, series, colors):
|
||||
unique = series.unique()
|
||||
# unique and colors length can be differed
|
||||
# depending on slice value
|
||||
mapped = dict(zip(unique, colors))
|
||||
return [mapped[v] for v in series.values]
|
||||
|
||||
def _check_colors(self, collections, linecolors=None, facecolors=None,
|
||||
mapping=None):
|
||||
"""
|
||||
Check each artist has expected line colors and face colors
|
||||
|
||||
Parameters
|
||||
----------
|
||||
collections : list-like
|
||||
list or collection of target artist
|
||||
linecolors : list-like which has the same length as collections
|
||||
list of expected line colors
|
||||
facecolors : list-like which has the same length as collections
|
||||
list of expected face colors
|
||||
mapping : Series
|
||||
Series used for color grouping key
|
||||
used for andrew_curves, parallel_coordinates, radviz test
|
||||
"""
|
||||
|
||||
from matplotlib.lines import Line2D
|
||||
from matplotlib.collections import (
|
||||
Collection, PolyCollection, LineCollection
|
||||
)
|
||||
conv = self.colorconverter
|
||||
if linecolors is not None:
|
||||
|
||||
if mapping is not None:
|
||||
linecolors = self._get_colors_mapped(mapping, linecolors)
|
||||
linecolors = linecolors[:len(collections)]
|
||||
|
||||
assert len(collections) == len(linecolors)
|
||||
for patch, color in zip(collections, linecolors):
|
||||
if isinstance(patch, Line2D):
|
||||
result = patch.get_color()
|
||||
# Line2D may contains string color expression
|
||||
result = conv.to_rgba(result)
|
||||
elif isinstance(patch, (PolyCollection, LineCollection)):
|
||||
result = tuple(patch.get_edgecolor()[0])
|
||||
else:
|
||||
result = patch.get_edgecolor()
|
||||
|
||||
expected = conv.to_rgba(color)
|
||||
assert result == expected
|
||||
|
||||
if facecolors is not None:
|
||||
|
||||
if mapping is not None:
|
||||
facecolors = self._get_colors_mapped(mapping, facecolors)
|
||||
facecolors = facecolors[:len(collections)]
|
||||
|
||||
assert len(collections) == len(facecolors)
|
||||
for patch, color in zip(collections, facecolors):
|
||||
if isinstance(patch, Collection):
|
||||
# returned as list of np.array
|
||||
result = patch.get_facecolor()[0]
|
||||
else:
|
||||
result = patch.get_facecolor()
|
||||
|
||||
if isinstance(result, np.ndarray):
|
||||
result = tuple(result)
|
||||
|
||||
expected = conv.to_rgba(color)
|
||||
assert result == expected
|
||||
|
||||
def _check_text_labels(self, texts, expected):
|
||||
"""
|
||||
Check each text has expected labels
|
||||
|
||||
Parameters
|
||||
----------
|
||||
texts : matplotlib Text object, or its list-like
|
||||
target text, or its list
|
||||
expected : str or list-like which has the same length as texts
|
||||
expected text label, or its list
|
||||
"""
|
||||
if not is_list_like(texts):
|
||||
assert texts.get_text() == expected
|
||||
else:
|
||||
labels = [t.get_text() for t in texts]
|
||||
assert len(labels) == len(expected)
|
||||
for label, e in zip(labels, expected):
|
||||
assert label == e
|
||||
|
||||
def _check_ticks_props(self, axes, xlabelsize=None, xrot=None,
|
||||
ylabelsize=None, yrot=None):
|
||||
"""
|
||||
Check each axes has expected tick properties
|
||||
|
||||
Parameters
|
||||
----------
|
||||
axes : matplotlib Axes object, or its list-like
|
||||
xlabelsize : number
|
||||
expected xticks font size
|
||||
xrot : number
|
||||
expected xticks rotation
|
||||
ylabelsize : number
|
||||
expected yticks font size
|
||||
yrot : number
|
||||
expected yticks rotation
|
||||
"""
|
||||
from matplotlib.ticker import NullFormatter
|
||||
axes = self._flatten_visible(axes)
|
||||
for ax in axes:
|
||||
if xlabelsize or xrot:
|
||||
if isinstance(ax.xaxis.get_minor_formatter(), NullFormatter):
|
||||
# If minor ticks has NullFormatter, rot / fontsize are not
|
||||
# retained
|
||||
labels = ax.get_xticklabels()
|
||||
else:
|
||||
labels = ax.get_xticklabels() + ax.get_xticklabels(
|
||||
minor=True)
|
||||
|
||||
for label in labels:
|
||||
if xlabelsize is not None:
|
||||
tm.assert_almost_equal(label.get_fontsize(),
|
||||
xlabelsize)
|
||||
if xrot is not None:
|
||||
tm.assert_almost_equal(label.get_rotation(), xrot)
|
||||
|
||||
if ylabelsize or yrot:
|
||||
if isinstance(ax.yaxis.get_minor_formatter(), NullFormatter):
|
||||
labels = ax.get_yticklabels()
|
||||
else:
|
||||
labels = ax.get_yticklabels() + ax.get_yticklabels(
|
||||
minor=True)
|
||||
|
||||
for label in labels:
|
||||
if ylabelsize is not None:
|
||||
tm.assert_almost_equal(label.get_fontsize(),
|
||||
ylabelsize)
|
||||
if yrot is not None:
|
||||
tm.assert_almost_equal(label.get_rotation(), yrot)
|
||||
|
||||
def _check_ax_scales(self, axes, xaxis='linear', yaxis='linear'):
|
||||
"""
|
||||
Check each axes has expected scales
|
||||
|
||||
Parameters
|
||||
----------
|
||||
axes : matplotlib Axes object, or its list-like
|
||||
xaxis : {'linear', 'log'}
|
||||
expected xaxis scale
|
||||
yaxis : {'linear', 'log'}
|
||||
expected yaxis scale
|
||||
"""
|
||||
axes = self._flatten_visible(axes)
|
||||
for ax in axes:
|
||||
assert ax.xaxis.get_scale() == xaxis
|
||||
assert ax.yaxis.get_scale() == yaxis
|
||||
|
||||
def _check_axes_shape(self, axes, axes_num=None, layout=None,
|
||||
figsize=None):
|
||||
"""
|
||||
Check expected number of axes is drawn in expected layout
|
||||
|
||||
Parameters
|
||||
----------
|
||||
axes : matplotlib Axes object, or its list-like
|
||||
axes_num : number
|
||||
expected number of axes. Unnecessary axes should be set to
|
||||
invisible.
|
||||
layout : tuple
|
||||
expected layout, (expected number of rows , columns)
|
||||
figsize : tuple
|
||||
expected figsize. default is matplotlib default
|
||||
"""
|
||||
if figsize is None:
|
||||
figsize = self.default_figsize
|
||||
visible_axes = self._flatten_visible(axes)
|
||||
|
||||
if axes_num is not None:
|
||||
assert len(visible_axes) == axes_num
|
||||
for ax in visible_axes:
|
||||
# check something drawn on visible axes
|
||||
assert len(ax.get_children()) > 0
|
||||
|
||||
if layout is not None:
|
||||
result = self._get_axes_layout(_flatten(axes))
|
||||
assert result == layout
|
||||
|
||||
tm.assert_numpy_array_equal(
|
||||
visible_axes[0].figure.get_size_inches(),
|
||||
np.array(figsize, dtype=np.float64))
|
||||
|
||||
def _get_axes_layout(self, axes):
|
||||
x_set = set()
|
||||
y_set = set()
|
||||
for ax in axes:
|
||||
# check axes coordinates to estimate layout
|
||||
points = ax.get_position().get_points()
|
||||
x_set.add(points[0][0])
|
||||
y_set.add(points[0][1])
|
||||
return (len(y_set), len(x_set))
|
||||
|
||||
def _flatten_visible(self, axes):
|
||||
"""
|
||||
Flatten axes, and filter only visible
|
||||
|
||||
Parameters
|
||||
----------
|
||||
axes : matplotlib Axes object, or its list-like
|
||||
|
||||
"""
|
||||
axes = _flatten(axes)
|
||||
axes = [ax for ax in axes if ax.get_visible()]
|
||||
return axes
|
||||
|
||||
def _check_has_errorbars(self, axes, xerr=0, yerr=0):
|
||||
"""
|
||||
Check axes has expected number of errorbars
|
||||
|
||||
Parameters
|
||||
----------
|
||||
axes : matplotlib Axes object, or its list-like
|
||||
xerr : number
|
||||
expected number of x errorbar
|
||||
yerr : number
|
||||
expected number of y errorbar
|
||||
"""
|
||||
axes = self._flatten_visible(axes)
|
||||
for ax in axes:
|
||||
containers = ax.containers
|
||||
xerr_count = 0
|
||||
yerr_count = 0
|
||||
for c in containers:
|
||||
has_xerr = getattr(c, 'has_xerr', False)
|
||||
has_yerr = getattr(c, 'has_yerr', False)
|
||||
if has_xerr:
|
||||
xerr_count += 1
|
||||
if has_yerr:
|
||||
yerr_count += 1
|
||||
assert xerr == xerr_count
|
||||
assert yerr == yerr_count
|
||||
|
||||
def _check_box_return_type(self, returned, return_type, expected_keys=None,
|
||||
check_ax_title=True):
|
||||
"""
|
||||
Check box returned type is correct
|
||||
|
||||
Parameters
|
||||
----------
|
||||
returned : object to be tested, returned from boxplot
|
||||
return_type : str
|
||||
return_type passed to boxplot
|
||||
expected_keys : list-like, optional
|
||||
group labels in subplot case. If not passed,
|
||||
the function checks assuming boxplot uses single ax
|
||||
check_ax_title : bool
|
||||
Whether to check the ax.title is the same as expected_key
|
||||
Intended to be checked by calling from ``boxplot``.
|
||||
Normal ``plot`` doesn't attach ``ax.title``, it must be disabled.
|
||||
"""
|
||||
from matplotlib.axes import Axes
|
||||
types = {'dict': dict, 'axes': Axes, 'both': tuple}
|
||||
if expected_keys is None:
|
||||
# should be fixed when the returning default is changed
|
||||
if return_type is None:
|
||||
return_type = 'dict'
|
||||
|
||||
assert isinstance(returned, types[return_type])
|
||||
if return_type == 'both':
|
||||
assert isinstance(returned.ax, Axes)
|
||||
assert isinstance(returned.lines, dict)
|
||||
else:
|
||||
# should be fixed when the returning default is changed
|
||||
if return_type is None:
|
||||
for r in self._flatten_visible(returned):
|
||||
assert isinstance(r, Axes)
|
||||
return
|
||||
|
||||
assert isinstance(returned, Series)
|
||||
|
||||
assert sorted(returned.keys()) == sorted(expected_keys)
|
||||
for key, value in iteritems(returned):
|
||||
assert isinstance(value, types[return_type])
|
||||
# check returned dict has correct mapping
|
||||
if return_type == 'axes':
|
||||
if check_ax_title:
|
||||
assert value.get_title() == key
|
||||
elif return_type == 'both':
|
||||
if check_ax_title:
|
||||
assert value.ax.get_title() == key
|
||||
assert isinstance(value.ax, Axes)
|
||||
assert isinstance(value.lines, dict)
|
||||
elif return_type == 'dict':
|
||||
line = value['medians'][0]
|
||||
axes = line.axes
|
||||
if check_ax_title:
|
||||
assert axes.get_title() == key
|
||||
else:
|
||||
raise AssertionError
|
||||
|
||||
def _check_grid_settings(self, obj, kinds, kws={}):
|
||||
# Make sure plot defaults to rcParams['axes.grid'] setting, GH 9792
|
||||
|
||||
import matplotlib as mpl
|
||||
|
||||
def is_grid_on():
|
||||
xoff = all(not g.gridOn
|
||||
for g in self.plt.gca().xaxis.get_major_ticks())
|
||||
yoff = all(not g.gridOn
|
||||
for g in self.plt.gca().yaxis.get_major_ticks())
|
||||
return not (xoff and yoff)
|
||||
|
||||
spndx = 1
|
||||
for kind in kinds:
|
||||
if not _ok_for_gaussian_kde(kind):
|
||||
continue
|
||||
|
||||
self.plt.subplot(1, 4 * len(kinds), spndx)
|
||||
spndx += 1
|
||||
mpl.rc('axes', grid=False)
|
||||
obj.plot(kind=kind, **kws)
|
||||
assert not is_grid_on()
|
||||
|
||||
self.plt.subplot(1, 4 * len(kinds), spndx)
|
||||
spndx += 1
|
||||
mpl.rc('axes', grid=True)
|
||||
obj.plot(kind=kind, grid=False, **kws)
|
||||
assert not is_grid_on()
|
||||
|
||||
if kind != 'pie':
|
||||
self.plt.subplot(1, 4 * len(kinds), spndx)
|
||||
spndx += 1
|
||||
mpl.rc('axes', grid=True)
|
||||
obj.plot(kind=kind, **kws)
|
||||
assert is_grid_on()
|
||||
|
||||
self.plt.subplot(1, 4 * len(kinds), spndx)
|
||||
spndx += 1
|
||||
mpl.rc('axes', grid=False)
|
||||
obj.plot(kind=kind, grid=True, **kws)
|
||||
assert is_grid_on()
|
||||
|
||||
def _unpack_cycler(self, rcParams, field='color'):
|
||||
"""
|
||||
Auxiliary function for correctly unpacking cycler after MPL >= 1.5
|
||||
"""
|
||||
return [v[field] for v in rcParams['axes.prop_cycle']]
|
||||
|
||||
|
||||
def _check_plot_works(f, filterwarnings='always', **kwargs):
|
||||
import matplotlib.pyplot as plt
|
||||
ret = None
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter(filterwarnings)
|
||||
try:
|
||||
try:
|
||||
fig = kwargs['figure']
|
||||
except KeyError:
|
||||
fig = plt.gcf()
|
||||
|
||||
plt.clf()
|
||||
|
||||
ax = kwargs.get('ax', fig.add_subplot(211)) # noqa
|
||||
ret = f(**kwargs)
|
||||
|
||||
assert_is_valid_plot_return_object(ret)
|
||||
|
||||
try:
|
||||
kwargs['ax'] = fig.add_subplot(212)
|
||||
ret = f(**kwargs)
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
assert_is_valid_plot_return_object(ret)
|
||||
|
||||
with ensure_clean(return_filelike=True) as path:
|
||||
plt.savefig(path)
|
||||
finally:
|
||||
tm.close(fig)
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def curpath():
|
||||
pth, _ = os.path.split(os.path.abspath(__file__))
|
||||
return pth
|
||||
@@ -0,0 +1,385 @@
|
||||
# coding: utf-8
|
||||
|
||||
import itertools
|
||||
import string
|
||||
|
||||
import numpy as np
|
||||
from numpy import random
|
||||
import pytest
|
||||
|
||||
from pandas.compat import lzip, range
|
||||
import pandas.util._test_decorators as td
|
||||
|
||||
from pandas import DataFrame, MultiIndex, Series
|
||||
from pandas.tests.plotting.common import TestPlotBase, _check_plot_works
|
||||
import pandas.util.testing as tm
|
||||
|
||||
import pandas.plotting as plotting
|
||||
|
||||
""" Test cases for .boxplot method """
|
||||
|
||||
|
||||
@td.skip_if_no_mpl
|
||||
class TestDataFramePlots(TestPlotBase):
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_boxplot_legacy1(self):
|
||||
df = DataFrame(np.random.randn(6, 4),
|
||||
index=list(string.ascii_letters[:6]),
|
||||
columns=['one', 'two', 'three', 'four'])
|
||||
df['indic'] = ['foo', 'bar'] * 3
|
||||
df['indic2'] = ['foo', 'bar', 'foo'] * 2
|
||||
|
||||
_check_plot_works(df.boxplot, return_type='dict')
|
||||
_check_plot_works(df.boxplot, column=[
|
||||
'one', 'two'], return_type='dict')
|
||||
# _check_plot_works adds an ax so catch warning. see GH #13188
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
_check_plot_works(df.boxplot, column=['one', 'two'],
|
||||
by='indic')
|
||||
_check_plot_works(df.boxplot, column='one', by=['indic', 'indic2'])
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
_check_plot_works(df.boxplot, by='indic')
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
_check_plot_works(df.boxplot, by=['indic', 'indic2'])
|
||||
_check_plot_works(plotting._core.boxplot, data=df['one'],
|
||||
return_type='dict')
|
||||
_check_plot_works(df.boxplot, notch=1, return_type='dict')
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
_check_plot_works(df.boxplot, by='indic', notch=1)
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_boxplot_legacy2(self):
|
||||
df = DataFrame(np.random.rand(10, 2), columns=['Col1', 'Col2'])
|
||||
df['X'] = Series(['A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'B'])
|
||||
df['Y'] = Series(['A'] * 10)
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
_check_plot_works(df.boxplot, by='X')
|
||||
|
||||
# When ax is supplied and required number of axes is 1,
|
||||
# passed ax should be used:
|
||||
fig, ax = self.plt.subplots()
|
||||
axes = df.boxplot('Col1', by='X', ax=ax)
|
||||
ax_axes = ax.axes
|
||||
assert ax_axes is axes
|
||||
|
||||
fig, ax = self.plt.subplots()
|
||||
axes = df.groupby('Y').boxplot(ax=ax, return_type='axes')
|
||||
ax_axes = ax.axes
|
||||
assert ax_axes is axes['A']
|
||||
|
||||
# Multiple columns with an ax argument should use same figure
|
||||
fig, ax = self.plt.subplots()
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
axes = df.boxplot(column=['Col1', 'Col2'],
|
||||
by='X', ax=ax, return_type='axes')
|
||||
assert axes['Col1'].get_figure() is fig
|
||||
|
||||
# When by is None, check that all relevant lines are present in the
|
||||
# dict
|
||||
fig, ax = self.plt.subplots()
|
||||
d = df.boxplot(ax=ax, return_type='dict')
|
||||
lines = list(itertools.chain.from_iterable(d.values()))
|
||||
assert len(ax.get_lines()) == len(lines)
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_boxplot_return_type_none(self):
|
||||
# GH 12216; return_type=None & by=None -> axes
|
||||
result = self.hist_df.boxplot()
|
||||
assert isinstance(result, self.plt.Axes)
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_boxplot_return_type_legacy(self):
|
||||
# API change in https://github.com/pandas-dev/pandas/pull/7096
|
||||
import matplotlib as mpl # noqa
|
||||
|
||||
df = DataFrame(np.random.randn(6, 4),
|
||||
index=list(string.ascii_letters[:6]),
|
||||
columns=['one', 'two', 'three', 'four'])
|
||||
with pytest.raises(ValueError):
|
||||
df.boxplot(return_type='NOTATYPE')
|
||||
|
||||
result = df.boxplot()
|
||||
self._check_box_return_type(result, 'axes')
|
||||
|
||||
with tm.assert_produces_warning(False):
|
||||
result = df.boxplot(return_type='dict')
|
||||
self._check_box_return_type(result, 'dict')
|
||||
|
||||
with tm.assert_produces_warning(False):
|
||||
result = df.boxplot(return_type='axes')
|
||||
self._check_box_return_type(result, 'axes')
|
||||
|
||||
with tm.assert_produces_warning(False):
|
||||
result = df.boxplot(return_type='both')
|
||||
self._check_box_return_type(result, 'both')
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_boxplot_axis_limits(self):
|
||||
|
||||
def _check_ax_limits(col, ax):
|
||||
y_min, y_max = ax.get_ylim()
|
||||
assert y_min <= col.min()
|
||||
assert y_max >= col.max()
|
||||
|
||||
df = self.hist_df.copy()
|
||||
df['age'] = np.random.randint(1, 20, df.shape[0])
|
||||
# One full row
|
||||
height_ax, weight_ax = df.boxplot(['height', 'weight'], by='category')
|
||||
_check_ax_limits(df['height'], height_ax)
|
||||
_check_ax_limits(df['weight'], weight_ax)
|
||||
assert weight_ax._sharey == height_ax
|
||||
|
||||
# Two rows, one partial
|
||||
p = df.boxplot(['height', 'weight', 'age'], by='category')
|
||||
height_ax, weight_ax, age_ax = p[0, 0], p[0, 1], p[1, 0]
|
||||
dummy_ax = p[1, 1]
|
||||
|
||||
_check_ax_limits(df['height'], height_ax)
|
||||
_check_ax_limits(df['weight'], weight_ax)
|
||||
_check_ax_limits(df['age'], age_ax)
|
||||
assert weight_ax._sharey == height_ax
|
||||
assert age_ax._sharey == height_ax
|
||||
assert dummy_ax._sharey is None
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_boxplot_empty_column(self):
|
||||
df = DataFrame(np.random.randn(20, 4))
|
||||
df.loc[:, 0] = np.nan
|
||||
_check_plot_works(df.boxplot, return_type='axes')
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_figsize(self):
|
||||
df = DataFrame(np.random.rand(10, 5),
|
||||
columns=['A', 'B', 'C', 'D', 'E'])
|
||||
result = df.boxplot(return_type='axes', figsize=(12, 8))
|
||||
assert result.figure.bbox_inches.width == 12
|
||||
assert result.figure.bbox_inches.height == 8
|
||||
|
||||
def test_fontsize(self):
|
||||
df = DataFrame({"a": [1, 2, 3, 4, 5, 6]})
|
||||
self._check_ticks_props(df.boxplot("a", fontsize=16),
|
||||
xlabelsize=16, ylabelsize=16)
|
||||
|
||||
|
||||
@td.skip_if_no_mpl
|
||||
class TestDataFrameGroupByPlots(TestPlotBase):
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_boxplot_legacy1(self):
|
||||
grouped = self.hist_df.groupby(by='gender')
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
axes = _check_plot_works(grouped.boxplot, return_type='axes')
|
||||
self._check_axes_shape(list(axes.values), axes_num=2, layout=(1, 2))
|
||||
axes = _check_plot_works(grouped.boxplot, subplots=False,
|
||||
return_type='axes')
|
||||
self._check_axes_shape(axes, axes_num=1, layout=(1, 1))
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_boxplot_legacy2(self):
|
||||
tuples = lzip(string.ascii_letters[:10], range(10))
|
||||
df = DataFrame(np.random.rand(10, 3),
|
||||
index=MultiIndex.from_tuples(tuples))
|
||||
grouped = df.groupby(level=1)
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
axes = _check_plot_works(grouped.boxplot, return_type='axes')
|
||||
self._check_axes_shape(list(axes.values), axes_num=10, layout=(4, 3))
|
||||
|
||||
axes = _check_plot_works(grouped.boxplot, subplots=False,
|
||||
return_type='axes')
|
||||
self._check_axes_shape(axes, axes_num=1, layout=(1, 1))
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_boxplot_legacy3(self):
|
||||
tuples = lzip(string.ascii_letters[:10], range(10))
|
||||
df = DataFrame(np.random.rand(10, 3),
|
||||
index=MultiIndex.from_tuples(tuples))
|
||||
grouped = df.unstack(level=1).groupby(level=0, axis=1)
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
axes = _check_plot_works(grouped.boxplot, return_type='axes')
|
||||
self._check_axes_shape(list(axes.values), axes_num=3, layout=(2, 2))
|
||||
axes = _check_plot_works(grouped.boxplot, subplots=False,
|
||||
return_type='axes')
|
||||
self._check_axes_shape(axes, axes_num=1, layout=(1, 1))
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_grouped_plot_fignums(self):
|
||||
n = 10
|
||||
weight = Series(np.random.normal(166, 20, size=n))
|
||||
height = Series(np.random.normal(60, 10, size=n))
|
||||
with tm.RNGContext(42):
|
||||
gender = np.random.choice(['male', 'female'], size=n)
|
||||
df = DataFrame({'height': height, 'weight': weight, 'gender': gender})
|
||||
gb = df.groupby('gender')
|
||||
|
||||
res = gb.plot()
|
||||
assert len(self.plt.get_fignums()) == 2
|
||||
assert len(res) == 2
|
||||
tm.close()
|
||||
|
||||
res = gb.boxplot(return_type='axes')
|
||||
assert len(self.plt.get_fignums()) == 1
|
||||
assert len(res) == 2
|
||||
tm.close()
|
||||
|
||||
# now works with GH 5610 as gender is excluded
|
||||
res = df.groupby('gender').hist()
|
||||
tm.close()
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_grouped_box_return_type(self):
|
||||
df = self.hist_df
|
||||
|
||||
# old style: return_type=None
|
||||
result = df.boxplot(by='gender')
|
||||
assert isinstance(result, np.ndarray)
|
||||
self._check_box_return_type(
|
||||
result, None,
|
||||
expected_keys=['height', 'weight', 'category'])
|
||||
|
||||
# now for groupby
|
||||
result = df.groupby('gender').boxplot(return_type='dict')
|
||||
self._check_box_return_type(
|
||||
result, 'dict', expected_keys=['Male', 'Female'])
|
||||
|
||||
columns2 = 'X B C D A G Y N Q O'.split()
|
||||
df2 = DataFrame(random.randn(50, 10), columns=columns2)
|
||||
categories2 = 'A B C D E F G H I J'.split()
|
||||
df2['category'] = categories2 * 5
|
||||
|
||||
for t in ['dict', 'axes', 'both']:
|
||||
returned = df.groupby('classroom').boxplot(return_type=t)
|
||||
self._check_box_return_type(
|
||||
returned, t, expected_keys=['A', 'B', 'C'])
|
||||
|
||||
returned = df.boxplot(by='classroom', return_type=t)
|
||||
self._check_box_return_type(
|
||||
returned, t,
|
||||
expected_keys=['height', 'weight', 'category'])
|
||||
|
||||
returned = df2.groupby('category').boxplot(return_type=t)
|
||||
self._check_box_return_type(returned, t, expected_keys=categories2)
|
||||
|
||||
returned = df2.boxplot(by='category', return_type=t)
|
||||
self._check_box_return_type(returned, t, expected_keys=columns2)
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_grouped_box_layout(self):
|
||||
df = self.hist_df
|
||||
|
||||
pytest.raises(ValueError, df.boxplot, column=['weight', 'height'],
|
||||
by=df.gender, layout=(1, 1))
|
||||
pytest.raises(ValueError, df.boxplot,
|
||||
column=['height', 'weight', 'category'],
|
||||
layout=(2, 1), return_type='dict')
|
||||
pytest.raises(ValueError, df.boxplot, column=['weight', 'height'],
|
||||
by=df.gender, layout=(-1, -1))
|
||||
|
||||
# _check_plot_works adds an ax so catch warning. see GH #13188
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
box = _check_plot_works(df.groupby('gender').boxplot,
|
||||
column='height', return_type='dict')
|
||||
self._check_axes_shape(self.plt.gcf().axes, axes_num=2, layout=(1, 2))
|
||||
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
box = _check_plot_works(df.groupby('category').boxplot,
|
||||
column='height',
|
||||
return_type='dict')
|
||||
self._check_axes_shape(self.plt.gcf().axes, axes_num=4, layout=(2, 2))
|
||||
|
||||
# GH 6769
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
box = _check_plot_works(df.groupby('classroom').boxplot,
|
||||
column='height', return_type='dict')
|
||||
self._check_axes_shape(self.plt.gcf().axes, axes_num=3, layout=(2, 2))
|
||||
|
||||
# GH 5897
|
||||
axes = df.boxplot(column=['height', 'weight', 'category'], by='gender',
|
||||
return_type='axes')
|
||||
self._check_axes_shape(self.plt.gcf().axes, axes_num=3, layout=(2, 2))
|
||||
for ax in [axes['height']]:
|
||||
self._check_visible(ax.get_xticklabels(), visible=False)
|
||||
self._check_visible([ax.xaxis.get_label()], visible=False)
|
||||
for ax in [axes['weight'], axes['category']]:
|
||||
self._check_visible(ax.get_xticklabels())
|
||||
self._check_visible([ax.xaxis.get_label()])
|
||||
|
||||
box = df.groupby('classroom').boxplot(
|
||||
column=['height', 'weight', 'category'], return_type='dict')
|
||||
self._check_axes_shape(self.plt.gcf().axes, axes_num=3, layout=(2, 2))
|
||||
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
box = _check_plot_works(df.groupby('category').boxplot,
|
||||
column='height',
|
||||
layout=(3, 2), return_type='dict')
|
||||
self._check_axes_shape(self.plt.gcf().axes, axes_num=4, layout=(3, 2))
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
box = _check_plot_works(df.groupby('category').boxplot,
|
||||
column='height',
|
||||
layout=(3, -1), return_type='dict')
|
||||
self._check_axes_shape(self.plt.gcf().axes, axes_num=4, layout=(3, 2))
|
||||
|
||||
box = df.boxplot(column=['height', 'weight', 'category'], by='gender',
|
||||
layout=(4, 1))
|
||||
self._check_axes_shape(self.plt.gcf().axes, axes_num=3, layout=(4, 1))
|
||||
|
||||
box = df.boxplot(column=['height', 'weight', 'category'], by='gender',
|
||||
layout=(-1, 1))
|
||||
self._check_axes_shape(self.plt.gcf().axes, axes_num=3, layout=(3, 1))
|
||||
|
||||
box = df.groupby('classroom').boxplot(
|
||||
column=['height', 'weight', 'category'], layout=(1, 4),
|
||||
return_type='dict')
|
||||
self._check_axes_shape(self.plt.gcf().axes, axes_num=3, layout=(1, 4))
|
||||
|
||||
box = df.groupby('classroom').boxplot( # noqa
|
||||
column=['height', 'weight', 'category'], layout=(1, -1),
|
||||
return_type='dict')
|
||||
self._check_axes_shape(self.plt.gcf().axes, axes_num=3, layout=(1, 3))
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_grouped_box_multiple_axes(self):
|
||||
# GH 6970, GH 7069
|
||||
df = self.hist_df
|
||||
|
||||
# check warning to ignore sharex / sharey
|
||||
# this check should be done in the first function which
|
||||
# passes multiple axes to plot, hist or boxplot
|
||||
# location should be changed if other test is added
|
||||
# which has earlier alphabetical order
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
fig, axes = self.plt.subplots(2, 2)
|
||||
df.groupby('category').boxplot(
|
||||
column='height', return_type='axes', ax=axes)
|
||||
self._check_axes_shape(self.plt.gcf().axes,
|
||||
axes_num=4, layout=(2, 2))
|
||||
|
||||
fig, axes = self.plt.subplots(2, 3)
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
returned = df.boxplot(column=['height', 'weight', 'category'],
|
||||
by='gender', return_type='axes', ax=axes[0])
|
||||
returned = np.array(list(returned.values))
|
||||
self._check_axes_shape(returned, axes_num=3, layout=(1, 3))
|
||||
tm.assert_numpy_array_equal(returned, axes[0])
|
||||
assert returned[0].figure is fig
|
||||
|
||||
# draw on second row
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
returned = df.groupby('classroom').boxplot(
|
||||
column=['height', 'weight', 'category'],
|
||||
return_type='axes', ax=axes[1])
|
||||
returned = np.array(list(returned.values))
|
||||
self._check_axes_shape(returned, axes_num=3, layout=(1, 3))
|
||||
tm.assert_numpy_array_equal(returned, axes[1])
|
||||
assert returned[0].figure is fig
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
fig, axes = self.plt.subplots(2, 3)
|
||||
# pass different number of axes from required
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
axes = df.groupby('classroom').boxplot(ax=axes)
|
||||
|
||||
def test_fontsize(self):
|
||||
df = DataFrame({"a": [1, 2, 3, 4, 5, 6], "b": [0, 0, 0, 1, 1, 1]})
|
||||
self._check_ticks_props(df.boxplot("a", by="b", fontsize=16),
|
||||
xlabelsize=16, ylabelsize=16)
|
||||
@@ -0,0 +1,346 @@
|
||||
from datetime import date, datetime
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from pandas.compat import u
|
||||
from pandas.compat.numpy import np_datetime64_compat
|
||||
|
||||
from pandas import Index, Period, Series, Timestamp, date_range
|
||||
import pandas.core.config as cf
|
||||
import pandas.util.testing as tm
|
||||
|
||||
from pandas.tseries.offsets import Day, Micro, Milli, Second
|
||||
|
||||
converter = pytest.importorskip('pandas.plotting._converter')
|
||||
from pandas.plotting import (deregister_matplotlib_converters, # isort:skip
|
||||
register_matplotlib_converters)
|
||||
|
||||
|
||||
def test_timtetonum_accepts_unicode():
|
||||
assert (converter.time2num("00:01") == converter.time2num(u("00:01")))
|
||||
|
||||
|
||||
class TestRegistration(object):
|
||||
|
||||
def test_register_by_default(self):
|
||||
# Run in subprocess to ensure a clean state
|
||||
code = ("'import matplotlib.units; "
|
||||
"import pandas as pd; "
|
||||
"units = dict(matplotlib.units.registry); "
|
||||
"assert pd.Timestamp in units)'")
|
||||
call = [sys.executable, '-c', code]
|
||||
assert subprocess.check_call(call) == 0
|
||||
|
||||
def test_warns(self):
|
||||
plt = pytest.importorskip("matplotlib.pyplot")
|
||||
s = Series(range(12), index=date_range('2017', periods=12))
|
||||
_, ax = plt.subplots()
|
||||
|
||||
# Set to the "warning" state, in case this isn't the first test run
|
||||
converter._WARN = True
|
||||
with tm.assert_produces_warning(FutureWarning,
|
||||
check_stacklevel=False) as w:
|
||||
ax.plot(s.index, s.values)
|
||||
plt.close()
|
||||
|
||||
assert len(w) == 1
|
||||
assert "Using an implicitly registered datetime converter" in str(w[0])
|
||||
|
||||
def test_registering_no_warning(self):
|
||||
plt = pytest.importorskip("matplotlib.pyplot")
|
||||
s = Series(range(12), index=date_range('2017', periods=12))
|
||||
_, ax = plt.subplots()
|
||||
|
||||
# Set to the "warn" state, in case this isn't the first test run
|
||||
converter._WARN = True
|
||||
register_matplotlib_converters()
|
||||
with tm.assert_produces_warning(None) as w:
|
||||
ax.plot(s.index, s.values)
|
||||
|
||||
assert len(w) == 0
|
||||
|
||||
def test_pandas_plots_register(self):
|
||||
pytest.importorskip("matplotlib.pyplot")
|
||||
s = Series(range(12), index=date_range('2017', periods=12))
|
||||
# Set to the "warn" state, in case this isn't the first test run
|
||||
converter._WARN = True
|
||||
with tm.assert_produces_warning(None) as w:
|
||||
s.plot()
|
||||
|
||||
assert len(w) == 0
|
||||
|
||||
def test_matplotlib_formatters(self):
|
||||
units = pytest.importorskip("matplotlib.units")
|
||||
assert Timestamp in units.registry
|
||||
|
||||
ctx = cf.option_context("plotting.matplotlib.register_converters",
|
||||
False)
|
||||
with ctx:
|
||||
assert Timestamp not in units.registry
|
||||
|
||||
assert Timestamp in units.registry
|
||||
|
||||
def test_option_no_warning(self):
|
||||
pytest.importorskip("matplotlib.pyplot")
|
||||
ctx = cf.option_context("plotting.matplotlib.register_converters",
|
||||
False)
|
||||
plt = pytest.importorskip("matplotlib.pyplot")
|
||||
s = Series(range(12), index=date_range('2017', periods=12))
|
||||
_, ax = plt.subplots()
|
||||
|
||||
converter._WARN = True
|
||||
# Test without registering first, no warning
|
||||
with ctx:
|
||||
with tm.assert_produces_warning(None) as w:
|
||||
ax.plot(s.index, s.values)
|
||||
|
||||
assert len(w) == 0
|
||||
|
||||
# Now test with registering
|
||||
converter._WARN = True
|
||||
register_matplotlib_converters()
|
||||
with ctx:
|
||||
with tm.assert_produces_warning(None) as w:
|
||||
ax.plot(s.index, s.values)
|
||||
|
||||
assert len(w) == 0
|
||||
|
||||
def test_registry_resets(self):
|
||||
units = pytest.importorskip("matplotlib.units")
|
||||
dates = pytest.importorskip("matplotlib.dates")
|
||||
|
||||
# make a copy, to reset to
|
||||
original = dict(units.registry)
|
||||
|
||||
try:
|
||||
# get to a known state
|
||||
units.registry.clear()
|
||||
date_converter = dates.DateConverter()
|
||||
units.registry[datetime] = date_converter
|
||||
units.registry[date] = date_converter
|
||||
|
||||
register_matplotlib_converters()
|
||||
assert units.registry[date] is not date_converter
|
||||
deregister_matplotlib_converters()
|
||||
assert units.registry[date] is date_converter
|
||||
|
||||
finally:
|
||||
# restore original stater
|
||||
units.registry.clear()
|
||||
for k, v in original.items():
|
||||
units.registry[k] = v
|
||||
|
||||
def test_old_import_warns(self):
|
||||
with tm.assert_produces_warning(FutureWarning) as w:
|
||||
from pandas.tseries import converter
|
||||
converter.register()
|
||||
|
||||
assert len(w)
|
||||
assert ('pandas.plotting.register_matplotlib_converters' in
|
||||
str(w[0].message))
|
||||
|
||||
|
||||
class TestDateTimeConverter(object):
|
||||
|
||||
def setup_method(self, method):
|
||||
self.dtc = converter.DatetimeConverter()
|
||||
self.tc = converter.TimeFormatter(None)
|
||||
|
||||
def test_convert_accepts_unicode(self):
|
||||
r1 = self.dtc.convert("12:22", None, None)
|
||||
r2 = self.dtc.convert(u("12:22"), None, None)
|
||||
assert (r1 == r2), "DatetimeConverter.convert should accept unicode"
|
||||
|
||||
def test_conversion(self):
|
||||
rs = self.dtc.convert(['2012-1-1'], None, None)[0]
|
||||
xp = datetime(2012, 1, 1).toordinal()
|
||||
assert rs == xp
|
||||
|
||||
rs = self.dtc.convert('2012-1-1', None, None)
|
||||
assert rs == xp
|
||||
|
||||
rs = self.dtc.convert(date(2012, 1, 1), None, None)
|
||||
assert rs == xp
|
||||
|
||||
rs = self.dtc.convert(datetime(2012, 1, 1).toordinal(), None, None)
|
||||
assert rs == xp
|
||||
|
||||
rs = self.dtc.convert('2012-1-1', None, None)
|
||||
assert rs == xp
|
||||
|
||||
rs = self.dtc.convert(Timestamp('2012-1-1'), None, None)
|
||||
assert rs == xp
|
||||
|
||||
# also testing datetime64 dtype (GH8614)
|
||||
rs = self.dtc.convert(np_datetime64_compat('2012-01-01'), None, None)
|
||||
assert rs == xp
|
||||
|
||||
rs = self.dtc.convert(np_datetime64_compat(
|
||||
'2012-01-01 00:00:00+0000'), None, None)
|
||||
assert rs == xp
|
||||
|
||||
rs = self.dtc.convert(np.array([
|
||||
np_datetime64_compat('2012-01-01 00:00:00+0000'),
|
||||
np_datetime64_compat('2012-01-02 00:00:00+0000')]), None, None)
|
||||
assert rs[0] == xp
|
||||
|
||||
# we have a tz-aware date (constructed to that when we turn to utc it
|
||||
# is the same as our sample)
|
||||
ts = (Timestamp('2012-01-01')
|
||||
.tz_localize('UTC')
|
||||
.tz_convert('US/Eastern')
|
||||
)
|
||||
rs = self.dtc.convert(ts, None, None)
|
||||
assert rs == xp
|
||||
|
||||
rs = self.dtc.convert(ts.to_pydatetime(), None, None)
|
||||
assert rs == xp
|
||||
|
||||
rs = self.dtc.convert(Index([ts - Day(1), ts]), None, None)
|
||||
assert rs[1] == xp
|
||||
|
||||
rs = self.dtc.convert(Index([ts - Day(1), ts]).to_pydatetime(),
|
||||
None, None)
|
||||
assert rs[1] == xp
|
||||
|
||||
def test_conversion_float(self):
|
||||
decimals = 9
|
||||
|
||||
rs = self.dtc.convert(
|
||||
Timestamp('2012-1-1 01:02:03', tz='UTC'), None, None)
|
||||
xp = converter.dates.date2num(Timestamp('2012-1-1 01:02:03', tz='UTC'))
|
||||
tm.assert_almost_equal(rs, xp, decimals)
|
||||
|
||||
rs = self.dtc.convert(
|
||||
Timestamp('2012-1-1 09:02:03', tz='Asia/Hong_Kong'), None, None)
|
||||
tm.assert_almost_equal(rs, xp, decimals)
|
||||
|
||||
rs = self.dtc.convert(datetime(2012, 1, 1, 1, 2, 3), None, None)
|
||||
tm.assert_almost_equal(rs, xp, decimals)
|
||||
|
||||
def test_conversion_outofbounds_datetime(self):
|
||||
# 2579
|
||||
values = [date(1677, 1, 1), date(1677, 1, 2)]
|
||||
rs = self.dtc.convert(values, None, None)
|
||||
xp = converter.dates.date2num(values)
|
||||
tm.assert_numpy_array_equal(rs, xp)
|
||||
rs = self.dtc.convert(values[0], None, None)
|
||||
xp = converter.dates.date2num(values[0])
|
||||
assert rs == xp
|
||||
|
||||
values = [datetime(1677, 1, 1, 12), datetime(1677, 1, 2, 12)]
|
||||
rs = self.dtc.convert(values, None, None)
|
||||
xp = converter.dates.date2num(values)
|
||||
tm.assert_numpy_array_equal(rs, xp)
|
||||
rs = self.dtc.convert(values[0], None, None)
|
||||
xp = converter.dates.date2num(values[0])
|
||||
assert rs == xp
|
||||
|
||||
@pytest.mark.parametrize('time,format_expected', [
|
||||
(0, '00:00'), # time2num(datetime.time.min)
|
||||
(86399.999999, '23:59:59.999999'), # time2num(datetime.time.max)
|
||||
(90000, '01:00'),
|
||||
(3723, '01:02:03'),
|
||||
(39723.2, '11:02:03.200')
|
||||
])
|
||||
def test_time_formatter(self, time, format_expected):
|
||||
# issue 18478
|
||||
result = self.tc(time)
|
||||
assert result == format_expected
|
||||
|
||||
def test_dateindex_conversion(self):
|
||||
decimals = 9
|
||||
|
||||
for freq in ('B', 'L', 'S'):
|
||||
dateindex = tm.makeDateIndex(k=10, freq=freq)
|
||||
rs = self.dtc.convert(dateindex, None, None)
|
||||
xp = converter.dates.date2num(dateindex._mpl_repr())
|
||||
tm.assert_almost_equal(rs, xp, decimals)
|
||||
|
||||
def test_resolution(self):
|
||||
def _assert_less(ts1, ts2):
|
||||
val1 = self.dtc.convert(ts1, None, None)
|
||||
val2 = self.dtc.convert(ts2, None, None)
|
||||
if not val1 < val2:
|
||||
raise AssertionError('{0} is not less than {1}.'.format(val1,
|
||||
val2))
|
||||
|
||||
# Matplotlib's time representation using floats cannot distinguish
|
||||
# intervals smaller than ~10 microsecond in the common range of years.
|
||||
ts = Timestamp('2012-1-1')
|
||||
_assert_less(ts, ts + Second())
|
||||
_assert_less(ts, ts + Milli())
|
||||
_assert_less(ts, ts + Micro(50))
|
||||
|
||||
def test_convert_nested(self):
|
||||
inner = [Timestamp('2017-01-01'), Timestamp('2017-01-02')]
|
||||
data = [inner, inner]
|
||||
result = self.dtc.convert(data, None, None)
|
||||
expected = [self.dtc.convert(x, None, None) for x in data]
|
||||
assert (np.array(result) == expected).all()
|
||||
|
||||
|
||||
class TestPeriodConverter(object):
|
||||
|
||||
def setup_method(self, method):
|
||||
self.pc = converter.PeriodConverter()
|
||||
|
||||
class Axis(object):
|
||||
pass
|
||||
|
||||
self.axis = Axis()
|
||||
self.axis.freq = 'D'
|
||||
|
||||
def test_convert_accepts_unicode(self):
|
||||
r1 = self.pc.convert("2012-1-1", None, self.axis)
|
||||
r2 = self.pc.convert(u("2012-1-1"), None, self.axis)
|
||||
assert r1 == r2
|
||||
|
||||
def test_conversion(self):
|
||||
rs = self.pc.convert(['2012-1-1'], None, self.axis)[0]
|
||||
xp = Period('2012-1-1').ordinal
|
||||
assert rs == xp
|
||||
|
||||
rs = self.pc.convert('2012-1-1', None, self.axis)
|
||||
assert rs == xp
|
||||
|
||||
rs = self.pc.convert([date(2012, 1, 1)], None, self.axis)[0]
|
||||
assert rs == xp
|
||||
|
||||
rs = self.pc.convert(date(2012, 1, 1), None, self.axis)
|
||||
assert rs == xp
|
||||
|
||||
rs = self.pc.convert([Timestamp('2012-1-1')], None, self.axis)[0]
|
||||
assert rs == xp
|
||||
|
||||
rs = self.pc.convert(Timestamp('2012-1-1'), None, self.axis)
|
||||
assert rs == xp
|
||||
|
||||
rs = self.pc.convert(
|
||||
np_datetime64_compat('2012-01-01'), None, self.axis)
|
||||
assert rs == xp
|
||||
|
||||
rs = self.pc.convert(
|
||||
np_datetime64_compat('2012-01-01 00:00:00+0000'), None, self.axis)
|
||||
assert rs == xp
|
||||
|
||||
rs = self.pc.convert(np.array([
|
||||
np_datetime64_compat('2012-01-01 00:00:00+0000'),
|
||||
np_datetime64_compat('2012-01-02 00:00:00+0000')]),
|
||||
None, self.axis)
|
||||
assert rs[0] == xp
|
||||
|
||||
def test_integer_passthrough(self):
|
||||
# GH9012
|
||||
rs = self.pc.convert([0, 1], None, self.axis)
|
||||
xp = [0, 1]
|
||||
assert rs == xp
|
||||
|
||||
def test_convert_nested(self):
|
||||
data = ['2012-1-1', '2012-1-2']
|
||||
r1 = self.pc.convert([data, data], None, self.axis)
|
||||
r2 = [self.pc.convert(data, None, self.axis) for _ in range(2)]
|
||||
assert r1 == r2
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,75 @@
|
||||
# coding: utf-8
|
||||
|
||||
""" Test cases for GroupBy.plot """
|
||||
|
||||
|
||||
import numpy as np
|
||||
|
||||
import pandas.util._test_decorators as td
|
||||
|
||||
from pandas import DataFrame, Series
|
||||
from pandas.tests.plotting.common import TestPlotBase
|
||||
import pandas.util.testing as tm
|
||||
|
||||
|
||||
@td.skip_if_no_mpl
|
||||
class TestDataFrameGroupByPlots(TestPlotBase):
|
||||
|
||||
def test_series_groupby_plotting_nominally_works(self):
|
||||
n = 10
|
||||
weight = Series(np.random.normal(166, 20, size=n))
|
||||
height = Series(np.random.normal(60, 10, size=n))
|
||||
with tm.RNGContext(42):
|
||||
gender = np.random.choice(['male', 'female'], size=n)
|
||||
|
||||
weight.groupby(gender).plot()
|
||||
tm.close()
|
||||
height.groupby(gender).hist()
|
||||
tm.close()
|
||||
# Regression test for GH8733
|
||||
height.groupby(gender).plot(alpha=0.5)
|
||||
tm.close()
|
||||
|
||||
def test_plotting_with_float_index_works(self):
|
||||
# GH 7025
|
||||
df = DataFrame({'def': [1, 1, 1, 2, 2, 2, 3, 3, 3],
|
||||
'val': np.random.randn(9)},
|
||||
index=[1.0, 2.0, 3.0, 1.0, 2.0, 3.0, 1.0, 2.0, 3.0])
|
||||
|
||||
df.groupby('def')['val'].plot()
|
||||
tm.close()
|
||||
df.groupby('def')['val'].apply(lambda x: x.plot())
|
||||
tm.close()
|
||||
|
||||
def test_hist_single_row(self):
|
||||
# GH10214
|
||||
bins = np.arange(80, 100 + 2, 1)
|
||||
df = DataFrame({"Name": ["AAA", "BBB"],
|
||||
"ByCol": [1, 2],
|
||||
"Mark": [85, 89]})
|
||||
df["Mark"].hist(by=df["ByCol"], bins=bins)
|
||||
df = DataFrame({"Name": ["AAA"], "ByCol": [1], "Mark": [85]})
|
||||
df["Mark"].hist(by=df["ByCol"], bins=bins)
|
||||
|
||||
def test_plot_submethod_works(self):
|
||||
df = DataFrame({'x': [1, 2, 3, 4, 5],
|
||||
'y': [1, 2, 3, 2, 1],
|
||||
'z': list('ababa')})
|
||||
df.groupby('z').plot.scatter('x', 'y')
|
||||
tm.close()
|
||||
df.groupby('z')['x'].plot.line()
|
||||
tm.close()
|
||||
|
||||
def test_plot_kwargs(self):
|
||||
|
||||
df = DataFrame({'x': [1, 2, 3, 4, 5],
|
||||
'y': [1, 2, 3, 2, 1],
|
||||
'z': list('ababa')})
|
||||
|
||||
res = df.groupby('z').plot(kind='scatter', x='x', y='y')
|
||||
# check that a scatter plot is effectively plotted: the axes should
|
||||
# contain a PathCollection from the scatter plot (GH11805)
|
||||
assert len(res['a'].collections) == 1
|
||||
|
||||
res = df.groupby('z').plot.scatter(x='x', y='y')
|
||||
assert len(res['a'].collections) == 1
|
||||
@@ -0,0 +1,439 @@
|
||||
# coding: utf-8
|
||||
|
||||
""" Test cases for .hist method """
|
||||
|
||||
import numpy as np
|
||||
from numpy.random import randn
|
||||
import pytest
|
||||
|
||||
import pandas.util._test_decorators as td
|
||||
|
||||
from pandas import DataFrame, Series
|
||||
from pandas.tests.plotting.common import TestPlotBase, _check_plot_works
|
||||
import pandas.util.testing as tm
|
||||
|
||||
from pandas.plotting._compat import _mpl_ge_2_2_0
|
||||
from pandas.plotting._core import grouped_hist
|
||||
|
||||
|
||||
@td.skip_if_no_mpl
|
||||
class TestSeriesPlots(TestPlotBase):
|
||||
|
||||
def setup_method(self, method):
|
||||
TestPlotBase.setup_method(self, method)
|
||||
import matplotlib as mpl
|
||||
mpl.rcdefaults()
|
||||
|
||||
self.ts = tm.makeTimeSeries()
|
||||
self.ts.name = 'ts'
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_hist_legacy(self):
|
||||
_check_plot_works(self.ts.hist)
|
||||
_check_plot_works(self.ts.hist, grid=False)
|
||||
_check_plot_works(self.ts.hist, figsize=(8, 10))
|
||||
# _check_plot_works adds an ax so catch warning. see GH #13188
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
_check_plot_works(self.ts.hist, by=self.ts.index.month)
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
_check_plot_works(self.ts.hist, by=self.ts.index.month, bins=5)
|
||||
|
||||
fig, ax = self.plt.subplots(1, 1)
|
||||
_check_plot_works(self.ts.hist, ax=ax)
|
||||
_check_plot_works(self.ts.hist, ax=ax, figure=fig)
|
||||
_check_plot_works(self.ts.hist, figure=fig)
|
||||
tm.close()
|
||||
|
||||
fig, (ax1, ax2) = self.plt.subplots(1, 2)
|
||||
_check_plot_works(self.ts.hist, figure=fig, ax=ax1)
|
||||
_check_plot_works(self.ts.hist, figure=fig, ax=ax2)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
self.ts.hist(by=self.ts.index, figure=fig)
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_hist_bins_legacy(self):
|
||||
df = DataFrame(np.random.randn(10, 2))
|
||||
ax = df.hist(bins=2)[0][0]
|
||||
assert len(ax.patches) == 2
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_hist_layout(self):
|
||||
df = self.hist_df
|
||||
with pytest.raises(ValueError):
|
||||
df.height.hist(layout=(1, 1))
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
df.height.hist(layout=[1, 1])
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_hist_layout_with_by(self):
|
||||
df = self.hist_df
|
||||
|
||||
# _check_plot_works adds an `ax` kwarg to the method call
|
||||
# so we get a warning about an axis being cleared, even
|
||||
# though we don't explicing pass one, see GH #13188
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
axes = _check_plot_works(df.height.hist, by=df.gender,
|
||||
layout=(2, 1))
|
||||
self._check_axes_shape(axes, axes_num=2, layout=(2, 1))
|
||||
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
axes = _check_plot_works(df.height.hist, by=df.gender,
|
||||
layout=(3, -1))
|
||||
self._check_axes_shape(axes, axes_num=2, layout=(3, 1))
|
||||
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
axes = _check_plot_works(df.height.hist, by=df.category,
|
||||
layout=(4, 1))
|
||||
self._check_axes_shape(axes, axes_num=4, layout=(4, 1))
|
||||
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
axes = _check_plot_works(
|
||||
df.height.hist, by=df.category, layout=(2, -1))
|
||||
self._check_axes_shape(axes, axes_num=4, layout=(2, 2))
|
||||
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
axes = _check_plot_works(
|
||||
df.height.hist, by=df.category, layout=(3, -1))
|
||||
self._check_axes_shape(axes, axes_num=4, layout=(3, 2))
|
||||
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
axes = _check_plot_works(
|
||||
df.height.hist, by=df.category, layout=(-1, 4))
|
||||
self._check_axes_shape(axes, axes_num=4, layout=(1, 4))
|
||||
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
axes = _check_plot_works(
|
||||
df.height.hist, by=df.classroom, layout=(2, 2))
|
||||
self._check_axes_shape(axes, axes_num=3, layout=(2, 2))
|
||||
|
||||
axes = df.height.hist(by=df.category, layout=(4, 2), figsize=(12, 7))
|
||||
self._check_axes_shape(
|
||||
axes, axes_num=4, layout=(4, 2), figsize=(12, 7))
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_hist_no_overlap(self):
|
||||
from matplotlib.pyplot import subplot, gcf
|
||||
x = Series(randn(2))
|
||||
y = Series(randn(2))
|
||||
subplot(121)
|
||||
x.hist()
|
||||
subplot(122)
|
||||
y.hist()
|
||||
fig = gcf()
|
||||
axes = fig.axes
|
||||
assert len(axes) == 2
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_hist_by_no_extra_plots(self):
|
||||
df = self.hist_df
|
||||
axes = df.height.hist(by=df.gender) # noqa
|
||||
assert len(self.plt.get_fignums()) == 1
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_plot_fails_when_ax_differs_from_figure(self):
|
||||
from pylab import figure
|
||||
fig1 = figure()
|
||||
fig2 = figure()
|
||||
ax1 = fig1.add_subplot(111)
|
||||
with pytest.raises(AssertionError):
|
||||
self.ts.hist(ax=ax1, figure=fig2)
|
||||
|
||||
|
||||
@td.skip_if_no_mpl
|
||||
class TestDataFramePlots(TestPlotBase):
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_hist_df_legacy(self):
|
||||
from matplotlib.patches import Rectangle
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
_check_plot_works(self.hist_df.hist)
|
||||
|
||||
# make sure layout is handled
|
||||
df = DataFrame(randn(100, 3))
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
axes = _check_plot_works(df.hist, grid=False)
|
||||
self._check_axes_shape(axes, axes_num=3, layout=(2, 2))
|
||||
assert not axes[1, 1].get_visible()
|
||||
|
||||
df = DataFrame(randn(100, 1))
|
||||
_check_plot_works(df.hist)
|
||||
|
||||
# make sure layout is handled
|
||||
df = DataFrame(randn(100, 6))
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
axes = _check_plot_works(df.hist, layout=(4, 2))
|
||||
self._check_axes_shape(axes, axes_num=6, layout=(4, 2))
|
||||
|
||||
# make sure sharex, sharey is handled
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
_check_plot_works(df.hist, sharex=True, sharey=True)
|
||||
|
||||
# handle figsize arg
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
_check_plot_works(df.hist, figsize=(8, 10))
|
||||
|
||||
# check bins argument
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
_check_plot_works(df.hist, bins=5)
|
||||
|
||||
# make sure xlabelsize and xrot are handled
|
||||
ser = df[0]
|
||||
xf, yf = 20, 18
|
||||
xrot, yrot = 30, 40
|
||||
axes = ser.hist(xlabelsize=xf, xrot=xrot, ylabelsize=yf, yrot=yrot)
|
||||
self._check_ticks_props(axes, xlabelsize=xf, xrot=xrot,
|
||||
ylabelsize=yf, yrot=yrot)
|
||||
|
||||
xf, yf = 20, 18
|
||||
xrot, yrot = 30, 40
|
||||
axes = df.hist(xlabelsize=xf, xrot=xrot, ylabelsize=yf, yrot=yrot)
|
||||
self._check_ticks_props(axes, xlabelsize=xf, xrot=xrot,
|
||||
ylabelsize=yf, yrot=yrot)
|
||||
|
||||
tm.close()
|
||||
# make sure kwargs to hist are handled
|
||||
if _mpl_ge_2_2_0():
|
||||
kwargs = {"density": True}
|
||||
else:
|
||||
kwargs = {"normed": True}
|
||||
ax = ser.hist(cumulative=True, bins=4, **kwargs)
|
||||
# height of last bin (index 5) must be 1.0
|
||||
rects = [x for x in ax.get_children() if isinstance(x, Rectangle)]
|
||||
tm.assert_almost_equal(rects[-1].get_height(), 1.0)
|
||||
|
||||
tm.close()
|
||||
ax = ser.hist(log=True)
|
||||
# scale of y must be 'log'
|
||||
self._check_ax_scales(ax, yaxis='log')
|
||||
|
||||
tm.close()
|
||||
|
||||
# propagate attr exception from matplotlib.Axes.hist
|
||||
with pytest.raises(AttributeError):
|
||||
ser.hist(foo='bar')
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_hist_layout(self):
|
||||
df = DataFrame(randn(100, 3))
|
||||
|
||||
layout_to_expected_size = (
|
||||
{'layout': None, 'expected_size': (2, 2)}, # default is 2x2
|
||||
{'layout': (2, 2), 'expected_size': (2, 2)},
|
||||
{'layout': (4, 1), 'expected_size': (4, 1)},
|
||||
{'layout': (1, 4), 'expected_size': (1, 4)},
|
||||
{'layout': (3, 3), 'expected_size': (3, 3)},
|
||||
{'layout': (-1, 4), 'expected_size': (1, 4)},
|
||||
{'layout': (4, -1), 'expected_size': (4, 1)},
|
||||
{'layout': (-1, 2), 'expected_size': (2, 2)},
|
||||
{'layout': (2, -1), 'expected_size': (2, 2)}
|
||||
)
|
||||
|
||||
for layout_test in layout_to_expected_size:
|
||||
axes = df.hist(layout=layout_test['layout'])
|
||||
expected = layout_test['expected_size']
|
||||
self._check_axes_shape(axes, axes_num=3, layout=expected)
|
||||
|
||||
# layout too small for all 4 plots
|
||||
with pytest.raises(ValueError):
|
||||
df.hist(layout=(1, 1))
|
||||
|
||||
# invalid format for layout
|
||||
with pytest.raises(ValueError):
|
||||
df.hist(layout=(1,))
|
||||
with pytest.raises(ValueError):
|
||||
df.hist(layout=(-1, -1))
|
||||
|
||||
@pytest.mark.slow
|
||||
# GH 9351
|
||||
def test_tight_layout(self):
|
||||
if self.mpl_ge_2_0_1:
|
||||
df = DataFrame(randn(100, 3))
|
||||
_check_plot_works(df.hist)
|
||||
self.plt.tight_layout()
|
||||
|
||||
tm.close()
|
||||
|
||||
|
||||
@td.skip_if_no_mpl
|
||||
class TestDataFrameGroupByPlots(TestPlotBase):
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_grouped_hist_legacy(self):
|
||||
from matplotlib.patches import Rectangle
|
||||
|
||||
df = DataFrame(randn(500, 2), columns=['A', 'B'])
|
||||
df['C'] = np.random.randint(0, 4, 500)
|
||||
df['D'] = ['X'] * 500
|
||||
|
||||
axes = grouped_hist(df.A, by=df.C)
|
||||
self._check_axes_shape(axes, axes_num=4, layout=(2, 2))
|
||||
|
||||
tm.close()
|
||||
axes = df.hist(by=df.C)
|
||||
self._check_axes_shape(axes, axes_num=4, layout=(2, 2))
|
||||
|
||||
tm.close()
|
||||
# group by a key with single value
|
||||
axes = df.hist(by='D', rot=30)
|
||||
self._check_axes_shape(axes, axes_num=1, layout=(1, 1))
|
||||
self._check_ticks_props(axes, xrot=30)
|
||||
|
||||
tm.close()
|
||||
# make sure kwargs to hist are handled
|
||||
xf, yf = 20, 18
|
||||
xrot, yrot = 30, 40
|
||||
|
||||
if _mpl_ge_2_2_0():
|
||||
kwargs = {"density": True}
|
||||
else:
|
||||
kwargs = {"normed": True}
|
||||
|
||||
axes = grouped_hist(df.A, by=df.C, cumulative=True,
|
||||
bins=4, xlabelsize=xf, xrot=xrot,
|
||||
ylabelsize=yf, yrot=yrot, **kwargs)
|
||||
# height of last bin (index 5) must be 1.0
|
||||
for ax in axes.ravel():
|
||||
rects = [x for x in ax.get_children() if isinstance(x, Rectangle)]
|
||||
height = rects[-1].get_height()
|
||||
tm.assert_almost_equal(height, 1.0)
|
||||
self._check_ticks_props(axes, xlabelsize=xf, xrot=xrot,
|
||||
ylabelsize=yf, yrot=yrot)
|
||||
|
||||
tm.close()
|
||||
axes = grouped_hist(df.A, by=df.C, log=True)
|
||||
# scale of y must be 'log'
|
||||
self._check_ax_scales(axes, yaxis='log')
|
||||
|
||||
tm.close()
|
||||
# propagate attr exception from matplotlib.Axes.hist
|
||||
with pytest.raises(AttributeError):
|
||||
grouped_hist(df.A, by=df.C, foo='bar')
|
||||
|
||||
with tm.assert_produces_warning(FutureWarning):
|
||||
df.hist(by='C', figsize='default')
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_grouped_hist_legacy2(self):
|
||||
n = 10
|
||||
weight = Series(np.random.normal(166, 20, size=n))
|
||||
height = Series(np.random.normal(60, 10, size=n))
|
||||
with tm.RNGContext(42):
|
||||
gender_int = np.random.choice([0, 1], size=n)
|
||||
df_int = DataFrame({'height': height, 'weight': weight,
|
||||
'gender': gender_int})
|
||||
gb = df_int.groupby('gender')
|
||||
axes = gb.hist()
|
||||
assert len(axes) == 2
|
||||
assert len(self.plt.get_fignums()) == 2
|
||||
tm.close()
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_grouped_hist_layout(self):
|
||||
df = self.hist_df
|
||||
pytest.raises(ValueError, df.hist, column='weight', by=df.gender,
|
||||
layout=(1, 1))
|
||||
pytest.raises(ValueError, df.hist, column='height', by=df.category,
|
||||
layout=(1, 3))
|
||||
pytest.raises(ValueError, df.hist, column='height', by=df.category,
|
||||
layout=(-1, -1))
|
||||
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
axes = _check_plot_works(df.hist, column='height', by=df.gender,
|
||||
layout=(2, 1))
|
||||
self._check_axes_shape(axes, axes_num=2, layout=(2, 1))
|
||||
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
axes = _check_plot_works(df.hist, column='height', by=df.gender,
|
||||
layout=(2, -1))
|
||||
self._check_axes_shape(axes, axes_num=2, layout=(2, 1))
|
||||
|
||||
axes = df.hist(column='height', by=df.category, layout=(4, 1))
|
||||
self._check_axes_shape(axes, axes_num=4, layout=(4, 1))
|
||||
|
||||
axes = df.hist(column='height', by=df.category, layout=(-1, 1))
|
||||
self._check_axes_shape(axes, axes_num=4, layout=(4, 1))
|
||||
|
||||
axes = df.hist(column='height', by=df.category,
|
||||
layout=(4, 2), figsize=(12, 8))
|
||||
self._check_axes_shape(
|
||||
axes, axes_num=4, layout=(4, 2), figsize=(12, 8))
|
||||
tm.close()
|
||||
|
||||
# GH 6769
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
axes = _check_plot_works(
|
||||
df.hist, column='height', by='classroom', layout=(2, 2))
|
||||
self._check_axes_shape(axes, axes_num=3, layout=(2, 2))
|
||||
|
||||
# without column
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
axes = _check_plot_works(df.hist, by='classroom')
|
||||
self._check_axes_shape(axes, axes_num=3, layout=(2, 2))
|
||||
|
||||
axes = df.hist(by='gender', layout=(3, 5))
|
||||
self._check_axes_shape(axes, axes_num=2, layout=(3, 5))
|
||||
|
||||
axes = df.hist(column=['height', 'weight', 'category'])
|
||||
self._check_axes_shape(axes, axes_num=3, layout=(2, 2))
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_grouped_hist_multiple_axes(self):
|
||||
# GH 6970, GH 7069
|
||||
df = self.hist_df
|
||||
|
||||
fig, axes = self.plt.subplots(2, 3)
|
||||
returned = df.hist(column=['height', 'weight', 'category'], ax=axes[0])
|
||||
self._check_axes_shape(returned, axes_num=3, layout=(1, 3))
|
||||
tm.assert_numpy_array_equal(returned, axes[0])
|
||||
assert returned[0].figure is fig
|
||||
returned = df.hist(by='classroom', ax=axes[1])
|
||||
self._check_axes_shape(returned, axes_num=3, layout=(1, 3))
|
||||
tm.assert_numpy_array_equal(returned, axes[1])
|
||||
assert returned[0].figure is fig
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
fig, axes = self.plt.subplots(2, 3)
|
||||
# pass different number of axes from required
|
||||
axes = df.hist(column='height', ax=axes)
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_axis_share_x(self):
|
||||
df = self.hist_df
|
||||
# GH4089
|
||||
ax1, ax2 = df.hist(column='height', by=df.gender, sharex=True)
|
||||
|
||||
# share x
|
||||
assert ax1._shared_x_axes.joined(ax1, ax2)
|
||||
assert ax2._shared_x_axes.joined(ax1, ax2)
|
||||
|
||||
# don't share y
|
||||
assert not ax1._shared_y_axes.joined(ax1, ax2)
|
||||
assert not ax2._shared_y_axes.joined(ax1, ax2)
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_axis_share_y(self):
|
||||
df = self.hist_df
|
||||
ax1, ax2 = df.hist(column='height', by=df.gender, sharey=True)
|
||||
|
||||
# share y
|
||||
assert ax1._shared_y_axes.joined(ax1, ax2)
|
||||
assert ax2._shared_y_axes.joined(ax1, ax2)
|
||||
|
||||
# don't share x
|
||||
assert not ax1._shared_x_axes.joined(ax1, ax2)
|
||||
assert not ax2._shared_x_axes.joined(ax1, ax2)
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_axis_share_xy(self):
|
||||
df = self.hist_df
|
||||
ax1, ax2 = df.hist(column='height', by=df.gender, sharex=True,
|
||||
sharey=True)
|
||||
|
||||
# share both x and y
|
||||
assert ax1._shared_x_axes.joined(ax1, ax2)
|
||||
assert ax2._shared_x_axes.joined(ax1, ax2)
|
||||
|
||||
assert ax1._shared_y_axes.joined(ax1, ax2)
|
||||
assert ax2._shared_y_axes.joined(ax1, ax2)
|
||||
@@ -0,0 +1,356 @@
|
||||
# coding: utf-8
|
||||
|
||||
""" Test cases for misc plot functions """
|
||||
|
||||
import numpy as np
|
||||
from numpy import random
|
||||
from numpy.random import randn
|
||||
import pytest
|
||||
|
||||
from pandas.compat import lmap
|
||||
import pandas.util._test_decorators as td
|
||||
|
||||
from pandas import DataFrame
|
||||
from pandas.tests.plotting.common import TestPlotBase, _check_plot_works
|
||||
import pandas.util.testing as tm
|
||||
|
||||
import pandas.plotting as plotting
|
||||
|
||||
|
||||
@td.skip_if_mpl
|
||||
def test_import_error_message():
|
||||
# GH-19810
|
||||
df = DataFrame({"A": [1, 2]})
|
||||
|
||||
with pytest.raises(ImportError, match='matplotlib is required'):
|
||||
df.plot()
|
||||
|
||||
|
||||
@td.skip_if_no_mpl
|
||||
class TestSeriesPlots(TestPlotBase):
|
||||
|
||||
def setup_method(self, method):
|
||||
TestPlotBase.setup_method(self, method)
|
||||
import matplotlib as mpl
|
||||
mpl.rcdefaults()
|
||||
|
||||
self.ts = tm.makeTimeSeries()
|
||||
self.ts.name = 'ts'
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_autocorrelation_plot(self):
|
||||
from pandas.plotting import autocorrelation_plot
|
||||
_check_plot_works(autocorrelation_plot, series=self.ts)
|
||||
_check_plot_works(autocorrelation_plot, series=self.ts.values)
|
||||
|
||||
ax = autocorrelation_plot(self.ts, label='Test')
|
||||
self._check_legend_labels(ax, labels=['Test'])
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_lag_plot(self):
|
||||
from pandas.plotting import lag_plot
|
||||
_check_plot_works(lag_plot, series=self.ts)
|
||||
_check_plot_works(lag_plot, series=self.ts, lag=5)
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_bootstrap_plot(self):
|
||||
from pandas.plotting import bootstrap_plot
|
||||
_check_plot_works(bootstrap_plot, series=self.ts, size=10)
|
||||
|
||||
|
||||
@td.skip_if_no_mpl
|
||||
class TestDataFramePlots(TestPlotBase):
|
||||
|
||||
# This XPASSES when tested with mpl == 3.0.1
|
||||
@td.xfail_if_mpl_2_2
|
||||
@td.skip_if_no_scipy
|
||||
def test_scatter_matrix_axis(self):
|
||||
scatter_matrix = plotting.scatter_matrix
|
||||
|
||||
with tm.RNGContext(42):
|
||||
df = DataFrame(randn(100, 3))
|
||||
|
||||
# we are plotting multiples on a sub-plot
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
axes = _check_plot_works(scatter_matrix, filterwarnings='always',
|
||||
frame=df, range_padding=.1)
|
||||
axes0_labels = axes[0][0].yaxis.get_majorticklabels()
|
||||
|
||||
# GH 5662
|
||||
expected = ['-2', '0', '2']
|
||||
self._check_text_labels(axes0_labels, expected)
|
||||
self._check_ticks_props(
|
||||
axes, xlabelsize=8, xrot=90, ylabelsize=8, yrot=0)
|
||||
|
||||
df[0] = ((df[0] - 2) / 3)
|
||||
|
||||
# we are plotting multiples on a sub-plot
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
axes = _check_plot_works(scatter_matrix, filterwarnings='always',
|
||||
frame=df, range_padding=.1)
|
||||
axes0_labels = axes[0][0].yaxis.get_majorticklabels()
|
||||
expected = ['-1.0', '-0.5', '0.0']
|
||||
self._check_text_labels(axes0_labels, expected)
|
||||
self._check_ticks_props(
|
||||
axes, xlabelsize=8, xrot=90, ylabelsize=8, yrot=0)
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_andrews_curves(self, iris):
|
||||
from pandas.plotting import andrews_curves
|
||||
from matplotlib import cm
|
||||
|
||||
df = iris
|
||||
|
||||
_check_plot_works(andrews_curves, frame=df, class_column='Name')
|
||||
|
||||
rgba = ('#556270', '#4ECDC4', '#C7F464')
|
||||
ax = _check_plot_works(andrews_curves, frame=df,
|
||||
class_column='Name', color=rgba)
|
||||
self._check_colors(
|
||||
ax.get_lines()[:10], linecolors=rgba, mapping=df['Name'][:10])
|
||||
|
||||
cnames = ['dodgerblue', 'aquamarine', 'seagreen']
|
||||
ax = _check_plot_works(andrews_curves, frame=df,
|
||||
class_column='Name', color=cnames)
|
||||
self._check_colors(
|
||||
ax.get_lines()[:10], linecolors=cnames, mapping=df['Name'][:10])
|
||||
|
||||
ax = _check_plot_works(andrews_curves, frame=df,
|
||||
class_column='Name', colormap=cm.jet)
|
||||
cmaps = lmap(cm.jet, np.linspace(0, 1, df['Name'].nunique()))
|
||||
self._check_colors(
|
||||
ax.get_lines()[:10], linecolors=cmaps, mapping=df['Name'][:10])
|
||||
|
||||
length = 10
|
||||
df = DataFrame({"A": random.rand(length),
|
||||
"B": random.rand(length),
|
||||
"C": random.rand(length),
|
||||
"Name": ["A"] * length})
|
||||
|
||||
_check_plot_works(andrews_curves, frame=df, class_column='Name')
|
||||
|
||||
rgba = ('#556270', '#4ECDC4', '#C7F464')
|
||||
ax = _check_plot_works(andrews_curves, frame=df,
|
||||
class_column='Name', color=rgba)
|
||||
self._check_colors(
|
||||
ax.get_lines()[:10], linecolors=rgba, mapping=df['Name'][:10])
|
||||
|
||||
cnames = ['dodgerblue', 'aquamarine', 'seagreen']
|
||||
ax = _check_plot_works(andrews_curves, frame=df,
|
||||
class_column='Name', color=cnames)
|
||||
self._check_colors(
|
||||
ax.get_lines()[:10], linecolors=cnames, mapping=df['Name'][:10])
|
||||
|
||||
ax = _check_plot_works(andrews_curves, frame=df,
|
||||
class_column='Name', colormap=cm.jet)
|
||||
cmaps = lmap(cm.jet, np.linspace(0, 1, df['Name'].nunique()))
|
||||
self._check_colors(
|
||||
ax.get_lines()[:10], linecolors=cmaps, mapping=df['Name'][:10])
|
||||
|
||||
colors = ['b', 'g', 'r']
|
||||
df = DataFrame({"A": [1, 2, 3],
|
||||
"B": [1, 2, 3],
|
||||
"C": [1, 2, 3],
|
||||
"Name": colors})
|
||||
ax = andrews_curves(df, 'Name', color=colors)
|
||||
handles, labels = ax.get_legend_handles_labels()
|
||||
self._check_colors(handles, linecolors=colors)
|
||||
|
||||
with tm.assert_produces_warning(FutureWarning):
|
||||
andrews_curves(data=df, class_column='Name')
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_parallel_coordinates(self, iris):
|
||||
from pandas.plotting import parallel_coordinates
|
||||
from matplotlib import cm
|
||||
|
||||
df = iris
|
||||
|
||||
ax = _check_plot_works(parallel_coordinates,
|
||||
frame=df, class_column='Name')
|
||||
nlines = len(ax.get_lines())
|
||||
nxticks = len(ax.xaxis.get_ticklabels())
|
||||
|
||||
rgba = ('#556270', '#4ECDC4', '#C7F464')
|
||||
ax = _check_plot_works(parallel_coordinates,
|
||||
frame=df, class_column='Name', color=rgba)
|
||||
self._check_colors(
|
||||
ax.get_lines()[:10], linecolors=rgba, mapping=df['Name'][:10])
|
||||
|
||||
cnames = ['dodgerblue', 'aquamarine', 'seagreen']
|
||||
ax = _check_plot_works(parallel_coordinates,
|
||||
frame=df, class_column='Name', color=cnames)
|
||||
self._check_colors(
|
||||
ax.get_lines()[:10], linecolors=cnames, mapping=df['Name'][:10])
|
||||
|
||||
ax = _check_plot_works(parallel_coordinates,
|
||||
frame=df, class_column='Name', colormap=cm.jet)
|
||||
cmaps = lmap(cm.jet, np.linspace(0, 1, df['Name'].nunique()))
|
||||
self._check_colors(
|
||||
ax.get_lines()[:10], linecolors=cmaps, mapping=df['Name'][:10])
|
||||
|
||||
ax = _check_plot_works(parallel_coordinates,
|
||||
frame=df, class_column='Name', axvlines=False)
|
||||
assert len(ax.get_lines()) == (nlines - nxticks)
|
||||
|
||||
colors = ['b', 'g', 'r']
|
||||
df = DataFrame({"A": [1, 2, 3],
|
||||
"B": [1, 2, 3],
|
||||
"C": [1, 2, 3],
|
||||
"Name": colors})
|
||||
ax = parallel_coordinates(df, 'Name', color=colors)
|
||||
handles, labels = ax.get_legend_handles_labels()
|
||||
self._check_colors(handles, linecolors=colors)
|
||||
|
||||
with tm.assert_produces_warning(FutureWarning):
|
||||
parallel_coordinates(data=df, class_column='Name')
|
||||
with tm.assert_produces_warning(FutureWarning):
|
||||
parallel_coordinates(df, 'Name', colors=colors)
|
||||
|
||||
# not sure if this is indicative of a problem
|
||||
@pytest.mark.filterwarnings("ignore:Attempting to set:UserWarning")
|
||||
def test_parallel_coordinates_with_sorted_labels(self):
|
||||
""" For #15908 """
|
||||
from pandas.plotting import parallel_coordinates
|
||||
|
||||
df = DataFrame({"feat": [i for i in range(30)],
|
||||
"class": [2 for _ in range(10)] +
|
||||
[3 for _ in range(10)] +
|
||||
[1 for _ in range(10)]})
|
||||
ax = parallel_coordinates(df, 'class', sort_labels=True)
|
||||
polylines, labels = ax.get_legend_handles_labels()
|
||||
color_label_tuples = \
|
||||
zip([polyline.get_color() for polyline in polylines], labels)
|
||||
ordered_color_label_tuples = sorted(color_label_tuples,
|
||||
key=lambda x: x[1])
|
||||
prev_next_tupels = zip([i for i in ordered_color_label_tuples[0:-1]],
|
||||
[i for i in ordered_color_label_tuples[1:]])
|
||||
for prev, nxt in prev_next_tupels:
|
||||
# labels and colors are ordered strictly increasing
|
||||
assert prev[1] < nxt[1] and prev[0] < nxt[0]
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_radviz(self, iris):
|
||||
from pandas.plotting import radviz
|
||||
from matplotlib import cm
|
||||
|
||||
df = iris
|
||||
_check_plot_works(radviz, frame=df, class_column='Name')
|
||||
|
||||
rgba = ('#556270', '#4ECDC4', '#C7F464')
|
||||
ax = _check_plot_works(
|
||||
radviz, frame=df, class_column='Name', color=rgba)
|
||||
# skip Circle drawn as ticks
|
||||
patches = [p for p in ax.patches[:20] if p.get_label() != '']
|
||||
self._check_colors(
|
||||
patches[:10], facecolors=rgba, mapping=df['Name'][:10])
|
||||
|
||||
cnames = ['dodgerblue', 'aquamarine', 'seagreen']
|
||||
_check_plot_works(radviz, frame=df, class_column='Name', color=cnames)
|
||||
patches = [p for p in ax.patches[:20] if p.get_label() != '']
|
||||
self._check_colors(patches, facecolors=cnames, mapping=df['Name'][:10])
|
||||
|
||||
_check_plot_works(radviz, frame=df,
|
||||
class_column='Name', colormap=cm.jet)
|
||||
cmaps = lmap(cm.jet, np.linspace(0, 1, df['Name'].nunique()))
|
||||
patches = [p for p in ax.patches[:20] if p.get_label() != '']
|
||||
self._check_colors(patches, facecolors=cmaps, mapping=df['Name'][:10])
|
||||
|
||||
colors = [[0., 0., 1., 1.],
|
||||
[0., 0.5, 1., 1.],
|
||||
[1., 0., 0., 1.]]
|
||||
df = DataFrame({"A": [1, 2, 3],
|
||||
"B": [2, 1, 3],
|
||||
"C": [3, 2, 1],
|
||||
"Name": ['b', 'g', 'r']})
|
||||
ax = radviz(df, 'Name', color=colors)
|
||||
handles, labels = ax.get_legend_handles_labels()
|
||||
self._check_colors(handles, facecolors=colors)
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_subplot_titles(self, iris):
|
||||
df = iris.drop('Name', axis=1).head()
|
||||
# Use the column names as the subplot titles
|
||||
title = list(df.columns)
|
||||
|
||||
# Case len(title) == len(df)
|
||||
plot = df.plot(subplots=True, title=title)
|
||||
assert [p.get_title() for p in plot] == title
|
||||
|
||||
# Case len(title) > len(df)
|
||||
pytest.raises(ValueError, df.plot, subplots=True,
|
||||
title=title + ["kittens > puppies"])
|
||||
|
||||
# Case len(title) < len(df)
|
||||
pytest.raises(ValueError, df.plot, subplots=True, title=title[:2])
|
||||
|
||||
# Case subplots=False and title is of type list
|
||||
pytest.raises(ValueError, df.plot, subplots=False, title=title)
|
||||
|
||||
# Case df with 3 numeric columns but layout of (2,2)
|
||||
plot = df.drop('SepalWidth', axis=1).plot(subplots=True, layout=(2, 2),
|
||||
title=title[:-1])
|
||||
title_list = [ax.get_title() for sublist in plot for ax in sublist]
|
||||
assert title_list == title[:3] + ['']
|
||||
|
||||
def test_get_standard_colors_random_seed(self):
|
||||
# GH17525
|
||||
df = DataFrame(np.zeros((10, 10)))
|
||||
|
||||
# Make sure that the random seed isn't reset by _get_standard_colors
|
||||
plotting.parallel_coordinates(df, 0)
|
||||
rand1 = random.random()
|
||||
plotting.parallel_coordinates(df, 0)
|
||||
rand2 = random.random()
|
||||
assert rand1 != rand2
|
||||
|
||||
# Make sure it produces the same colors every time it's called
|
||||
from pandas.plotting._style import _get_standard_colors
|
||||
color1 = _get_standard_colors(1, color_type='random')
|
||||
color2 = _get_standard_colors(1, color_type='random')
|
||||
assert color1 == color2
|
||||
|
||||
def test_get_standard_colors_default_num_colors(self):
|
||||
from pandas.plotting._style import _get_standard_colors
|
||||
|
||||
# Make sure the default color_types returns the specified amount
|
||||
color1 = _get_standard_colors(1, color_type='default')
|
||||
color2 = _get_standard_colors(9, color_type='default')
|
||||
color3 = _get_standard_colors(20, color_type='default')
|
||||
assert len(color1) == 1
|
||||
assert len(color2) == 9
|
||||
assert len(color3) == 20
|
||||
|
||||
def test_plot_single_color(self):
|
||||
# Example from #20585. All 3 bars should have the same color
|
||||
df = DataFrame({'account-start': ['2017-02-03', '2017-03-03',
|
||||
'2017-01-01'],
|
||||
'client': ['Alice Anders', 'Bob Baker',
|
||||
'Charlie Chaplin'],
|
||||
'balance': [-1432.32, 10.43, 30000.00],
|
||||
'db-id': [1234, 2424, 251],
|
||||
'proxy-id': [525, 1525, 2542],
|
||||
'rank': [52, 525, 32],
|
||||
})
|
||||
ax = df.client.value_counts().plot.bar()
|
||||
colors = lmap(lambda rect: rect.get_facecolor(),
|
||||
ax.get_children()[0:3])
|
||||
assert all(color == colors[0] for color in colors)
|
||||
|
||||
def test_get_standard_colors_no_appending(self):
|
||||
# GH20726
|
||||
|
||||
# Make sure not to add more colors so that matplotlib can cycle
|
||||
# correctly.
|
||||
from matplotlib import cm
|
||||
color_before = cm.gnuplot(range(5))
|
||||
color_after = plotting._style._get_standard_colors(
|
||||
1, color=color_before)
|
||||
assert len(color_after) == len(color_before)
|
||||
|
||||
df = DataFrame(np.random.randn(48, 4), columns=list("ABCD"))
|
||||
|
||||
color_list = cm.gnuplot(np.linspace(0, 1, 16))
|
||||
p = df.A.plot.bar(figsize=(16, 7), color=color_list)
|
||||
assert (p.patches[1].get_facecolor()
|
||||
== p.patches[17].get_facecolor())
|
||||
@@ -0,0 +1,891 @@
|
||||
# coding: utf-8
|
||||
|
||||
""" Test cases for Series.plot """
|
||||
|
||||
|
||||
from datetime import datetime
|
||||
from itertools import chain
|
||||
|
||||
import numpy as np
|
||||
from numpy.random import randn
|
||||
import pytest
|
||||
|
||||
from pandas.compat import lrange, range
|
||||
import pandas.util._test_decorators as td
|
||||
|
||||
import pandas as pd
|
||||
from pandas import DataFrame, Series, date_range
|
||||
from pandas.tests.plotting.common import (
|
||||
TestPlotBase, _check_plot_works, _ok_for_gaussian_kde,
|
||||
_skip_if_no_scipy_gaussian_kde)
|
||||
import pandas.util.testing as tm
|
||||
|
||||
import pandas.plotting as plotting
|
||||
|
||||
|
||||
@td.skip_if_no_mpl
|
||||
class TestSeriesPlots(TestPlotBase):
|
||||
|
||||
def setup_method(self, method):
|
||||
TestPlotBase.setup_method(self, method)
|
||||
import matplotlib as mpl
|
||||
mpl.rcdefaults()
|
||||
|
||||
self.ts = tm.makeTimeSeries()
|
||||
self.ts.name = 'ts'
|
||||
|
||||
self.series = tm.makeStringSeries()
|
||||
self.series.name = 'series'
|
||||
|
||||
self.iseries = tm.makePeriodSeries()
|
||||
self.iseries.name = 'iseries'
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_plot(self):
|
||||
_check_plot_works(self.ts.plot, label='foo')
|
||||
_check_plot_works(self.ts.plot, use_index=False)
|
||||
axes = _check_plot_works(self.ts.plot, rot=0)
|
||||
self._check_ticks_props(axes, xrot=0)
|
||||
|
||||
ax = _check_plot_works(self.ts.plot, style='.', logy=True)
|
||||
self._check_ax_scales(ax, yaxis='log')
|
||||
|
||||
ax = _check_plot_works(self.ts.plot, style='.', logx=True)
|
||||
self._check_ax_scales(ax, xaxis='log')
|
||||
|
||||
ax = _check_plot_works(self.ts.plot, style='.', loglog=True)
|
||||
self._check_ax_scales(ax, xaxis='log', yaxis='log')
|
||||
|
||||
_check_plot_works(self.ts[:10].plot.bar)
|
||||
_check_plot_works(self.ts.plot.area, stacked=False)
|
||||
_check_plot_works(self.iseries.plot)
|
||||
|
||||
for kind in ['line', 'bar', 'barh', 'kde', 'hist', 'box']:
|
||||
if not _ok_for_gaussian_kde(kind):
|
||||
continue
|
||||
_check_plot_works(self.series[:5].plot, kind=kind)
|
||||
|
||||
_check_plot_works(self.series[:10].plot.barh)
|
||||
ax = _check_plot_works(Series(randn(10)).plot.bar, color='black')
|
||||
self._check_colors([ax.patches[0]], facecolors=['black'])
|
||||
|
||||
# GH 6951
|
||||
ax = _check_plot_works(self.ts.plot, subplots=True)
|
||||
self._check_axes_shape(ax, axes_num=1, layout=(1, 1))
|
||||
|
||||
ax = _check_plot_works(self.ts.plot, subplots=True, layout=(-1, 1))
|
||||
self._check_axes_shape(ax, axes_num=1, layout=(1, 1))
|
||||
ax = _check_plot_works(self.ts.plot, subplots=True, layout=(1, -1))
|
||||
self._check_axes_shape(ax, axes_num=1, layout=(1, 1))
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_plot_figsize_and_title(self):
|
||||
# figsize and title
|
||||
_, ax = self.plt.subplots()
|
||||
ax = self.series.plot(title='Test', figsize=(16, 8), ax=ax)
|
||||
self._check_text_labels(ax.title, 'Test')
|
||||
self._check_axes_shape(ax, axes_num=1, layout=(1, 1), figsize=(16, 8))
|
||||
|
||||
def test_dont_modify_rcParams(self):
|
||||
# GH 8242
|
||||
key = 'axes.prop_cycle'
|
||||
colors = self.plt.rcParams[key]
|
||||
_, ax = self.plt.subplots()
|
||||
Series([1, 2, 3]).plot(ax=ax)
|
||||
assert colors == self.plt.rcParams[key]
|
||||
|
||||
def test_ts_line_lim(self):
|
||||
fig, ax = self.plt.subplots()
|
||||
ax = self.ts.plot(ax=ax)
|
||||
xmin, xmax = ax.get_xlim()
|
||||
lines = ax.get_lines()
|
||||
assert xmin <= lines[0].get_data(orig=False)[0][0]
|
||||
assert xmax >= lines[0].get_data(orig=False)[0][-1]
|
||||
tm.close()
|
||||
|
||||
ax = self.ts.plot(secondary_y=True, ax=ax)
|
||||
xmin, xmax = ax.get_xlim()
|
||||
lines = ax.get_lines()
|
||||
assert xmin <= lines[0].get_data(orig=False)[0][0]
|
||||
assert xmax >= lines[0].get_data(orig=False)[0][-1]
|
||||
|
||||
def test_ts_area_lim(self):
|
||||
_, ax = self.plt.subplots()
|
||||
ax = self.ts.plot.area(stacked=False, ax=ax)
|
||||
xmin, xmax = ax.get_xlim()
|
||||
line = ax.get_lines()[0].get_data(orig=False)[0]
|
||||
assert xmin <= line[0]
|
||||
assert xmax >= line[-1]
|
||||
tm.close()
|
||||
|
||||
# GH 7471
|
||||
_, ax = self.plt.subplots()
|
||||
ax = self.ts.plot.area(stacked=False, x_compat=True, ax=ax)
|
||||
xmin, xmax = ax.get_xlim()
|
||||
line = ax.get_lines()[0].get_data(orig=False)[0]
|
||||
assert xmin <= line[0]
|
||||
assert xmax >= line[-1]
|
||||
tm.close()
|
||||
|
||||
tz_ts = self.ts.copy()
|
||||
tz_ts.index = tz_ts.tz_localize('GMT').tz_convert('CET')
|
||||
_, ax = self.plt.subplots()
|
||||
ax = tz_ts.plot.area(stacked=False, x_compat=True, ax=ax)
|
||||
xmin, xmax = ax.get_xlim()
|
||||
line = ax.get_lines()[0].get_data(orig=False)[0]
|
||||
assert xmin <= line[0]
|
||||
assert xmax >= line[-1]
|
||||
tm.close()
|
||||
|
||||
_, ax = self.plt.subplots()
|
||||
ax = tz_ts.plot.area(stacked=False, secondary_y=True, ax=ax)
|
||||
xmin, xmax = ax.get_xlim()
|
||||
line = ax.get_lines()[0].get_data(orig=False)[0]
|
||||
assert xmin <= line[0]
|
||||
assert xmax >= line[-1]
|
||||
|
||||
def test_label(self):
|
||||
s = Series([1, 2])
|
||||
_, ax = self.plt.subplots()
|
||||
ax = s.plot(label='LABEL', legend=True, ax=ax)
|
||||
self._check_legend_labels(ax, labels=['LABEL'])
|
||||
self.plt.close()
|
||||
_, ax = self.plt.subplots()
|
||||
ax = s.plot(legend=True, ax=ax)
|
||||
self._check_legend_labels(ax, labels=['None'])
|
||||
self.plt.close()
|
||||
# get name from index
|
||||
s.name = 'NAME'
|
||||
_, ax = self.plt.subplots()
|
||||
ax = s.plot(legend=True, ax=ax)
|
||||
self._check_legend_labels(ax, labels=['NAME'])
|
||||
self.plt.close()
|
||||
# override the default
|
||||
_, ax = self.plt.subplots()
|
||||
ax = s.plot(legend=True, label='LABEL', ax=ax)
|
||||
self._check_legend_labels(ax, labels=['LABEL'])
|
||||
self.plt.close()
|
||||
# Add lebel info, but don't draw
|
||||
_, ax = self.plt.subplots()
|
||||
ax = s.plot(legend=False, label='LABEL', ax=ax)
|
||||
assert ax.get_legend() is None # Hasn't been drawn
|
||||
ax.legend() # draw it
|
||||
self._check_legend_labels(ax, labels=['LABEL'])
|
||||
|
||||
def test_line_area_nan_series(self):
|
||||
values = [1, 2, np.nan, 3]
|
||||
s = Series(values)
|
||||
ts = Series(values, index=tm.makeDateIndex(k=4))
|
||||
|
||||
for d in [s, ts]:
|
||||
ax = _check_plot_works(d.plot)
|
||||
masked = ax.lines[0].get_ydata()
|
||||
# remove nan for comparison purpose
|
||||
exp = np.array([1, 2, 3], dtype=np.float64)
|
||||
tm.assert_numpy_array_equal(np.delete(masked.data, 2), exp)
|
||||
tm.assert_numpy_array_equal(
|
||||
masked.mask, np.array([False, False, True, False]))
|
||||
|
||||
expected = np.array([1, 2, 0, 3], dtype=np.float64)
|
||||
ax = _check_plot_works(d.plot, stacked=True)
|
||||
tm.assert_numpy_array_equal(ax.lines[0].get_ydata(), expected)
|
||||
ax = _check_plot_works(d.plot.area)
|
||||
tm.assert_numpy_array_equal(ax.lines[0].get_ydata(), expected)
|
||||
ax = _check_plot_works(d.plot.area, stacked=False)
|
||||
tm.assert_numpy_array_equal(ax.lines[0].get_ydata(), expected)
|
||||
|
||||
def test_line_use_index_false(self):
|
||||
s = Series([1, 2, 3], index=['a', 'b', 'c'])
|
||||
s.index.name = 'The Index'
|
||||
_, ax = self.plt.subplots()
|
||||
ax = s.plot(use_index=False, ax=ax)
|
||||
label = ax.get_xlabel()
|
||||
assert label == ''
|
||||
_, ax = self.plt.subplots()
|
||||
ax2 = s.plot.bar(use_index=False, ax=ax)
|
||||
label2 = ax2.get_xlabel()
|
||||
assert label2 == ''
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_bar_log(self):
|
||||
expected = np.array([1e-1, 1e0, 1e1, 1e2, 1e3, 1e4])
|
||||
|
||||
_, ax = self.plt.subplots()
|
||||
ax = Series([200, 500]).plot.bar(log=True, ax=ax)
|
||||
tm.assert_numpy_array_equal(ax.yaxis.get_ticklocs(), expected)
|
||||
tm.close()
|
||||
|
||||
_, ax = self.plt.subplots()
|
||||
ax = Series([200, 500]).plot.barh(log=True, ax=ax)
|
||||
tm.assert_numpy_array_equal(ax.xaxis.get_ticklocs(), expected)
|
||||
tm.close()
|
||||
|
||||
# GH 9905
|
||||
expected = np.array([1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1])
|
||||
|
||||
_, ax = self.plt.subplots()
|
||||
ax = Series([0.1, 0.01, 0.001]).plot(log=True, kind='bar', ax=ax)
|
||||
ymin = 0.0007943282347242822
|
||||
ymax = 0.12589254117941673
|
||||
res = ax.get_ylim()
|
||||
tm.assert_almost_equal(res[0], ymin)
|
||||
tm.assert_almost_equal(res[1], ymax)
|
||||
tm.assert_numpy_array_equal(ax.yaxis.get_ticklocs(), expected)
|
||||
tm.close()
|
||||
|
||||
_, ax = self.plt.subplots()
|
||||
ax = Series([0.1, 0.01, 0.001]).plot(log=True, kind='barh', ax=ax)
|
||||
res = ax.get_xlim()
|
||||
tm.assert_almost_equal(res[0], ymin)
|
||||
tm.assert_almost_equal(res[1], ymax)
|
||||
tm.assert_numpy_array_equal(ax.xaxis.get_ticklocs(), expected)
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_bar_ignore_index(self):
|
||||
df = Series([1, 2, 3, 4], index=['a', 'b', 'c', 'd'])
|
||||
_, ax = self.plt.subplots()
|
||||
ax = df.plot.bar(use_index=False, ax=ax)
|
||||
self._check_text_labels(ax.get_xticklabels(), ['0', '1', '2', '3'])
|
||||
|
||||
def test_bar_user_colors(self):
|
||||
s = Series([1, 2, 3, 4])
|
||||
ax = s.plot.bar(color=['red', 'blue', 'blue', 'red'])
|
||||
result = [p.get_facecolor() for p in ax.patches]
|
||||
expected = [(1., 0., 0., 1.),
|
||||
(0., 0., 1., 1.),
|
||||
(0., 0., 1., 1.),
|
||||
(1., 0., 0., 1.)]
|
||||
assert result == expected
|
||||
|
||||
def test_rotation(self):
|
||||
df = DataFrame(randn(5, 5))
|
||||
# Default rot 0
|
||||
_, ax = self.plt.subplots()
|
||||
axes = df.plot(ax=ax)
|
||||
self._check_ticks_props(axes, xrot=0)
|
||||
|
||||
_, ax = self.plt.subplots()
|
||||
axes = df.plot(rot=30, ax=ax)
|
||||
self._check_ticks_props(axes, xrot=30)
|
||||
|
||||
def test_irregular_datetime(self):
|
||||
rng = date_range('1/1/2000', '3/1/2000')
|
||||
rng = rng[[0, 1, 2, 3, 5, 9, 10, 11, 12]]
|
||||
ser = Series(randn(len(rng)), rng)
|
||||
_, ax = self.plt.subplots()
|
||||
ax = ser.plot(ax=ax)
|
||||
xp = datetime(1999, 1, 1).toordinal()
|
||||
ax.set_xlim('1/1/1999', '1/1/2001')
|
||||
assert xp == ax.get_xlim()[0]
|
||||
|
||||
def test_unsorted_index_xlim(self):
|
||||
ser = Series([0., 1., np.nan, 3., 4., 5., 6.],
|
||||
index=[1., 0., 3., 2., np.nan, 3., 2.])
|
||||
_, ax = self.plt.subplots()
|
||||
ax = ser.plot(ax=ax)
|
||||
xmin, xmax = ax.get_xlim()
|
||||
lines = ax.get_lines()
|
||||
assert xmin <= np.nanmin(lines[0].get_data(orig=False)[0])
|
||||
assert xmax >= np.nanmax(lines[0].get_data(orig=False)[0])
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_pie_series(self):
|
||||
# if sum of values is less than 1.0, pie handle them as rate and draw
|
||||
# semicircle.
|
||||
series = Series(np.random.randint(1, 5),
|
||||
index=['a', 'b', 'c', 'd', 'e'], name='YLABEL')
|
||||
ax = _check_plot_works(series.plot.pie)
|
||||
self._check_text_labels(ax.texts, series.index)
|
||||
assert ax.get_ylabel() == 'YLABEL'
|
||||
|
||||
# without wedge labels
|
||||
ax = _check_plot_works(series.plot.pie, labels=None)
|
||||
self._check_text_labels(ax.texts, [''] * 5)
|
||||
|
||||
# with less colors than elements
|
||||
color_args = ['r', 'g', 'b']
|
||||
ax = _check_plot_works(series.plot.pie, colors=color_args)
|
||||
|
||||
color_expected = ['r', 'g', 'b', 'r', 'g']
|
||||
self._check_colors(ax.patches, facecolors=color_expected)
|
||||
|
||||
# with labels and colors
|
||||
labels = ['A', 'B', 'C', 'D', 'E']
|
||||
color_args = ['r', 'g', 'b', 'c', 'm']
|
||||
ax = _check_plot_works(series.plot.pie, labels=labels,
|
||||
colors=color_args)
|
||||
self._check_text_labels(ax.texts, labels)
|
||||
self._check_colors(ax.patches, facecolors=color_args)
|
||||
|
||||
# with autopct and fontsize
|
||||
ax = _check_plot_works(series.plot.pie, colors=color_args,
|
||||
autopct='%.2f', fontsize=7)
|
||||
pcts = ['{0:.2f}'.format(s * 100)
|
||||
for s in series.values / float(series.sum())]
|
||||
expected_texts = list(chain.from_iterable(zip(series.index, pcts)))
|
||||
self._check_text_labels(ax.texts, expected_texts)
|
||||
for t in ax.texts:
|
||||
assert t.get_fontsize() == 7
|
||||
|
||||
# includes negative value
|
||||
with pytest.raises(ValueError):
|
||||
series = Series([1, 2, 0, 4, -1], index=['a', 'b', 'c', 'd', 'e'])
|
||||
series.plot.pie()
|
||||
|
||||
# includes nan
|
||||
series = Series([1, 2, np.nan, 4], index=['a', 'b', 'c', 'd'],
|
||||
name='YLABEL')
|
||||
ax = _check_plot_works(series.plot.pie)
|
||||
self._check_text_labels(ax.texts, ['a', 'b', '', 'd'])
|
||||
|
||||
def test_pie_nan(self):
|
||||
s = Series([1, np.nan, 1, 1])
|
||||
_, ax = self.plt.subplots()
|
||||
ax = s.plot.pie(legend=True, ax=ax)
|
||||
expected = ['0', '', '2', '3']
|
||||
result = [x.get_text() for x in ax.texts]
|
||||
assert result == expected
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_hist_df_kwargs(self):
|
||||
df = DataFrame(np.random.randn(10, 2))
|
||||
_, ax = self.plt.subplots()
|
||||
ax = df.plot.hist(bins=5, ax=ax)
|
||||
assert len(ax.patches) == 10
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_hist_df_with_nonnumerics(self):
|
||||
# GH 9853
|
||||
with tm.RNGContext(1):
|
||||
df = DataFrame(
|
||||
np.random.randn(10, 4), columns=['A', 'B', 'C', 'D'])
|
||||
df['E'] = ['x', 'y'] * 5
|
||||
_, ax = self.plt.subplots()
|
||||
ax = df.plot.hist(bins=5, ax=ax)
|
||||
assert len(ax.patches) == 20
|
||||
|
||||
_, ax = self.plt.subplots()
|
||||
ax = df.plot.hist(ax=ax) # bins=10
|
||||
assert len(ax.patches) == 40
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_hist_legacy(self):
|
||||
_check_plot_works(self.ts.hist)
|
||||
_check_plot_works(self.ts.hist, grid=False)
|
||||
_check_plot_works(self.ts.hist, figsize=(8, 10))
|
||||
# _check_plot_works adds an ax so catch warning. see GH #13188
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
_check_plot_works(self.ts.hist,
|
||||
by=self.ts.index.month)
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
_check_plot_works(self.ts.hist,
|
||||
by=self.ts.index.month, bins=5)
|
||||
|
||||
fig, ax = self.plt.subplots(1, 1)
|
||||
_check_plot_works(self.ts.hist, ax=ax)
|
||||
_check_plot_works(self.ts.hist, ax=ax, figure=fig)
|
||||
_check_plot_works(self.ts.hist, figure=fig)
|
||||
tm.close()
|
||||
|
||||
fig, (ax1, ax2) = self.plt.subplots(1, 2)
|
||||
_check_plot_works(self.ts.hist, figure=fig, ax=ax1)
|
||||
_check_plot_works(self.ts.hist, figure=fig, ax=ax2)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
self.ts.hist(by=self.ts.index, figure=fig)
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_hist_bins_legacy(self):
|
||||
df = DataFrame(np.random.randn(10, 2))
|
||||
ax = df.hist(bins=2)[0][0]
|
||||
assert len(ax.patches) == 2
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_hist_layout(self):
|
||||
df = self.hist_df
|
||||
with pytest.raises(ValueError):
|
||||
df.height.hist(layout=(1, 1))
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
df.height.hist(layout=[1, 1])
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_hist_layout_with_by(self):
|
||||
df = self.hist_df
|
||||
|
||||
# _check_plot_works adds an ax so catch warning. see GH #13188
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
axes = _check_plot_works(df.height.hist,
|
||||
by=df.gender, layout=(2, 1))
|
||||
self._check_axes_shape(axes, axes_num=2, layout=(2, 1))
|
||||
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
axes = _check_plot_works(df.height.hist,
|
||||
by=df.gender, layout=(3, -1))
|
||||
self._check_axes_shape(axes, axes_num=2, layout=(3, 1))
|
||||
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
axes = _check_plot_works(df.height.hist,
|
||||
by=df.category, layout=(4, 1))
|
||||
self._check_axes_shape(axes, axes_num=4, layout=(4, 1))
|
||||
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
axes = _check_plot_works(df.height.hist,
|
||||
by=df.category, layout=(2, -1))
|
||||
self._check_axes_shape(axes, axes_num=4, layout=(2, 2))
|
||||
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
axes = _check_plot_works(df.height.hist,
|
||||
by=df.category, layout=(3, -1))
|
||||
self._check_axes_shape(axes, axes_num=4, layout=(3, 2))
|
||||
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
axes = _check_plot_works(df.height.hist,
|
||||
by=df.category, layout=(-1, 4))
|
||||
self._check_axes_shape(axes, axes_num=4, layout=(1, 4))
|
||||
|
||||
with tm.assert_produces_warning(UserWarning):
|
||||
axes = _check_plot_works(df.height.hist,
|
||||
by=df.classroom, layout=(2, 2))
|
||||
self._check_axes_shape(axes, axes_num=3, layout=(2, 2))
|
||||
|
||||
axes = df.height.hist(by=df.category, layout=(4, 2), figsize=(12, 7))
|
||||
self._check_axes_shape(axes, axes_num=4, layout=(4, 2),
|
||||
figsize=(12, 7))
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_hist_no_overlap(self):
|
||||
from matplotlib.pyplot import subplot, gcf
|
||||
x = Series(randn(2))
|
||||
y = Series(randn(2))
|
||||
subplot(121)
|
||||
x.hist()
|
||||
subplot(122)
|
||||
y.hist()
|
||||
fig = gcf()
|
||||
axes = fig.axes
|
||||
assert len(axes) == 2
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_hist_secondary_legend(self):
|
||||
# GH 9610
|
||||
df = DataFrame(np.random.randn(30, 4), columns=list('abcd'))
|
||||
|
||||
# primary -> secondary
|
||||
_, ax = self.plt.subplots()
|
||||
ax = df['a'].plot.hist(legend=True, ax=ax)
|
||||
df['b'].plot.hist(ax=ax, legend=True, secondary_y=True)
|
||||
# both legends are dran on left ax
|
||||
# left and right axis must be visible
|
||||
self._check_legend_labels(ax, labels=['a', 'b (right)'])
|
||||
assert ax.get_yaxis().get_visible()
|
||||
assert ax.right_ax.get_yaxis().get_visible()
|
||||
tm.close()
|
||||
|
||||
# secondary -> secondary
|
||||
_, ax = self.plt.subplots()
|
||||
ax = df['a'].plot.hist(legend=True, secondary_y=True, ax=ax)
|
||||
df['b'].plot.hist(ax=ax, legend=True, secondary_y=True)
|
||||
# both legends are draw on left ax
|
||||
# left axis must be invisible, right axis must be visible
|
||||
self._check_legend_labels(ax.left_ax,
|
||||
labels=['a (right)', 'b (right)'])
|
||||
assert not ax.left_ax.get_yaxis().get_visible()
|
||||
assert ax.get_yaxis().get_visible()
|
||||
tm.close()
|
||||
|
||||
# secondary -> primary
|
||||
_, ax = self.plt.subplots()
|
||||
ax = df['a'].plot.hist(legend=True, secondary_y=True, ax=ax)
|
||||
# right axes is returned
|
||||
df['b'].plot.hist(ax=ax, legend=True)
|
||||
# both legends are draw on left ax
|
||||
# left and right axis must be visible
|
||||
self._check_legend_labels(ax.left_ax, labels=['a (right)', 'b'])
|
||||
assert ax.left_ax.get_yaxis().get_visible()
|
||||
assert ax.get_yaxis().get_visible()
|
||||
tm.close()
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_df_series_secondary_legend(self):
|
||||
# GH 9779
|
||||
df = DataFrame(np.random.randn(30, 3), columns=list('abc'))
|
||||
s = Series(np.random.randn(30), name='x')
|
||||
|
||||
# primary -> secondary (without passing ax)
|
||||
_, ax = self.plt.subplots()
|
||||
ax = df.plot(ax=ax)
|
||||
s.plot(legend=True, secondary_y=True, ax=ax)
|
||||
# both legends are dran on left ax
|
||||
# left and right axis must be visible
|
||||
self._check_legend_labels(ax, labels=['a', 'b', 'c', 'x (right)'])
|
||||
assert ax.get_yaxis().get_visible()
|
||||
assert ax.right_ax.get_yaxis().get_visible()
|
||||
tm.close()
|
||||
|
||||
# primary -> secondary (with passing ax)
|
||||
_, ax = self.plt.subplots()
|
||||
ax = df.plot(ax=ax)
|
||||
s.plot(ax=ax, legend=True, secondary_y=True)
|
||||
# both legends are dran on left ax
|
||||
# left and right axis must be visible
|
||||
self._check_legend_labels(ax, labels=['a', 'b', 'c', 'x (right)'])
|
||||
assert ax.get_yaxis().get_visible()
|
||||
assert ax.right_ax.get_yaxis().get_visible()
|
||||
tm.close()
|
||||
|
||||
# seconcary -> secondary (without passing ax)
|
||||
_, ax = self.plt.subplots()
|
||||
ax = df.plot(secondary_y=True, ax=ax)
|
||||
s.plot(legend=True, secondary_y=True, ax=ax)
|
||||
# both legends are dran on left ax
|
||||
# left axis must be invisible and right axis must be visible
|
||||
expected = ['a (right)', 'b (right)', 'c (right)', 'x (right)']
|
||||
self._check_legend_labels(ax.left_ax, labels=expected)
|
||||
assert not ax.left_ax.get_yaxis().get_visible()
|
||||
assert ax.get_yaxis().get_visible()
|
||||
tm.close()
|
||||
|
||||
# secondary -> secondary (with passing ax)
|
||||
_, ax = self.plt.subplots()
|
||||
ax = df.plot(secondary_y=True, ax=ax)
|
||||
s.plot(ax=ax, legend=True, secondary_y=True)
|
||||
# both legends are dran on left ax
|
||||
# left axis must be invisible and right axis must be visible
|
||||
expected = ['a (right)', 'b (right)', 'c (right)', 'x (right)']
|
||||
self._check_legend_labels(ax.left_ax, expected)
|
||||
assert not ax.left_ax.get_yaxis().get_visible()
|
||||
assert ax.get_yaxis().get_visible()
|
||||
tm.close()
|
||||
|
||||
# secondary -> secondary (with passing ax)
|
||||
_, ax = self.plt.subplots()
|
||||
ax = df.plot(secondary_y=True, mark_right=False, ax=ax)
|
||||
s.plot(ax=ax, legend=True, secondary_y=True)
|
||||
# both legends are dran on left ax
|
||||
# left axis must be invisible and right axis must be visible
|
||||
expected = ['a', 'b', 'c', 'x (right)']
|
||||
self._check_legend_labels(ax.left_ax, expected)
|
||||
assert not ax.left_ax.get_yaxis().get_visible()
|
||||
assert ax.get_yaxis().get_visible()
|
||||
tm.close()
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_plot_fails_with_dupe_color_and_style(self):
|
||||
x = Series(randn(2))
|
||||
with pytest.raises(ValueError):
|
||||
_, ax = self.plt.subplots()
|
||||
x.plot(style='k--', color='k', ax=ax)
|
||||
|
||||
@pytest.mark.slow
|
||||
@td.skip_if_no_scipy
|
||||
def test_hist_kde(self):
|
||||
|
||||
_, ax = self.plt.subplots()
|
||||
ax = self.ts.plot.hist(logy=True, ax=ax)
|
||||
self._check_ax_scales(ax, yaxis='log')
|
||||
xlabels = ax.get_xticklabels()
|
||||
# ticks are values, thus ticklabels are blank
|
||||
self._check_text_labels(xlabels, [''] * len(xlabels))
|
||||
ylabels = ax.get_yticklabels()
|
||||
self._check_text_labels(ylabels, [''] * len(ylabels))
|
||||
|
||||
_skip_if_no_scipy_gaussian_kde()
|
||||
_check_plot_works(self.ts.plot.kde)
|
||||
_check_plot_works(self.ts.plot.density)
|
||||
_, ax = self.plt.subplots()
|
||||
ax = self.ts.plot.kde(logy=True, ax=ax)
|
||||
self._check_ax_scales(ax, yaxis='log')
|
||||
xlabels = ax.get_xticklabels()
|
||||
self._check_text_labels(xlabels, [''] * len(xlabels))
|
||||
ylabels = ax.get_yticklabels()
|
||||
self._check_text_labels(ylabels, [''] * len(ylabels))
|
||||
|
||||
@pytest.mark.slow
|
||||
@td.skip_if_no_scipy
|
||||
def test_kde_kwargs(self):
|
||||
_skip_if_no_scipy_gaussian_kde()
|
||||
|
||||
sample_points = np.linspace(-100, 100, 20)
|
||||
_check_plot_works(self.ts.plot.kde, bw_method='scott', ind=20)
|
||||
_check_plot_works(self.ts.plot.kde, bw_method=None, ind=20)
|
||||
_check_plot_works(self.ts.plot.kde, bw_method=None, ind=np.int(20))
|
||||
_check_plot_works(self.ts.plot.kde, bw_method=.5, ind=sample_points)
|
||||
_check_plot_works(self.ts.plot.density, bw_method=.5,
|
||||
ind=sample_points)
|
||||
_, ax = self.plt.subplots()
|
||||
ax = self.ts.plot.kde(logy=True, bw_method=.5, ind=sample_points,
|
||||
ax=ax)
|
||||
self._check_ax_scales(ax, yaxis='log')
|
||||
self._check_text_labels(ax.yaxis.get_label(), 'Density')
|
||||
|
||||
@pytest.mark.slow
|
||||
@td.skip_if_no_scipy
|
||||
def test_kde_missing_vals(self):
|
||||
_skip_if_no_scipy_gaussian_kde()
|
||||
|
||||
s = Series(np.random.uniform(size=50))
|
||||
s[0] = np.nan
|
||||
axes = _check_plot_works(s.plot.kde)
|
||||
|
||||
# gh-14821: check if the values have any missing values
|
||||
assert any(~np.isnan(axes.lines[0].get_xdata()))
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_hist_kwargs(self):
|
||||
_, ax = self.plt.subplots()
|
||||
ax = self.ts.plot.hist(bins=5, ax=ax)
|
||||
assert len(ax.patches) == 5
|
||||
self._check_text_labels(ax.yaxis.get_label(), 'Frequency')
|
||||
tm.close()
|
||||
|
||||
_, ax = self.plt.subplots()
|
||||
ax = self.ts.plot.hist(orientation='horizontal', ax=ax)
|
||||
self._check_text_labels(ax.xaxis.get_label(), 'Frequency')
|
||||
tm.close()
|
||||
|
||||
_, ax = self.plt.subplots()
|
||||
ax = self.ts.plot.hist(align='left', stacked=True, ax=ax)
|
||||
tm.close()
|
||||
|
||||
@pytest.mark.slow
|
||||
@td.skip_if_no_scipy
|
||||
def test_hist_kde_color(self):
|
||||
_, ax = self.plt.subplots()
|
||||
ax = self.ts.plot.hist(logy=True, bins=10, color='b', ax=ax)
|
||||
self._check_ax_scales(ax, yaxis='log')
|
||||
assert len(ax.patches) == 10
|
||||
self._check_colors(ax.patches, facecolors=['b'] * 10)
|
||||
|
||||
_skip_if_no_scipy_gaussian_kde()
|
||||
_, ax = self.plt.subplots()
|
||||
ax = self.ts.plot.kde(logy=True, color='r', ax=ax)
|
||||
self._check_ax_scales(ax, yaxis='log')
|
||||
lines = ax.get_lines()
|
||||
assert len(lines) == 1
|
||||
self._check_colors(lines, ['r'])
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_boxplot_series(self):
|
||||
_, ax = self.plt.subplots()
|
||||
ax = self.ts.plot.box(logy=True, ax=ax)
|
||||
self._check_ax_scales(ax, yaxis='log')
|
||||
xlabels = ax.get_xticklabels()
|
||||
self._check_text_labels(xlabels, [self.ts.name])
|
||||
ylabels = ax.get_yticklabels()
|
||||
self._check_text_labels(ylabels, [''] * len(ylabels))
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_kind_both_ways(self):
|
||||
s = Series(range(3))
|
||||
kinds = (plotting._core._common_kinds +
|
||||
plotting._core._series_kinds)
|
||||
_, ax = self.plt.subplots()
|
||||
for kind in kinds:
|
||||
if not _ok_for_gaussian_kde(kind):
|
||||
continue
|
||||
s.plot(kind=kind, ax=ax)
|
||||
getattr(s.plot, kind)()
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_invalid_plot_data(self):
|
||||
s = Series(list('abcd'))
|
||||
_, ax = self.plt.subplots()
|
||||
for kind in plotting._core._common_kinds:
|
||||
if not _ok_for_gaussian_kde(kind):
|
||||
continue
|
||||
with pytest.raises(TypeError):
|
||||
s.plot(kind=kind, ax=ax)
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_valid_object_plot(self):
|
||||
s = Series(lrange(10), dtype=object)
|
||||
for kind in plotting._core._common_kinds:
|
||||
if not _ok_for_gaussian_kde(kind):
|
||||
continue
|
||||
_check_plot_works(s.plot, kind=kind)
|
||||
|
||||
def test_partially_invalid_plot_data(self):
|
||||
s = Series(['a', 'b', 1.0, 2])
|
||||
_, ax = self.plt.subplots()
|
||||
for kind in plotting._core._common_kinds:
|
||||
if not _ok_for_gaussian_kde(kind):
|
||||
continue
|
||||
with pytest.raises(TypeError):
|
||||
s.plot(kind=kind, ax=ax)
|
||||
|
||||
def test_invalid_kind(self):
|
||||
s = Series([1, 2])
|
||||
with pytest.raises(ValueError):
|
||||
s.plot(kind='aasdf')
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_dup_datetime_index_plot(self):
|
||||
dr1 = date_range('1/1/2009', periods=4)
|
||||
dr2 = date_range('1/2/2009', periods=4)
|
||||
index = dr1.append(dr2)
|
||||
values = randn(index.size)
|
||||
s = Series(values, index=index)
|
||||
_check_plot_works(s.plot)
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_errorbar_plot(self):
|
||||
|
||||
s = Series(np.arange(10), name='x')
|
||||
s_err = np.random.randn(10)
|
||||
d_err = DataFrame(randn(10, 2), index=s.index, columns=['x', 'y'])
|
||||
# test line and bar plots
|
||||
kinds = ['line', 'bar']
|
||||
for kind in kinds:
|
||||
ax = _check_plot_works(s.plot, yerr=Series(s_err), kind=kind)
|
||||
self._check_has_errorbars(ax, xerr=0, yerr=1)
|
||||
ax = _check_plot_works(s.plot, yerr=s_err, kind=kind)
|
||||
self._check_has_errorbars(ax, xerr=0, yerr=1)
|
||||
ax = _check_plot_works(s.plot, yerr=s_err.tolist(), kind=kind)
|
||||
self._check_has_errorbars(ax, xerr=0, yerr=1)
|
||||
ax = _check_plot_works(s.plot, yerr=d_err, kind=kind)
|
||||
self._check_has_errorbars(ax, xerr=0, yerr=1)
|
||||
ax = _check_plot_works(s.plot, xerr=0.2, yerr=0.2, kind=kind)
|
||||
self._check_has_errorbars(ax, xerr=1, yerr=1)
|
||||
|
||||
ax = _check_plot_works(s.plot, xerr=s_err)
|
||||
self._check_has_errorbars(ax, xerr=1, yerr=0)
|
||||
|
||||
# test time series plotting
|
||||
ix = date_range('1/1/2000', '1/1/2001', freq='M')
|
||||
ts = Series(np.arange(12), index=ix, name='x')
|
||||
ts_err = Series(np.random.randn(12), index=ix)
|
||||
td_err = DataFrame(randn(12, 2), index=ix, columns=['x', 'y'])
|
||||
|
||||
ax = _check_plot_works(ts.plot, yerr=ts_err)
|
||||
self._check_has_errorbars(ax, xerr=0, yerr=1)
|
||||
ax = _check_plot_works(ts.plot, yerr=td_err)
|
||||
self._check_has_errorbars(ax, xerr=0, yerr=1)
|
||||
|
||||
# check incorrect lengths and types
|
||||
with pytest.raises(ValueError):
|
||||
s.plot(yerr=np.arange(11))
|
||||
|
||||
s_err = ['zzz'] * 10
|
||||
# MPL > 2.0.0 will most likely use TypeError here
|
||||
with pytest.raises((TypeError, ValueError)):
|
||||
s.plot(yerr=s_err)
|
||||
|
||||
# This XPASSES when tested with mpl == 3.0.1
|
||||
@td.xfail_if_mpl_2_2
|
||||
def test_table(self):
|
||||
_check_plot_works(self.series.plot, table=True)
|
||||
_check_plot_works(self.series.plot, table=self.series)
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_series_grid_settings(self):
|
||||
# Make sure plot defaults to rcParams['axes.grid'] setting, GH 9792
|
||||
self._check_grid_settings(Series([1, 2, 3]),
|
||||
plotting._core._series_kinds +
|
||||
plotting._core._common_kinds)
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_standard_colors(self):
|
||||
from pandas.plotting._style import _get_standard_colors
|
||||
|
||||
for c in ['r', 'red', 'green', '#FF0000']:
|
||||
result = _get_standard_colors(1, color=c)
|
||||
assert result == [c]
|
||||
|
||||
result = _get_standard_colors(1, color=[c])
|
||||
assert result == [c]
|
||||
|
||||
result = _get_standard_colors(3, color=c)
|
||||
assert result == [c] * 3
|
||||
|
||||
result = _get_standard_colors(3, color=[c])
|
||||
assert result == [c] * 3
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_standard_colors_all(self):
|
||||
import matplotlib.colors as colors
|
||||
from pandas.plotting._style import _get_standard_colors
|
||||
|
||||
# multiple colors like mediumaquamarine
|
||||
for c in colors.cnames:
|
||||
result = _get_standard_colors(num_colors=1, color=c)
|
||||
assert result == [c]
|
||||
|
||||
result = _get_standard_colors(num_colors=1, color=[c])
|
||||
assert result == [c]
|
||||
|
||||
result = _get_standard_colors(num_colors=3, color=c)
|
||||
assert result == [c] * 3
|
||||
|
||||
result = _get_standard_colors(num_colors=3, color=[c])
|
||||
assert result == [c] * 3
|
||||
|
||||
# single letter colors like k
|
||||
for c in colors.ColorConverter.colors:
|
||||
result = _get_standard_colors(num_colors=1, color=c)
|
||||
assert result == [c]
|
||||
|
||||
result = _get_standard_colors(num_colors=1, color=[c])
|
||||
assert result == [c]
|
||||
|
||||
result = _get_standard_colors(num_colors=3, color=c)
|
||||
assert result == [c] * 3
|
||||
|
||||
result = _get_standard_colors(num_colors=3, color=[c])
|
||||
assert result == [c] * 3
|
||||
|
||||
def test_series_plot_color_kwargs(self):
|
||||
# GH1890
|
||||
_, ax = self.plt.subplots()
|
||||
ax = Series(np.arange(12) + 1).plot(color='green', ax=ax)
|
||||
self._check_colors(ax.get_lines(), linecolors=['green'])
|
||||
|
||||
def test_time_series_plot_color_kwargs(self):
|
||||
# #1890
|
||||
_, ax = self.plt.subplots()
|
||||
ax = Series(np.arange(12) + 1, index=date_range(
|
||||
'1/1/2000', periods=12)).plot(color='green', ax=ax)
|
||||
self._check_colors(ax.get_lines(), linecolors=['green'])
|
||||
|
||||
def test_time_series_plot_color_with_empty_kwargs(self):
|
||||
import matplotlib as mpl
|
||||
|
||||
def_colors = self._unpack_cycler(mpl.rcParams)
|
||||
index = date_range('1/1/2000', periods=12)
|
||||
s = Series(np.arange(1, 13), index=index)
|
||||
|
||||
ncolors = 3
|
||||
|
||||
_, ax = self.plt.subplots()
|
||||
for i in range(ncolors):
|
||||
ax = s.plot(ax=ax)
|
||||
self._check_colors(ax.get_lines(), linecolors=def_colors[:ncolors])
|
||||
|
||||
def test_xticklabels(self):
|
||||
# GH11529
|
||||
s = Series(np.arange(10), index=['P%02d' % i for i in range(10)])
|
||||
_, ax = self.plt.subplots()
|
||||
ax = s.plot(xticks=[0, 3, 5, 9], ax=ax)
|
||||
exp = ['P%02d' % i for i in [0, 3, 5, 9]]
|
||||
self._check_text_labels(ax.get_xticklabels(), exp)
|
||||
|
||||
def test_custom_business_day_freq(self):
|
||||
# GH7222
|
||||
from pandas.tseries.offsets import CustomBusinessDay
|
||||
s = Series(range(100, 121), index=pd.bdate_range(
|
||||
start='2014-05-01', end='2014-06-01',
|
||||
freq=CustomBusinessDay(holidays=['2014-05-26'])))
|
||||
|
||||
_check_plot_works(s.plot)
|
||||
|
||||
@pytest.mark.xfail
|
||||
def test_plot_accessor_updates_on_inplace(self):
|
||||
s = Series([1, 2, 3, 4])
|
||||
_, ax = self.plt.subplots()
|
||||
ax = s.plot(ax=ax)
|
||||
before = ax.xaxis.get_ticklocs()
|
||||
|
||||
s.drop([0, 1], inplace=True)
|
||||
_, ax = self.plt.subplots()
|
||||
after = ax.xaxis.get_ticklocs()
|
||||
tm.assert_numpy_array_equal(before, after)
|
||||
Reference in New Issue
Block a user