【问题标题】:Insert Image of Pandas Plot in DataFrame在 DataFrame 中插入 Pandas Plot 的图像
【发布时间】:2020-08-12 22:03:18
【问题描述】:

几天来,我一直在为这个问题绞尽脑汁,因此希望得到社区的帮助。我在 Jupyter Notebook 中使用 Python 3,但最终希望将其设为脚本。

问题

我有一个包含三列(查询、URL、趋势)的 Pandas DataFrame。所有的数据都在工作。我什至能够为每个查询生成绘图图像;但是,我无法在我的 DataFrame 的 Trends 列中显示趋势图的图像。它只显示AxesSubplot(0.125,0.125;0.775x0.755)。没有错误消息(虽然,我已经纠缠了一些)。

我的尝试

我查看了 fig.savefig() ,这似乎接近我需要的,但不是 100% 确定如何在我的情况下使它工作,因为它输出所有的图,我需要一个图询问。

我也尝试过this solution on Stack,但我无法为我的代码实现它(虽然它已经接近了)。

This article 也非常接近我正在寻找结果的实现(以及我当前的实现),但我不知道如何获取我刚刚创建的绘图图像的 HTML URL。同样,理想情况下,不需要保存图像,因为这可能是通过电子邮件发送的每日报告。

目前的结果

数据框

查询网址趋势

0 玛格丽特·特鲁多 https://montreal.ctvnews.ca/margaret-trudeau-d... AxesSubplot(0.125,0.125;0.775x0.755)

1 Nick Cordero https://people.com/theater/nick-cordero-doctor... AxesSubplot(0.125,0.125;0.775x0.755)

等等。

这些是从 DataFrame 下方的代码中得出的趋势图。

等等。

看起来一切正常,但是......

预期结果

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')

【问题讨论】:

    标签: python pandas dataframe matplotlib


    【解决方案1】:

    一旦你已经构建了fig,你必须将它转换为二进制,然后作为值存储到一个var中

    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()
    

    然后我做了dataframe.to_html(escape=False),它确实生成了带有图像的HTML。

    显然我在这里使用的是 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)
    

    你能检查一下它是否有效吗? :)

    【讨论】:

    • 嘿Caio!这真的很有帮助。我遇到了与我原来的问题类似的问题。所以,我尝试了你的代码作为独立的,它有效!然后我将它集成到我的代码中。它现在将 值放入数据框中,但不会显示图像。经过几次试验后,我添加了 plt.show() 以确保为每一行创建一个图。是的,是的。然后尝试调用包装在显示 HTML 中的函数。显示(HTML(趋势搜索('加拿大')))。不知道我错过了什么,但我们显然很接近!
    • 我想通了。调用to_html()时需要加上escape=False
    • 如何保存为.xlsx?
    • 从 Pandas 数据框中可以选择另存为 excel df.to_excel('path/file.xlsx')。不确定它是否会正确显示图像。
    猜你喜欢
    • 2014-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-22
    • 1970-01-01
    • 2018-08-13
    相关资源
    最近更新 更多