0

Please note, I've looked at other questions like question and my problem is different and not a duplicate!

I would like to have two plots, with the same x axis in matplotlib. I thought this should be achieved via constrained_layout, but apparently this is not the case. Here is an example code.

import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.gridspec as grd

x = np.arange(0, 30, 0.001)
df_line = pd.DataFrame({"x": x, "y": np.sin(x)})

df_bar = pd.DataFrame({
    "x_bar": [1, 7, 10, 20, 30], 
    "y_bar": [0.0, 0.3, 0.4, 0.1, 0.2]
})

fig = plt.subplots(constrained_layout=True)
gs = grd.GridSpec(2, 1, height_ratios=[3, 2], wspace=0.1)
ax1 = plt.subplot(gs[0])
sns.lineplot(data=df_line, x=df_line["x"], y=df_line["y"], ax=ax1)
ax1.set_xlabel("time", fontsize="22")
ax1.set_ylabel("y values", fontsize="22")
plt.yticks(fontsize=16)
plt.xticks(fontsize=16)
plt.setp(ax1.get_legend().get_texts(), fontsize="22")
ax2 = plt.subplot(gs[1])
sns.barplot(data=df_bar, x="x_bar", y="y_bar", ax=ax2)
ax2.set_xlabel("time", fontsize="22")
ax2.set_ylabel("y values", fontsize="22")
plt.yticks(fontsize=16)
plt.xticks(fontsize=16)

this leads to the following figure. fig 1

However, I would like to see the corresponding x values of both plot aligned. How can I achieve this? Note, I've tried to use the following related question. However, this doesn't fully apply to my situation. First with the high number of x points (which I need in reality) point plots is make the picture to big and slow for loading. On top, I can't use the rank method as my categories for the barplot are not evenly distributed. They are specific points on the x axis which should be aligned with the corresponding point on the lineplot

Alex
  • 6,610
  • 3
  • 20
  • 38
swissy
  • 7
  • 3
  • 1
    I am not sure that seaborn can do this. The bars are put on a linear scale (0,1,2,3,4 in this case) and the displayed values are just labels. I guess you should plot yourself the bars with the x you want. – mozway Aug 04 '21 at 12:35
  • How about plotting ``axvline`` instead of using bar plot? This way you can adjust the x axis the way you want and not linear like bar plot. – Karina Aug 04 '21 at 12:52
  • If you create a scale with equal intervals up to 30 and give it a label for the x-axis of the second graph, you will get something close to what you want. Is this the answer? `ax1.set_xticks(np.arange(1,30,7));ax1.set_xticklabels(df_bar.x_bar.tolist())` – r-beginners Aug 04 '21 at 13:03
  • @Karina happy to use axvline. Can you show me how this would work for the example code? – swissy Aug 04 '21 at 13:12

1 Answers1

1
x = np.arange(0, 30, 0.001)
df_line = pd.DataFrame({"x": x, "y": np.sin(x)})

df_bar = pd.DataFrame({
    "x_bar": [1, 7, 10, 20, 30], 
    "y_bar": [0.0, 0.3, 0.4, 0.1, 0.2]
})

fig, (ax1, ax2) = plt.subplots(2,1)
ax1.plot(df_line['x'], df_line['y'])
for i in range(len(df_bar['x_bar'])):
    ax2.axvline(x=df_bar['x_bar'][i], ymin=0, ymax=df_bar['y_bar'][i])

Output:

enter image description here

---edit---

I incorporated @mozway advice for linewidth:

lw = (300/ax1.get_xlim()[1])
ax2.axvline(x=df_bar['x_bar'][i], ymin=0, ymax=df_bar['y_bar'][i], solid_capstyle='butt', lw=lw)

Output:

enter image description here

or:

enter image description here

Karina
  • 1,252
  • 2
  • 5
  • 16
  • thank you so much! the only point which I would like to fix is that the axis (x-axis) are alinged. Is this doable? – swissy Aug 04 '21 at 13:40
  • Add `sharex=True` to `subplots` – mozway Aug 04 '21 at 13:50
  • Or `ax2.set_xlim(ax1.get_xlim())` if you want both to have xticks – mozway Aug 04 '21 at 13:52
  • 1
    @Karina in `axvline` try to set `solid_capstyle='butt', lw=10` (test which lw value is best) – mozway Aug 04 '21 at 13:56
  • as mozway said, ``sharex=True`` omit the xticklabels from ``ax1``. but instead of ``lw=10`` I prefer ``lw = (300/ax1.get_xlim()[1])``, 300 is arbitrary. The problem with hard code ``lw=10`` is when the data get bigger, the line would still be ``lw=10``, which then hard to see – Karina Aug 04 '21 at 14:25
  • @swissy refer to my edit. The linewidth is now thicker and the x-axis are aligned. – Karina Aug 04 '21 at 14:28