Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Moving Collections between axes

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?

like image 609
unutbu Avatar asked Feb 21 '18 22:02

unutbu


1 Answers

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

like image 200
ImportanceOfBeingErnest Avatar answered Oct 04 '22 20:10

ImportanceOfBeingErnest