Python 圖像處理 OpenCV (9):圖像處理形態學開運算、閉運算以及梯度運算

前文傳送門:

「Python 圖像處理 OpenCV (1):入門」

「Python 圖像處理 OpenCV (2):像素處理與 Numpy 操作以及 Matplotlib 显示圖像」

「Python 圖像處理 OpenCV (3):圖像屬性、圖像感興趣 ROI 區域及通道處理」

「Python 圖像處理 OpenCV (4):圖像算數運算以及修改顏色空間」

「Python 圖像處理 OpenCV (5):圖像的幾何變換」

「Python 圖像處理 OpenCV (6):圖像的閾值處理」

「Python 圖像處理 OpenCV (7):圖像平滑(濾波)處理」

「Python 圖像處理 OpenCV (8):圖像腐蝕與圖像膨脹」

引言

前面介紹了圖像形態學的兩種基礎算法,圖像腐蝕和圖像膨脹,本篇接着介紹圖像形態學中的開運算、閉運算以及梯度運算。

由於內容的連貫性,請先閱讀前文「Python 圖像處理 OpenCV (8):圖像腐蝕與圖像膨脹」,了解清楚圖像的腐蝕與膨脹基礎原理。

不然真的沒辦法理解開運算和閉運算。

第一件事情還是給圖像增加噪聲,思路沿用之前加噪聲的思路,使用 Numpy 給圖片添加黑白兩種噪聲點,代碼如下:

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

# 讀取圖片
img = cv.imread("demo.png", cv.IMREAD_UNCHANGED)
source = cv.cvtColor(img, cv.COLOR_BGR2RGB)
rows, cols, chn = source.shape

# 加噪聲-白點噪聲
for i in range(500):
    x = np.random.randint(0, rows)
    y = np.random.randint(0, cols)
    source[x, y, :] = 255

# 圖像保存 白點噪聲圖像
cv.imwrite("demo_noise_white.jpg", source)
print("白點噪聲添加完成")

# 重新讀取圖像
img1 = cv.imread("demo.png", cv.IMREAD_UNCHANGED)
source1 = cv.cvtColor(img1, cv.COLOR_BGR2RGB)

# 加噪聲-黑點噪聲
for i in range(1000):
    x = np.random.randint(0, rows)
    y = np.random.randint(0, cols)
    source1[x, y, :] = 0

# 圖像保存 黑點噪聲圖像
cv.imwrite("demo_noise_black.jpg", source1)
print("黑點噪聲添加完成")

# 显示結果
titles = ['White Img','Black Img']
images = [source, source1]

# matplotlib 繪圖
for i in range(2):
   plt.subplot(1, 2, i+1), plt.imshow(images[i],'gray')
   plt.title(titles[i])
   plt.xticks([]),plt.yticks([])

plt.show()

形態學開運算

圖像開運算實際上是一個組合運算,開運算是圖像先進行腐蝕,再進行膨脹的運算。

圖像被腐蝕后,去除了噪聲,但是也壓縮了圖像;接着對腐蝕過的圖像進行膨脹處理,使得剛才在腐蝕過程中被壓縮的圖像得以恢復原狀。

下面是一個圖像開運算的流程圖:

開運算的一些特性:

  • 開運算能夠除去孤立的小點,毛刺和小橋,而總的位置和形狀不便。
  • 開運算是一個基於幾何運算的濾波器。
  • 結構元素大小的不同將導致濾波效果的不同。
  • 不同的結構元素的選擇導致了不同的分割,即提取出不同的特徵。

我們先不管開運算 OpenCV 為我們提供的函數是什麼,先使用前面介紹過的圖像腐蝕與膨脹處理看下結果:

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

# 讀取圖片
source = cv.imread("demo_noise_white.jpg", cv.IMREAD_GRAYSCALE)

# 設置卷積核
kernel = np.ones((5, 5),np.uint8)

# 圖像腐蝕
erode_img = cv.erode(source, kernel)

# 圖像膨脹
dilate_result = cv.dilate(erode_img, kernel)

# 显示結果
titles = ['Source Img','Erode Img','Dilate Img']
images = [source, erode_img, dilate_result]

# matplotlib 繪圖
for i in range(3):
   plt.subplot(1, 3, i+1), plt.imshow(images[i],'gray')
   plt.title(titles[i])
   plt.xticks([]),plt.yticks([])

plt.show()

可以看到降噪的效果還是不錯的。

接着看 OpenCV 為開運算提供的函數。

圖像開運算主要使用到的函數是 morphologyEx() 它是形態學擴展的一組函數,而其中的 cv.MORPH_OPEN 對應的是開運算。

使用時語法如下:

dst = cv.morphologyEx(src, cv.MORPH_OPEN, kernel)
  • src: 原圖形
  • cv2.MORPH_OPEN: 表示開運算
  • kernel: 卷積核

我們再使用 morphologyEx() 函數去重新實現下剛才的圖像開運算,看下和之前的結果有啥區別:

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

# 讀取圖片
source = cv.imread("demo_noise_white.jpg", cv.IMREAD_GRAYSCALE)

# 設置卷積核
kernel = np.ones((5, 5),np.uint8)

#圖像開運算
dst = cv.morphologyEx(source, cv.MORPH_OPEN, kernel)

# 显示結果
titles = ['Source Img','Dst Img']
images = [source, dst]

# matplotlib 繪圖
for i in range(2):
   plt.subplot(1, 2, i+1), plt.imshow(images[i],'gray')
   plt.title(titles[i])
   plt.xticks([]),plt.yticks([])

plt.show()

至少從肉眼的角度上看不出來和之前的方式有啥區別,實際上也沒啥區別。

形態學閉運算

與開運算相反的是閉運算,閉運算是圖像先膨脹,后腐蝕,它有助於關閉前景物體內部的小孔,或物體上的小黑點。

先看下圖像閉運算的流程圖:

閉運算的一些特性:

  • 閉運算能夠填平小湖(即小孔),彌合小裂縫,而總的位置和形狀不變。
  • 閉運算是通過填充圖像的凹角來濾波圖像的。
  • 結構元素大小的不同將導致濾波效果的不同。
  • 不同結構元素的選擇導致了不同的分割。

首先還是用 dilate()erode() 函數實現一下圖像閉運算,代碼如下:

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

# 讀取圖片
source = cv.imread("demo_noise_black.jpg", cv.IMREAD_GRAYSCALE)

# 設置卷積核
kernel = np.ones((5, 5),np.uint8)

# 圖像膨脹
dilate_result = cv.dilate(source, kernel)

# 圖像腐蝕
erode_img = cv.erode(dilate_result, kernel)

# 显示結果
titles = ['Source Img','Dilate Img','Erode Img']
images = [source, dilate_result, erode_img]

# matplotlib 繪圖
for i in range(3):
   plt.subplot(1, 3, i+1), plt.imshow(images[i],'gray')
   plt.title(titles[i])
   plt.xticks([]),plt.yticks([])

plt.show()

如果想要使用形態學擴展的函數 morphologyEx() 則需要把裏面的參數換成 MORPH_CLOSE ,同樣,既然是形態學擴展函數,那麼圖像腐蝕和圖像膨脹也有對應的參數:

  • 圖像腐蝕: MORPH_ERODE
  • 圖像膨脹: MORPH_DILATE

接着還是使用 MORPH_CLOSE 參數來實現下圖像的閉運算:

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

# 讀取圖片
source = cv.imread("demo_noise_black.jpg", cv.IMREAD_GRAYSCALE)

# 設置卷積核
kernel = np.ones((5, 5),np.uint8)

# 圖像閉運算
dst = cv.morphologyEx(source, cv.MORPH_CLOSE, kernel)

# 显示結果
titles = ['Source Img','Dst Img']
images = [source, dst]

# matplotlib 繪圖
for i in range(2):
   plt.subplot(1, 2, i+1), plt.imshow(images[i],'gray')
   plt.title(titles[i])
   plt.xticks([]),plt.yticks([])

plt.show()

形態學梯度運算

圖像形態學的梯度運算和前面的開運算閉運算是一樣的,都是組合函數。

梯度運算實際上是圖像膨脹減去圖像腐蝕后的結果,最終我們得到的是一個類似於圖像輪廓的圖形。

梯度運算在 morphologyEx() 函數中的參數是 MORPH_GRADIENT ,示例代碼如下:

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

# 讀取圖片
source = cv.imread("demo.png", cv.IMREAD_GRAYSCALE)

# 設置卷積核
kernel = np.ones((5, 5), np.uint8)

# 圖像梯度運算
dst = cv.morphologyEx(source, cv.MORPH_GRADIENT, kernel)

# 显示結果
titles = ['Source Img','Dst Img']
images = [source, dst]

# matplotlib 繪圖
for i in range(2):
   plt.subplot(1, 2, i+1), plt.imshow(images[i],'gray')
   plt.title(titles[i])
   plt.xticks([]),plt.yticks([])

plt.show()

示例代碼

如果有需要獲取源碼的同學可以在公眾號回復「OpenCV」進行獲取。

參考

http://www.woshicver.com/

https://blog.csdn.net/Eastmount/article/details/83651172

https://blog.csdn.net/hanshanbuleng/article/details/80657148

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

※教你寫出一流的銷售文案?

Zookeeper分佈式鎖

分佈式解決方案源碼,請幫我點個star哦!
原文地址為https://www.cnblogs.com/haixiang/p/13112710.html,轉載請註明出處!

zookeeper客戶端選型

  • 原生zookeeper客戶端,有watcher一次性、無超時重連機制等一系列問題
  • ZkClient,解決了原生客戶端一些問題,一些存量老系統中還在使用
  • curator,提供了各種應用場景(封裝了分佈式鎖,計數器等),新項目首選

分佈式鎖使用場景

在單體項目中jvm中的鎖即可完成需要,但是微服務、分佈式環境下,同一個服務可能部署在多台服務器上,多個jvm之間無法通過常用的jvm鎖來完成同步操作,需要借用分佈式鎖來完成上鎖、釋放鎖。例如在訂單服務中,我們需要根據日期來生成訂單號流水,就有可能產生相同的時間日期,從而出現重複訂單號。(jdk8使用LocalDateTime線程安全,不會存在這樣的問題)

zookeeper分佈式鎖實現原理

  • zookeeper中規定,在同一時刻,不能有多個客戶端創建同一個節點,我們可以利用這個特性實現分佈式鎖。zookeeper臨時節點只在session生命周期存在,session一結束會自動銷毀。
  • watcher機制,在代表鎖資源的節點被刪除,即可以觸發watcher解除阻塞重新去獲取鎖,這也是zookeeper分佈式鎖較其他分佈式鎖方案的一大優勢。

基於臨時節點方案

第一種方案實現較為簡單,邏輯就是誰創建成功該節點,誰就持有鎖,創建失敗的自己進行阻塞,A線程先持有鎖,B線程獲取失敗就會阻塞,同時對/lockPath設置監聽,A線程執行完操作后刪除節點,觸發監聽器,B線程此時解除阻塞,重新去獲取鎖。

我們模仿原生jdk的lock接口設計,採用模板方法設計模式來編寫分佈式鎖,這樣的好處是擴展性強,我們可以快速切換到redis分佈式鎖、數據庫分佈式鎖等實現方式。

創建Lock接口

public interface Lock {
    /**
     * 獲取鎖
     */
    void getLock() throws Exception;

    /**
     * 釋放鎖
     */
    void unlock() throws Exception;
}

AbstractTemplateLock抽象類

public abstract class AbstractTemplateLock implements Lock {
    @Override
    public void getLock() {
        if (tryLock()) {
            System.out.println(Thread.currentThread().getName() + "獲取鎖成功");
        } else {
            //等待
            waitLock();//事件監聽 如果節點被刪除則可以重新獲取
            //重新獲取
            getLock();
        }
    }
    protected abstract void waitLock();
    protected abstract boolean tryLock();
    protected abstract void releaseLock();
    @Override
    public void unlock() {
        releaseLock();
    }
}

zookeeper分佈式鎖邏輯

@Slf4j
public class ZkTemplateLock extends AbstractTemplateLock {
    private static final String zkServers = "127.0.0.1:2181";
    private static final int sessionTimeout = 8000;
    private static final int connectionTimeout = 5000;

    private static final String lockPath = "/lockPath";


    private ZkClient client;

    public ZkTemplateLock() {
        client = new ZkClient(zkServers, sessionTimeout, connectionTimeout);
        log.info("zk client 連接成功:{}",zkServers);
    }

    @Override
    protected void waitLock() {
        CountDownLatch latch = new CountDownLatch(1);

        IZkDataListener listener = new IZkDataListener() {
            @Override
            public void handleDataDeleted(String dataPath) throws Exception {
                System.out.println("監聽到節點被刪除");
                latch.countDown();
            }
            @Override
            public void handleDataChange(String dataPath, Object data) throws Exception {}
        };
        //完成 watcher 註冊
        client.subscribeDataChanges(lockPath, listener);

        //阻塞自己
        if (client.exists(lockPath)) {
            try {
                latch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //取消watcher註冊
        client.unsubscribeDataChanges(lockPath, listener);
    }

    @Override
    protected boolean tryLock() {
        try {
            client.createEphemeral(lockPath);
            System.out.println(Thread.currentThread().getName()+"獲取到鎖");
        } catch (Exception e) {
            log.error("創建失敗");
            return false;
        }
        return true;
    }

    @Override
    public void releaseLock() {
       client.delete(this.lockPath);
    }
}

缺點

每次去競爭鎖,都只會有一個線程拿到鎖,當線程數龐大時會發生“驚群”現象,zookeeper節點可能會運行緩慢甚至宕機。這是因為其他線程沒獲取到鎖時都會監聽/lockPath節點,當A線程釋放完畢,海量的線程都同時停止阻塞,去爭搶鎖,這種操作十分耗費資源,且性能大打折扣。

基於臨時順序節點方案

臨時順序節點與臨時節點不同的是產生的節點是有序的,我們可以利用這一特點,只讓當前線程監聽上一序號的線程,每次獲取鎖的時候判斷自己的序號是否為最小,最小即獲取到鎖,執行完畢就刪除當前節點繼續判斷誰為最小序號的節點。

臨時順序節點操作源碼

@Slf4j
public class ZkSequenTemplateLock extends AbstractTemplateLock {
    private static final String zkServers = "127.0.0.1:2181";
    private static final int sessionTimeout = 8000;
    private static final int connectionTimeout = 5000;
    private static final String lockPath = "/lockPath";
    private String beforePath;
    private String currentPath;
    private ZkClient client;

    public ZkSequenTemplateLock() {
        client = new ZkClient(zkServers);
        if (!client.exists(lockPath)) {
            client.createPersistent(lockPath);

        }
        log.info("zk client 連接成功:{}",zkServers);

    }

    @Override
    protected void waitLock() {
        CountDownLatch latch = new CountDownLatch(1);
        IZkDataListener listener = new IZkDataListener() {
            @Override
            public void handleDataDeleted(String dataPath) throws Exception {
                System.out.println("監聽到節點被刪除");
                latch.countDown();
            }
            @Override
            public void handleDataChange(String dataPath, Object data) throws Exception {}
        };
        //給排在前面的節點增加數據刪除的watcher,本質是啟動另一個線程去監聽上一個節點
        client.subscribeDataChanges(beforePath, listener);

        //阻塞自己
        if (client.exists(beforePath)) {
            try {
                System.out.println("阻塞"+currentPath);
                latch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //取消watcher註冊
        client.unsubscribeDataChanges(beforePath, listener);
    }

    @Override
    protected boolean tryLock() {
        if (currentPath == null) {
            //創建一個臨時順序節點
            currentPath = client.createEphemeralSequential(lockPath + "/", "lock-data");
            System.out.println("current:" + currentPath);
        }

        //獲得所有的子節點並排序。臨時節點名稱為自增長的字符串
        List<String> childrens = client.getChildren(lockPath);
        //排序list,按自然順序排序
        Collections.sort(childrens);
        if (currentPath.equals(lockPath + "/" + childrens.get(0))) {
            return true;
        } else {
            //如果當前節點不是排第一,則獲取前面一個節點信息,賦值給beforePath
            int curIndex = childrens.indexOf(currentPath.substring(lockPath.length() + 1));
            beforePath = lockPath + "/" + childrens.get(curIndex - 1);
        }
        System.out.println("beforePath"+beforePath);
        return false;
    }

    @Override
    public void releaseLock() {
        System.out.println("delete:" + currentPath);
        client.delete(currentPath);
    }
}

Curator分佈式鎖工具

curator提供了以下種類的鎖:

  • 共享可重入鎖(Shared Reentrant Lock):全局同步鎖,同一時間不會有兩個客戶端持有一個鎖
  • 共享鎖:與共享可重入鎖類似,但是不可重入(有時候會因為這個原因造成死鎖)
  • 共享可重入讀寫鎖
  • 共享信號量
  • Multi Shared Lock:管理多種鎖的容器實體

我們採用第一種Shared Reentrant Lock中的InterProcessMutex來完成上鎖、釋放鎖的的操作

public class ZkLockWithCuratorTemplate implements Lock {
    // zk host地址
    private String host = "localhost";

    // zk自增存儲node
    private String lockPath = "/curatorLock";

    // 重試休眠時間
    private static final int SLEEP_TIME_MS = 1000;
    // 最大重試1000次
    private static final int MAX_RETRIES = 1000;
    //會話超時時間
    private static final int SESSION_TIMEOUT = 30 * 1000;
    //連接超時時間
    private static final int CONNECTION_TIMEOUT = 3 * 1000;
		//curator核心操作類
    private CuratorFramework curatorFramework;

    InterProcessMutex lock;

   public ZkLockWithCuratorTemplate() {
       curatorFramework = CuratorFrameworkFactory.builder()
               .connectString(host)
               .connectionTimeoutMs(CONNECTION_TIMEOUT)
               .sessionTimeoutMs(SESSION_TIMEOUT)
               .retryPolicy(new ExponentialBackoffRetry(SLEEP_TIME_MS, MAX_RETRIES))
               .build();
       curatorFramework.start();
       lock = new InterProcessMutex (curatorFramework, lockPath);
    }

    @Override
    public void getLock() throws Exception {
        //5s后超時釋放鎖
         lock.acquire(5, TimeUnit.SECONDS);
    }

    @Override
    public void unlock() throws Exception {
        lock.release();
    }
}

源碼以及測試類地址

https://github.com/Motianshi/distribute-tool

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※想知道最厲害的網頁設計公司"嚨底家"!

※別再煩惱如何寫文案,掌握八大原則!

※產品缺大量曝光嗎?你需要的是一流包裝設計!

(數據科學學習手札87)利用adjustText解決matplotlib文字標籤遮擋問題

本文示例代碼、數據已上傳至我的Github倉庫https://github.com/CNFeffery/DataScienceStudyNotes

1 簡介

  在進行數據可視化時我們常常需要在可視化作品上進行一些文字標註,譬如對散點圖我們可以將每個散點對應的屬性信息標註在每個散點旁邊,但隨着散點量的增多,或圖像上的某個區域聚集了較多的散點時,疊加上的文字標註會擠在一起相互疊置,出現如圖1所示的情況:

圖1

  出現這種情況非常影響數據可視化作品的呈現效果,而我們下面要介紹的adjustText是一個輔助matplotlib所繪製的圖像自動調整文字位置以緩解遮擋現象的庫,其靈感來源於R中非常著名的輔助ggplot2解決文字遮擋問題的ggrepel

圖2

  它通過算法迭代,在一輪輪的迭代過程中逐漸消除文字遮擋現象:

圖3

  下面我們就來學習如何使用adjustText解決matplotlib圖像文字遮擋問題。

2 使用adjustText解決文字遮擋問題

2.1 從一個簡單的例子出發

  使用pip install adjustTextconda install -c conda-forge adjusttext 來安裝adjustText。安裝成功之後,首先生成隨機示例數據以方便之後的演示:

import matplotlib.pyplot as plt
from adjustText import adjust_text
import numpy as np

#解決中文显示問題
plt.rcParams['font.sans-serif'] = ['SimHei']

seed = np.random.RandomState(42) # 固定隨機數水平
x, y = seed.uniform(0, 1, [2, 100]) # 產生固定的均勻分佈隨機數
texts = [f'文字{i}' for i in range(x.__len__())]

  接着我們先不使用adjustText調整圖像,直接繪製出原始的散點+文字標籤

fig, ax = plt.subplots(figsize=(8, 8))
ax.scatter(x, y, c='SeaGreen', s=10) # 繪製散點

# 繪製所有點對應的文字標籤
for x_, y_, text in zip(x, y, texts):
    plt.text(x_, y_, text, fontsize=12)

# 美觀起見隱藏頂部與右側邊框線
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)

fig.savefig('圖4.png', dpi=300, bbox_inches='tight', pad_inches=0) # 保存圖像

圖4

  可以看到,在通常的情況下,散點聚集的區域內文字標籤非常容易重疊在一起,接下來我們使用adjustText的基礎功能來消除文字重疊現象:

圖5

  這時可以看到與圖4相比,圖5中的所有文字都沒有出現彼此重疊現象,adjustText幫助我們自動微調了文字的擺放位置,並且距離原始散點偏移較大的文字還貼心的加上了連接線,至此,我們就初探了adjustText的強大功能,接下來我們來學習adjustText的更多功能。

2.2 adjust_text的用法

  adjustText中的核心功能都通過調用函數adjust_text來實現,其核心參數如下:

texts:List型,每個元素都是表示單個文字標籤對應的matplotlib.text.Text對象

ax:繪製文字標籤的目標axe對象,默認為最近一次的axe對象

lim:int型,控制迭代調整文本標籤位置的次數,默認為500次

precision:float型,用於決定迭代停止的精度,默認為0.01,即所有標籤相互遮擋部分的長和寬占所有標籤自身長寬之和的比例,addjust_text會在精度達到precision和迭代次數超過lim這兩個條件中至少有一個滿足時停止迭代

only_move:字典型,用於指定文本標籤與不同對象發生遮擋時的位移策略,鍵有'points''text''objects',對應的值可選'xy''x''y',分別代表豎直和水平方向均調整、只調整水平方向以及只調整豎直方向

arrowprops:字典型,用於設置偏移后的文字標籤與原始位置之間的連線樣式,下文會作具體演示

save_steps:bool型,用於決定是否保存記錄迭代過程中各輪的幀圖像,默認為False

save_prefix:str型,當save_steps設置為True時,用於指定中間幀保存的路徑,默認為”,即當前工作路徑

  下面我們來演示一下這些參數的使用效果,首先我們來看看only_move參數的效果,在圖6的基礎上,我們設置only_move={'text': 'x'},即當文字出現遮擋時,只在水平方向上進行偏移,這裏將save_steps設置為True以直觀地查看偏移過程:

fig, ax = plt.subplots(figsize=(8, 8))
ax.scatter(x, y, c='SeaGreen', s=10) # 繪製散點

# 使用adjustText修正文字重疊現象
new_texts = [plt.text(x_, y_, text, fontsize=12) for x_, y_, text in zip(x, y, texts)]
adjust_text(new_texts, 
            only_move={'text': 'x'},
            arrowprops=dict(arrowstyle='-', color='grey'),
            save_steps=True)

# 美觀起見隱藏頂部與右側邊框線
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)

圖6

  可以看到在整個迭代微調的過程中,每個標籤只在水平方向發生位移,你可以根據自己作圖的實際需要靈活調整這裏的平移策略。接下來我們來看看arrowprops對可視化結果的影響,在之前的例子里我們設置了arrowprops={arrowstyle='-', color='grey'},其中arrowstyle用於設定連線的線型,color不用多說,接下來我們添加參數lw用於控制線的寬度,並對線型與顏色進行修改:

fig, ax = plt.subplots(figsize=(8, 8))
ax.scatter(x, y, c='SeaGreen', s=10) # 繪製散點

# 使用adjustText修正文字重疊現象
new_texts = [plt.text(x_, y_, text, fontsize=12) for x_, y_, text in zip(x, y, texts)]
adjust_text(new_texts, 
            arrowprops=dict(arrowstyle='->', 
                            color='red',
                            lw=1))

# 美觀起見隱藏頂部與右側邊框線
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)

fig.savefig('圖7.png', dpi=300, bbox_inches='tight', pad_inches=0) # 保存圖像

  這時連線隨着我們自定義的設置改變到相應的樣式:

圖7

  有關adjustText的更多參數設置信息和示例可以去官方文檔(https://adjusttext.readthedocs.io/en/latest/ )查看。

  以上就是本文的全部內容,如有疑問歡迎在評論區與我們討論。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※別再煩惱如何寫文案,掌握八大原則!

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※超省錢租車方案

※教你寫出一流的銷售文案?

網頁設計最專業,超強功能平台可客製化

※產品缺大量曝光嗎?你需要的是一流包裝設計!

難以想像!座頭鯨游進澳洲內陸30公里 專家憂被鱷魚吃掉

摘錄自2020年9月14日自由時報報導

澳洲卡卡杜國家公園的東鱷魚河,近來有座頭鯨迷路游進去深入內陸30公里,導致鱷魚和鯨魚共存的狀況出現,專家憂心一旦鯨魚擱淺,可能就會成為鱷魚現成的美食。

據《BBC》報導,海洋生態學家帕爾默(Carole Palmer)表示,這是澳洲從未發生過的事情。由於這隻座頭鯨的身長達到16公尺,體型相當龐大,因此帕爾默認為在一般狀況下牠不會被河裡眾多的鱷魚所干擾,但假如座頭鯨擱淺在淺水區那就不一樣了,畢竟人力不可能迅速移動那麼大隻的座頭鯨,鱷魚這時就會趁機而入。

目前並不清楚為什麼這些座頭鯨會迷路,鯨魚通常會在春季到較溫暖的海域生活,以便養育後代,之後才會返回南極海域覓食,因此有人推測座頭鯨在往南游的過程中可能誤入河口,就這樣游到了東鱷魚河上游。

生物多樣性
國際新聞
澳洲
座頭鯨
鱷魚

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

※推薦評價好的iphone維修中心

研究:1993年《生物多樣性公約》 至今成功保育48個物種免於滅絕

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

※教你寫出一流的銷售文案?

※超省錢租車方案

反聖嬰現象形成 颶風、野火恐更活躍

摘錄自2020年9月14日聯合報報導

國家海洋暨大氣管理局(NOAA)11日宣布,「反聖嬰現象」(La Nia,又稱拉尼娜現象)已然形成;此現象將影響颶風季節的剩餘時間,並可能至少持續整個冬季,直到春季才回到略為放鬆的「中性」狀態。

拉尼娜(La Nia)與聖嬰現象(El Nio)相反。反聖嬰現象讓赤道熱帶太平洋的海水異常變冷,可能影響太平洋以外的天氣模式。由於預料反聖嬰現象到來,NOAA得以在8月初預報「極端活躍」的颶風季節,颶風表現可能更為激烈。

NOAA氣象預報員表示,反聖嬰現象有75%可能性會停留整個冬季。讓太平洋西北地區、北部平原,大湖區和新英格蘭北部地區的降雪機率,高於平均水平。大西洋中部及南部、南部/中部平原和西南部的降雪,則可能更加稀少。

反聖嬰現象即將到來,對中部和南加州來說是個壞消息,那裡海拔較高的積雪可能減少、冬季風暴減少,可能延長今年的火災季節。當地的野火嚴重程度近來已創下紀錄。

氣候變遷
國際新聞
反聖嬰
颶風
野火

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

網頁設計最專業,超強功能平台可客製化

少砍樹啤酒就降價 巴西酒商護亞馬遜雨林

摘錄自2020年9月14日中央社報導

全球最大酒商安海斯-布希英博集團(AB InBev)旗下的巴西酒商美洲飲料公司(Ambev)推出了不尋常的新啤酒,將拯救亞馬遜雨林以及熱愛啤酒兩大訴求結合。

這款名為科羅拉多亞馬遜(Colorado Amazonica)的新啤酒,根據亞馬遜雨林的林木砍伐速度來定價。林木砍伐數量減少時,這種啤酒就會比較便宜,但林木越少,價格就越貴。所有收入將捐贈給亞馬遜地區的一個原住民、當地居民和小農耕種者社區網。

科羅拉多亞馬遜啤酒已在9月3日上市,售價約一美元,到了10日,價格已上漲46%。

氣候變遷
國際新聞
巴西
亞馬遜雨林

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

※教你寫出一流的銷售文案?

巴西大沼澤火災 美洲豹主要棲息地逾7成燒毀

摘錄自2020年9月16日中央社報導

位於巴西中西部馬托格羅索州大沼澤的水遇州立公園是全世界美洲豹最集中的地方,如今卻因森林火災蔓延,嚴重威脅美洲豹和其他物種的生存。

英國廣播公司巴西新聞網(BBC News Brasil)今(15日)報導,位於馬托格羅索州(Mato Grosso)占地10.8公頃的水遇州立公園(Parque Estadual Encontro dasÁguas),目前已有超過7成範圍被大火燒毀。

如同水遇州立公園,整個大沼澤(Pantanal)地區的火勢也迅速蔓延,迄今已燒毀逾230萬公頃林地,範圍相當於這整個生物群系在巴西15%的面積。

根據巴西國家太空署(Inpe),今年1月至9月初,大沼澤共記錄1.21萬處火災,創下1999年以來同期最高紀錄。

美洲豹已被國際自然保育聯盟(IUCN)和巴西環境部視為幾乎瀕危物種。根據研究,全球90%的美洲虎集中在南美洲。

巴西生物學家波柳薩(Ricardo Boulhosa)指出,這些火災是人為的,無法控制,所以變成森林大火,危害美洲豹的生存。

非政府組織Panthera研究員托爾塔托(Fernando Tortato)強調水遇州立公園的重要性,因為那裡一直是受保護的生態走廊,確保美洲豹的優質棲息地,園內有許多美洲豹可以觀察,有利於發展生態旅遊。

生物多樣性
國際新聞
巴西
大沼澤
美洲豹
動物棲地
森林野火

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※想知道最厲害的網頁設計公司"嚨底家"!

※別再煩惱如何寫文案,掌握八大原則!

※產品缺大量曝光嗎?你需要的是一流包裝設計!

這些低價高配的合資SUV,最低僅11萬不到!

67萬元在我們的印象中,法國人總喜歡在造型設計上大下筆墨,怎麼不實用怎麼來,所以大家都覺得很少會有一款法系車能與“性價比”沾邊。但是。從天逸C5 AIRCROSS開始情況似乎就有點不一樣了。這款緊湊型SUV不僅完美繼承了法系車飄逸的設計風格,並且在配置和價格上都算得上實在,這對於預算吃緊又想得到更多的消費者來說可是個好事。

不知大家有沒有覺得,15萬左右的購車預算是最尷尬的,說多不多,說少不少,尤其是在挑選SUV車型的時候,如今國產+合資一大堆選擇,看得眼花繚亂。

而隨着國產SUV的崛起,不少人也在鼓吹買國產車就是“低價高配”,這也使得很多對汽車不怎麼了解的消費者錯過了一些優秀的合資車型。那麼今天就要給大家介紹幾款極具性價比的合資品牌SUV,讓大家知道所謂的“低價高配”並不是國產車的專屬。

1、北京現代 全新ix35

官方指導價:11.58-18.88萬元

作為一款合資品牌車型,ix35的價格的確是非常給力了,最入門的車型在有些4S店僅11萬不到,實在是令人意想不到。而參考現代車一直以來的耐用性,ix35可以說就是目前市面上你能買到的價格最低,且總體表現最穩定的合資緊湊型SUV了。

從外形上看,新款車型在歷經換代后整體風格更加陽剛硬朗了,甚至還有點小硬漢的感覺。內飾也同樣如此,採用全新的設計和布局,而方正的造型也明顯與外觀呼應。

配置方面,全系標配ESp、上坡輔助、后駐車雷達等,中配及以上車型則相應增加了胎壓監測、陡坡緩降、無鑰匙進入/啟動、9.6英寸中控液晶显示屏(帶倒車雷達/影像)、自動大燈與電加熱/摺疊后視鏡等等。

考慮到其中配車型13.99萬元的售價,以合資品牌的標準看,這配置已經足夠厚道了。

動力方面,ix35全系均搭載了傳統的2.0L自然吸氣發動機,傳動上匹配6速手動或6速手自一體變速箱。雖然數據並不亮眼,但勝在性能成熟穩定,並且後期的使用故障率和維護成本都較低,所以從家用車SUV的角度來看,ix35無疑是一款非常省錢又省心的車型。

2、東風雪鐵龍 天逸C5 AIRCROSS

官方指導價:15.27-23.67萬元

在我們的印象中,法國人總喜歡在造型設計上大下筆墨,怎麼不實用怎麼來,所以大家都覺得很少會有一款法系車能與“性價比”沾邊。

但是!從天逸C5 AIRCROSS開始情況似乎就有點不一樣了。這款緊湊型SUV不僅完美繼承了法系車飄逸的設計風格,並且在配置和價格上都算得上實在,這對於預算吃緊又想得到更多的消費者來說可是個好事。

首先進入到車內,第一感覺就是讓你懷疑這根本就不是一輛售價僅15萬元起的SUV,因為無論是獨具一格的內飾設計,還是雙色皮革的搭配,都讓你感受到實實在在的質感提升。

配置上就更不用說了,除入門版車型外,其餘車型均配備了有多個安全氣囊、胎壓監測、全景天窗、無鑰匙進入/啟動、皮質多功能方向盤、全液晶儀錶盤、全車車窗一鍵升降、電加熱/摺疊后視鏡,自動大燈與自動空調等等,應有盡有!

所以對於一款法系車來說,天逸C5 AIRCROSS的確在“性價比”方面打了一場漂亮的翻身仗,也證明了美貌和實力是可以兼得的。

3、上汽斯柯達 柯珞克

預計售價:13.88萬起

斯柯達也是一個容易被人國內消費者忽略的品牌,所以最後推薦的就是近期即將上市的一款入門緊湊型SUV-柯珞克,而13.88萬的預售價格也十分值得期待。

在外形上,柯珞克採用了與柯迪亞克相同的家族式設計語言,中庸的造型適合絕大部分消費者。而在車身尺寸上,新車長寬高為4432/1841/1614mm,軸距為2688mm,也就是比繽智、昂科拉都要稍大一些。

動力上,新車搭載的是1.2T和1.4T發動機,匹配7速DSG雙離合變速箱,想想不到15萬就能買到這樣一款德系品質(大眾平台)SUV,是不是覺得自己賺了?所以野帝停產後,柯珞克或將成為大眾集團在15萬元左右SUV市場的主力車型。

好了!以上就是今天給大家推薦的三款15萬元左右、極具性價比的合資品牌SUV。大家如果還有其他想了解的購車話題,歡迎留言評論,盡量滿足大家需求。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

內在藏有硬實力!20萬起買這款SUV很超值!

發動機:1。8T/2。0T最大馬力(ps):180/186/220最大扭矩(Nm):300/320/350變速箱:7DCT驅動方式:前置前驅/前置四驅底盤懸挂:麥弗遜式獨立懸架/多連桿獨立懸挂動態表現應該算是車主們對柯迪亞克最滿意的一個方面吧。在此前的對比評測中,無論是加速、行駛平順性、油耗表現,還是剎車的成績,柯迪亞克都算得上是同級數一數二的水平。

曾經有不少想要買車的朋友說,20萬以下不買SUV,因為只有去到中型SUV的級別,才有SUV應有的空間和通過性。而現在市場上有許多合資中型SUV的空間真的讓人垂涎欲滴,比如日系的豐田漢蘭達和本田冠道,也有德系的大眾途觀L和美系的別克昂科威。選擇真的挺多。

然而在這麼多完美選擇之中,卻有人選擇了比較非主流的斯柯達-柯迪亞克,這車買得到底值不值?一起看看車主怎說吧!

長寬高:4698*1883*1676mm

軸距:2791mm

定位:中型SUV

雖然斯柯達在中國的品牌影響力比不上大眾或豐田這些一線品牌,可是在車型設計上也算不上遜色,車主們對整體外觀設計還是比較滿意的。前臉的“凹”字型中網是家族式設計比較顯著的特徵,上中貫穿着兩大燈,下進氣格柵很舒展,整體前臉比較霸氣;車身側面沒有太多設計亮點,不過整體還算協調,車尾設計也比較低調。

內飾風格很簡潔,很居家,大面積的木飾板看上去很有質感,儀錶盤採用的綠色點綴也是斯柯達比較標誌性的設計,個人感覺很具特色,呈現出比較“清新”的風格。柯迪亞克的外觀內飾設計沒有漢蘭達和冠道那麼具有吸引力,也可以體驗出車主們都比較喜歡低調點的風格。

發動機:1.8T/2.0T

最大馬力(ps):180/186/220

最大扭矩(Nm):300/320/350

變速箱:7DCT

驅動方式:前置前驅/前置四驅

底盤懸挂:麥弗遜式獨立懸架/多連桿獨立懸挂

動態表現應該算是車主們對柯迪亞克最滿意的一個方面吧。在此前的對比評測中,無論是加速、行駛平順性、油耗表現,還是剎車的成績,柯迪亞克都算得上是同級數一數二的水平。

1米8的試乘員坐在前排調整到舒適坐姿,頭部空間為4指,保持前排坐姿不變,同一位試乘員坐進後排,頭部空間為4指,腿部空間大於兩拳。在同級車型中,柯迪亞克的乘坐空間表現其實比較中庸,不過除了動力方面,車主們表示最為滿意的是其空間。不過一般的中型SUV,其實空間表現都能滿足大部分人的需求吧。

從車主口碑中,我們可以看出,動力和空間是車主們最滿意的方面,其外觀也是喜歡的人特別喜歡。而最不滿意的基本都是配置方面比較遜色。

如果從價位出發,柯迪亞克瞄準的競爭對手應該是昂科威和探界者,不過也比較難體現出競爭力,最主要還是在動力方面有一定的優勢。所以大多數選擇柯迪亞克的車主們都是奔着自己喜歡的外觀內飾,不錯的動力表現,以及相對於冠道和途觀L更低的售價。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

※推薦評價好的iphone維修中心