【问题标题】:How to extend a matplotlib axis if the ticks are labels and not numeric?如果刻度是标签而不是数字,如何扩展 matplotlib 轴?
【发布时间】:2020-10-28 11:13:45
【问题描述】:

我有许多图表,用 matplotlib 和 seaborn 制作,如下例所示。

  • 我在折线图上展示了某些数量如何随时间演变
  • x 轴标签不是数字,而是字符串(例如“Q1”或“2018 上半年”等)
  • 我需要将 x 轴“延伸”到右侧,其中包含一个空白句点。 图表必须显示从 Q1 到 Q4,但没有 Q4 的数据(Q4 列充满了 nans )
  • 我需要这个,因为我需要将图表与其他有第四季度数据的图表并排显示
  • matplotlib 不显示充满 nan 的列
  • 如果 x 轴是数字,则很容易扩展绘图范围;因为它不是数字,所以我不知道每个刻度对应哪个 x_range
  • 我在下面找到了解决方案。它可以工作,但并不优雅:我使用整数作为 x 轴,加 1,然后将标签设置回字符串。 有没有更优雅的方式?

这是代码:

import numpy as np
import pandas as pd

import matplotlib.pyplot as plt
import matplotlib
from matplotlib.ticker import FuncFormatter
import seaborn as sns

df =pd.DataFrame()
df['period'] = ['Q1','Q2','Q3','Q4']
df['a'] = [3,4,5,np.nan]
df['b'] = [4,4,6,np.nan]
df = df.set_index( 'period')

fig, ax = plt.subplots(1,2)
sns.lineplot( data = df, ax =ax[0])

df_idx = df.index

df2 = df.set_index( np.arange(1, len(df_idx) + 1 ))

sns.lineplot(data = df2, ax = ax[1])
ax[1].set_xlim(1,4)
ax[1].set_xticklabels(df.index)

【问题讨论】:

    标签: python matplotlib


    【解决方案1】:

    您可以为ax[0]添加这些代码行

    left_buffer,right_buffer = 3,2
    labels = ['Q1','Q2','Q3','Q4']
    
    extanded_labels = ['']*left_buffer + labels + ['']*right_buffer
    left_range = list(range(-left_buffer,0))
    right_range = list(range(len(labels),len(labels)+right_buffer))
    ticks_range = left_range + list(range(len(labels))) + right_range
    aux_range = list(range(len(extanded_labels)))
    
    ax[0].set_xticks(ticks_range)
    ax[0].set_xticklabels(extanded_labels)
    
    xticks = ax[0].xaxis.get_major_ticks()
    for ind in aux_range[0:left_buffer]: xticks[ind].tick1line.set_visible(False)
    for ind in aux_range[len(labels)+left_buffer:len(labels)+left_buffer+right_buffer]: xticks[ind].tick1line.set_visible(False)
    

    其中left_bufferright_buffer 是您要分别添加到左侧和右侧的边距。运行代码,你会得到

    【讨论】:

    • 太棒了,我欠你一杯啤酒!只有一个问题 - 有没有一种简单的方法来调整范围,以便左右有一点差距?右侧子图立即从第一个 xtick 开始,而左侧子图则不会
    • 另外,如果我需要向左延长一两个句点怎么办?有没有一种简单的方法可以做到这一点?
    • @Pythonistaan​​onymous 不客气 :) 当然,看看我更新的帖子 :)
    • 不确定它是否值得一个单独的问题,但有没有办法告诉 matplotlib 如果它们是 nans,不要“砍掉”最左边和最右边的数据点?
    【解决方案2】:

    我实际上可能找到了一个更简单的解决方案:我可以通过绘制数据框的 x = 索引来绘制一条透明线 (alpha = 0),即所有标签,包括所有值都是 nans 的标签,并且 y =数据框的平均值,以确保它在范围内:

    sns.lineplot(x = df.index, y = np.ones(df.shape[0]) * df.mean().mean()  , ax = ax[0], alpha =0 )
    

    这假设 y 轴的比例没有手动更改;更好的方法是检查它是否有:

    y_centre = np.mean([ax[0].get_ylim()])
    sns.lineplot(x = df.index, y = np.ones(df.shape[0]) * y_centre  , ax = ax[0], alpha =0 )
    

    绘制一条透明线会强制 matplotlib 扩展轴以显示所有 x 值,即使是所有其他值都是 nans 的那些。

    【讨论】:

      猜你喜欢
      • 2011-09-18
      • 2019-12-18
      • 2021-06-14
      • 2012-12-19
      • 2019-01-07
      • 2012-03-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多