FooBar
FooBar

Reputation: 16478

Pandas plot: Assign Colors

I have many data frames that I am plotting for a presentation. These all have different columns, but all contain the same additional column foobar. At the moment, I am plotting these different data frames using

df.plot(secondary_y='foobar')

Unfortunately, since these data frames all have different additional columns with different ordering, the color of foobar is always different. This makes the presentation slides unnecessary complicated. I would like, throughout the different plots, assign that foobar is plotted bold and black.

Looking at the docs, the only thing coming close appears to be the parameter colormap - I would need to ensure that the xth color in the color map is always black, where x is the order of foobar in the data frame. Seems to be more complicated than it should be, also this wouldn't make it bold.

Is there a (better) approach?

Upvotes: 2

Views: 2440

Answers (3)

FooBar
FooBar

Reputation: 16478

I used @unutbut's answer and extended it to allow for a secondary y axis and correct legends:

def emphasize_plot(ax, df, col, **emphargs):
    columns = [c for c in df.columns if c != col]
    ax2 = ax.twinx()
    df[columns].plot(ax=ax)
    df[col].plot(ax=ax2, **emphargs)
    lines, labels = ax.get_legend_handles_labels()
    lines2, labels2 = ax2.get_legend_handles_labels()
    ax2.legend(lines + lines2, labels + labels2, loc=0)

Upvotes: 0

unutbu
unutbu

Reputation: 879103

Perhaps you could define a function which handles the special column in a separate plot call:

def emphasize_plot(ax, df, col, **emphargs):
    columns = [c for c in df.columns if c != col]
    df[columns].plot(ax=ax)
    df[col].plot(ax=ax, **emphargs)

Using code from tcaswell's example,

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

def emphasize_plot(ax, df, col, **emphargs):
    columns = [c for c in df.columns if c != col]
    df[columns].plot(ax=ax)
    df[col].plot(ax=ax, **emphargs)

fig, ax = plt.subplots()
th = np.linspace(0, 2*np.pi, 1024)
df = pd.DataFrame({'cos': np.cos(th), 'foobar': np.sin(th),
                  'foo': np.sin(th + 1), 'bar': np.cos(th +1)}, index=th)
df2 = pd.DataFrame({'cos': -np.cos(th), 'foobar': -np.sin(th)}, index=th)

emphasize_plot(ax, df, 'foobar', lw=2, c='k')
emphasize_plot(ax, df2, 'foobar', lw=2, c='k')
plt.show()

yields

enter image description here

Upvotes: 1

tacaswell
tacaswell

Reputation: 87356

I would suggest using matplotlib directly rather than the dataframe plotting methods. If df.plot returned the artists it added instead of an Axes object it wouldn't be too bad to change the color of the line after it was plotted.

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

def pandas_plot(ax, df, callout_key):
    """
    Parameters
    ----------
    ax : mpl.Axes
        The axes to draw to

    df : DataFrame
        Data to plot

    callout_key : str
        key to highlight

    """
    artists = {}

    x = df.index.values
    for k, v in df.iteritems():
        style_kwargs = {}
        if k == callout_key:
            style_kwargs['c'] = 'k'
            style_kwargs['lw'] = 2
        ln, = ax.plot(x, v.values, **style_kwargs)
        artists[k] = ln

    ax.legend()
    ax.set_xlim(np.min(x), np.max(x))

    return artists

Usage:

fig, ax = plt.subplots()
ax2 = ax.twinx()

th = np.linspace(0, 2*np.pi, 1024)
df = pd.DataFrame({'cos': np.cos(th), 'sin': np.sin(th),
                  'foo': np.sin(th + 1), 'bar': np.cos(th +1)}, index=th)
df2 = pd.DataFrame({'cos': -np.cos(th), 'sin': -np.sin(th)}, index=th)

pandas_plot(ax, df, 'sin')
pandas_plot(ax2, df2, 'sin')

enter image description here

Upvotes: 1

Related Questions