Matlibplot с аннотацией при наведении - PullRequest
0 голосов
/ 12 июля 2020

Я пытаюсь создать код Python, чтобы показать линейный график c с помощью matlibplot, и в то же время показывает информацию о x и y в разбросанных точках. Я нашел этот код, и это в значительной степени то, что я хочу сделать:

import matplotlib.pyplot as plt

def update_annot(ind, line, annot, ydata):
    x, y = line.get_data()
    annot.xy = (x[ind["ind"][0]], y[ind["ind"][0]])
    # Get x and y values, then format them to be displayed
    x_values = " ".join(list(map(str, ind["ind"])))
    y_values = " ".join(str(ydata[n]) for n in ind["ind"])
    text = "{}, {}".format(x_values, y_values)
    annot.set_text(text)
    annot.get_bbox_patch().set_alpha(0.4)

def hover(event, line_info):
    line, annot, ydata = line_info
    vis = annot.get_visible()
    if event.inaxes == ax:
        # Draw annotations if cursor in right position
        print(dir(line))
        cont, ind = line.contains(event)
        if cont:
            update_annot(ind, line, annot, ydata)
            annot.set_visible(True)
            fig.canvas.draw_idle()
        else:
            # Don't draw annotations
            if vis:
                annot.set_visible(False)
                fig.canvas.draw_idle()

def plot_line(x, y):
    line, = plt.plot(x, y, marker="o")
    # Annotation style may be changed here
    annot = ax.annotate("", xy=(0, 0), xytext=(-20, 20), textcoords="offset points",bbox=dict(boxstyle="round", fc="w"),arrowprops=dict(arrowstyle="->"))
    annot.set_visible(False)
    line_info = [line, annot, y]
    fig.canvas.mpl_connect("motion_notify_event",lambda event: hover(event, line_info))

# Your data values to plot
x1 = range(21)
y1 = range(0, 21)
x2 = range(21)
y2 = range(0, 42, 2)
# Plot line graphs
fig, ax = plt.subplots()
plot_line(x1, y1)
#plot_line(x2, y2)
plt.show()

Он работает нормально со случайными данными, но когда я пытаюсь сделать то же самое с реальными данными, поступающими из файла с информацией о разных столбцах, я получаю ошибки. Это код, который я использую:

import time
from datetime import datetime,timedelta
import subprocess
import sys
import os
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import style


def grafico():
    grafico = "1"
    if grafico =="1":
        input_indice="1"
        x=[]
        y=[]
        style.use("ggplot")
        input_año="2020"
        input_año=int(input_año)
        input_mes = "01"


        # GRÁFICO PARA IBEX35
        if input_indice =="1":
                input_año = str(input_año)
                dt = pd.read_csv('~/Test.txt', delimiter=',')
                dt_fecha = dt.loc[dt['Date'].str.contains(input_año + "-" + input_mes)]
                fecha=dt_fecha.Date
                for row in fecha:
                    fecha=row[5:]
                    x.append(fecha)
                apertura=dt_fecha.Open
                for row in apertura:
                    apertura=row
                    y.append(apertura)
                def update_annot(ind, line, annot, ydata):
                    x, y = line.get_data()
                    annot.xy = (x[ind["ind"][0]], y[ind["ind"][0]])
                    x_values = " ".join(list(map(str, ind["ind"])))
                    y_values = " ".join(str(ydata[n]) for n in ind["ind"])
                    text = "{}, {}".format(x_values, y_values)
                    annot.set_text(text)
                    annot.get_bbox_patch().set_alpha(0.4)
                def hover(event, line_info):
                    line, annot, ydata = line_info
                    vis = annot.get_visible()
                    if event.inaxes == ax:
                        print(dir(line))
                        cont, ind = line.contains(event)
                        if cont:
                            update_annot(ind, line, annot, ydata)
                            annot.set_visible(True)
                            fig.canvas.draw_idle()
                        else:
                            if vis:
                                annot.set_visible(False)
                                fig.canvas.draw_idle()
                fig, ax = plt.subplots()
                line=plt.plot(x,y,color="red", marker="o")
                annot = ax.annotate("", xy=(0, 0), xytext=(-20, 20), textcoords="offset points",bbox=dict(boxstyle="round", fc="w"),arrowprops=dict(arrowstyle="->"))
                annot.set_visible(False)
                line_info = [line, annot, y]
                fig.canvas.mpl_connect("motion_notify_event",lambda event: hover(event, line_info))
                plt.show()
                sys.exit()
while True:
    grafico()

Данные в файле Test.txt следующие:

Date,Open,High,Low,Close,Volume,Dividends,Stock Splits
2020-01-02,9639.1,9705.4,9615.1,9691.2,142379600,0,0
2020-01-03,9631.2,9650.7,9581.2,9646.6,135130000,0,0
2020-01-06,9585.4,9618.2,9492.7,9600.9,103520400,0,0
2020-01-07,9623.1,9657.9,9557.9,9579.8,133476100,0,0

График c отображается, но когда я двигаюсь указав мышью на некоторые из разбросанных точек, я получаю сообщение об ошибке: cont, ind = line.contains (event) AttributeError: объект 'list' не имеет атрибута 'contains'

Пример, который работает, использует диапазон для отображения на графике c, но мои данные не являются типом диапазона, это тип списка. Не могли бы вы помочь мне с этим? Большое спасибо.

1 Ответ

0 голосов
/ 12 июля 2020

Я потратил некоторое время, почему это происходит, но не смог найти ни одного. если это помогает ниже, работает нормально

import time
from datetime import datetime,timedelta
import subprocess
import sys
import os
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import style
def grafico():
    grafico = "1"
    if grafico =="1":
        input_indice="1"
        x=[]
        y=[]
        style.use("ggplot")
        input_año="2020"
        input_año=int(input_año)
        input_mes = "01"
        # GRÁFICO PARA IBEX35
        if input_indice =="1":
                input_año = str(input_año)
                dt = pd.read_csv('~/Test.txt', delimiter=',')
                dt_fecha = dt.loc[dt['Date'].str.contains(input_año + "-" + input_mes)]
                fecha=dt_fecha.Date
                for row in fecha:
                    fecha=row[5:]
                    x.append(fecha)
                apertura=dt_fecha.Open
                for row in apertura:
                    apertura=row
                    y.append(apertura)
    def update_annot(ind, line, annot, ydata):
        x, y = line.get_data()
        annot.xy = (x[ind["ind"][0]], y[ind["ind"][0]])
        # Get x and y values, then format them to be displayed
        x_values = " ".join(list(map(str, ind["ind"])))
        y_values = " ".join(str(ydata[n]) for n in ind["ind"])
        text = "{}, {}".format(x_values, y_values)
        annot.set_text(text)
        annot.get_bbox_patch().set_alpha(0.4)

    def hover(event, line_info):
        line, annot, ydata = line_info
        vis = annot.get_visible()
        if event.inaxes == ax:
            # Draw annotations if cursor in right position
            print(dir(line))
            cont, ind = line.contains(event)
            if cont:
                update_annot(ind, line, annot, ydata)
                annot.set_visible(True)
                fig.canvas.draw_idle()
            else:
                # Don't draw annotations
                if vis:
                    annot.set_visible(False)
                    fig.canvas.draw_idle()

    def plot_line(x, y):
        line, = plt.plot(x, y, marker="o")
        # Annotation style may be changed here
        annot = ax.annotate("", xy=(0, 0), xytext=(-20, 20), textcoords="offset points",bbox=dict(boxstyle="round", fc="w"),arrowprops=dict(arrowstyle="->"))
        annot.set_visible(False)
        line_info = [line, annot, y]
        fig.canvas.mpl_connect("motion_notify_event",lambda event: hover(event, line_info))

    fig, ax = plt.subplots()
    plot_line(x, y)
    plt.show()
grafico()

Вывод

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...