7

While playing with ImportanceOfBeingErnest's code to move artists between axes, I thought it would easy to extend it to collections (such as PathCollections generated by plt.scatter) as well. No such luck:

import matplotlib.pyplot as plt
import numpy as np
import pickle

x = np.linspace(-3, 3, 100)
y = np.exp(-x**2/2)/np.sqrt(2*np.pi)
a = np.random.normal(size=10000)

fig, ax = plt.subplots()
ax.scatter(x, y)

pickle.dump(fig, open("/tmp/figA.pickle", "wb"))
# plt.show()

fig, ax = plt.subplots()
ax.hist(a, bins=20, density=True, ec="k")

pickle.dump(fig, open("/tmp/figB.pickle", "wb"))
# plt.show()

plt.close("all")

# Now unpickle the figures and create a new figure
#    then add artists to this new figure

figA = pickle.load(open("/tmp/figA.pickle", "rb"))
figB = pickle.load(open("/tmp/figB.pickle", "rb"))

fig, ax = plt.subplots()

for figO in [figA, figB]:
    lists = [figO.axes[0].lines, figO.axes[0].patches, figO.axes[0].collections]
    addfunc = [ax.add_line, ax.add_patch, ax.add_collection]
    for lis, func in zip(lists, addfunc):
        for artist in lis[:]:
            artist.remove()
            artist.axes = ax
            # artist.set_transform(ax.transData) 
            artist.figure = fig
            func(artist)

ax.relim()
ax.autoscale_view()

plt.close(figA)
plt.close(figB)
plt.show()

yields

enter image description here

Removing artist.set_transform(ax.transData) (at least when calling ax.add_collection) seems to help a little, but notice that the y-offset is still off: enter image description here How does one properly move collections from one axes to another?

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677

1 Answers1

3

The scatter has an IdentityTransform as master transform. The data transform is the internal offset transform. One would hence need to treat the scatter separately.

from matplotlib.collections import PathCollection
from matplotlib.transforms import IdentityTransform

# ...

if type(artist) == PathCollection:
    artist.set_transform(IdentityTransform())
    artist._transOffset = ax.transData
else:
    artist.set_transform(ax.transData) 

Unfortunately, there is no set_offset_transform method, such that one needs to replace the ._transOffset attribute to set the offset transform.

enter image description here

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712