Eric Auld
Eric Auld

Reputation: 1244

Matplotlib: collecting lines onto the same axis

I'm just starting using Matplotlib the "right" way. I'm writing various programs that will each give me back a time series, and I'm looking to superimpose the graphs of the various time series, like this:

enter image description here

I think what I want is a single Axes instance defined in the main function, then I call each of my little functions, and they all return a Line2D instance, and then I'll put them all on the Axes object I created.

But I'm having trouble taking an existing Line2D object and adding it to an existing Axes object (like I'd want to do with the output of my function.) I thought of taking a Line2D called a and say ax.add_line(a).

import matplotlib.pyplot as plt

a, = plt.plot([1,2,3], [3,4,5], label = 'a')
fig, ax = plt.subplots()
ax.add_line(a)

Gives me a RuntimeError: "Can not put single artist in more than one figure."

I'm guessing that over time Matplotlib has stopped wanting users to be able to add a given line to any Axes they want. A similar thing is discussed in the comments of this answer, except there they're talking about an Axes object in two different Figure objects.

What's the best way to accomplish what I want? I'd rather keep my main script tidy, and not say ax.plot(some_data) over and over when I want to superimpose these lines.

Upvotes: 0

Views: 569

Answers (2)

ImportanceOfBeingErnest
ImportanceOfBeingErnest

Reputation: 339290

Indeed, you cannot add the same artist to more than one axes or figure. But for what I understand from your question, that isn't really necessary.

So let's just do as you propose;

"I thought of taking a Line2D called a and say ax.add_line(a)."

import numpy as np
import matplotlib.pyplot as plt

def get_line(label="a"):
    return plt.Line2D(np.linspace(0,1,10), np.random.rand(10), label = label)

fig, ax = plt.subplots()
ax.add_line(get_line(label="a"))
ax.add_line(get_line(label="b"))
ax.add_line(get_line(label="z"))
ax.legend()

plt.show()

The way matplotlib would recommend is to create functions that take an axes as input and plot to that axes.

import numpy as np
import matplotlib.pyplot as plt

def plot_line(ax=None, label="a"):
    ax = ax or plt.gca()
    line, = ax.plot(np.linspace(0,1,10), np.random.rand(10), label = label)
    return line

fig, ax = plt.subplots()
plot_line(ax, label="a")
plot_line(ax, label="b")
plot_line(ax, label="z")
ax.legend()

plt.show()

Upvotes: 1

Sheldore
Sheldore

Reputation: 39052

A possible work around for your problem:

import matplotlib.pyplot as plt

x = np.array([1,2,3])
y = np.array([3,4,5])
label = '1'

def plot(x,y,label):
    a, = plt.plot(x,y, label = label)
    return a

fig, ax = plt.subplots()
plot(x,y,label)
plot(x,1.5*y,label)

You can put your plot command now in a loop with changing labels. You can still use the ax handle to modify/define the plot parameters.

Upvotes: 0

Related Questions