无法在 matplotlib 中设置 plt.xticks

Posted

技术标签:

【中文标题】无法在 matplotlib 中设置 plt.xticks【英文标题】:Unable to set plt.xticks in matplotlib 【发布时间】:2018-11-22 04:04:49 【问题描述】:

我有一个 pandas 数据框 (df)

Parameter   Date    Concentration   Unit    Prescribed Standard     Exceeding Standard? (Yes/No)    Remarks
1   NaN     02/01/2017  26.10   µg/m3  NaN     NaN     NaN
2   NaN     03/01/2017  30.27   µg/m3  NaN     NaN     NaN
3   NaN     04/01/2017  36.36   µg/m3  NaN     NaN     NaN
4   NaN     05/01/2017  33.41   µg/m3  NaN     NaN     NaN

我正在尝试绘制Date vs Concentration的时间序列图 我使用.to_datetime() 将日期转换为日期时间对象

    Parameter   Date    Concentration   Unit    Prescribed Standard     Exceeding Standard? (Yes/No)    Remarks
1   NaN     2017-01-02  26.10   µg/m3  NaN     NaN     NaN
2   NaN     2017-01-03  30.27   µg/m3  NaN     NaN     NaN
3   NaN     2017-01-04  36.36   µg/m3  NaN     NaN     NaN
4   NaN     2017-01-05  33.41   µg/m3  NaN     NaN     NaN

时间序列图很容易使用:

plt.plot(df["Date"][:322], df["Concentration"][:322], "+", color="red", linewidth=0.5)

但如果我尝试将 xlabels 更改为其他任何内容,比如月份名称,plt.xticks(["Jan", "Feb","Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"])]) 我会收到错误消息:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
~/.local/lib/python3.6/site-packages/pandas/core/tools/datetimes.py in _convert_listlike(arg, box, format, name, tz)
    302             try:
--> 303                 values, tz = tslib.datetime_to_datetime64(arg)
    304                 return DatetimeIndex._simple_new(values, name=name, tz=tz)

pandas/_libs/tslib.pyx in pandas._libs.tslib.datetime_to_datetime64()

TypeError: Unrecognized value type: <class 'str'>

During handling of the above exception, another exception occurred:

OutOfBoundsDatetime                       Traceback (most recent call last)
~/.local/lib/python3.6/site-packages/pandas/plotting/_converter.py in _convert_1d(values, unit, axis)
    310             try:
--> 311                 values = tools.to_datetime(values)
    312                 if isinstance(values, Index):

~/.local/lib/python3.6/site-packages/pandas/core/tools/datetimes.py in to_datetime(arg, errors, dayfirst, yearfirst, utc, box, format, exact, unit, infer_datetime_format, origin)
    379     elif is_list_like(arg):
--> 380         result = _convert_listlike(arg, box, format)
    381     else:

~/.local/lib/python3.6/site-packages/pandas/core/tools/datetimes.py in _convert_listlike(arg, box, format, name, tz)
    305             except (ValueError, TypeError):
--> 306                 raise e
    307 

~/.local/lib/python3.6/site-packages/pandas/core/tools/datetimes.py in _convert_listlike(arg, box, format, name, tz)
    293                     yearfirst=yearfirst,
--> 294                     require_iso8601=require_iso8601
    295                 )

pandas/_libs/tslib.pyx in pandas._libs.tslib.array_to_datetime()

pandas/_libs/tslib.pyx in pandas._libs.tslib.array_to_datetime()

pandas/_libs/tslib.pyx in pandas._libs.tslib.array_to_datetime()

pandas/_libs/tslib.pyx in pandas._libs.tslib.array_to_datetime()

pandas/_libs/tslib.pyx in pandas._libs.tslib.convert_datetime_to_tsobject()

pandas/_libs/tslib.pyx in pandas._libs.tslib._check_dts_bounds()

OutOfBoundsDatetime: Out of bounds nanosecond timestamp: 1-01-01 00:00:00

During handling of the above exception, another exception occurred:

AttributeError                            Traceback (most recent call last)
<ipython-input-26-7f51ae7566c4> in <module>()
      4 
      5 plt.plot(df_btm_pm25["Date"][:322], df_btm_pm25["Concentration"][:322], "+", color="red", linewidth=0.5)
----> 6 plt.xticks(["Jan", "Feb","Mar", "Apr", "May", "Jun", "Jul"])#, "Aug", "Sept", "Oct", "Nov", "Dec"])
      7 #axes.set_xticks(x)
      8 axes.locator_params(nbins=12)

~/.local/lib/python3.6/site-packages/matplotlib/pyplot.py in xticks(*args, **kwargs)
   1722         labels = ax.get_xticklabels()
   1723     elif len(args)==1:
-> 1724         locs = ax.set_xticks(args[0])
   1725         labels = ax.get_xticklabels()
   1726     elif len(args)==2:

~/.local/lib/python3.6/site-packages/matplotlib/axes/_base.py in set_xticks(self, ticks, minor)
   3206             Default is ``False``.
   3207         """
-> 3208         ret = self.xaxis.set_ticks(ticks, minor=minor)
   3209         self.stale = True
   3210         return ret

~/.local/lib/python3.6/site-packages/matplotlib/axis.py in set_ticks(self, ticks, minor)
   1676         """
   1677         # XXX if the user changes units, the information will be lost here
-> 1678         ticks = self.convert_units(ticks)
   1679         if len(ticks) > 1:
   1680             xleft, xright = self.get_view_interval()

~/.local/lib/python3.6/site-packages/matplotlib/axis.py in convert_units(self, x)
   1524             return x
   1525 
-> 1526         ret = self.converter.convert(x, self.units, self)
   1527         return ret
   1528 

~/.local/lib/python3.6/site-packages/pandas/plotting/_converter.py in convert(values, unit, axis)
    278                       for v in values]
    279         else:
--> 280             values = DatetimeConverter._convert_1d(values, unit, axis)
    281         return values
    282 

~/.local/lib/python3.6/site-packages/pandas/plotting/_converter.py in _convert_1d(values, unit, axis)
    315                     values = [_dt_to_float_ordinal(x) for x in values]
    316             except Exception:
--> 317                 values = _dt_to_float_ordinal(values)
    318 
    319         return values

~/.local/lib/python3.6/site-packages/pandas/plotting/_converter.py in _dt_to_float_ordinal(dt)
    263         base = dates.epoch2num(dt.asi8 / 1.0E9)
    264     else:
--> 265         base = dates.date2num(dt)
    266     return base
    267 

~/.local/lib/python3.6/site-packages/matplotlib/dates.py in date2num(d)
    450         if not d.size:
    451             return d
--> 452         return _to_ordinalf_np_vectorized(d)
    453 
    454 

~/.local/lib/python3.6/site-packages/numpy/lib/function_base.py in __call__(self, *args, **kwargs)
   2753             vargs.extend([kwargs[_n] for _n in names])
   2754 
-> 2755         return self._vectorize_call(func=func, args=vargs)
   2756 
   2757     def _get_ufunc_and_otypes(self, func, args):

~/.local/lib/python3.6/site-packages/numpy/lib/function_base.py in _vectorize_call(self, func, args)
   2823             res = func()
   2824         else:
-> 2825             ufunc, otypes = self._get_ufunc_and_otypes(func=func, args=args)
   2826 
   2827             # Convert args to object arrays first

~/.local/lib/python3.6/site-packages/numpy/lib/function_base.py in _get_ufunc_and_otypes(self, func, args)
   2783 
   2784             inputs = [arg.flat[0] for arg in args]
-> 2785             outputs = func(*inputs)
   2786 
   2787             # Performance note: profiling indicates that -- for simple

~/.local/lib/python3.6/site-packages/matplotlib/dates.py in _to_ordinalf(dt)
    253         tzi = UTC
    254 
--> 255     base = float(dt.toordinal())
    256 
    257     # If it's sufficiently datetime-like, it will have a `date()` method

AttributeError: 'str' object has no attribute 'toordinal'

不过,我可以通过set_xticks 更改刻度。我在这里错过了什么?

【问题讨论】:

我无法轻松地将您的表格转换为代码以提供适当的解决方案 (minimal reproducible example)。所以我只想提一下,您可能应该使用 datetimes 来绘制和 matplotlib.dates 定位器和标签格式化器。 @ImportanceOfBeingErnest 我没有正确获得第二部分。这是 csv 数据文件的链接:pastebin.com/3zuhckN7 【参考方案1】:

正如@ImportanceOfBeingErnest 建议的那样,您应该使用locators 重新格式化xtick 标签。我在下面实现了它们:

import matplotlib.pyplot as plt
import pandas as pd
import matplotlib.dates as mdates # For formatting dates


fig, ax = plt.subplots(ncols=2, nrows=1, figsize=(15, 4.18))

# Make the original plot
ax[0].plot(df["Date"][:322], 
           df["Concentration"][:322], 
           "+", color="red", linewidth=0.5)
ax[0].set_title('Original plot')

# New xticks plot
months = mdates.MonthLocator()          # Add tick every month
days = mdates.DayLocator(range(1,32,5)) # Add tick every 5th day in a month
monthFmt = mdates.DateFormatter('%b')   # Use abbreviated month name

# Add the locators to the axis
ax[1].xaxis.set_major_locator(months)
ax[1].xaxis.set_major_formatter(monthFmt)
ax[1].xaxis.set_minor_locator(days)
ax[1].plot(df["Date"][:322], 
           df["Concentration"][:322], 
           "+", color="red", linewidth=0.5)
ax[1].set_title('Updated xticks')

plt.show()

这里有一些有用的资源:

matplotlib.dates api strftime() directives This example,我大量借鉴

【讨论】:

以上是关于无法在 matplotlib 中设置 plt.xticks的主要内容,如果未能解决你的问题,请参考以下文章

在 matplotlib 中设置可变点大小

在 matplotlib 中设置颜色条范围

python 在Matplotlib中设置图例

在 Matplotlib 中设置绘图画布的大小

如何在 ipython 笔记本中设置 matplotlib 图形默认大小?

在 matplotlib 中设置子图的大小