How to show only the first and last tick labels on the x-axis with subplots
Question:
To show only the first and last tick on x-axis, of both a line chart and bar chart side-by-side, produced by matplotlib and pandas.GroupBy, I have below lines.
However only the bar chart shows what’s wanted. The line chart has the latest month on the left upmost (it shall be on the right upmost), and missing the x tick on the right.
What went wrong and how can I correct it?
import matplotlib
import matplotlib.pyplot as plt
import pandas as pd
from io import StringIO
csvfile = StringIO(
"""
Name;Year - Month;Score;Upvote
Mike;2023-01;884.22;5
Mike;2022-12;5472.81;36
Mike;2022-11;2017.59;15
Mike;2022-10;1845.23;14
Mike;2022-08;1984.32;15
Mike;2022-07;1033.33;8
Mike;2022-06;1587.64;24
Mike;2022-05;1019.93;20
Mike;2022-04;2359.3;45
Mike;2022-03;7478.72;140
""")
df = pd.read_csv(csvfile, sep = ';', engine='python')
for group_name, sub_frame in df.groupby("Name"):
fig, axes = plt.subplots(nrows=1,ncols=2,figsize=(10,5))
sub_frame_sorted = sub_frame.sort_values('Year - Month') # sort the data-frame by a column
sub_frame_sorted.plot(ax=axes[1], x="Year - Month", y="Score")
sub_frame_sorted.plot(ax=axes[0], kind='bar', x="Year - Month", y="Upvote")
axes[0].set_xticks([axes[0].get_xticks()[0], axes[0].get_xticks()[-1]])
axes[1].set_xticks([axes[1].get_xticks()[0], axes[1].get_xticks()[-1]])
plt.setp(axes[0].get_xticklabels(), rotation=0)
plt.setp(axes[1].get_xticklabels(), rotation=0)
plt.show()
Answers:
Since your x-axis is a string, the x ticks won’t be at position x, but at position 0..len(sub_frame_sorted)-1
. For whatever reason (someone might come up with an explanation but it looks like a bug), if you debug axes[1].get_xticklabels()
for Name Kate
you’ll see:
[
Text(-1.0, 0, '2022-07'),
Text(0.0, 0, '2022-03'),
Text(1.0, 0, '2022-04'),
Text(2.0, 0, '2022-05'),
Text(3.0, 0, '2022-06'),
Text(4.0, 0, '2022-07'),
Text(5.0, 0, '')
]
In order to avoid empty or wrong labels, you can provide the position directly since you know the data you’re plotting (sub_frame_sorted
):
import matplotlib.pyplot as plt
import pandas as pd
from io import StringIO
csvfile = StringIO(
"""
Name;Year - Month;Score;Upvote
Mike;2022-09;192;5
Mike;2022-08;708;5
Mike;2022-07;140;3
Mike;2022-05;144;8
Mike;2022-04;60;10
Mike;2022-03;108;4
Kate;2022-07;19850;5
Kate;2022-06;19105;2
Kate;2022-05;23740;3
Kate;2022-04;19780;9
Kate;2022-03;15495;4 """)
df = pd.read_csv(csvfile, sep = ';', engine='python')
for group_name, sub_frame in df.groupby("Name"):
fig, axes = plt.subplots(nrows=1,ncols=2,figsize=(10,5))
sub_frame_sorted = sub_frame.sort_values('Year - Month') # sort the data-frame by a column
sub_frame_sorted.plot(ax=axes[0], kind='bar', x="Year - Month", y="Upvote")
axes[1].plot(sub_frame_sorted["Year - Month"], sub_frame_sorted["Score"])
axes[0].set_xticks([axes[0].get_xticks()[0], axes[0].get_xticks()[-1]])
axes[1].set_xticks([0, len(sub_frame_sorted) - 1])
plt.setp(axes[0].get_xticklabels(), rotation=0)
plt.setp(axes[1].get_xticklabels(), rotation=0)
plt.show()
Edit: replacing pandas plot
with matplotlib plot
makes the ticks consistent again, so I would tend to say it’s a pandas bug.
Output:
To show only the first and last tick on x-axis, of both a line chart and bar chart side-by-side, produced by matplotlib and pandas.GroupBy, I have below lines.
However only the bar chart shows what’s wanted. The line chart has the latest month on the left upmost (it shall be on the right upmost), and missing the x tick on the right.
What went wrong and how can I correct it?
import matplotlib
import matplotlib.pyplot as plt
import pandas as pd
from io import StringIO
csvfile = StringIO(
"""
Name;Year - Month;Score;Upvote
Mike;2023-01;884.22;5
Mike;2022-12;5472.81;36
Mike;2022-11;2017.59;15
Mike;2022-10;1845.23;14
Mike;2022-08;1984.32;15
Mike;2022-07;1033.33;8
Mike;2022-06;1587.64;24
Mike;2022-05;1019.93;20
Mike;2022-04;2359.3;45
Mike;2022-03;7478.72;140
""")
df = pd.read_csv(csvfile, sep = ';', engine='python')
for group_name, sub_frame in df.groupby("Name"):
fig, axes = plt.subplots(nrows=1,ncols=2,figsize=(10,5))
sub_frame_sorted = sub_frame.sort_values('Year - Month') # sort the data-frame by a column
sub_frame_sorted.plot(ax=axes[1], x="Year - Month", y="Score")
sub_frame_sorted.plot(ax=axes[0], kind='bar', x="Year - Month", y="Upvote")
axes[0].set_xticks([axes[0].get_xticks()[0], axes[0].get_xticks()[-1]])
axes[1].set_xticks([axes[1].get_xticks()[0], axes[1].get_xticks()[-1]])
plt.setp(axes[0].get_xticklabels(), rotation=0)
plt.setp(axes[1].get_xticklabels(), rotation=0)
plt.show()
Since your x-axis is a string, the x ticks won’t be at position x, but at position 0..len(sub_frame_sorted)-1
. For whatever reason (someone might come up with an explanation but it looks like a bug), if you debug axes[1].get_xticklabels()
for Name Kate
you’ll see:
[
Text(-1.0, 0, '2022-07'),
Text(0.0, 0, '2022-03'),
Text(1.0, 0, '2022-04'),
Text(2.0, 0, '2022-05'),
Text(3.0, 0, '2022-06'),
Text(4.0, 0, '2022-07'),
Text(5.0, 0, '')
]
In order to avoid empty or wrong labels, you can provide the position directly since you know the data you’re plotting (sub_frame_sorted
):
import matplotlib.pyplot as plt
import pandas as pd
from io import StringIO
csvfile = StringIO(
"""
Name;Year - Month;Score;Upvote
Mike;2022-09;192;5
Mike;2022-08;708;5
Mike;2022-07;140;3
Mike;2022-05;144;8
Mike;2022-04;60;10
Mike;2022-03;108;4
Kate;2022-07;19850;5
Kate;2022-06;19105;2
Kate;2022-05;23740;3
Kate;2022-04;19780;9
Kate;2022-03;15495;4 """)
df = pd.read_csv(csvfile, sep = ';', engine='python')
for group_name, sub_frame in df.groupby("Name"):
fig, axes = plt.subplots(nrows=1,ncols=2,figsize=(10,5))
sub_frame_sorted = sub_frame.sort_values('Year - Month') # sort the data-frame by a column
sub_frame_sorted.plot(ax=axes[0], kind='bar', x="Year - Month", y="Upvote")
axes[1].plot(sub_frame_sorted["Year - Month"], sub_frame_sorted["Score"])
axes[0].set_xticks([axes[0].get_xticks()[0], axes[0].get_xticks()[-1]])
axes[1].set_xticks([0, len(sub_frame_sorted) - 1])
plt.setp(axes[0].get_xticklabels(), rotation=0)
plt.setp(axes[1].get_xticklabels(), rotation=0)
plt.show()
Edit: replacing pandas plot
with matplotlib plot
makes the ticks consistent again, so I would tend to say it’s a pandas bug.
Output: