Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Monkey patching pandas and matplotlib to remove spines for df.plot()

Tags:

The question:

I'm trying to grasp the concept of monkey patching and at the same time make a function to produce the perfect time-series plot. How can I include the following matplotlib functionality in pandas pandas.DataFrame.plot()?

ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.spines['left'].set_visible(False)

complete code at the end of the question


The details:


I think the default settings in df.plot() is pretty neat, especially if you're running a Jupyter Notebook with a dark theme like chesterish from dunovank:

df.plot default

And I'd like to use it for as much of my data analysis workflow as possible, but I'd really like to remove the frame (or what's called spines) like this:

df.plot no frames

Arguably, this is a perfect time-series plot. But df.plot() doesn't have a built-in argument for this. The closest thing seems to be grid = False, but that takes away the whole grid in the same run:

enter image description here


What I've tried


I know I can wrap the spine snippet in a function along with df.plot() so I end up with this:

Snippet 1:

def plotPerfect(df, spline):

    ax = df.plot()

    if not spline:
        ax.spines['top'].set_visible(False)
        ax.spines['right'].set_visible(False)
        ax.spines['bottom'].set_visible(False)
        ax.spines['left'].set_visible(False)

    return(ax)

plotPerfect(df = df, spline = False)

Output 1:

enter image description here

But is that the "best" way to do it with regards to flexibilty and readability for future amendments? Or even the fastest with regards to execution time if we're talking hundreds of plots?

I know how I can get the df.plot() source, but everything from there leaves me baffled. So how do I include those settings in df.plot? And perhaps the wrapped function approach is just as good as monkey patching?


Snippet with full code and sample data:


To reproduce the example 100%, paste this into a Jupyter Notebook cell with the chesterish theme activated:

# imports
import pandas as pd
import numpy as np
from jupyterthemes import jtplot

# Sample data
np.random.seed(123)
rows = 50
dfx = pd.DataFrame(np.random.randint(90,110,size=(rows, 1)), columns=['Variable Y'])
dfy = pd.DataFrame(np.random.randint(25,68,size=(rows, 1)), columns=[' Variable X'])
df = pd.concat([dfx,dfy], axis = 1)
jtplot.style()

# Plot with default settings
df.plot()

# Wrap df.plot() and matplotlib spine in a function
def plotPerfect(df, spline):

    ax = df.plot()

    if not spline:
        ax.spines['top'].set_visible(False)
        ax.spines['right'].set_visible(False)
        ax.spines['bottom'].set_visible(False)
        ax.spines['left'].set_visible(False)

    return(ax)

# Plot the perfect time-series plot
plotPerfect(df = df, spline = False)
like image 786
vestland Avatar asked Feb 01 '19 07:02

vestland


People also ask

How do you remove a legend from a data frame plot?

Using plt. gca(). legend_. remove() after the call to parallel_coordinates successfully turned off the legend.

How do I remove axis labels in pandas?

To hide or remove X-axis labels, use set(xlabel=None). To display the figure, use show() method.

Can pandas generate plots?

Pandas uses the plot() method to create diagrams. We can use Pyplot, a submodule of the Matplotlib library to visualize the diagram on the screen. Read more about Matplotlib in our Matplotlib Tutorial.


1 Answers

This seems like an xyproblem.

Monkey patching (The Y)

The question asks for monkey patching pandas plot function to add additional features. This can in this case be done by replacing the pandas.plotting._core.plot_frame function with a custom version of it.

import pandas as pd
import pandas.plotting._core
orginal = pandas.plotting._core.plot_frame

def myplot(*args, **kwargs):
    spline = kwargs.pop("spline", True)
    ax = orginal(*args, **kwargs)
    ax.set_frame_on(spline)
    ax.grid(not spline)
    ax.tick_params(left=spline, bottom=spline)
    return ax

pandas.plotting._core.plot_frame = myplot

Then use it as

df = pd.DataFrame([[0.1, 0.1], [0.9, 0.9]]).set_index(0)
df.plot()             ## Normal Plot
df.plot(spline=False) ## "Despined" Plot 

enter image description here

Note that if in jupyter notebook, the cell with the monkey patching cannot be run more than once, else it would end up in recursion.

Styling (The X)

The above is pretty overkill for changing the style of a plot. One should rather use the style options of matplotlib.

mystyle = {"axes.spines.left" : False,
           "axes.spines.right" : False,
           "axes.spines.bottom" : False,
           "axes.spines.top" : False,
           "axes.grid" : True,
           "xtick.bottom" : False,
           "ytick.left" : False,}

Then to apply this for some plots in the notebook, use the plt.style.context manager,

import pandas as pd
import matplotlib.pyplot as plt

df = pd.DataFrame([[0.1, 0.1], [0.9, 0.9]]).set_index(0)

df.plot()             ## Normal Plot

with plt.style.context(mystyle):
    df.plot()         ## "Despined" Plot 

enter image description here

Or, if you want to apply this style globally, update the rcParams.

plt.rcParams.update(mystyle)
like image 192
ImportanceOfBeingErnest Avatar answered Oct 05 '22 02:10

ImportanceOfBeingErnest