2022年7月31日 星期日

Markdown 語法學習筆記 (一) : 基本網頁元素

這幾天在準備下個月客家語文學會線上講座的簡報, 為此複習了之前所寫的 GitHub 筆記, 發現其實 README.md 中使用的 Mark down 語法也可以用來寫網頁, 語法超簡單. 本篇是在下面這篇筆記基礎上, 再參考網路上的資料重新整理而成 : 


以下針對十個常用網頁元素改用較簡單的 Markdown 語法來撰寫, GitHub 會將 .md 的文件翻譯成真正的 HTML 碼 :


1. 標題 (轉成 h1~h6) : 

標題的 mark down 符號為 #, h1~h6 分別使用 1~6 個 # 號, 後面跟著標題文字, 例如 : 

# h1 標題
## h2 標題
### h3 標題
#### h4 標題
##### h5 標題
###### h6 標題

結果如下 :


轉成的 HTML 如下 :

<h1 id="h1-標題">h1 標題</h1>
<h2 id="h2-標題">h2 標題</h2>
<h3 id="h3-標題">h3 標題</h3>
<h4 id="h4-標題">h4 標題</h4>
<h5 id="h5-標題">h5 標題</h5>
<h6 id="h6-標題">h6 標題</h6>

可見它會將文字內容拿來當 id.


2. 段落 (轉成 p) : 

段落的 mark down 為兩個以上空格加上跳行, 例如 : 

下面有三個段落:
段落 1  
段落 2  
段落 3  

注意, '下面有三個段落:' 後面是直接跳行, 而 '段落 1' ~ '段落 3' 後面則是有兩個空格再跳行, 結果如下 : 

轉成的 HTML 如下 : 

<p>下面有三個段落:
段落 1<br />
段落 2<br />
段落 3</p>

可見它是把整個當一個段落, 中間用 <br> 跳行. 


3. 水平分隔線 (轉成 hr) : 

水平分隔線的 mark down 可用三個以上的 * (星號), - (負號), 或 _ (底線) 表示, 中間可以有一個以上的空格, 但該列不能為有其他字元, 例如 :

***
* * *
---
- - -
___
_ _ _ 

結果如下 : 


感覺線條有點粗, 轉成的 HTML 如下 : 

<hr />
<hr />
<hr />
<hr />
<hr />
<hr />

 
4. 文字效果 : 

文字效果主要有粗體, 斜體, 底線, 刪除線, 上標, 下標等. 


(1). 斜體 : 

斜體是在文字左右用一個 * (星號) 或 _ (底線) 包起來, 例如 :

*斜體文字*
_斜體文字_


(2). 粗體 : 

粗體是在文字左右用兩個 * (星號) 或 _ (底線) 包起來, 例如 :

**粗體文字**
__粗體文字__


(3). 粗斜體 : 

粗體是在文字左右用三個 * (星號) 或 _ (底線) 包起來, 例如 :

***粗斜體文字***
___粗斜體文字___


(4). 文字加底線 : 

文字加底線是直接用 HTML 的 <u> 與 </u> 包起來, 例如 :

<u>文字加底線</u>


(5). 刪除線 : 

刪除線是在文字左右用兩個 ~ (波浪) 包起來, 例如 :

~~文字加刪除線~~


(6). 上標與下標 : 

上標是直接用 HTML 的 <sup> 與 </sup> 包起來; 下標則是用 <sub> 與 </sub> 包起來, 例如 :

x<sub>a</sub><sup>2</sup>


(7). 注音 : 

上標是直接用 HTML 的 <sup> 與 </sup> 包起來, 例如 : 

<ruby>鱻<rt>ㄒㄧㄢ</rt></ruby>

結果如下 : 


轉成的 HTML 如下 : 

<p><em>斜體文字</em>
<em>斜體文字</em></p>

<p><strong>粗體文字</strong>
<strong>粗體文字</strong></p>

<p><strong><em>粗斜體文字</em></strong>
<strong><em>粗斜體文字</em></strong></p>

<p><u>文字加底線</u></p>

<p><del>文字加刪除線</del></p>

<p>x<sub>a</sub><sup>2</sup></p>

<p><ruby>鱻<rt>ㄒㄧㄢ</rt></ruby></p>


5. 清單 : 

清單有符號清單與編號清單兩種, 前者是無序的, 會轉成 ul 與 li 元素; 後者則以數字為序, 會轉成 ol 與 li 元素. 


(1). 符號清單 : 

符號清單的 mark down 可用一個 * (星號), + (加號) 或 - (負號) 開頭, 後面跟著一個空格, 然後是清單項目的文字, 例如 :

* 德魯納酒店
* 非常律師禹英禑
+ 馬氏文通
+ 事林廣記</li>
- 春上村樹
- 大江健三郎

結果如下 : 


可見 Mark down 一律轉出 bullet 效果的清單, 轉成的 HTML 如下 : 

<ul>
  <li>德魯納酒店</li>
  <li>非常律師禹英禑</li>
  <li>馬氏文通</li>
  <li>事林廣記</li>
  <li>春上村樹</li>
  <li>大江健三郎</li>
</ul>


(2). 編號清單 : 

編號清單的 Mark down 語法是編號後面加一個小數點, 空一格 (此為必要) 再接清單項目文字, 美跳一列就會自動增量顯示下一個項目編號, 但只能用數字, 用英文字母 A. B. C. 無效, 例如 :

1. 德魯納酒店
2. 非常律師禹英禑
3. 馬氏文通
4. 事林廣記
5. 春上村樹
6. 大江健三郎

結果如下 : 


轉成的 HTML 如下 :

<ol>
  <li>德魯納酒店</li>
  <li>非常律師禹英禑</li>
  <li>馬氏文通</li>
  <li>事林廣記</li>
  <li>春上村樹</li>
  <li>大江健三郎</li>
</ol>


(3). 巢狀清單 : 

巢狀清單是指套疊兩層以上的清單, 首先來看內外層都是編號清單的組合 : 

* 韓劇
  - 德魯納酒店
  - 非常律師禹英禑
* 古籍
  + 馬氏文通
  + 事林廣記
* 日本作家
  - 春上村樹
  - 大江健三郎

結果如下 : 


可見第一層會用實心圓點 (solid bullet), 而第二層改用空心圓點. 轉成的 HTML 如下 :

<ul>
  <li>韓劇
    <ul>
      <li>德魯納酒店</li>
      <li>非常律師禹英禑</li>
    </ul>
  </li>
  <li>古籍
    <ul>
      <li>馬氏文通</li>
      <li>事林廣記</li>
    </ul>
  </li>
  <li>日本作家
    <ul>
      <li>春上村樹</li>
      <li>大江健三郎</li>
    </ul>
  </li>
</ul>

其次測試外層是符號, 內層是編號的組合 : 

* 韓劇
  1. 德魯納酒店
  2. 非常律師禹英禑
* 古籍
  1. 馬氏文通
  2. 事林廣記
* 日本作家
  1. 春上村樹
  2. 大江健三郎

結果如下 : 


可見內層的編號清單會使用小寫羅馬數字, 轉成的 HTML 如下 :

<ul>
  <li>韓劇
    <ol>
      <li>德魯納酒店</li>
      <li>非常律師禹英禑</li>
    </ol>
  </li>
  <li>古籍
    <ol>
      <li>馬氏文通</li>
      <li>事林廣記</li>
    </ol>
  </li>
  <li>日本作家
    <ol>
      <li>春上村樹</li>
      <li>大江健三郎</li>
    </ol>
  </li>
</ul>

最後來測試外層是編號, 內層是符號的組合 : 

1. 韓劇
  - 德魯納酒店
  - 非常律師禹英禑
2. 古籍
  + 馬氏文通
  + 事林廣記
3. 日本作家
  * 春上村樹
  * 大江健三郎

結果如下 : 


可見外層會用阿拉伯數字, 內層會用空心圓點, 轉成的 HTML 如下 :

<ol>
  <li>韓劇
    <ul>
      <li>德魯納酒店</li>
      <li>非常律師禹英禑</li>
    </ul>
  </li>
  <li>古籍
    <ul>
      <li>馬氏文通</li>
      <li>事林廣記</li>
    </ul>
  </li>
  <li>日本作家
    <ul>
      <li>春上村樹</li>
      <li>大江健三郎</li>
    </ul>
  </li>
</ol>

而內外層都是編號的組合無法使用, 因為會導致編號錯亂. 

參考 :



6. 表格 : 

表格的 mark down 使用 | 來區隔欄位, 用內容為 ---- 的一列來區隔表頭與其他列, 若要設定各欄對齊方式, 可在區隔列以下列為內容 :
  • :---- (靠左對齊)
  • :-----: (置中對齊)
  • ----: (靠右對齊)
例如 :

|第一欄   |第二欄   |
|----|----|
|第一列第一欄   |第一列第二欄   |
|第二列第一欄   |第二列第二欄   | 

結果如下 : 


可見表頭預設是粗體置中對齊, 轉成的 HTML 如下 : 

<table>
  <thead>
    <tr>
      <th>第一欄</th>
      <th>第二欄</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>第一列第一欄</td>
      <td>第一列第二欄</td>
    </tr>
    <tr>
      <td>第二列第一欄</td>
      <td>第二列第二欄</td>
    </tr>
  </tbody>
</table>

下面範例是設定左欄靠左對齊; 右欄靠右對齊 : 

|第一欄   |第二欄   |
|:----|----:|
|第一列第一欄   |第一列第二欄   |
|第二列第一欄   |第二列第二欄   | 

結果如下 : 


轉成的 HTML 如下 : 

<table>
  <thead>
    <tr>
      <th style="text-align: left">第一欄</th>
      <th style="text-align: right">第二欄</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">第一列第一欄</td>
      <td style="text-align: right">第一列第二欄</td>
    </tr>
    <tr>
      <td style="text-align: left">第二列第一欄</td>
      <td style="text-align: right">第二列第二欄</td>
    </tr>
  </tbody>
</table>


7. 圖片 : 

圖片的 mark down 語法為 : 

![替代文字](圖檔位置) 


其中替代文字即 img 標籤的 alt 屬性值, 圖檔位置可以用完整 URL, 也可以用相對路徑. 注意, 替代文字與圖檔位置都不可以用括號括起來, 例如 :

![可愛的小咪](images/cat.jpg)

或使用完整 URL :  

![可愛的小咪](https://yaohuang1966.github.io/images/cat.jpg)  

結果如下 : 


轉成的 HTML 如下 : 

<img src="https://yaohuang1966.github.io/images/cat.jpg" alt="alt 可愛的小咪" />


8. 超連結 : 

超連結的 mark down 語法為 : 

[連結名稱](連結網址){:屬性設定} 

連結名稱就是 a 標籤的內容文字, 後面的 {} 可有可無, 這是用來設定屬性的, 若要在新頁籤開啟網頁可用 {:target="_blank"}, 例如 :  

[Google](https://www.google.com.tw){:target="_blank"}

結果如下 : 

參考 :

轉成的 HTML 如下 : 

<a href="https://www.google.com.tw" target="_blank">Google</a>

也可以設定網頁內超連結 (稱為 anchor), 點擊後會前往同一網頁內的特定錨點, 首先用下列語法在網頁中設定一個錨點 : 

{#錨點名稱} 

例如在長網頁底下通常會有按 "Top" 或 "返回上面" 超連結回到最上面的功能, 可設為 :

{#top}

然後在底下建立一個頁內超連結例如 : 

[返回頂端](#top) 

小括弧裡面這時不是放 URL, 而是錨點名稱, 結果如下 : 


按此超連結就會回到 {#top} 所在的頁面頂端. 轉成的 HTML 如下 : 

<a href="#top">返回頂端</a>


9. 音訊 : 

Mark down 沒有音訊的語法, 而是直接嵌入 audio 標籤, 例如 : 

<audio src="media/your_answer_clip.mp3" controls>不支援 audio</audio>

結果如下 : 



10. 視訊 : 

Mark down 沒有視訊的語法, 而是直接嵌入 video 標籤, 例如 : 

<audio src="media/your_answer_clip.mp3" controls>不支援 audio</audio>

結果如下 : 


完整範例如下 :


產生此範例網頁的 Mark down 原始碼如下 :


注意, GitHub 網站儲存庫的任意子目錄下都可以用 Mark down 語法編輯一個 index.md 檔, 只要存取此目錄 GitHub 預設就會去該目錄下找尋 index.htm 或 index.md, 如果只有 index.md, 就將其翻譯成 index.htm 後回應給用戶端. 由於網站根目錄下的 index.md 另有用途, 故新增了一個 markdown 子目錄, 然後將 index.md 上傳至此目錄下, 但圖檔, 音訊與視訊檔的相對位置需加以調整 (前面加上 ../ 往上跳一層才存取得到). 

參考 : 




2022年7月26日 星期二

方便好用的線上 Python 執行環境 trinket.io

今天參加 Python 內訓課程時老師介紹了 trinket.io 這個線上 Python 線上執行環境, 其實我去年就發現了這個好用的線上資源, 參考 :


根據網頁說明, 此 Python 執行環境已預裝 Numpy, SciPy, Matplotlib 等套件, 參考 :


但我實際測試發現 Pandas , Seaborn, 與 Bokeh 也有預裝, 但可惜 plotly 沒有, 下面是 Seaborn 繪圖範例 : 

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd

election={'votes': [608590, 5522119, 8170231],
          'candidates': ['James Soong', 'Korea Fish', 'Tsai Ing-Wen']}
data=pd.DataFrame(election)
sns.barplot(x='candidates', y='votes', data=data)    
plt.title('2020 Presidential Election')
plt.xlabel('Candidates')
plt.ylabel('Votes(Million)')
plt.show()

結果如下 : 




下面是 Bokeh 繪圖範例 : 

import random
from bokeh.plotting import figure, show
x=list(range(0, 26))
y=random.sample(range(0, 100), 26)

colors=["#%02x%02x%02x" % (255, int(round(value * 255 / 100)), 255) for value in y]
p=figure(
    title="Vectorized colors example",
    sizing_mode="stretch_width",
    max_width=400,
    height=250)
line=p.line(x, y, line_color="blue", line_width=1)
circle=p.circle(x, y, fill_color=colors, line_color="blue", size=15)
show(p)

參考 :


結果如下 : 




申請免費帳號就可以將程式儲存在 trinket.io, 就可以分享給他人下載. 

2022年7月25日 星期一

重看醫道 (精華剪輯版)

昨晚偶然在 bilibili 找到韓劇醫道的精華版, 哇, 真的好懷念, 忍不住熬夜重看 :   


這個剪輯版是從許浚決心前往漢陽參加科舉醫科考試開始, 略去了前半部的荒唐歲月. 

山陰名醫柳義泰與他的好友三積大師有幾句令我至今都常想起的話 : 
  • 如果身為一位大夫只想利用職務來取得榮華富貴, 這種人不適合當大夫, 只適合去當商人. 想要賺錢就去學商, 賺錢的速度比學醫還快得多, 何必辛苦地讀醫書呢?  (柳義泰)
  • 一個手持利刀的武士和一隻猛獸, 也沒有大夫的手來得可怕. 大夫的雙手絕不容許犯下任何一次過失. (柳義泰)
  • 大夫可以救病人, 病人也可以救大夫. 大夫每次醫好一名病人, 就可以從虛幻的貪念以及邪惡的內心中拯救自己. (三積大師)
母親以前曾說, 我們鎮上的那個吳醫師, 都利用下一個病人進診間的空檔翻看旁邊厚厚的醫案, 真的無時無刻不在鑽研醫術, 這讓我覺得, 如果抱著發財夢去當醫師, 那個 CP 值實在太低了! 還不如一開始就進商學院. 

這部韓劇我大約是在 2010 年左右看的, 後來還把  VCD 借給同事當時正要進入醫學院的女兒看, 希望對她有所啟發, 也希望多年後仍不忘初衷. 

2022年7月24日 星期日

2022 年第 30 周記事

本周是典型的炎夏, 但溫度比往年還要高, 週六回到鄉下, 睡前覺得非常悶熱, 突然想起幾周前到貨的露營帳篷, 拿上頂樓拆開後進去試躺, 哇, 樓板還是溫熱的, 雖然站起來涼風徐徐非常舒服, 但只要躺下去就覺得 '不要不要', 即使鋪上錫箔墊子還是熱烘烘, 這下我真的失算了, 沒想到就是樓地板散熱慢, 底下房間才會悶熱啊 :





昨天去爬山時發現東邊山上烏雲密布, 以為今天會下雨, 結果還是熱一整天, 四隻小貓也都躺在車庫水泥地板上睡覺, 真是熱斃了 : 




小舅最近來菜園除草, 準備八月開始種小番茄, 我最近都很忙, 菜園只能任其荒涼長草, 今天去種子行買了 20 株韭菜, 但因為去小漢也沒時間種, 只好請爸明天種在空心菜旁的菜圃了. 

本周學習進展不錯, Seaborn 已測完長條圖與折線圖, 但在書上看到 Bokeh 的介紹, 覺得也很有興趣 (網頁介面 + 互動式), 列入視覺化的下個練功項目. 不過下周末要交學會課程簡報, 要暫停 Seaborn 與量化投資的學習一周了. 

儲能型太陽能系統安裝 (二)

下午忙完爸的便當後已四點, 正猶豫要不要放棄爬山, 改去小漢買亞角鐵與螺絲等, 最後決定去小漢, 因為天氣越來越熱, 感覺缺電的可能性越來越大, 必須快點將太陽能板裝好, 以應付短暫的跳電. 昨天下午回到鄉下後就到頂樓再次確認所需部品項目, 數目, 與尺寸, 參考上一篇 : 


下午去小漢購買了下列材料 : 
  • 十呎亞角鐵 :  4 支, 一支 350 元 (店員說今年漲好多), 共 1400 元
  • 6.5cm 長螺絲螺母對 + 華司 (直徑 2cm) :  8 組, 每組 9.5 元共 76元
  • 短螺絲 (長 2cm) 螺母對 (圓頭, 不需華司) : 30 組, 90 元
  • 壁虎 : 4 個
  • L 形鐵片 : 4 個, 每個 25 元, 共 100 元
總共 1678 元.

那十呎的亞角鐵則依據上回安裝並聯型太陽能板的尺寸現場裁切, 因為我預留再添加一塊的空間, 所以支架的設計都完全一樣, 新板子長寬稍大, 但都可以放得下. 時隔兩年多有點忘記怎麼操作那台砂輪切割機, 櫃台的美女跑來支援, 叮嚀安全事項 (角鐵 L 形要朝下較安全), 費了半小時終於裁切完畢 : 




回到家已五點半, 也沒時間組裝支架, 下周再繼續唄. 

2022年7月23日 星期六

好站 : 量化投資 Finlab.tw

今天在尋找 Bokeh 的教學資料時偶然發現了這個網站 :  


此網站主要是在做 Python 量化投資教學 (透過 Hahow 學校平台), 我大致看了一下內容, 覺得含金量頗高, 網站中的一些教學文章有許多值得參考學習之處, 我看了關於 Bokeh 的兩篇覺得還不錯 :


下面這篇站長韓博士的大作正好搔到我癢處, 我以前就是一檔一檔用 PHP 爬的 (要兩天才跑完一輪啊! 爬太勤怕被封鎖), 現在有更好的辦法, 參考 :


或許等我盲修瞎練一陣子之後可以去 Hahow 買一堂課來上看看. 嗯, 只要是有上乘內功的, 吸星大法都不會放過. 

好書 : 無線通訊射頻晶片模組設計 (系統篇 + 晶片篇)

二哥今天拿兩本全華出版的射頻晶片書籍, 問我是否市圖能找到, 兩本的修訂版市圖都有找到, 但要排隊預約, 我翻了一下覺得是理論與實務兼具的好書, 兩位作者 (張盛富張嘉展) 都是中正大學通訊所的教授 : 
  1. 無線通訊射頻晶片模組設計. 射頻系統篇(修訂版, 2008)
  2. 無線通訊射頻晶片模組設計 .射頻晶片篇(第二版, 2015) 



想說乾脆買下來唄, 結果上博客來與誠品等網站居然都賣完補貨中! 去露天找二手書竟然一本都沒有! 可見此書非常搶手, 那就只好排隊了. 

2022年7月22日 星期五

Python 學習筆記 : Seaborn 資料視覺化 (二)

在前一篇 Seaborn 測試中已了解 Seaborn 並非用來完全取代 Matplotlib, 而是擴充其統計繪圖功能, 使用時還是要匯入 Matplotlib, 顯示圖形仍然是使用 plt.show(). Seaborn 的好處是它提供預設主題背景來使圖形更美觀, 介面更簡單. 本系列之前的文章參考 : 


Seaborn 教學文件參考 :

https://www.python-graph-gallery.com/ (Seaborn 繪圖範例網站)

參考書目 :
  1. Python 網路爬蟲與資料視覺化 (旗標, 2017, 陳允傑) 第 14 章
  2. Python 資料可視化之美 (深智, 2020, 張傑) 第 3 章
  3. Python 資料科學手冊 (碁峰, 2017, 何敏煌譯) 第 4 章
  4. Python資料可視化攻略 (碁峰, 2021)
  5. Pandas 資料清理, 重塑, 過濾, 視覺化 (旗標, 2021) 第 12 章
在資料來源方面, Seaborn 有別於 Matplotlib 之處是支援 Pandas 的 DataFrame 資料結構, 且內建 load_dataset() 可載入線上資料集供學習者測試, 故以下測試均以此資料集為資料來源.

>>> import seaborn as sns   
>>> sns.get_dataset_names()       
['anagrams', 'anscombe', 'attention', 'brain_networks', 'car_crashes', 'diamonds', 'dots', 'exercise', 'flights', 'fmri', 'gammas', 'geyser', 'iris', 'mpg', 'penguins', 'planets', 'taxis', 'tips', 'titanic']


六. 關聯性圖表 (Relational plots) : 

Seaborn 的關聯性圖表有下列三種 : 
  • 折線圖 lineplot()
  • 散布圖 scatterplot() :
  • 散點圖 relplot() : 
折線圖適合用來呈現一個變數對連續時間變數的變化趨勢; 散布圖與散點圖則適合用來觀察兩個變數. 其中散點圖 relplot() 為與 Pandas 緊密結合之畫布等級 (figure-level) 函式, 可用 DataFrame 直接繪製出 Matplotlib 的多軸 (多子圖) 圖形, 一次畫出多種圖形. 折線圖函式 lineplot() 與散布圖函式 scatterplot 則是軸等級函式. 


1. 折線圖 :

折線圖適合繪製時間序列變數, 可用來呈現資料的時間趨勢. 繪製折線圖可用軸等級的 lineplot() 函式或畫布等級的 relplot(kind='line') 函式. 

首先用 sns.lineplot() 繪製折線圖, 其主要參數如下 : 

lineplot(x, y, data [, hue, style, palette, markers, size, sizes, dashes])

說明如下 :
  • x :  X 軸資料欄位名稱 (字串)
  • y : Y 軸資料欄位名稱 (字串)
  • hue : 用來表示第三軸的色調 (字串)
  • data : Pandas 的 DataFrame 資料
  • style : 區分樣式的欄位名稱
  • palette : 色彩範本
  • markers : 是否顯示資料點標記 (True/False), 預設 False 
  • size : 線條寬度類型
  • sizes : 線條寬度
  • dashes : 是否使用虛線 (True/False), 預設 True
其中最重要的是 x, y, data 這三個參數, data 就是 DataFrame 變數名稱, x 與 y 是 DataFrame 中的欄位名稱字串, 分別指定 X, Y 軸的資料來源. 

參考 : 


以航班旅客數量資料集 'flight' 為例, 裡面有自 1949 年以來每個月的旅客數統計, 例如 : 

>>> import seaborn as sns   
>>> import matplotlib.pyplot as plt   
>>> import pandas as pd   
>>> df=sns.load_dataset('flights')       
>>> df      
     year month  passengers
0    1949   Jan         112
1    1949   Feb         118
2    1949   Mar         132
3    1949   Apr         129
4    1949   May         121
..    ...   ...         ...
139  1960   Aug         606
140  1960   Sep         508
141  1960   Oct         461
142  1960   Nov         390
143  1960   Dec         432

[144 rows x 3 columns]

可見這是一個典型的時間序列資料, 有 year, month, 以及 passenger 三個欄位, 資料是逐年再逐月排列, 如果直接繪製 passenger 對 year 的圖形, 會繪製出以平均值為中心, 與其 95% 信賴區間為範圍的折線圖, 例如 :

>>> sns.set()    
>>> sns.lineplot(x="year", y="passengers", data=df)       
<matplotlib.axes._subplots.AxesSubplot object at 0x000001CC3A2827F0>
>>> plt.show()      

結果如下 : 




可見除了折線外, 周圍還有陰影, 這是因為一個時間點 (例如 1949 年) 有多筆資料, Seaborn 會計算其平均值與 95% 的信賴區間, 平均值用來繪製圖中的折線, 而信賴區間則用來繪製折線周圍的陰影. 完整程式碼如下 :


測試 6-1 : 呼叫 lineplot() 繪製折線圖 (1) - 單變數多值 [看原始碼]

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd

df=sns.load_dataset('flights')
sns.set()
sns.lineplot(x="year", y="passengers", data=df)
plt.show()

如果每個時間點只有一筆資料,  則就只有一條折線而沒有信賴區間的陰影區, 例如可呼叫 DataFrame 物件的 query() 函式搜尋五月份的旅客資料 : 

>>> may_flights=df.query("month=='May'")     # 搜尋 5 月份資料    
>>> may_flights     
     year month  passengers
4    1949   May         121
16   1950   May         125
28   1951   May         172
40   1952   May         183
52   1953   May         229
64   1954   May         234
76   1955   May         270
88   1956   May         318
100  1957   May         355
112  1958   May         363
124  1959   May         420
136  1960   May         472

可見 query() 會傳回一個新的 DataFrame 物件, 只包含每年五月份的旅客數, 以此 DatFrame 作為 資料源傳給 data 參數來繪製折線圖 : 

>>> sns.lineplot(x="year", y="passengers", data=may_flights)    
<matplotlib.axes._subplots.AxesSubplot object at 0x000001CC38FC9C50>
>>> plt.show()   

結果如下 :




這樣就不會有信賴區間, 只有折線而已了. 完整程式碼如下 :


測試 6-2 : 呼叫 lineplot() 繪製折線圖 (2) - 單變數單值 [看原始碼]

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd

df=sns.load_dataset('flights')
may_flights=df.query("month=='May'") 
sns.set()
sns.lineplot(x="year", y="passengers", data=may_flights)
plt.show()

可以呼叫 DataFrame 物件的 pivot() 函式做樞紐分析, 這樣每年的資料會分月展開成不同欄位, 亦即原本的 passengers 欄位會被拆成 Jan~Dec 之 12 個月份, 例如 : 

>>> flights_wide=df.pivot("year", "month", "passengers")   
>>> flights_wide   
month  Jan  Feb  Mar  Apr  May  Jun  Jul  Aug  Sep  Oct  Nov  Dec
year                                                             
1949   112  118  132  129  121  135  148  148  136  119  104  118
1950   115  126  141  135  125  149  170  170  158  133  114  140
1951   145  150  178  163  172  178  199  199  184  162  146  166
1952   171  180  193  181  183  218  230  242  209  191  172  194
1953   196  196  236  235  229  243  264  272  237  211  180  201
1954   204  188  235  227  234  264  302  293  259  229  203  229
1955   242  233  267  269  270  315  364  347  312  274  237  278
1956   284  277  317  313  318  374  413  405  355  306  271  306
1957   315  301  356  348  355  422  465  467  404  347  305  336
1958   340  318  362  348  363  435  491  505  404  359  310  337
1959   360  342  406  396  420  472  548  559  463  407  362  405
1960   417  391  419  461  472  535  622  606  508  461  390  432

可見 panssenger 欄位已經根據 month 欄位展開了, 以此做為資料源繪圖 : 

>>> sns.lineplot(data=flights_wide)   
<matplotlib.axes._subplots.AxesSubplot object at 0x00000239302116A0>
>>> plt.ylabel('passengers')       
Text(0, 0.5, 'passengers')   
>>> plt.show()    

此處因為呼叫 lineplot() 時無法指定 Y 軸欄位 (因 'passenger' 欄位已被展開), 畫出的圖形沒有 Y 軸標籤, 因此利用 Matplotlib 的 ylabel() 函式來設定, 結果如下 :




可見 Seaborn 會自動將各月欄位列為圖例 (legend), 圖形呈現每年各月旅客數之折線圖. 完整程式碼如下 : 


測試 6-3 : 呼叫 lineplot() 繪製折線圖 (3) - 繪製多變數折線圖 [看原始碼]

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd

sns.set()
df=sns.load_dataset('flights')
flights_wide=df.pivot("year", "month", "passengers")
sns.lineplot(data=flights_wide)
plt.ylabel('passengers')
plt.show()

從上面圖形可知, Seaborn 對於多變數的折線圖預設會用虛線來繪製, 這可以傳入 dashes=False 參數來改成實線, 例如 : 


測試 6-4 : 呼叫 lineplot() 繪製折線圖 (4) - 顯示實線 [看原始碼]

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd

sns.set()
df=sns.load_dataset('flights')
flights_wide=df.pivot("year", "month", "passengers")
sns.lineplot(data=flights_wide, dashes=False)
plt.ylabel('passengers')
plt.show()

結果如下 : 




也可以傳入 markers=True 來顯示資料點標記, 例如 : 


測試 6-5 : 呼叫 lineplot() 繪製折線圖 (5) - 顯示資料點標記 [看原始碼]

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd

sns.set()
df=sns.load_dataset('flights')
flights_wide=df.pivot("year", "month", "passengers")
sns.lineplot(data=flights_wide, dashes=False, markers=True)
plt.ylabel('passengers')
plt.show()

結果如下 : 




可見每一個資料點 (轉折處) 都自動標示不同的標記了 (依月份, 如圖例所示) .

在上面的範例中使用 DataFrame 物件的 pivot() 方法做樞紐分析將月份展開, 但 Seaborn 繪圖函式的 hue 參數可以直接將月份 month 當作第三維變數, 不需要樞紐分析展開 month 就可以直接畫出多變數的折線圖, 例如 : 


測試 6-6 : 呼叫 lineplot() 繪製折線圖 (6) - 使用 hue 參數 [看原始碼]

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd

sns.set()
df=sns.load_dataset('flights')
sns.lineplot(x='year', y='passengers', hue='month', data=df)
plt.show()

此處除了指定 x, y 欄位外, 還用 hue 參數指定第三維變數 month, 結果如下 : 




另外還可以用 style 參數指定要以哪個欄位區分不同樣式, 例如 :


測試 6-7 : 呼叫 lineplot() 繪製折線圖 (7) - 使用 style 參數 [看原始碼]

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd

sns.set()
df=sns.load_dataset('flights')
sns.lineplot(x='year', y='passengers', hue='month', style='month', data=df)
plt.show()

此例以 month 欄位區分樣式, 結果如下 :



結果與上面的測試 6-3 相同. 

除了用 lineplot() 外, 呼叫 relplot() 並傳入 kind='line' 參數也可以繪製折線圖, 例如 : 


測試 6-8 : 呼叫 relplot() 繪製折線圖 - 使用 kind='line' 參數 [看原始碼]

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd

sns.set()
df=sns.load_dataset('flights')
sns.relplot(x='year', y='passengers', hue='month', kind='line', data=df)
plt.show()

結果如下 : 




與上面用 lineplot() 所繪製的折線圖不同之處是, 圖例 (legend) 是放在圖形外的右側, 優點是不會跟圖形搶地盤. 當然也可以傳入 style 參數將實線改為虛線, 或傳入 markers 參數加上資料點標記. 

2022年7月21日 星期四

好站 : 7個Python使用BeautifulSoup開發網頁爬蟲的實用技巧

BeautifulSoup 是寫 Python 爬蟲程式必用的套件, 只要不是 Javscript 產生的網頁都能用它搭配 requests 套件來順利抓到想要擷取的資料, 與我很多年之前用 PHP 寫網路爬蟲相比, 真的是簡單到不行, 用過之後根本不會想回去用 PHP 了. 

今天在整理瀏覽器頁籤時看到暫存了好久的一篇文章, 寫得簡單扼要, 值得一讀 :


其實 Python 網頁爬蟲程式的基本結構很簡單, 匯入 requests 與 BeautifulSoup 後就用 requests.get() 擷取網頁, 然後將回應物件的 text 屬性值丟給 BeautifulSoup 解析網頁內容, 建立 BeautifulSoup 物件即可, 基本的程式結構如下 : 

import requests  
from bs4 import BeautifulSoup

headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) \
                           AppleWebKit/537.36 (KHTML, like Gecko) \
                           Chrome/102.0.0.0 Safari/537.36'}
url='要抓的網頁網址'
r=requests.get(url, headers=headers)
soup=BeautifulSoup(r.text, 'lxml')

然後就可以呼叫它最常用四個方法去抓資料了 :
  • find(tag [, 屬性=值, limit=個數]) :
    傳回第一個找到的 Tag 物件.  
  • find_all(tag [, 屬性=值, limit=個數]) :
    傳回所有符合之 Tag 物件組成之串列. 第一參數也可以傳入標籤串列, 例如 ['a','span']. 
  • select_one(tag) : 
    傳回第一個找到的 Tag 物件.
  • select(css [, limit=個數]) : 
    第一參數是 css 字串, 例如 '.book' 是傳回 id=book 的 Tag 物件串列 (只有一個元素); 而 '#book' 則是傳回 class=book 的 Tag 物件串列. 
注意, 若屬性為樣式類別時不可用 class (關鍵字), 必須改用 class_ 才行. 

雖然常常在寫爬蟲, 但我的 BeautifulSoup 筆記卻寫了好久都還沒完成, 這篇就列入參考唄.  

關於虛擬幣

我對區塊鏈技術很有興趣, 因為它也可以應用在 IoT 上, 但對虛擬幣卻很陌生, 上個月在公司內訓中聽了專家的講座後開始有點概念了, 最近也寫了爬蟲程式來抓乙太幣與虛擬幣價格變化, 藉以觀察市場脈動, 但對於不熟悉的東西不可貿然投, 須進一步研究理解.  

今天看到市場先生這篇文章, 簡要地說明了虛擬幣與區塊鏈概念 : 


摘要如下 : 
  1. 比特幣是利用區塊鏈技術去建立一個不需要第三方機構認證的去中心化帳本, 可實現不會錯帳與重複的虛擬貨幣交易. 
  2. 乙太坊同樣是使用區塊鏈技術, 但它不僅僅是紀錄帳本, 還可以記錄與執行程式, 亦即可把程式寫在區塊鏈上, 只要條件符合就會執行這些指令碼, 因此可用來實現智能合約, 區塊鏈無法被竄改之特性可以確保這些合約被忠實執行, 它可用在 ICO 募資, 電子錢包, 遊戲, 借貸, NFT 發行, 衍生性商品合約等應用上. 去中心化金融 DeFi乙太坊創辦人為俄裔加拿大人布特林
  3. 以太幣 (ETH) 是這些區塊鏈上程式碼 (智能合約) 在執行時所需付出的費用代幣(稱為GAS燃料), 執行任何乙太坊程序都會消耗燃料, 當燃料用盡程式就不會繼續運作, 這也避免了寫程式時可能造成無限迴圈的問題. 除了執行智能合約需要使用乙太幣外, 區塊鏈上的交易手續費, 礦工挖礦的獎勵等都會用以太幣支付. 
  4. 比特幣的價值是建立在總量有限上, 乙太幣則不同, 它是一種消耗品, 沒有總量限制, 每年會新產生一定數量的以太幣做為礦工獎勵 (每年最多挖出 1800 萬顆 ETH), 也會做為燃料 GAS 在執行指令時被消耗掉. 比特幣的定位比較像是貨幣, 而以太幣則像是一種代幣, 其價值取決於市場的供需, 除了投機性炒作以外, 其根本需求來自於以太坊區塊鏈的應用, 當越多應用要在以太坊上執行, 對以太幣的需求就會越高; 但當人們不再使用以太坊時它也會失去價值. 以太幣與比特幣最大的不同處是, 以太幣多了智能合約與 Dapp 的功能.
  5. 智能合約是可自動執行的合約, 利用 Dapp 創建一個合約, 將買賣雙方之間的協議條款寫入代碼中 (例如程式碼可以寫如果怎樣條件就執行什麼事情), 然後將此合約放在去中心化的區塊鏈網路上, 可確保合約一定能被執行, 而且不會有被竄改與違約的可能. 

2022年7月19日 星期二

Python 學習筆記 : 同時追蹤比特幣與乙太幣行情

本篇是前兩篇追蹤兩大虛擬幣 : 比特幣與虛擬幣行情的綜合測試, 參考 :


主要修改部分是爬蟲函式名稱, 因為可通用所以改成 coingecko_crawler(), 其餘只是複製貼上, 完整程式碼如下 : 


測試 1 : 擷取 CoinGecko 網站資料繪製比特幣+乙太幣價格變化圖形 [看原始碼]

import requests
import pandas as pd
import matplotlib.pyplot as plt
from PIL import Image

def coingecko_crawler(url):
    res=requests.get(url)
    prices=res.json()['stats']
    df=pd.DataFrame(prices)
    df.columns=['datetime', 'TWD']
    df['datetime']=pd.to_datetime(df['datetime'], unit='ms')
    df['datetime'] += pd.DateOffset(hours=8)
    df.index=df['datetime']
    return df

def notify_image(msg, token, image):
    url='https://notify-api.line.me/api/notify'
    headers={'Authorization': 'Bearer ' + token}
    data={'message': msg}
    image=open(image, 'rb')
    imageFile={'imageFile': image}
    r=requests.post(url, headers=headers, data=data, files=imageFile)
    if r.status_code==requests.codes.ok:
        return '圖片發送成功!'
    else:
        return f'圖片發送失敗: {r.status_code}'

plt.rcParams["font.family"]=["Microsoft JhengHei"]
token='ud7PaDL45fz849A0e1f5oaMCbRIkxMXapQCt7PfNkzz'   
# 比特幣
url='https://www.coingecko.com/price_charts/1/twd/90_days.json'
btc=coingecko_crawler(url)
btc['100MA']=btc['TWD'].rolling(window=100).mean()
btc[['TWD', '100MA']].plot(kind='line')
last_time=str(btc.iloc[-1:].index.values[0])[0:19]
last_price=int(btc.iloc[-1:]["TWD"].values[0])
plt.title(f'比特幣 {last_time} 台幣 {last_price} 元')
plt.xlabel('')
plt.ylabel('價格(台幣)')
plt.grid(True)
plt.legend(['價格', '100小時均價'], loc='best') 
plt.savefig('btc_prices.jpg')
img=Image.open('btc_prices.jpg')       # 開啟檔案   
img=img.crop((18, 26, 590, 453))       # 裁切圖片去除外圍白邊  
img.save('btc_prices.jpg')                    # 回存檔案   
msg=f'\n比特幣 {last_time} 台幣 {last_price} 元'
notify_image(msg, token, 'btc_prices.jpg')

# 乙太幣
url='https://www.coingecko.com/price_charts/279/twd/90_days.json'
eth=coingecko_crawler(url)
eth['100MA']=eth['TWD'].rolling(window=100).mean()
eth[['TWD', '100MA']].plot(kind='line')
last_time=str(eth.iloc[-1:].index.values[0])[0:19]
last_price=int(eth.iloc[-1:]["TWD"].values[0])
plt.title(f'乙太幣 {last_time} 台幣 {last_price} 元')
plt.xlabel('')
plt.ylabel('價格(台幣)')
plt.grid(True)
plt.legend(['價格', '100小時均價'], loc='best') 
plt.savefig('eth_prices.jpg')
img=Image.open('eth_prices.jpg')       # 開啟檔案   
img=img.crop((0, 26, 590, 453))       # 裁切圖片去除外圍白邊  
img.save('eth_prices.jpg')             # 回存檔案   
msg=f'\n乙太幣 {last_time} 台幣 {last_price} 元'
notify_image(msg, token, 'eth_prices.jpg')
#plt.show()  # 測試時才使用

此處最後一列的 plt.show() 是測試時檢視用, 上線時要註解掉. 結果如下 : 




可見兩大虛擬幣走勢幾乎一樣. 

接下來是佈署到樹莓派, 但因為此程式在繪圖時用到微軟正黑體中文字型, 樹莓派沒有此字型, 故須下載字型後進型設定, 方法參考 :


用 WinSCP 將爬蟲程式傳送到樹莓派後用下列指令將其改為可執行 :

pi@raspberrypi:~ $ sudo chmod +x /home/pi/btc_eth_prices_line_notify.py

然後編輯 Crontab, 加入執行此程式的時間指令, 參考 :

 
pi@raspberrypi:~ $ crontab -e   
crontab: installing new crontab
pi@raspberrypi:~ $ crontab -l    
0 16 * * 1-5 /usr/bin/python3 /home/pi/twstock_dashboard_update.py
*/30 9-14 * * 1-5 /usr/bin/python3 /home/pi/yahoo_twstock_monitor.py
0 8,18 * * * /usr/bin/python3 /home/pi/btc_eth_prices_line_notify.py    

OK, 收工啦. 

樹莓派執行 Pandas 出現 "Original error was: libf77blas.so.3"

晚上在佈署比特幣與乙太幣爬蟲程式到樹莓派時, 手動執行卻出現如下錯誤 : 

pi@raspberrypi:~ $ python3 btc_eth_prices_line_notify.py    
Traceback (most recent call last):
  File "btc_eth_prices_line_notify.py", line 2, in <module>
    import pandas as pd
  File "/home/pi/.local/lib/python3.7/site-packages/pandas/__init__.py", line 17, in <module>
    "Unable to import required dependencies:\n" + "\n".join(missing_dependencies)
ImportError: Unable to import required dependencies:
numpy:

IMPORTANT: PLEASE READ THIS FOR ADVICE ON HOW TO SOLVE THIS ISSUE!

Importing the numpy C-extensions failed. This error can happen for
many reasons, often due to issues with your setup or how NumPy was
installed.

We have compiled some common reasons and troubleshooting tips at:

    https://numpy.org/devdocs/user/troubleshooting-importerror.html

Please note and check the following:

  * The Python version is: Python3.7 from "/usr/bin/python3"
  * The NumPy version is: "1.20.3"

and make sure that they are the versions you expect.
Please carefully study the documentation linked above for further help.

Original error was: libf77blas.so.3: cannot open shared object file: No such file or directory    

乍看似乎是在 import pandas 時出現錯誤, 但實際上是載入 Numpy 中的 C 程式時有問題, 因為 Pandas 是以 Numpy 為基礎的. 進入 IDLE 介面匯入 numpy 果然出現與上面相同的錯誤訊息, 匯入 pandas 也是一樣. 

以 "Original error was: libf77blas.so.3" 搜尋, 在下面這篇文章找到解決辦法 :

 
原來只要用下列指令安裝 libatlas-base-dev 即可 : 

sudo apt-get install libatlas-base-dev

pi@raspberrypi:~ $ sudo apt-get install libatlas-base-dev    
正在讀取套件清單... 完成
正在重建相依關係
正在讀取狀態資料... 完成
下列的額外套件將被安裝:
  libatlas3-base
建議套件:
  libatlas-doc liblapack-doc
下列【新】套件將會被安裝:
  libatlas-base-dev libatlas3-base
升級 0 個,新安裝 2 個,移除 0 個,有 0 個未被升級。
需要下載 5,365 kB 的套件檔。
此操作完成之後,會多佔用 32.1 MB 的磁碟空間。
是否繼續進行 [Y/n]? [Y/n] Y
下載:1 http://mirror.ossplanet.net/raspbian/raspbian buster/main armhf libatlas3-base armhf 3.10.3-8+rpi1 [2,399 kB]
下載:2 http://mirror.ossplanet.net/raspbian/raspbian buster/main armhf libatlas-base-dev armhf 3.10.3-8+rpi1 [2,966 kB]
取得 5,365 kB 用了 6s (902 kB/s)
選取了原先未選的套件 libatlas3-base:armhf。
(讀取資料庫 ... 目前共安裝了 168524 個檔案和目錄。)
正在準備解包 .../libatlas3-base_3.10.3-8+rpi1_armhf.deb……
Unpacking libatlas3-base:armhf (3.10.3-8+rpi1) ...
選取了原先未選的套件 libatlas-base-dev:armhf。
正在準備解包 .../libatlas-base-dev_3.10.3-8+rpi1_armhf.deb……
Unpacking libatlas-base-dev:armhf (3.10.3-8+rpi1) ...
設定 libatlas3-base:armhf (3.10.3-8+rpi1) ...
update-alternatives: 在自動模式下以 /usr/lib/arm-linux-gnueabihf/atlas/libblas.so.3 來提供 /usr/lib/arm-linux-gnueabihf/libblas.so.3 (libblas.so.3-arm-linux-gnueabihf)
update-alternatives: 在自動模式下以 /usr/lib/arm-linux-gnueabihf/atlas/liblapack.so.3 來提供 /usr/lib/arm-linux-gnueabihf/liblapack.so.3 (liblapack.so.3-arm-linux-gnueabihf)
設定 libatlas-base-dev:armhf (3.10.3-8+rpi1) ...
update-alternatives: 在自動模式下以 /usr/lib/arm-linux-gnueabihf/atlas/libblas.so 來提供 /usr/lib/arm-linux-gnueabihf/libblas.so (libblas.so-arm-linux-gnueabihf)
update-alternatives: 在自動模式下以 /usr/lib/arm-linux-gnueabihf/atlas/liblapack.so 來提供 /usr/lib/arm-linux-gnueabihf/liblapack.so (liblapack.so-arm-linux-gnueabihf)
執行 libc-bin (2.28-10+rpi1) 的觸發程式……

經過這樣處理後就能順利匯入 Numpy 與 Pamdas 了 :

pi@raspberrypi:~ $ python3    
Python 3.7.3 (default, Jan 22 2021, 20:04:44)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy as np    
>>> np.__version__    
'1.20.3'
>>> import pandas as pd   
>>> pd.__version__    
'1.2.4'

但再次執行爬蟲程式還是失敗, 因為爬蟲程式裡面用到了中文字型 "微軟正黑體", 而樹莓派預設並未支援此字型 : 

pi@raspberrypi:~ $ python3 btc_eth_prices_line_notify.py    
Unable to init server: Could not connect: Connection refused
Unable to init server: 無法連接:Connection refused

(btc_eth_prices_line_notify.py:10639): Gdk-CRITICAL **: 20:43:38.213: gdk_cursor_new_for_display: assertion 'GDK_IS_DISPLAY (display)' failed

(btc_eth_prices_line_notify.py:10639): Gdk-CRITICAL **: 20:43:38.228: gdk_cursor_new_for_display: assertion 'GDK_IS_DISPLAY (display)' failed
/usr/lib/python3/dist-packages/matplotlib/font_manager.py:1241: UserWarning: findfont: Font family ['Microsoft JhengHei'] not found. Falling back to DejaVu Sans.
  (prop.get_family(), self.defaultFamily[fontext]))

但我參考之前的文章要做字型設定時卻發現 matplotlib 似乎版本太舊, 找不到預期之字型資料夾, 所以乾脆用 pip3 install matplotlib -U 指令將 Matplotlib 版本升級到最新, 然後就可以依照之前的文章上傳並設定微軟正黑體 : 


Python 3.7.3 (default, Jan 22 2021, 20:04:44)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import matplotlib  
>>> matplotlib.__version__    
'3.5.2'   

這樣就可以順利在樹莓派用 Matplotlib 繪製含有中文的圖形了.

儲能型太陽能系統安裝 (一)

我在四月底向仁武一個賣家購買了一塊 340W 的太陽能板與 100AH 深循環電池, 至今兩個半月多都還沒時間架起來, 上週日去小漢買止水帶時問了亞角鐵價格, 現在 10 尺長一條漲到 350 元, 兩年前安裝並聯型時才 200 元, 居然漲這麼多! 參考 : 

測量之前的並聯型支架尺寸仍可用, 預留再擴充一塊太陽能板的位置, 所以支架部分不需要重新設計, 所需材料整理如下 :
  • 10 尺不銹亞角鋼 : 4 支
  • 螺絲螺母 : 20 對
  • 地虎 : 4 支
亞角鋼須裁成三部分, 尺寸如下 :
  • 216 cm * 2 (左右斜邊)
  • 184 cm * 2 (上下高低邊)
  • 68 cm * 2 (兩側立柱)
設計圖參考 : 


配電材料 :
  • 4 對 1 接頭 : 2 個
  • 瓦時電表 : 1 個
  • 電線 : 2 捆
  • 無熔絲開關 : 1 個
配線分成交流 110V 與直流 12V 兩個迴路, 初步規劃從三樓往東邊走線下樓到車庫後再配電到室內, 主要供緊急照明, 無線基地台, 與電視等較低功率設備使用. 目前並聯型用的大同瓦時計是露天買的二手新品, 記得是 500 元 :


現在露天的台製瓦時計價位約 600~800 左右 :


中國製約 300~400 元, 但品質堪慮, 還是看看就好. 

Python 學習筆記 : 乙太幣行情追蹤

上週利用爬蟲去比特幣網站 CoinGeko 抓比特幣行情, 然後用 Matplotlib 繪製價格趨勢圖以 Line Notify 推播, 參考 : 

 
其實抓第二大虛擬幣乙太幣的價格方法相同, 只是 json 資料源網址不同而已 : 





主要是改 url 部分, 然後將 'btc' 改成 'eth' 就可以報完工了 : 


測試 1 : 擷取 CoinGecko 網站資料繪製乙太幣價格變化圖形 [看原始碼]

import requests
import pandas as pd
import matplotlib.pyplot as plt
from PIL import Image

def coingecko_eth_crawler(url):
    res=requests.get(url)
    prices=res.json()['stats']
    df=pd.DataFrame(prices)
    df.columns=['datetime', 'TWD']
    df['datetime']=pd.to_datetime(df['datetime'], unit='ms')
    df['datetime'] += pd.DateOffset(hours=8)
    df.index=df['datetime']
    return df

def notify_image(msg, token, image):
    url='https://notify-api.line.me/api/notify'
    headers={'Authorization': 'Bearer ' + token}
    data={'message': msg}
    image=open(image, 'rb')
    imageFile={'imageFile': image}
    r=requests.post(url, headers=headers, data=data, files=imageFile)
    if r.status_code==requests.codes.ok:
        return '圖片發送成功!'
    else:
        return f'圖片發送失敗: {r.status_code}'

plt.rcParams["font.family"]=["Microsoft JhengHei"]
url='https://www.coingecko.com/price_charts/279/twd/90_days.json'  
eth=coingecko_eth_crawler(url)
eth['100MA']=eth['TWD'].rolling(window=100).mean()
eth[['TWD', '100MA']].plot(kind='line')
last_time=str(eth.iloc[-1:].index.values[0])[0:19]
last_price=int(eth.iloc[-1:]["TWD"].values[0])
plt.title(f'乙太幣 {last_time} 台幣 {last_price} 元')
plt.xlabel('')
plt.ylabel('價格(台幣)')
plt.grid(True)
plt.legend(['價格', '100小時均價'], loc='best') 
plt.savefig('eth_prices.jpg')
img=Image.open('eth_prices.jpg')       # 開啟檔案   
img=img.crop((0, 26, 590, 453))         # 裁切圖片去除外圍白邊  
img.save('eth_prices.jpg')                    # 回存檔案   
token='ud7PaDL45fz849A0e1f5oaMCbRIkxMXapQCt7PfNkzz'
msg='乙太幣價格變化'
notify_image(msg, token, 'eth_prices.jpg')
plt.show()

此例是從比特幣那篇最後的範例修改而來 (中文化+調整時差), 結果如下 : 




從曲線趨勢看 (典型 W 底), 最近比特幣與乙太幣似乎有谷底翻身之勢啊!