Matplotlib add a default watermark

Question:

I’m using matplotlib for work and company policy is to include a watermark on every plot we make. Is there a way to set matplotlib to do this by default?

I’m currently passing each Axes object into a helper function which adds the watermark in the bottom left corner.

import matplotlib.pyplot as plt

def add_watermark(ax):
    ax.text(ax.get_xlim()[0] + 0.1, 
            ax.get_ylim()[0] + 0.1, 
            "<Company Name>", 
            alpha=0.5)

fig, ax = plt.subplots(1, 1)
x = np.fromiter((np.random.uniform() for _ in range(100)), dtype=np.float32)
y = np.fromiter((np.random.uniform() for _ in range(100)), dtype=np.float32)
ax.scatter(x, y)
add_watermark(ax)

I would like to modify the default behavior of matplotlib so that I don’t have to pass each axes instance into a helper function.

Asked By: Clemson

||

Answers:

I think the cleanest solution for this is to create a “company plot template” within a separate python script (e.g. called companyplots.py) that’s somewhere within python’s module search path.

You can do this either by simply having it in the same folder as your actual plots, or e.g. by creating a /some/path/to/user_modules folder and correctly setting the $PYTHONPATH variable to include the path to it.

Within this file, collect all necessary imports and setup a function with default plot settings, e.g.:

def companyFigure((rows,cols),(width,height)=(768,576),dpi=72,fig_kwargs={}):
    """
    first, reset mpl style to default, then enforce a new one. 
    This is helpful when the new style does not overwrite *all* attributes 
    """
    style="ggplot" ##<- put your own style file here, if you have one
    mpl.rcParams.update(mpl.rcParamsDefault)
    mpl.style.use(style)

    ## that's your function:
    def add_watermark(ax):
        ax.text(ax.get_xlim()[0] + 0.1, 
                ax.get_ylim()[0] + 0.1, 
                "<Company Name>", 
                alpha=0.5)

    ## create figure with some arguments
    fig,ax=plt.subplots(rows,cols,
            figsize=(width/float(dpi),height/float(dpi)),
            dpi=dpi,
            **fig_kwargs
            )

    ## I'm presuming that you may want to have subplots somewhere down the line;
    ## for the sake of consistency, I'm thus making sure that "ax" is always a dict:
    if rows==1 and cols==1:
        ax={0:ax}

    for a in ax:
        add_watermark(a)

    return fig,ax

Now, all future plots can fall back to this template, simply by running:

from companyplots import *

fig,ax=companyFigure((2,1),(500,300))
## do your plotting here...
plt.show()
Answered By: Asmus

You may easily subclass and monkey-patch the default axes. So create a file matplotlib_company.py like this

import matplotlib.axes
from matplotlib.offsetbox import AnchoredText

class MyAxes(matplotlib.axes.Axes):
    def __init__(self, *args, **kwargs):

        super().__init__(*args, **kwargs)
        ab = AnchoredText("<company name>", loc="lower left", frameon=False,
                          borderpad=0, prop=dict(alpha=0.5))
        ab.set_zorder(0)
        self.add_artist(ab)

matplotlib.axes.Axes = MyAxes

Then import it everywhere you need it. I.e. the following

import matplotlib_company
import matplotlib.pyplot as plt
plt.plot([1,2,3])
plt.show()

creates

enter image description here

Since Matplotlib version 3.6 and Seaborn 0.12, I use:

def addwatermark(ax):
    """ Place watermark in bottom right of figure. """
    text = "<watermark>"
    ax.annotate(text, xy=(0.3, 0.1), xycoords='axes fraction', alpha=0.4, fontsize='large', rotation=45, fontweight=550)

You can add this in a separate addwatermark.py file and call from addwatermark.py import addwatermark.

Usage example:

import matplotlib.pyplot as plt
from addwatermark.py import addwatermark

fig, ax = plt.subplots()
ax.plot(x=[1, 2, 3, 4, 5], y=[1, 2, 3, 4, 5])
addwatermark(ax)
plt.show()

Also Seaborn works:

import seaborn as sns
import matplotlib.pyplot as plt
from addwatermark.py import addwatermark
ax = sns.scatterplot(x=[1, 2, 3, 4, 5], y=[1, 2, 3, 4, 5])
addwatermark(ax)
plt.show()

If you use facetgrid or pairgrid in Seaborn, the axes can be accessed through their attribute ax.

Matplotlib also has an example, but that did not work with Seaborn.

Answered By: Jelmer Mulder
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.