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.
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()
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
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.
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.
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()
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
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.