3

Context:
The journal I want to submit my paper to only accepts .tiff (doesn't work with LaTeX), .jpg (not suitable for graphs), and .eps (which doesn't work with alpha transparency, unless I rasterize the image, which leads to huge file sizes). Many of my plots use seaborn's regplot, which plots transparent confidence intervals. Is it possible to plot non-transparent CIs without completely re-doing all of my graphs manually (e.g. as dashed lines or a solid color in the background)?

Example:

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

sns.set_style("ticks")
np.random.seed(0)
n = 50

fig, ax = plt.subplots(figsize=(8,6))

x = np.random.randn(n)
y1 = np.random.randn(n)
y2 = np.random.randn(n)

sns.regplot(x, y1, ax=ax)
sns.regplot(x, y2, ax=ax)

plt.show()

Example of a regplot with transparent overlapping confidence intervals

What would be the easiest / best way to save this as an .eps file without losing information from the overlapping confidence intervals?

Fred S
  • 1,421
  • 6
  • 21
  • 37

1 Answers1

4

The problem is that you need transparency to show the two confidence intervals overlapping. One would need to rasterize the image.

I don't actually see the problem of using jpg if the journal accepts it. You may control the quality of the image using

plt.savefig(__file__+".jpg", quality=95)

Using eps is also possible, here, instead of rasterizing everything, you may rasterize only the confidence interval fill_between-curves. The advantange is that the axes, labels and points are still vecor graphics and won't look pixelated on different zoom levels.

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import PolyCollection as p
import seaborn as sns

sns.set_style("ticks")
np.random.seed(0)
n = 50

fig, ax = plt.subplots(figsize=(8,6))

x = np.random.randn(n)
y1 = np.random.randn(n)
y2 = np.random.randn(n)

sns.regplot(x, y1, ax=ax)
sns.regplot(x, y2, ax=ax)

plt.savefig(__file__+".jpg", quality=95)
for c in ax.findobj(p):
    c.set_zorder(-1)
    c.set_rasterized(True)
#everything on zorder -1 or lower will be rasterized
ax.set_rasterization_zorder(0)

plt.savefig(__file__+".eps")
plt.savefig(__file__+".png")
plt.show()

The final eps file looks like this:
enter image description here

While the filesize is of course a bit larger, I'm not sure if this is a real problem.

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
  • Oh, I didn't know you could only rasterize parts of the image. That's pretty neat. Thanks! The journal is pretty strict about file sizes, which is why I didn't want to use mostly uncompressed JPGs. For the initial submission, I used a workaround of replacing the `fill_between` part in the seaborn source code with dashed lines, but your solution looks much more elegant. – Fred S Jun 01 '17 at 13:50
  • 1
    PS why are you comparing the string repr of the type instead of using `isinstance`? Also I think matplotlib axes have a function that returns all artists of a given type, but I forget what it's called. – mwaskom Jun 01 '17 at 13:50
  • 1
    @mwaskom The function you mean is called `ax.findobj`. I was simply too lazy and copied the str repr from the output. But I changed it now. Concerning jpg, it's of course not ideal, but there is very little difference between a png and a jpg if the jpg quality is high enough. You will always need to stick to the journal's requirements, whether they make any sense or not. – ImportanceOfBeingErnest Jun 01 '17 at 14:03