diff --git a/.travis.yml b/.travis.yml index 13c9ee226d73c..86a6f05494649 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,6 @@ language: python python: - 2.6 - 2.7 -# - 3.1 # travis EOL - 3.2 - 3.3 diff --git a/RELEASE.rst b/RELEASE.rst index 51ed383648929..e98bce6295315 100644 --- a/RELEASE.rst +++ b/RELEASE.rst @@ -112,6 +112,8 @@ pandas 0.11.0 df = DataFrame(dict(A = ts)) df['2001'] + - added option `display.mpl_style` providing a sleeker visual style + for plots. Based on https://gist.github.com/huyng/816622 (GH3075_). **API Changes** @@ -278,6 +280,7 @@ pandas 0.11.0 .. _GH2993: https://github.com/pydata/pandas/issues/2993 .. _GH3115: https://github.com/pydata/pandas/issues/3115 .. _GH3070: https://github.com/pydata/pandas/issues/3070 +.. _GH3075: https://github.com/pydata/pandas/issues/3075 .. _GH3130: https://github.com/pydata/pandas/issues/3130 pandas 0.10.1 diff --git a/ci/install.sh b/ci/install.sh index ec72c5aff3ff6..a4c9f7518fd5a 100755 --- a/ci/install.sh +++ b/ci/install.sh @@ -68,5 +68,8 @@ fi; # make sure the desired locale is generated if [ x"$LOCALE_OVERRIDE" != x"" ]; then + # piggyback this build for plotting tests. oh boy. + pip install $PIP_ARGS --use-mirrors matplotlib; + sudo locale-gen "$LOCALE_OVERRIDE" fi diff --git a/ci/script.sh b/ci/script.sh index c405299b1e717..92ac30697e6cc 100755 --- a/ci/script.sh +++ b/ci/script.sh @@ -6,6 +6,10 @@ if [ x"$LOCALE_OVERRIDE" != x"" ]; then export LC_ALL="$LOCALE_OVERRIDE"; echo "Setting LC_ALL to $LOCALE_OVERRIDE" (cd /; python -c 'import pandas; print("pandas detected console encoding: %s" % pandas.get_option("display.encoding"))') + + # also do slow tests here, especially plotting + nosetests --exe -w /tmp -A "not network" pandas; + exit fi if [ x"$VBENCH" != x"true" ]; then diff --git a/doc/source/v0.11.0.txt b/doc/source/v0.11.0.txt index 87b861a45dbae..0193714a5d30c 100644 --- a/doc/source/v0.11.0.txt +++ b/doc/source/v0.11.0.txt @@ -301,6 +301,8 @@ Enhancements - DataFrame.from_records now accepts not only dicts but any instance of the collections.Mapping ABC. + - added option `display.with_wmp_style` providing a sleeker visual style + for plots. Based on https://gist.github.com/huyng/816622 (GH3075_). See the `full release notes `__ or issue tracker @@ -325,3 +327,4 @@ on GitHub for a complete list. .. _GH3076: https://github.com/pydata/pandas/issues/3076 .. _GH3059: https://github.com/pydata/pandas/issues/3059 .. _GH3070: https://github.com/pydata/pandas/issues/3070 +.. _GH3075: https://github.com/pydata/pandas/issues/3075 diff --git a/pandas/core/config.py b/pandas/core/config.py index 106dabd1bc134..96cb33a45d172 100644 --- a/pandas/core/config.py +++ b/pandas/core/config.py @@ -703,6 +703,14 @@ def inner(x): return inner +def is_one_of_factory(legal_values): + def inner(x): + from pandas.core.common import pprint_thing as pp + if not x in legal_values: + pp_values = map(pp, legal_values) + raise ValueError("Value must be one of %s" % pp("|".join(pp_values))) + + return inner # common type validators, for convenience # usage: register_option(... , validator = is_int) diff --git a/pandas/core/config_init.py b/pandas/core/config_init.py index ba580d437d28b..692f5cfb85890 100644 --- a/pandas/core/config_init.py +++ b/pandas/core/config_init.py @@ -1,6 +1,6 @@ import pandas.core.config as cf from pandas.core.config import (is_int, is_bool, is_text, is_float, - is_instance_factory) + is_instance_factory,is_one_of_factory) from pandas.core.format import detect_console_encoding """ @@ -147,6 +147,38 @@ perform a null check when repr'ing. """ +pc_mpl_style_doc = """ +: bool + + Setting this to 'default' will modify the rcParams used by matplotlib + to give plots a more pleasing visual style by default. + Setting this to None/False restores the values to their initial value. +""" + +style_backup = dict() +def mpl_style_cb(key): + import sys + from pandas.tools.plotting import mpl_stylesheet + global style_backup + + val = cf.get_option(key) + + if 'matplotlib' not in sys.modules.keys(): + if not(val): # starting up, we get reset to None + return val + raise Exception("matplotlib has not been imported. aborting") + + import matplotlib.pyplot as plt + + + if val == 'default': + style_backup = dict([(k,plt.rcParams[k]) for k in mpl_stylesheet]) + plt.rcParams.update(mpl_stylesheet) + elif not val: + if style_backup: + plt.rcParams.update(style_backup) + + return val with cf.config_prefix('display'): cf.register_option('precision', 7, pc_precision_doc, validator=is_int) @@ -177,6 +209,9 @@ cf.register_option('line_width', 80, pc_line_width_doc) cf.register_option('chop_threshold', None, pc_chop_threshold_doc) cf.register_option('max_seq_items', None, pc_max_seq_items) + cf.register_option('mpl_style', None, pc_mpl_style_doc, + validator=is_one_of_factory([None, False, 'default']), + cb=mpl_style_cb) tc_sim_interactive_doc = """ : boolean diff --git a/pandas/tests/test_graphics.py b/pandas/tests/test_graphics.py index 015a2ff9379b9..676f48378b9f4 100644 --- a/pandas/tests/test_graphics.py +++ b/pandas/tests/test_graphics.py @@ -8,6 +8,7 @@ from pandas import Series, DataFrame, MultiIndex, PeriodIndex, date_range import pandas.util.testing as tm from pandas.util.testing import ensure_clean +from pandas.core.config import set_option,get_option,config_prefix import numpy as np @@ -69,7 +70,7 @@ def test_bar_colors(self): import matplotlib.pyplot as plt import matplotlib.colors as colors - default_colors = 'brgyk' + default_colors = plt.rcParams.get('axes.color_cycle') custom_colors = 'rgcby' plt.close('all') @@ -693,6 +694,21 @@ def test_grouped_hist(self): for ax in axes.ravel(): self.assert_(len(ax.patches) > 0) + def test_option_mpl_style(self): + # just a sanity check + try: + import matplotlib + except: + raise nose.SkipTest + + set_option('display.mpl_style', 'default') + set_option('display.mpl_style', None) + set_option('display.mpl_style', False) + try: + set_option('display.mpl_style', 'default2') + except ValueError: + pass + def _check_plot_works(f, *args, **kwargs): import matplotlib.pyplot as plt diff --git a/pandas/tools/plotting.py b/pandas/tools/plotting.py index aca5e8a723c1b..b74b6b24262f9 100644 --- a/pandas/tools/plotting.py +++ b/pandas/tools/plotting.py @@ -23,6 +23,71 @@ except ImportError: pass +# Extracted from https://gist.github.com/huyng/816622 +# this is the rcParams set when setting display.with_mpl_style +# to True. +mpl_stylesheet = { + 'axes.axisbelow': True, + 'axes.color_cycle': ['#348ABD', + '#7A68A6', + '#A60628', + '#467821', + '#CF4457', + '#188487', + '#E24A33'], + 'axes.edgecolor': '#bcbcbc', + 'axes.facecolor': '#eeeeee', + 'axes.grid': True, + 'axes.labelcolor': '#555555', + 'axes.labelsize': 'large', + 'axes.linewidth': 1.0, + 'axes.titlesize': 'x-large', + 'figure.edgecolor': 'white', + 'figure.facecolor': 'white', + 'figure.figsize': (6.0, 4.0), + 'figure.subplot.hspace': 0.5, + 'font.family': 'monospace', + 'font.monospace': ['Andale Mono', + 'Nimbus Mono L', + 'Courier New', + 'Courier', + 'Fixed', + 'Terminal', + 'monospace'], + 'font.size': 10, + 'interactive': True, + 'keymap.all_axes': ['a'], + 'keymap.back': ['left', 'c', 'backspace'], + 'keymap.forward': ['right', 'v'], + 'keymap.fullscreen': ['f'], + 'keymap.grid': ['g'], + 'keymap.home': ['h', 'r', 'home'], + 'keymap.pan': ['p'], + 'keymap.save': ['s'], + 'keymap.xscale': ['L', 'k'], + 'keymap.yscale': ['l'], + 'keymap.zoom': ['o'], + 'legend.fancybox': True, + 'lines.antialiased': True, + 'lines.linewidth': 1.0, + 'patch.antialiased': True, + 'patch.edgecolor': '#EEEEEE', + 'patch.facecolor': '#348ABD', + 'patch.linewidth': 0.5, + 'toolbar': 'toolbar2', + 'xtick.color': '#555555', + 'xtick.direction': 'in', + 'xtick.major.pad': 6.0, + 'xtick.major.size': 0.0, + 'xtick.minor.pad': 6.0, + 'xtick.minor.size': 0.0, + 'ytick.color': '#555555', + 'ytick.direction': 'in', + 'ytick.major.pad': 6.0, + 'ytick.major.size': 0.0, + 'ytick.minor.pad': 6.0, + 'ytick.minor.size': 0.0 +} def _get_standard_kind(kind): return {'density': 'kde'}.get(kind, kind)