Как построить термометр? - PullRequest
0 голосов
/ 20 февраля 2019

В последнем, очень широком вопросе был задан вопрос, как нанести на карту matplotlib несколько символов, таких как "круги, квадраты, прямоугольники, звезды, термометры и прямоугольники".Из этого списка все, кроме термометров, очевидны, как показано в документации или во многих существующих ответах на стекопотоки.Поскольку ОП вообще не интересовался термоментерами, я бы лучше задал новый вопрос именно о термометрах здесь.

Как построить термометры в matplotlib?

В принципе, вы можете нанести любой понравившийся вам символ, сделав его либо marker, либо Path.Там, кажется, нет никакого символа Unicode для термометров, хотя. Шрифт потрясающий имеет символ термометра и возможно нанесение символов FontAwesome в matplotlib .Тем не менее, есть только 5 различных заливок

enter image description here

Кроме того, цвет такого символа шрифта является однородным, хотя в идеале можно было бы иметь внутреннюю часть термометра(«ртутный столб») другого цвета (вероятно, в основном красного цвета по ассоциативным причинам) или других цветов, чтобы также кодировать температуру в цвете.

Таким образом, возможно, чтобы в значении температуры был ртутьСтолб кодирует температуру (или фактически любое другое количество) с точки зрения цвета и уровня наполнения?И если да, то как?

( Я дал ответ ниже, альтернативы или улучшения этого метода приветствуются в качестве дальнейших ответов здесь. )

1 Ответ

0 голосов
/ 20 февраля 2019

Можно построить термометр, состоящий из двух частей, для создания двух Path s: внешнего корпуса и внутреннего ртутного столба.Для этого можно создать пути с нуля и позволить внутреннему пути быть переменным в зависимости от (нормализованного) входного параметра.

Тогда можно построить оба пути как отдельные точечные диаграммы.Далее мы создадим класс, который имеет метод scatter, который работает аналогично обычному scatter, за исключением того, что он также принимает дополнительные аргументы temp для температуры и tempnorm для нормализации температуры на входе.

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.path as mpath

class TemperaturePlot():

    @staticmethod
    def get_hull():
        verts1 = np.array([[0,-128],[70,-128],[128,-70],[128,0],
                          [128,32.5],[115.8,61.5],[96,84.6],[96,288],
                          [96,341],[53,384],[0,384]])
        verts2 = verts1[:-1,:] * np.array([-1,1])
        codes1 = [1,4,4,4,4,4,4,2,4,4,4]
        verts3 = np.array([[0,-80],[44,-80],[80,-44],[80,0],
                          [80,34.3],[60.7,52],[48,66.5],[48,288],
                          [48,314],[26.5,336],[0,336]])
        verts4 = verts3[:-1,:] * np.array([-1,1])
        verts = np.concatenate((verts1, verts2[::-1], verts4, verts3[::-1]))
        codes = codes1 + codes1[::-1][:-1]
        return mpath.Path(verts/256., codes+codes)

    @staticmethod
    def get_mercury(s=1):
        a = 0; b = 64; c = 35
        d = 320 - b
        e = (1-s)*d
        verts1 = np.array([[a,-b],[c,-b],[b,-c],[b,a],[b,c],[c,b],[a,b]])
        verts2 = verts1[:-1,:] * np.array([-1,1])
        verts3 = np.array([[0,0],[32,0],[32,288-e],[32,305-e],
                           [17.5,320-e],[0,320-e]])
        verts4 = verts3[:-1,:] * np.array([-1,1])
        codes = [1] + [4]*12 + [1,2,2,4,4,4,4,4,4,2,2]
        verts = np.concatenate((verts1, verts2[::-1], verts3, verts4[::-1]))
        return mpath.Path(verts/256., codes)

    def scatter(self, x,y, temp=1, tempnorm=None, ax=None, **kwargs):
        self.ax = ax or plt.gca()
        temp = np.atleast_1d(temp)
        ec = kwargs.pop("edgecolor", "black")
        kwargs.update(linewidth=0)
        self.inner = self.ax.scatter(x,y, **kwargs)
        kwargs.update(c=None, facecolor=ec, edgecolor=None, color=None)
        self.outer = self.ax.scatter(x,y, **kwargs)
        self.outer.set_paths([self.get_hull()])
        if not tempnorm:
            mi, ma = np.nanmin(temp), np.nanmax(temp)
            if mi == ma:
                mi=0
            tempnorm = plt.Normalize(mi,ma)
        ipaths = [self.get_mercury(tempnorm(t)) for t in temp]
        self.inner.set_paths(ipaths)

Использование этого класса может выглядеть следующим образом:

plt.rcParams["figure.figsize"] = (5.5,3) 
plt.rcParams["figure.dpi"] = 72*3

fig, ax = plt.subplots()
p = TemperaturePlot()
p.scatter([.25,.5,.75], [.3,.4,.5], s=[800,1200,1600], temp=[28,39,35], color="C3",
          ax=ax, transform=ax.transAxes)

plt.show()

, где мы строим 3 термометра с разными температурами, изображенными заполнением столба «ртуть».Поскольку нормализация не указана, она нормализует температуры [28,39,35] между их минимальным и максимальным значениями.

enter image description here

Или мы можем использовать цвет (c) и temp для отображения температуры, как в

np.random.seed(42)
fig, ax = plt.subplots()
n = 42
x = np.linspace(0,100,n)
y = np.cumsum(np.random.randn(n))+5

ax.plot(x,y, color="darkgrey", lw=2.5)

p = TemperaturePlot()
p.scatter(x[::4],y[::4]+3, s=300, temp=y[::4], c=y[::4], edgecolor="k", cmap="RdYlBu_r")

ax.set_ylim(-6,18)
plt.show()

enter image description here

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