在matplotlib中更改月份标签,而不更改区域设置

huangapple go评论78阅读模式
英文:

Change month labels in matplotlib without changing the locale

问题

使用这个示例图表作为示例:
在matplotlib中更改月份标签,而不更改区域设置

使用以下代码:

import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import matplotlib.cbook as cbook

data = cbook.get_sample_data('goog.npz', np_load=True)['price_data'][0:200]

fig, ax = plt.subplots(figsize=(10, 7), constrained_layout=True)
ax.plot('date', 'adj_close', data=data)
# ax.xaxis.set_major_locator(mdates.MonthLocator())
# ax.grid(True)
ax.set_ylabel(r'Price [$]')

ax.xaxis.set_major_formatter(
    mdates.ConciseDateFormatter(ax.xaxis.get_major_locator()))

plt.savefig("chart.png")

我需要将月份从英文更改为西班牙文,即:Dec 更改为 Dic,Apr 更改为 Abr,Jan 更改为 Ene 等等。

我可以通过像这样更改地区设置来完成:

locale.setlocale(locale.LC_TIME, 'es_ES')

但我无法在脚本中使用它,因为它在无服务器虚拟机上运行,您无法更改任何操作系统配置。

所以我考虑了从英文月份手动更改标签的方法。我看到了使用 DateFormatter 的示例,但这不起作用,因为它再次依赖于系统区域设置来获取月份名称,使用 strftime,而我看到的任何其他格式化程序都使用数字而不是日期。所以有没有办法本地化月份的名称?

更新
下面添加了解决方案。

英文:

With this plot as an example:
在matplotlib中更改月份标签,而不更改区域设置

With the code:

import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import matplotlib.cbook as cbook

data = cbook.get_sample_data('goog.npz', np_load=True)['price_data'][0:200]

fig, ax = plt.subplots(figsize=(10, 7), constrained_layout=True)
ax.plot('date', 'adj_close', data=data)
# ax.xaxis.set_major_locator(mdates.MonthLocator())
# ax.grid(True)
ax.set_ylabel(r'Price [$]')

ax.xaxis.set_major_formatter(
    mdates.ConciseDateFormatter(ax.xaxis.get_major_locator()))

plt.savefig("chart.png")

And I need to change the months from English to Spanish, ie: Dec to Dic, Apr to Abr, Jan to Ene and so on.

I can do it by changing the locale like so:

locale.setlocale(locale.LC_TIME, 'es_ES')

But I can't use it in the script because it runs on a serverless vm where you can't change any of the os configuration.

So I thought in changing the labels "manually" from an English month to a Spanish one. I've seen examples using DateFormatter but that doesn't work because again it relies in the system locale for the months names using strftime and any other fromatter I've seen has been using numbers not dates. So is there any solution to localize the names of the months?

Update
Added solution below

答案1

得分: 1

一种方法是使用 babel.dates 来进行日期格式化,它允许使用区域设置参数而不改变系统的区域设置。

基本语法如下:

babel.dates.format_datetime([日期时间对象], [格式], locale=[区域设置])

请注意,格式不使用 % 符号。查看包文档以获取更多信息和示例。

要使用此包来格式化 Matplotlib 刻度标签,您可以重新实现来自Matplotlib源代码DateFormatter,并将 strftime() 调用替换为 babel.dates.format_datetime()

作为概念验证:

import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import matplotlib.cbook as cbook
import babel.dates

class CustomDateFormatter(mdates.ticker.Formatter):
   
    def __init__(self, fmt, fmtloc, tz=None, *, usetex=None):
        self.tz = mdates.UTC
        self.fmt = fmt
        self.fmtloc = fmtloc
        self._usetex = (usetex if usetex is not None else
                        mpl.rcParams['text.usetex'])

    def __call__(self, x, pos=0):
        result = babel.dates.format_datetime(mdates.num2date(x, self.tz), self.fmt, locale=self.fmtloc)
        return mdates._wrap_in_tex(result) if self._usetex else result

data = cbook.get_sample_data('goog.npz', np_load=True)['price_data'][0:200]

fig, ax = plt.subplots(figsize=(10, 7), constrained_layout=True)
ax.plot('date', 'adj_close', data=data)
ax.set_ylabel(r'Price [$]')
ax.xaxis.set_major_formatter(
    CustomDateFormatter("MMM yyyy", "es"))

plt.savefig("chart.png")

结果:

在matplotlib中更改月份标签,而不更改区域设置

对于 ConciseDateFormatter,这个想法是一样的,但这个类要复杂得多,因此您需要在许多地方进行修改,以便正确处理命名空间(类似于上面代码中的 mdates.num2date,而不是原始类中的普通 num2dates 调用)。

英文:

One way is to use babel.dates for the date formatting, which allows for a locale argument without changing the system locale.

The basic syntax is:

babel.dates.format_datetime([datetime object], [format], locale=[locale])

Note that the format does not use % signs. See the package documentation for more information and many examples.

To use this package to format Matplotlib tick labels you can re-implement DateFormatter from the matplotlib source and replace the strftime() call with babel.dates.format_datetime().

As a proof of concept:

import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import matplotlib.cbook as cbook
import babel.dates

class CustomDateFormatter(mdates.ticker.Formatter):
   
    def __init__(self, fmt, fmtloc, tz=None, *, usetex=None):
        self.tz = mdates.UTC
        self.fmt = fmt
        self.fmtloc = fmtloc
        self._usetex = (usetex if usetex is not None else
                        mpl.rcParams['text.usetex'])

    def __call__(self, x, pos=0):
        result = babel.dates.format_datetime(mdates.num2date(x, self.tz), self.fmt, locale=self.fmtloc)
        return mdates._wrap_in_tex(result) if self._usetex else result

data = cbook.get_sample_data('goog.npz', np_load=True)['price_data'][0:200]

fig, ax = plt.subplots(figsize=(10, 7), constrained_layout=True)
ax.plot('date', 'adj_close', data=data)
ax.set_ylabel(r'Price [$]')
ax.xaxis.set_major_formatter(
    CustomDateFormatter("MMM yyyy", "es"))

plt.savefig("chart.png")

Result:

在matplotlib中更改月份标签,而不更改区域设置

For ConciseDateFormatter this idea is the same but this class is much more complex so you will need to modify it in many places in order to get the namespaces right (similar to for example mdates.num2date in the code above instead of a plain num2dates call in the original class).

答案2

得分: 1

使用这个 [答案][1] 和 [Marijn][2] 的答案我得到了以下解决方案它使用 `set_xticklabels` 来更改标签并使用 [Babel][3] 来将月份更改为本地化版本而不更改 `locale`:

```python
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import matplotlib.cbook as cbook
import babel.dates
import matplotlib.ticker as mticker

data = cbook.get_sample_data('goog.npz', np_load=True)['price_data'][0:200]

fig, ax = plt.subplots(figsize=(10, 7), constrained_layout=True)
ax.plot('date', 'adj_close', data=data)
# ax.xaxis.set_major_locator(mdates.MonthLocator())
# ax.grid(True)
ax.set_ylabel(r'Price [$]')

ax.xaxis.set_major_formatter(
    mdates.ConciseDateFormatter(ax.xaxis.get_major_locator()))

ticks_loc = ax.get_xticks().tolist()
ax.xaxis.set_major_locator(mticker.FixedLocator(ticks_loc))
ax.set_xticklabels([babel.dates.format_datetime(mdates.num2date(x),'yyyy',locale='es') 
        if mdates.num2date(x).month == 1
        else babel.dates.format_datetime(mdates.num2date(x),'MMM',locale='es')
        for x in ticks_loc])

plt.savefig("chart.png")

它产生了:

在matplotlib中更改月份标签,而不更改区域设置


<details>
<summary>英文:</summary>

Using this [answer][1] and the answer by [Marijn][2] I came up with this solution that uses `set_xticklabels` to change the labels and [Babel][3] to change the months to a localized version without changing the `locale`:

    import matplotlib.pyplot as plt
    import matplotlib.dates as mdates
    import matplotlib.cbook as cbook
    import babel.dates
    import matplotlib.ticker as mticker
    
    data = cbook.get_sample_data(&#39;goog.npz&#39;, np_load=True)[&#39;price_data&#39;][0:200]
    
    fig, ax = plt.subplots(figsize=(10, 7), constrained_layout=True)
    ax.plot(&#39;date&#39;, &#39;adj_close&#39;, data=data)
    # ax.xaxis.set_major_locator(mdates.MonthLocator())
    # ax.grid(True)
    ax.set_ylabel(r&#39;Price [$]&#39;)
    
    ax.xaxis.set_major_formatter(
        mdates.ConciseDateFormatter(ax.xaxis.get_major_locator()))
    
    ticks_loc = ax.get_xticks().tolist()
    ax.xaxis.set_major_locator(mticker.FixedLocator(ticks_loc))
    ax.set_xticklabels([babel.dates.format_datetime(mdates.num2date(x),&#39;yyyy&#39;,locale=&#39;es&#39;) 
            if mdates.num2date(x).month == 1
            else babel.dates.format_datetime(mdates.num2date(x),&#39;MMM&#39;,locale=&#39;es&#39;)
            for x in ticks_loc])
    
    plt.savefig(&quot;chart.png&quot;)


It produces:

[![enter image description here][4]][4]


  [1]: https://stackoverflow.com/a/63755285/1128695
  [2]: https://stackoverflow.com/a/75051766/1128695
  [3]: https://babel.pocoo.org/en/latest/
  [4]: https://i.stack.imgur.com/GZ4eV.png

</details>



huangapple
  • 本文由 发表于 2023年1月9日 05:11:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/75051327.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定