To plot multiple lines in Python, call plt.plot() once for each line before plt.show(): every call adds another line to the same graph. Give each line a label and call plt.legend() so readers can tell them apart. You can also plot all columns of a NumPy array or a pandas DataFrame in one call. This guide covers each approach with real Matplotlib windows, plus colors and styles, many lines in a loop, legends, subplots and lines on different scales.
Every example was run with Python 3.12.5, Matplotlib 3.11.2, NumPy 2.5.3 and pandas 3.0.6; the screenshots are the real Matplotlib windows. The full list of line options is in the Matplotlib reference for pyplot.plot.
Plot multiple lines on the same graph
import matplotlib.pyplot as plt
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]
new_york = [3, 5, 10, 16, 21, 26]
chicago = [-3, -1, 5, 11, 17, 22]
miami = [20, 21, 23, 25, 27, 28]
plt.plot(months, new_york, label="New York") # each plot() call adds one line
plt.plot(months, chicago, label="Chicago")
plt.plot(months, miami, label="Miami")
plt.title("Average temperature (°C)")
plt.legend()
plt.show()

plt.plot() calls, one graph, one legend.Matplotlib gives each new line the next colour in its cycle automatically. You can check what is on the axes with ax.get_lines():
import matplotlib.pyplot as plt
from matplotlib.colors import to_hex
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]
fig, ax = plt.subplots()
ax.plot(months, [3, 5, 10, 16, 21, 26], label="New York")
ax.plot(months, [-3, -1, 5, 11, 17, 22], label="Chicago")
for line in ax.get_lines():
print(f"{line.get_label():10} color={to_hex(line.get_color())} points={len(line.get_xdata())}")
Output:
New York color=#1f77b4 points=6
Chicago color=#ff7f0e points=6

Plot multiple lines from a NumPy array
If y is a 2-D array, plot() draws one line per column. Since Matplotlib 3.4 you can pass a list of labels too:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 2 * np.pi, 100)
Y = np.column_stack([np.sin(x), np.cos(x), np.sin(2 * x)]) # shape (100, 3): one column per line
lines = plt.plot(x, Y, label=["sin(x)", "cos(x)", "sin(2x)"]) # one call, three lines
print(len(lines), "lines from an array of shape", Y.shape)
plt.legend()
plt.show()
Output:
3 lines from an array of shape (100, 3)

plt.plot(x, Y) call draws a line for each column of Y.Different colors, line styles and markers
import matplotlib.pyplot as plt
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]
plt.plot(months, [3, 5, 10, 16, 21, 26], color="tab:red", linestyle="-", marker="o", label="New York")
plt.plot(months, [-3, -1, 5, 11, 17, 22], color="tab:blue", linestyle="--", marker="s", label="Chicago")
plt.plot(months, [20, 21, 23, 25, 27, 28], color="tab:green", linestyle=":", linewidth=3, label="Miami")
plt.legend()
plt.grid(alpha=0.3)
plt.show()

color, linestyle, marker and linewidth per line.Many lines in a loop
For more than a handful of lines, loop over the data and take the colours from a colormap so neighbouring lines are easy to tell apart:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 200)
frequencies = [0.5, 1.0, 1.5, 2.0, 2.5, 3.0]
colors = plt.cm.viridis(np.linspace(0, 1, len(frequencies))) # one colour per line
fig, ax = plt.subplots(figsize=(8, 4.5))
for f, color in zip(frequencies, colors):
ax.plot(x, np.sin(f * x) + f, color=color, label=f"f = {f}")
ax.legend(ncols=2, fontsize=9)
plt.tight_layout()
plt.show()

Plot multiple lines from a pandas DataFrame
DataFrame.plot() draws one line per column. Choose the x column with x= and the lines with y=[...]:
import pandas as pd
import matplotlib.pyplot as plt
df = pd.DataFrame({
"month": ["Jan", "Feb", "Mar", "Apr", "May", "Jun"],
"Laptops": [120, 135, 150, 160, 172, 190],
"Phones": [200, 190, 210, 230, 225, 240],
"Tablets": [80, 85, 83, 90, 95, 100],
})
ax = df.plot(x="month", y=["Laptops", "Phones", "Tablets"], marker="o", figsize=(7, 4)) # one line per column
ax.set_ylabel("Units sold")
plt.tight_layout()
plt.show()

Legend placement and labels at the end of lines
With several lines, a legend inside the plot can hide data. Move it outside with bbox_to_anchor, or write each label next to the last point of its line:
import matplotlib.pyplot as plt
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]
fig, ax = plt.subplots(figsize=(8, 4))
for city, temps in {"New York": [3, 5, 10, 16, 21, 26], "Chicago": [-3, -1, 5, 11, 17, 22],
"Miami": [20, 21, 23, 25, 27, 28], "Seattle": [6, 7, 9, 12, 15, 18]}.items():
line, = ax.plot(months, temps)
ax.annotate(city, (months[-1], temps[-1]), xytext=(6, 0), textcoords="offset points",
color=line.get_color(), va="center") # label at the end of each line
ax.legend(ax.get_lines(), ["New York", "Chicago", "Miami", "Seattle"],
loc="upper left", bbox_to_anchor=(1.12, 1)) # legend outside the axes
plt.tight_layout()
plt.show()

More legend options: put the legend outside the plot and change the legend font size.
One line per subplot
When lines have different units or would overlap too much, give each one its own subplot and share the x-axis:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(1, 13)
series = {"Revenue": x * 10 + 5, "Costs": x * 7 + 20, "Profit": x * 3 - 15}
fig, axes = plt.subplots(3, 1, figsize=(7, 6), sharex=True)
for ax, (name, y) in zip(axes, series.items()):
ax.plot(x, y, marker="o")
ax.set_title(name, fontsize=10)
axes[-1].set_xlabel("Month")
plt.tight_layout()
plt.show()

plt.subplots(3, 1, sharex=True): one line per panel.Two lines with different y scales
import matplotlib.pyplot as plt
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]
fig, ax1 = plt.subplots(figsize=(7, 4))
ax1.plot(months, [120, 135, 150, 160, 172, 190], color="tab:blue", label="Revenue (k$)")
ax2 = ax1.twinx() # second y-axis for a line on a different scale
ax2.plot(months, [8.5, 9.1, 9.8, 10.2, 10.1, 11.0], color="tab:red", label="Margin (%)")
fig.legend(loc="upper left", bbox_to_anchor=(0.12, 0.88))
plt.tight_layout()
plt.show()
