Вставить изображение Pandas Plot в DataFrame - PullRequest
1 голос
/ 29 апреля 2020

Я уже несколько дней ломаю голову над этим вопросом и поэтому хотел, чтобы сообщество помогло. Я использую Python 3 в ноутбуке Jupyter, но хочу со временем сделать этот скрипт.

Проблема

У меня есть Pandas DataFrame, который имеет три столбцы (запрос, URL, тренд). Все данные работают. Я даже могу создавать изображения для каждого запроса; Тем не менее, я не могу получить изображения графиков трендов для отображения в столбце Тенденции моего DataFrame. Это просто показывает AxesSubplot(0.125,0.125;0.775x0.755). Там нет сообщений об ошибках (хотя, я несколько позвонил).

Что я пробовал

Я посмотрел на fig.savefig ( ) и это, кажется, близко к тому, что мне нужно, но не уверен на 100%, как заставить это работать в моей ситуации, так как он выводит все графики, и мне нужен один график на запрос.

Я также дал это решение в стеке a go, но я не смог реализовать его для своего кода (хотя оно близко).

Эта статья также очень близка к реализации, которую я ищу в плане результатов (и моей текущей реализации), но я не знаю, как получить URL-адрес HTML изображение сюжета, который я только что создал. Кроме того, в идеале изображение не нужно сохранять, поскольку это, вероятно, будет ежедневный отчет, отправляемый по электронной почте.

Результаты на данный момент

Датафрейм

Запрос URL-адреса Trend

0 Маргарет Трюдо https://montreal.ctvnews.ca/margaret-trudeau-d ... AxesSubplot (0.125,0.125; 0.775x0.755)

1 Ник Кордеро https://people.com/theater/nick-cordero-doctor ... AxesSubplot (0,125,0,125; 0,775x0,755)

И так далее.

Это графики тренда, которые выходят из кода чуть ниже фрейма данных.

Image of trend plot output

Image of trend plot output

И т. Д.

Кажется, все работает, но ...

Ожидаемый результат

DataFrame должен то же самое, что и выше, но я хочу, чтобы AxesSubplot(0.125,0.125;0.775x0.755) был изображением графика тренда.

Текущий код

from googlesearch import search

import pandas as pd
import matplotlib.pyplot as plt
from pytrends.request import TrendReq

pytrend = TrendReq()

def trending_searches(geo):
    geo_lower = str.lower(geo) # Need geolocation to be lowercase to work
    df = pytrend.trending_searches(pn=geo_lower)

    queries = [] # Hold all processed queries

    for index, row in df.iterrows():
        i = str(row)
        j = str.strip(i, '0    ')
        k = j.split("\n", 1)[0]
        queries.append(k)

    # Gets the trend data 
    trend = pd.DataFrame(get_trend(queries))

    # Gets the first URL from each query on Google
    urls = pd.DataFrame(get_urls(queries))

    # column lable
    trend.columns = ["Trend"]
    urls.columns = ["URL"]
    df.columns = ['Query']

    #Concat all into one dataframe
    result = pd.concat([df, urls, trend], axis=1)

    #html = result.to_html() #Convert to HTML for emails

    return result #html

def get_trend(kw: list) -> list:

    query = kw

    # Get trend data
    my_results_list = []
    for j in query:    
        pytrend.build_payload(kw_list=[j])
        df = pytrend.interest_over_time()
        my_results_list.append(df)

    # Plot trend data
    plots = []
    for i in range(len(my_results_list)):
        if my_results_list[i].empty == True: # To mitigate queries that have no data
            plots.append("No data avaiable")
        else:
            plot = my_results_list[i].plot(kind='line', figsize=(5,1), sharex=True)
            plots.append(plot)

    return plots

def get_urls(kw: list) -> list:

    query = kw

    my_results_list = []
    for j in query:    
        for i in search(j,        # The query you want to run
                    tld = 'ca',  # The top level domain
                    lang = 'en',  # The language
                    num = 10,     # Number of results per page
                    start = 0,    # First result to retrieve
                    stop = 1,  # Last result to retrieve
                    pause = 2.0,  # Lapse between HTTP requests
                   ):

            my_results_list.append(i)

    return my_results_list

trending_searches('Canada')

1 Ответ

0 голосов
/ 29 апреля 2020

Когда у вас уже есть fig, вы должны преобразовать его в двоичный файл, а затем сохранить в переменную как значение

buf = io.BytesIO()
fig.savefig(buf, format='png')
buf.seek(0)
string = base64.b64encode(buf.read())

Затем вам нужно объединить теги HTML, которые соответствует выводу изображения

uri = 'data:image/png;base64,' + urllib.parse.quote(string)
html = '<img src = "%s"/>' % uri

Чтобы смоделировать ваш фрейм данных, я создал 3 списка и добавил каждый результат к нему следующим образом:

for i in range(10):
    ...
    query.append(i+1)
    url.append("google.com")
    trend.append(html)

df = pd.DataFrame({"query": query,"url": url,"trend":trend})
df.head()

enter image description here

Затем я сделал dataframe.to_html(escape=False), и это привело к HTML с изображениями.

enter image description here

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

Итак, наконец, я пришел к следующему коду:

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import urllib, urllib.parse, base64, io, base64
from IPython.core.display import display, HTML

# simulate dataframe
query = []
url = []
trend = []
for i in range(10):

    #save fig
    plt.plot(np.random.rand(5));
    fig = plt.gcf();

    #store it as binary
    buf = io.BytesIO()
    fig.savefig(buf, format='png')
    buf.seek(0)
    string = base64.b64encode(buf.read())

    #complement with HTML tags
    uri = 'data:image/png;base64,' + urllib.parse.quote(string)
    html = '<img src = "%s"/>' % uri

    #clear matplotlib's cache
    plt.clf()

    #append results
    query.append(i+1)
    url.append("google.com")
    trend.append(html)

#build df
df = pd.DataFrame({"query": query,"url": url,"trend":trend})
#parse into html
html = df.to_html(escape=False)

Не могли бы вы проверить, работает ли он? :)

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