Reputation: 2300
I am trying to make a dual y-axis plot using the new seaborn interface (seaborn.objects, available in v0.12). However, I am having difficulties getting it to work.
My first try is this:
import seaborn.objects as so
df = pd.DataFrame(
{"x": [1, 2, 3, 4, 5], "y1": [5, 2, 1, 6, 2], "y2": [100, 240, 130, 570, 120]}
)
fig, ax1 = plt.subplots(1, 1, figsize=(10, 5))
ax2 = ax1.twinx()
so.Plot(df, x="x").add(so.Bar(), y="y1", ax=ax1).add(so.Line(), y="y2", ax=ax2)
But this will create the seaborn plot with one y-axis and an empty dual-axis plot.
Upvotes: 0
Views: 849
Reputation: 2300
Here is the solution I finally came up with:
import seaborn.objects as so
import pandas as pd
import matplotlib.pyplot as plt
df = pd.DataFrame(
{"x": [1, 2, 3, 4, 5], "y1": [5, 2, 1, 6, 2], "y2": [1000, 240, 1300, 570, 120]}
)
fig, ax1 = plt.subplots(1, 1, figsize=(6, 4))
ax2 = ax1.twinx()
ax1.tick_params(axis="x", labelrotation=45)
p1 = (
so.Plot(df, x="x", y="y1")
.add(so.Bar(width=0.7))
.label(x="Month", y="Data 1", title="TITLE")
.on(ax1)
.plot()
)
p2 = (
so.Plot(df, x="x", y="y2")
.add(so.Line(color="orange", linewidth=3))
.label(y="Data 2", title="TITLE")
.scale(y=so.Continuous().label(like="{x:,.0f}"))
.on(ax2)
.plot()
)
The result is pretty much what I was looking for.
Now here is an interesting fact. The above image was generated with python 3.10.11 and seaborn 0.12.2.
When switching to python 3.11.4 and seaborn 0.13.2, I get the following (note the y-axis tick labels on the left:
This seems to be a bug in seaborn.
Upvotes: 0
Reputation: 1376
How can we refine this?
h= sns.load_dataset("healthexp")
fig, ax = plt.subplots(1, 1, figsize=(10, 5))
ax.clear()
plt.close()
ax2= ax.twinx()
p=(
so.Plot(h, x="Year")
)
p.add(so.Bar(),so.Agg('sum'), y="Spending_USD").on(ax).plot()
p=p.add(so.Line(),so.Agg(), y="Life_Expectancy").on(ax2)
p=p.label(
x="",
y="",
title="Spending",
)
p
Even the output of original plot has messed up axis label.
df = pd.DataFrame(
{"x": [1, 2, 3, 4, 5], "y1": [5, 2, 1, 6, 2], "y2": [100, 240, 130, 570, 120]}
)
fig, ax1 = plt.subplots(1, 1, figsize=(10, 5))
ax2 = ax1.twinx()
p = so.Plot(df, x="x")
p.add(so.Bar(), y="y1").on(ax1).plot()
p.add(so.Line(), y="y2").on(ax2).plot()
Upvotes: 1
Reputation: 49032
You'll want to call Plot.on
to use pre-existing matplotlib axes:
import seaborn.objects as so
df = pd.DataFrame(
{"x": [1, 2, 3, 4, 5], "y1": [5, 2, 1, 6, 2], "y2": [100, 240, 130, 570, 120]}
)
fig, ax1 = plt.subplots(1, 1, figsize=(10, 5))
ax2 = ax1.twinx()
p = so.Plot(df, x="x")
p.add(so.Bar(), y="y1").on(ax1).plot()
p.add(so.Line(), y="y2").on(ax2).plot()
Note that there will likely be a Plot.twin
method to make this more natural, but it's not been implemented yet.
Upvotes: 1