1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        用 Python 制作酷炫的可視化大屏,特簡單!

        共 19390字,需瀏覽 39分鐘

         ·

        2022-01-02 10:38

        點擊下方AI算法與圖像處理”,一起進步!

        重磅干貨,第一時間送達

        作者 | 小F
        來源 | 法納斯特
        在數(shù)據(jù)時代,我們每個人既是數(shù)據(jù)的生產(chǎn)者,也是數(shù)據(jù)的使用者,然而初次獲取和存儲的原始數(shù)據(jù)雜亂無章、信息冗余、價值較低。
        要想數(shù)據(jù)達到生動有趣、讓人一目了然、豁然開朗的效果,就需要借助數(shù)據(jù)可視化。
        以前給大家介紹過使用Streamlit庫制作大屏,今天給大家?guī)硪粋€新方法。
        通過Python的Dash庫,來制作一個酷炫的可視化大屏!
        先來看一下整體效果,好像還不錯哦。


        主要使用Python的Dash庫、Plotly庫、Requests庫。
        其中Requests爬取數(shù)據(jù),Plotly制作可視化圖表,Dash搭建可視化頁面。
        原始數(shù)據(jù)是小F的博客數(shù)據(jù),數(shù)據(jù)存儲在MySqL數(shù)據(jù)庫中。
        如此看來,和Streamlit庫的搭建流程,所差不多。
        關(guān)于Dash庫,網(wǎng)上的資料不是很多,基本上只能看官方文檔和案例,下面小F簡單介紹一下。
        Dash是一個用于構(gòu)建Web應用程序的高效Python框架,特別適合使用Python進行數(shù)據(jù)分析的
        Dash是建立在Flask,Plotly.js和React.js之上,非常適合在純Python中,使用高度自定義的用戶界面,構(gòu)建數(shù)據(jù)可視化應用程序。
        相關(guān)文檔
        說明:https://dash.plotly.com/introduction
        案例:https://dash.gallery/Portal/
        源碼:https://github.com/plotly/dash-sample-apps/
        具體的大家可以去看文檔學習,多動手練習。
        下面就給大家講解下如何通過Dash搭建可視化大屏~


        01. 數(shù)據(jù)


        使用的數(shù)據(jù)是博客數(shù)據(jù),主要是下方兩處紅框的信息。
        通過爬蟲代碼爬取下來,存儲在MySQL數(shù)據(jù)庫中。

        其中MySQL的安裝,大家可以自行百度,都挺簡單的。

        安裝好后,進行啟用,以及創(chuàng)建數(shù)據(jù)庫。

        #?啟動MySQL,?輸入密碼
        mysql?-u?root?-p

        #?創(chuàng)建名為my_database的數(shù)據(jù)庫
        create?database?my_database;

        其它相關(guān)的操作命令如下所示。

        #?顯示MySQL中所有的數(shù)據(jù)庫
        show?databases;

        #?選擇my_database數(shù)據(jù)庫
        use?my_database;

        #?顯示my_database數(shù)據(jù)庫中所有的表
        show?tables;

        #?刪除表
        drop?table?info;
        drop?table?`2021-12-26`;

        #?顯示表中的內(nèi)容,?執(zhí)行SQL查詢語句
        select?*?from?info;
        select?*?from?`2021-12-26`;

        搞定上面的步驟后,就可以運行爬蟲代碼。

        數(shù)據(jù)爬取代碼如下。這里使用到了pymysql這個庫,需要pip安裝下。

        import?requests
        import?re
        from?bs4?import?BeautifulSoup
        import?time
        import?random
        import?pandas?as?pd
        from?sqlalchemy?import?create_engine
        import?datetime?as?dt


        def?get_info():
        ????"""獲取大屏第一列信息數(shù)據(jù)"""
        ????headers?=?{
        ????????'User-Agent':?'Mozilla/5.0?(MSIE?10.0;?Windows?NT?6.1;?Trident/5.0)',
        ????????'referer':?'https:?//?passport.csdn.net?/?login',
        ????}
        ????#?我的博客地址
        ????url?=?'https://blog.csdn.net/river_star1/article/details/121463591'
        ????try:
        ????????resp?=?requests.get(url,?headers=headers)
        ????????now?=?dt.datetime.now().strftime("%Y-%m-%d?%X")
        ????????soup?=?BeautifulSoup(resp.text,?'lxml')
        ????????author_name?=?soup.find('div',?class_='user-info?d-flex?flex-column?profile-intro-name-box').find('a').get_text(strip=True)
        ????????head_img?=?soup.find('div',?class_='avatar-box?d-flex?justify-content-center?flex-column').find('a').find('img')['src']
        ????????row1_nums?=?soup.find_all('div',?class_='data-info?d-flex?item-tiling')[0].find_all('span',?class_='count')
        ????????row2_nums?=?soup.find_all('div',?class_='data-info?d-flex?item-tiling')[1].find_all('span',?class_='count')
        ????????level_mes?=?soup.find_all('div',?class_='data-info?d-flex?item-tiling')[0].find_all('dl')[-1]['title'].split(',')[0]
        ????????rank?=?soup.find('div',?class_='data-info?d-flex?item-tiling').find_all('dl')[-1]['title']
        ????????info?=?{
        ????????????'date':?now,#時間
        ????????????'head_img':?head_img,#頭像
        ????????????'author_name':?author_name,#用戶名
        ????????????'article_num':?str(row1_nums[0].get_text()),#文章數(shù)
        ????????????'fans_num':?str(row2_nums[1].get_text()),#粉絲數(shù)
        ????????????'like_num':?str(row2_nums[2].get_text()),#喜歡數(shù)
        ????????????'comment_num':?str(row2_nums[3].get_text()),#評論數(shù)
        ????????????'level':?level_mes,#等級
        ????????????'visit_num':?str(row1_nums[3].get_text()),#訪問數(shù)
        ????????????'score':?str(row2_nums[0].get_text()),#積分
        ????????????'rank':?str(row1_nums[2].get_text()),#排名
        ????????}
        ????????df_info?=?pd.DataFrame([info.values()],?columns=info.keys())
        ????????return?df_info
        ????except?Exception?as?e:
        ????????print(e)
        ????????return?get_info()


        def?get_type(title):
        ????"""設(shè)置文章類型(依據(jù)文章名稱)"""
        ????the_type?=?'其他'
        ????article_types?=?['項目',?'數(shù)據(jù)可視化',?'代碼',?'圖表',?'Python',?'可視化',?'數(shù)據(jù)',?'面試',?'視頻',?'動態(tài)',?'下載']
        ????for?article_type?in?article_types:
        ????????if?article_type?in?title:
        ????????????the_type?=?article_type
        ????????????break
        ????return?the_type


        def?get_blog():
        ????"""獲取大屏第二、三列信息數(shù)據(jù)"""
        ????headers?=?{
        ????????'User-Agent':?'Mozilla/5.0?(MSIE?10.0;?Windows?NT?6.1;?Trident/5.0)',
        ????????'referer':?'https:?//?passport.csdn.net?/?login',
        ????}
        ????base_url?=?'https://blog.csdn.net/river_star1/article/list/'
        ????resp?=?requests.get(base_url+"1",?headers=headers,??timeout=3)
        ????max_page?=?int(re.findall(r'var?listTotal?=?(\d+);',?resp.text)[0])//40+1
        ????df?=?pd.DataFrame(columns=['url',?'title',?'date',?'read_num',?'comment_num',?'type'])
        ????count?=?0
        ????for?i?in?range(1,?max_page+1):
        ????????url?=?base_url?+?str(i)
        ????????resp?=?requests.get(url,?headers=headers)
        ????????soup?=?BeautifulSoup(resp.text,?'lxml')
        ????????articles?=?soup.find("div",?class_='article-list').find_all('div',?class_='article-item-box?csdn-tracking-statistics')
        ????????for?article?in?articles[1:]:
        ????????????a_url?=?article.find('h4').find('a')['href']
        ????????????title?=?article.find('h4').find('a').get_text(strip=True)[2:]
        ????????????issuing_time?=?article.find('span',?class_="date").get_text(strip=True)
        ????????????num_list?=?article.find_all('span',?class_="read-num")
        ????????????read_num?=?num_list[0].get_text(strip=True)
        ????????????if?len(num_list)?>?1:
        ????????????????comment_num?=?num_list[1].get_text(strip=True)
        ????????????else:
        ????????????????comment_num?=?0
        ????????????the_type?=?get_type(title)
        ????????????df.loc[count]?=?[a_url,?title,?issuing_time,?int(read_num),?int(comment_num),?the_type]
        ????????????count?+=?1
        ????????time.sleep(random.choice([1,?1.1,?1.3]))
        ????return?df


        if?__name__?==?'__main__':
        ????#?今天的時間
        ????today?=?dt.datetime.today().strftime("%Y-%m-%d")
        ????#?連接mysql數(shù)據(jù)庫
        ????engine?=?create_engine('mysql+pymysql://root:123456@localhost/my_database?charset=utf8')

        ????#?獲取大屏第一列信息數(shù)據(jù),?并寫入my_database數(shù)據(jù)庫的info表中,?如若表已存在,?刪除覆蓋
        ????df_info?=?get_info()
        ????print(df_info)
        ????df_info.to_sql("info",?con=engine,?if_exists='replace',?index=False)

        ????#?獲取大屏第二、三列信息數(shù)據(jù),?并寫入my_database數(shù)據(jù)庫的日期表中,?如若表已存在,?刪除覆蓋
        ????df_article?=?get_blog()
        ????print(df_article)
        ????df_article.to_sql(today,?con=engine,?if_exists='replace',?index=True)

        運行成功后,就可以去數(shù)據(jù)庫查詢信息了。

        info表,包含日期、頭圖、博客名、文章數(shù)、粉絲數(shù)、點贊數(shù)、評論數(shù)、等級數(shù)、訪問數(shù)、積分數(shù)、排名數(shù)。

        日期表,包含文章地址、標題、日期、閱讀數(shù)、評論數(shù)、類型。

        其中爬蟲代碼可設(shè)置時運行,info表為60秒,日期表為60分鐘。

        盡量不要太頻繁,容易被封IP,或者選擇使用代理池。

        這樣便可以做到數(shù)據(jù)實時更新。

        既然數(shù)據(jù)已經(jīng)有了,下面就可以來編寫頁面了。


        02. 大屏搭建


        導入相關(guān)的Python庫,同樣可以通過pip進行安裝。

        from?spider_py?import?get_info,?get_blog
        from?dash?import?dcc
        import?dash
        from?dash?import?html
        import?pandas?as?pd
        import?plotly.graph_objs?as?go
        from?dash.dependencies?import?Input,?Output
        import?datetime?as?dt
        from?sqlalchemy?import?create_engine
        from?flask_caching?import?Cache
        import?numpy?as?np

        設(shè)置一些基本的配置參數(shù),如數(shù)據(jù)庫連接、網(wǎng)頁樣式、Dash實例、圖表顏色。

        #?今天的時間
        today?=?dt.datetime.today().strftime("%Y-%m-%d")

        #?連接數(shù)據(jù)庫
        engine?=?create_engine('mysql+pymysql://root:123456@localhost/my_database?charset=utf8')

        #?導入css樣式
        external_css?=?[
        ????"https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css",
        ????"https://cdnjs.cloudflare.com/ajax/libs/skeleton/2.0.4/skeleton.min.css"
        ]

        #?創(chuàng)建一個實例
        app?=?dash.Dash(__name__,?external_stylesheets=external_css)
        server?=?app.server

        #?可以選擇使用緩存,?減少頻繁的數(shù)據(jù)請求
        #?cache?=?Cache(app.server,?config={
        #?????'CACHE_TYPE':?'filesystem',
        #?????'CACHE_DIR':?'cache-directory'
        #?})

        #?讀取info表的數(shù)據(jù)
        info?=?pd.read_sql('info',?con=engine)

        #?圖表顏色
        color_scale?=?['#2c0772',?'#3d208e',?'#8D7DFF',?'#CDCCFF',?'#C7FFFB',?'#ff2c6d',?'#564b43',?'#161d33']

        這里將緩存代碼注釋掉了,如有頻繁的頁面刷新請求,就可以選擇使用。

        def?indicator(text,?id_value):
        ????"""第一列的文字及數(shù)字信息顯示"""
        ????return?html.Div([
        ????html.P(text,?className="twelve?columns?indicator_text"),
        ????html.P(id=id_value,?className="indicator_value"),
        ],?className="col?indicator")


        def?get_news_table(data):
        ????"""獲取文章列表,?根據(jù)閱讀排序"""
        ????df?=?data.copy()
        ????df.sort_values('read_num',?inplace=True,?ascending=False)
        ????titles?=?df['title'].tolist()
        ????urls?=?df['url'].tolist()

        ????return?html.Table([html.Tbody([
        ????????html.Tr([
        ????????????html.Td(
        ????????????????html.A(titles[i],?href=urls[i],?target="_blank",))
        ????????],?style={'height':?'30px',?'fontSize':?'16'})for?i?in?range(min(len(df),?100))
        ????])],?style={"height":?"90%",?"width":?"98%"})


        #[email protected](timeout=3590),?可選擇設(shè)置緩存,?我沒使用
        def?get_df():
        ????"""獲取當日最新的文章數(shù)據(jù)"""
        ????df?=?pd.read_sql(today,?con=engine)
        ????df['date_day']?=?df['date'].apply(lambda?x:?x.split('?')[0]).astype('datetime64[ns]')
        ????df['date_month']?=?df['date'].apply(lambda?x:?x[:7].split('-')[0]?+?"年"?+?x[:7].split('-')[-1]?+?"月")
        ????df['weekday']?=?df['date_day'].dt.weekday
        ????df['year']?=?df['date_day'].dt.year
        ????df['month']?=?df['date_day'].dt.month
        ????df['week']?=?df['date_day'].dt.isocalendar().week
        ????return?df


        #?導航欄的圖片及標題
        head?=?html.Div([
        ????html.Div(html.Img(src='./assets/img.jpg',?height="100%"),?style={"float":?"left",?"height":?"90%",?"margin-top":?"5px",?"border-radius":?"50%",?"overflow":?"hidden"}),
        ????html.Span("{}博客的Dashboard".format(info['author_name'][0]),?className='app-title'),
        ],?className="row?header")

        #?第一列的文字及數(shù)字信息
        columns?=?info.columns[3:]
        col_name?=?['文章數(shù)',?'關(guān)注數(shù)',?'喜歡數(shù)',?'評論數(shù)',?'等級',?'訪問數(shù)',?'積分',?'排名']
        row1?=?html.Div([
        ????indicator(col_name[i],?col)?for?i,?col?in?enumerate(columns)
        ],?className='row')

        #?第二列
        row2?=?html.Div([
        ????html.Div([
        ????????html.P("每月文章寫作情況"),
        ????????dcc.Graph(id="bar",?style={"height":?"90%",?"width":?"98%"},?config=dict(displayModeBar=False),)
        ????],?className="col-4?chart_div",),
        ????html.Div([
        ????????html.P("各類型文章占比情況"),
        ????????dcc.Graph(id="pie",?style={"height":?"90%",?"width":?"98%"},?config=dict(displayModeBar=False),)
        ????],?className="col-4?chart_div"),
        ????html.Div([
        ????????html.P("各類型文章閱讀情況"),
        ????????dcc.Graph(id="mix",?style={"height":?"90%",?"width":?"98%"},?config=dict(displayModeBar=False),)
        ????],?className="col-4?chart_div",)
        ],?className='row')

        #?年數(shù)統(tǒng)計,?我的是2019?2020?2021
        years?=?get_df()['year'].unique()
        select_list?=?['每月文章',?'類型占比',?'類型閱讀量',?'每日情況']

        #?兩個可交互的下拉選項
        dropDowm1?=?html.Div([
        ????html.Div([
        ????????dcc.Dropdown(id='dropdown1',
        ?????????????????options=[{'label':?'{}年'.format(year),?'value':?year}?for?year?in?years],
        ?????????????????value=years[1],?style={'width':?'40%'})
        ????????],?className='col-6',?style={'padding':?'2px',?'margin':?'0px?5px?0px'}),
        ????html.Div([
        ????????dcc.Dropdown(id='dropdown2',
        ?????????????????options=[{'label':?select_list[i],?'value':?item}?for?i,?item?in?enumerate(['bar',?'pie',?'mix',?'heatmap'])],
        ?????????????????value='heatmap',?style={'width':?'40%'})
        ????????],?className='col-6',?style={'padding':?'2px',?'margin':?'0px?5px?0px'})
        ],?className='row')

        #?第三列
        row3?=?html.Div([
        ????html.Div([
        ????????html.P("每日寫作情況"),
        ????????dcc.Graph(id="heatmap",?style={"height":?"90%",?"width":?"98%"},?config=dict(displayModeBar=False),)
        ????],?className="col-6?chart_div",),
        ????html.Div([
        ????????html.P("文章列表"),
        ????????html.Div(get_news_table(get_df()),?id='click-data'),
        ????],?className="col-6?chart_div",?style={"overflowY":?"scroll"})
        ],?className='row')

        #?總體情況
        app.layout?=?html.Div([
        ????#?定時器
        ????dcc.Interval(id="stream",?interval=1000*60,?n_intervals=0),
        ????dcc.Interval(id="river",?interval=1000*60*60,?n_intervals=0),
        ????html.Div(id="load_info",?style={"display":?"none"},),
        ????html.Div(id="load_click_data",?style={"display":?"none"},),
        ????head,
        ????html.Div([
        ????????row1,
        ????????row2,
        ????????dropDowm1,
        ????????row3,
        ????],?style={'margin':?'0%?30px'}),
        ])

        上面的代碼,就是網(wǎng)頁的布局,效果如下。

        網(wǎng)頁可以劃分為三列。第一列為info表中的數(shù)據(jù)展示,第二、三列為博客文章的數(shù)據(jù)展示。

        相關(guān)的數(shù)據(jù)需要通過回調(diào)函數(shù)進行更新,這樣才能做到實時刷新。

        各個數(shù)值及圖表的回調(diào)函數(shù)代碼如下所示。

        #?回調(diào)函數(shù),?60秒刷新info數(shù)據(jù),?即第一列的數(shù)值實時刷新
        @app.callback(Output('load_info',?'children'),?[Input("stream",?"n_intervals")])
        def?load_info(n):
        ????try:
        ????????df?=?pd.read_sql('info',?con=engine)
        ????????return?df.to_json()
        ????except:
        ????????pass


        #?回調(diào)函數(shù),?60分鐘刷新今日數(shù)據(jù),?即第二、三列的數(shù)值實時刷新(爬取文章數(shù)據(jù),?并寫入數(shù)據(jù)庫中)
        @app.callback(Output('load_click_data',?'children'),?[Input("river",?"n_intervals")])
        def?cwarl_data(n):
        ????if?n?!=?0:
        ????????df_article?=?get_blog()
        ????????df_article.to_sql(today,?con=engine,?if_exists='replace',?index=True)


        #?回調(diào)函數(shù),?第一個柱狀圖
        @app.callback(Output('bar',?'figure'),?[Input("river",?"n_intervals")])
        def?get_bar(n):
        ????df?=?get_df()
        ????df_date_month?=?pd.DataFrame(df['date_month'].value_counts(sort=False))
        ????df_date_month.sort_index(inplace=True)
        ????trace?=?go.Bar(
        ????????x=df_date_month.index,
        ????????y=df_date_month['date_month'],
        ????????text=df_date_month['date_month'],
        ????????textposition='auto',
        ????????marker=dict(color='#33ffe6')
        ????)
        ????layout?=?go.Layout(
        ????????margin=dict(l=40,?r=40,?t=10,?b=50),
        ????????yaxis=dict(gridcolor='#e2e2e2'),
        ????????paper_bgcolor='rgba(0,0,0,0)',
        ????????plot_bgcolor='rgba(0,0,0,0)',
        ????)
        ????return?go.Figure(data=[trace],?layout=layout)


        #?回調(diào)函數(shù),?中間的餅圖
        @app.callback(Output('pie',?'figure'),?[Input("river",?"n_intervals")])
        def?get_pie(n):
        ????df?=?get_df()
        ????df_types?=?pd.DataFrame(df['type'].value_counts(sort=False))
        ????trace?=?go.Pie(
        ????????labels=df_types.index,
        ????????values=df_types['type'],
        ????????marker=dict(colors=color_scale[:len(df_types.index)])
        ????)
        ????layout?=?go.Layout(
        ????????margin=dict(l=50,?r=50,?t=50,?b=50),
        ????????paper_bgcolor='rgba(0,0,0,0)',
        ????????plot_bgcolor='rgba(0,0,0,0)',
        ????)
        ????return?go.Figure(data=[trace],?layout=layout)


        #?回調(diào)函數(shù),?左下角熱力圖
        @app.callback(Output('heatmap',?'figure'),
        ??????????????[Input("dropdown1",?"value"),?Input('river',?'n_intervals')])
        def?get_heatmap(value,?n):
        ????df?=?get_df()
        ????grouped_by_year?=?df.groupby('year')
        ????data?=?grouped_by_year.get_group(value)
        ????cross?=?pd.crosstab(data['weekday'],?data['week'])
        ????cross.sort_index(inplace=True)
        ????trace?=?go.Heatmap(
        ????????x=['第{}周'.format(i)?for?i?in?cross.columns],
        ????????y=["星期{}".format(i+1)?if?i?!=?6?else?"星期日"?for?i?in?cross.index],
        ????????z=cross.values,
        ????????colorscale="Blues",
        ????????reversescale=False,
        ????????xgap=4,
        ????????ygap=5,
        ????????showscale=False
        ????)
        ????layout?=?go.Layout(
        ????????margin=dict(l=50,?r=40,?t=30,?b=50),
        ????)
        ????return?go.Figure(data=[trace],?layout=layout)


        #?回調(diào)函數(shù),?第二個柱狀圖(柱狀圖+折線圖)
        @app.callback(Output('mix',?'figure'),?[Input("river",?"n_intervals")])
        def?get_mix(n):
        ????df?=?get_df()
        ????df_type_visit_sum?=?pd.DataFrame(df['read_num'].groupby(df['type']).sum())
        ????df['read_num']?=?df['read_num'].astype('float')
        ????df_type_visit_mean?=?pd.DataFrame(df['read_num'].groupby(df['type']).agg('mean').round(2))
        ????trace1?=?go.Bar(
        ????????x=df_type_visit_sum.index,
        ????????y=df_type_visit_sum['read_num'],
        ????????name='總閱讀',
        ????????marker=dict(color='#ffc97b'),
        ????????yaxis='y',
        ????)
        ????trace2?=?go.Scatter(
        ????????x=df_type_visit_mean.index,
        ????????y=df_type_visit_mean['read_num'],
        ????????name='平均閱讀',
        ????????yaxis='y2',
        ????????line=dict(color='#161D33')
        ????)
        ????layout?=?go.Layout(
        ????????margin=dict(l=60,?r=60,?t=30,?b=50),
        ????????showlegend=False,
        ????????yaxis=dict(
        ????????????side='left',
        ????????????title='閱讀總數(shù)',
        ????????????gridcolor='#e2e2e2'
        ????????),
        ????????yaxis2=dict(
        ????????????showgrid=False,??#?網(wǎng)格
        ????????????title='閱讀平均',
        ????????????anchor='x',
        ????????????overlaying='y',
        ????????????side='right'
        ????????),
        ????????paper_bgcolor='rgba(0,0,0,0)',
        ????????plot_bgcolor='rgba(0,0,0,0)',
        ????)
        ????return?go.Figure(data=[trace1,?trace2],?layout=layout)


        #?點擊事件,?選擇兩個下拉選項,?點擊對應區(qū)域的圖表,?文章列表會刷新
        @app.callback(Output('click-data',?'children'),
        ????????[Input('pie',?'clickData'),
        ?????????Input('bar',?'clickData'),
        ?????????Input('mix',?'clickData'),
        ?????????Input('heatmap',?'clickData'),
        ?????????Input('dropdown1',?'value'),
        ?????????Input('dropdown2',?'value'),
        ?????????])
        def?display_click_data(pie,?bar,?mix,?heatmap,?d_value,?fig_type):
        ????try:
        ????????df?=?get_df()
        ????????if?fig_type?==?'pie':
        ????????????type_value?=?pie['points'][0]['label']
        ????????????#?date_month_value?=?clickdata['points'][0]['x']
        ????????????data?=?df[df['type']?==?type_value]
        ????????elif?fig_type?==?'bar':
        ????????????date_month_value?=?bar['points'][0]['x']
        ????????????data?=?df[df['date_month']?==?date_month_value]
        ????????elif?fig_type?==?'mix':
        ????????????type_value?=?mix['points'][0]['x']
        ????????????data?=?df[df['type']?==?type_value]
        ????????else:
        ????????????z?=?heatmap['points'][0]['z']
        ????????????if?z?==?0:
        ????????????????return?None
        ????????????else:
        ????????????????week?=?heatmap['points'][0]['x'][1:-1]
        ????????????????weekday?=?heatmap['points'][0]['y'][-1]
        ????????????????if?weekday?==?'日':
        ????????????????????weekday?=?7
        ????????????????year?=?d_value
        ????????????????data?=?df[(df['weekday']?==?int(weekday)-1)?&?(df['week']?==?int(week))?&?(df['year']?==?year)]
        ????????return?get_news_table(data)
        ????except:
        ????????return?None


        #?第一列的數(shù)值
        def?update_info(col):
        ????def?get_data(json,?n):
        ????????df?=?pd.read_json(json)
        ????????return?df[col][0]
        ????return?get_data


        for?col?in?columns:
        ????app.callback(Output(col,?"children"),
        ?????????????????[Input('load_info',?'children'),?Input("stream",?"n_intervals")]
        ?????)(update_info(col))


        圖表的數(shù)據(jù)和樣式全在這里設(shè)置,兩個下拉欄的數(shù)據(jù)交互也在這里完成。
        需要注意右側(cè)下拉欄的類型,需和你所要點擊圖表類型一致,這樣文章列表才會更新。
        每日情況對應熱力圖,類型閱讀量對應第二列第三個圖表,類型占比對應餅圖,每月文章對應第一個柱狀圖的點擊事件。
        最后啟動程序代碼。

        if?__name__?==?'__main__':
        ????#?debug模式,?端口7777
        ????app.run_server(debug=True,?threaded=True,?port=7777)
        ????#?正常模式,?網(wǎng)頁右下角的調(diào)試按鈕將不會出現(xiàn)
        ????#?app.run_server(port=7777)


        這樣就能在本地看到可視化大屏頁面,瀏覽器打開如下地址。

        http://127.0.0.1:7777


        對于網(wǎng)頁的布局、背景顏色等,主要通過CSS進行設(shè)置。

        這一部分可能是大家所要花費時間去理解的。

        body{
        ????margin:0;
        ????padding:?0;
        ????background-color:?#161D33;
        ????font-family:?'Open?Sans',?sans-serif;
        ????color:?#506784;
        ????-webkit-user-select:?none;??/*?Chrome?all?/?Safari?all?*/
        ????-moz-user-select:?none;?????/*?Firefox?all?*/
        ????-ms-user-select:?none;??????/*?IE?10+?*/
        ????user-select:?none;??????????/*?Likely?future?*/
        }

        .modal?{
        ????display:?block;??/*Hidden?by?default?*/
        ????position:?fixed;?/*?Stay?in?place?*/
        ????z-index:?1000;?/*?Sit?on?top?*/
        ????left:?0;
        ????top:?0;
        ????width:?100%;?/*?Full?width?*/
        ????height:?100%;?/*?Full?height?*/
        ????overflow:?auto;?/*?Enable?scroll?if?needed?*/
        ????background-color:?rgb(0,0,0);?/*?Fallback?color?*/
        ????background-color:?rgba(0,0,0,0.4);?/*?Black?w/?opacity?*/
        }

        .modal-content?{
        ????background-color:?white;
        ????margin:?5%?auto;?/*?15%?from?the?top?and?centered?*/
        ????padding:?20px;
        ????width:?30%;?/*?Could?be?more?or?less,?depending?on?screen?size?*/
        ????color:#506784;
        }

        ._dash-undo-redo?{
        ??display:?none;
        }

        .app-title{
        ????color:white;
        ????font-size:3rem;
        ????letter-spacing:-.1rem;
        ????padding:10px;
        ????vertical-align:middle
        }

        .header{
        ????margin:0px;
        ????background-color:#161D33;
        ????height:70px;
        ????color:white;
        ????padding-right:2%;
        ????padding-left:2%
        }

        .indicator{
        ??border-radius:?5px;
        ??background-color:?#f9f9f9;
        ??margin:?10px;
        ??padding:?15px;
        ??position:?relative;
        ??box-shadow:?2px?2px?2px?lightgrey;
        }

        .indicator_text{
        ????text-align:?center;
        ????float:?left;
        ????font-size:?17px;
        ????}

        .indicator_value{
        ????text-align:center;
        ????color:?#2a3f5f;
        ????font-size:?35px;
        }

        .add{
        ????height:?34px;
        ????background:?#119DFF;
        ????border:?1px?solid?#119DFF;
        ????color:?white;
        }

        .chart_div{
        ????background-color:?#f9f9f9;
        ????border-radius:?5px;
        ????height:?390px;
        ????margin:5px;
        ????padding:?15px;
        ????position:?relative;
        ????box-shadow:?2px?2px?2px?lightgrey;
        }

        .col-4?{
        ????flex:?0?0?32.65%;
        ????max-width:?33%;
        }

        .col-6?{
        ????flex:?0?0?49.3%;
        ????max-width:?50%;
        }

        .chart_div?p{
        ????color:?#2a3f5f;
        ????font-size:?15px;
        ????text-align:?center;
        }

        td{
        ????text-align:?left;
        ????padding:?0px;
        }

        table{
        ????border:?1px;
        ????font-size:1.3rem;
        ????width:100%;
        ????font-family:Ubuntu;
        }

        .tabs_div{
        ????margin:0px;
        ????height:30px;
        ????font-size:13px;
        ????margin-top:1px
        }

        tr:nth-child(even)?{
        ????background-color:?#d6e4ea;
        ????-webkit-print-color-adjust:?exact;
        }

        如今低代碼平臺的出現(xiàn),或許以后再也不用去寫煩人的HTML、CSS等。拖拖拽拽,即可輕松完成一個大屏的制作。

        好了,今天的分享到此結(jié)束,大家可以自行去動手練習。


        參考鏈接:

        https://github.com/ffzs/dash_blog_dashboard

        https://www.cnblogs.com/feffery/p/14826195.html

        https://github.com/plotly/dash-sample-apps/tree/main/apps/dash-oil-and-gas

        努力分享優(yōu)質(zhì)的計算機視覺相關(guān)內(nèi)容,歡迎關(guān)注:

        交流群


        歡迎加入公眾號讀者群一起和同行交流,目前有美顏、三維視覺、計算攝影、檢測、分割、識別、醫(yī)學影像、GAN、算法競賽等微信群


        個人微信(如果沒有備注不拉群!
        請注明:地區(qū)+學校/企業(yè)+研究方向+昵稱



        下載1:何愷明頂會分享


        AI算法與圖像處理」公眾號后臺回復:何愷明,即可下載。總共有6份PDF,涉及 ResNet、Mask RCNN等經(jīng)典工作的總結(jié)分析


        下載2:終身受益的編程指南:Google編程風格指南


        AI算法與圖像處理」公眾號后臺回復:c++,即可下載。歷經(jīng)十年考驗,最權(quán)威的編程規(guī)范!



        下載3 CVPR2021

        AI算法與圖像處公眾號后臺回復:CVPR,即可下載1467篇CVPR?2020論文 和 CVPR 2021 最新論文


        瀏覽 83
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            久久久久女人精品毛片九一韩国 | 在线免费观看黄片视频 | 五月婷婷精品 | 欧美高清操逼 | 91福利国产成人精品播放 | 操逼免费网站 | 色色操 | 欧美一级黄片免费看 | 8050午夜一级 | 天天综合日 |