Como ignorar datas vazias (fins de semana) em um gráfico Matplotlib Python financeira?
-
13-09-2019 - |
Pergunta
ax.plot_date((dates, dates), (highs, lows), '-')
Atualmente estou usando esse comando para traçar altos e baixos financeiros usando Matplotlib . Ele funciona muito bem, mas como faço para remover os espaços em branco no eixo X deixado por dias sem dados de mercado, tais como fins de semana e feriados?
Eu tenho listas de datas, altos, baixos, fecha e abre. Não consigo encontrar qualquer exemplos de criação de um gráfico com um eixo x que datas dos espetáculos, mas não impõe uma escala constante.
Solução
Eu acho que você precisa "artificialmente sintetizar" a forma exata do enredo você quer usando xticks
para definir os rótulos de escala para as cordas que representam as datas (de colocar claro que os carrapatos em intervalos equidistantes, embora as datas que você está representando não estão equidistantes) e, em seguida, usando um plot
simples.
Outras dicas
Há um exemplo de como fazer isso no site da Matplotlib:
https://matplotlib.org/gallery/ticks_and_spines/date_index_formatter.html
I usará tipicamente NumPy de NaN (não um número), para os valores inválido ou não presente. Eles são representados por Matplotlib como lacunas na trama e NumPy faz parte de Pylab / Matplotlib.
>>> import pylab
>>> xs = pylab.arange(10.) + 733632. # valid date range
>>> ys = [1,2,3,2,pylab.nan,2,3,2,5,2.4] # some data (one undefined)
>>> pylab.plot_date(xs, ys, ydate=False, linestyle='-', marker='')
[<matplotlib.lines.Line2D instance at 0x0378D418>]
>>> pylab.show()
Uma das características anunciadas de scikits.timeseries é "Criar parcelas de séries temporais com rótulos dos eixos de forma inteligente espaçados ".
Você pode ver alguns exemplos de parcelas aqui . No primeiro exemplo (mostrado abaixo) a freqüência 'negócio' é usado para os dados, o que automaticamente feriados e fins de semana exclui e similares. Também máscaras falta pontos de dados, o que você vê como lacunas neste enredo, em vez de linearmente interpolando-los.
Até resposta data (2018) com Matplotlib 2.1.2, Python 2.7.12
A função equidate_ax
alças tudo que você precisa para uma data x eixo simples com espaçamento equidistante dos pontos de dados. Realizado com ticker.FuncFormatter
baseado em neste exemplo .
from __future__ import division
from matplotlib import pyplot as plt
from matplotlib.ticker import FuncFormatter
import numpy as np
import datetime
def equidate_ax(fig, ax, dates, fmt="%Y-%m-%d", label="Date"):
"""
Sets all relevant parameters for an equidistant date-x-axis.
Tick Locators are not affected (set automatically)
Args:
fig: pyplot.figure instance
ax: pyplot.axis instance (target axis)
dates: iterable of datetime.date or datetime.datetime instances
fmt: Display format of dates
label: x-axis label
Returns:
None
"""
N = len(dates)
def format_date(index, pos):
index = np.clip(int(index + 0.5), 0, N - 1)
return dates[index].strftime(fmt)
ax.xaxis.set_major_formatter(FuncFormatter(format_date))
ax.set_xlabel(label)
fig.autofmt_xdate()
#
# Some test data (with python dates)
#
dates = [datetime.datetime(year, month, day) for year, month, day in [
(2018,2,1), (2018,2,2), (2018,2,5), (2018,2,6), (2018,2,7), (2018,2,28)
]]
y = np.arange(6)
# Create plots. Left plot is default with a gap
fig, [ax1, ax2] = plt.subplots(1, 2)
ax1.plot(dates, y, 'o-')
ax1.set_title("Default")
ax1.set_xlabel("Date")
# Right plot will show equidistant series
# x-axis must be the indices of your dates-list
x = np.arange(len(dates))
ax2.plot(x, y, 'o-')
ax2.set_title("Equidistant Placement")
equidate_ax(fig, ax2, dates)
Eu corri para este problema novamente e foi capaz de criar uma função decente para lidar com esta questão, especialmente em relação datetimes intraday. Crédito para @Primer para esta resposta.
def plot_ts(ts, step=5, figsize=(10,7), title=''):
"""
plot timeseries ignoring date gaps
Params
------
ts : pd.DataFrame or pd.Series
step : int, display interval for ticks
figsize : tuple, figure size
title: str
"""
fig, ax = plt.subplots(figsize=figsize)
ax.plot(range(ts.dropna().shape[0]), ts.dropna())
ax.set_title(title)
ax.set_xticks(np.arange(len(ts.dropna())))
ax.set_xticklabels(ts.dropna().index.tolist());
# tick visibility, can be slow for 200,000+ ticks
xticklabels = ax.get_xticklabels() # generate list once to speed up function
for i, label in enumerate(xticklabels):
if not i%step==0:
label.set_visible(False)
fig.autofmt_xdate()
funcionalidade scikits.timeseries tem sido amplamente mudou-se para pandas, então agora você pode resample uma trama de dados de modo a incluir apenas os valores nos dias de semana.
>>>import pandas as pd
>>>import matplotlib.pyplot as plt
>>>s = pd.Series(list(range(10)), pd.date_range('2015-09-01','2015-09-10'))
>>>s
2015-09-01 0
2015-09-02 1
2015-09-03 2
2015-09-04 3
2015-09-05 4
2015-09-06 5
2015-09-07 6
2015-09-08 7
2015-09-09 8
2015-09-10 9
>>> s.resample('B', label='right', closed='right').last()
2015-09-01 0
2015-09-02 1
2015-09-03 2
2015-09-04 3
2015-09-07 6
2015-09-08 7
2015-09-09 8
2015-09-10 9
e, em seguida, para traçar a trama de dados como normal
s.resample('B', label='right', closed='right').last().plot()
plt.show()