Форум программистов, компьютерный форум, киберфорум
Python: GUI, графика
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.75/8: Рейтинг темы: голосов - 8, средняя оценка - 4.75
 Аватар для Михалыч
1011 / 355 / 59
Регистрация: 28.02.2013
Сообщений: 939

Рисование heatmap (упростить код)

15.07.2022, 17:11. Показов 1839. Ответов 18

Студворк — интернет-сервис помощи студентам
Добрый день!

Есть набор данных размером 500 на 200 (сделал просто случайные):

Python
1
2
3
N = 500
M = 200
data = numpy.random.random((N, M))
Что бы представить данные в цвете использую свою функцию save_heat_map, которая создает соразмерный белый QPixmap (500 на 200), потом вызывает функцию create_heat_map, которая определяет максимальное значение от data и попиксельно раскрашивает пиксели в зависимости от значения из набора данных, т.е. каждому пикселю соответствует какое-то значение data (цвет пикселя (0,0) будет зависеть от data[0,0]). Затем файл (картинка с размером 500 на 200) с результатом сохраняется.

Вопрос: хорошо когда картинка 500 на 200, а не 5000 на 2000 =) как сделать быстрее? (цветовая гамма не важна)
Код:
Кликните здесь для просмотра всего текста
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import sys
from PySide2.QtGui import QPixmap, QColor
from PySide2.QtWidgets import QMainWindow, QApplication, QLabel, QHBoxLayout, QPushButton, QWidget
import numpy
 
# 1. Случайные числа в матрице N на M
N = 500
M = 200
data = numpy.random.random((N, M))
 
 
class MainWindow(QMainWindow):
 
    def __init__(self):
        super(MainWindow, self).__init__()
        self.title = "Image Viewer"
        self.setWindowTitle(self.title)
        central_widget = QWidget()
        box = QHBoxLayout()
        self.label = QLabel()
        self.button = QPushButton("Click me")
        self.button.clicked.connect(self.save_heat_map)
        box.addWidget(self.label)
        box.addWidget(self.button)
        central_widget.setLayout(box)
        self.setCentralWidget(central_widget)
 
    def save_heat_map(self):
        # создадим соразмерный pixmap_zone и сделаем его прозрачным
        pixmap_zone = QPixmap(N, M)
        pixmap_zone.fill(QColor(255, 255, 255, 255))
        # Нарисуем тепловую карту
        qimg_zone = pixmap_zone.toImage()
        heat_map = self.create_heat_map(data, N, M, qimg_zone)
        heat_map.save('test_output.png')
 
 
    def create_heat_map(self, arr, width: int, height: int, qimg_zone):
        max_el = arr.max()
        for x in range(width):
            for y in range(height):
                if arr[x, y] >= max_el:
                    qimg_zone.setPixelColor(x, y, QColor(255, 0, 0, 255))
                # красный
                elif max_el * 1.00 > arr[x, y] >= max_el * 0.90:
                    qimg_zone.setPixelColor(x, y, QColor(255, 10, 0, 255))
                # рыжий
                elif max_el * 0.90 > arr[x, y] >= max_el * 0.95:
                    qimg_zone.setPixelColor(x, y, QColor(255, 40, 0, 255))
                elif max_el * 0.95 > arr[x, y] >= max_el * 0.80:
                    qimg_zone.setPixelColor(x, y, QColor(255, 80, 0, 255))
                elif max_el * 0.80 > arr[x, y] >= max_el * 0.85:
                    qimg_zone.setPixelColor(x, y, QColor(255, 120, 0, 255))
                elif max_el * 0.85 > arr[x, y] >= max_el * 0.70:
                    qimg_zone.setPixelColor(x, y, QColor(255, 150, 0, 255))
                # желтый
                elif max_el * 0.70 > arr[x, y] >= max_el * 0.65:
                    qimg_zone.setPixelColor(x, y, QColor(255, 170, 0, 255))
                elif max_el * 0.65 > arr[x, y] >= max_el * 0.60:
                    qimg_zone.setPixelColor(x, y, QColor(255, 190, 0, 255))
                elif max_el * 0.60 > arr[x, y] >= max_el * 0.55:
                    qimg_zone.setPixelColor(x, y, QColor(255, 210, 0, 255))
                elif max_el * 0.55 > arr[x, y] >= max_el * 0.50:
                    qimg_zone.setPixelColor(x, y, QColor(255, 230, 0, 255))
                elif max_el * 0.50 > arr[x, y] >= max_el * 0.45:
                    qimg_zone.setPixelColor(x, y, QColor(255, 255, 0, 255))
                # салатовый
                elif max_el * 0.45 > arr[x, y] >= max_el * 0.475:
                    qimg_zone.setPixelColor(x, y, QColor(230, 255, 0, 255))
                elif max_el * 0.475 > arr[x, y] >= max_el * 0.450:
                    qimg_zone.setPixelColor(x, y, QColor(210, 255, 0, 255))
                elif max_el * 0.450 > arr[x, y] >= max_el * 0.425:
                    qimg_zone.setPixelColor(x, y, QColor(180, 255, 0, 255))
                elif max_el * 0.425 > arr[x, y] >= max_el * 0.400:
                    qimg_zone.setPixelColor(x, y, QColor(150, 255, 0, 255))
                # зеленый
                elif max_el * 0.400 > arr[x, y] >= max_el * 0.39:
                    qimg_zone.setPixelColor(x, y, QColor(100, 255, 0, 255))
                elif max_el * 0.39 > arr[x, y] >= max_el * 0.38:
                    qimg_zone.setPixelColor(x, y, QColor(70, 255, 0, 255))
                elif max_el * 0.38 > arr[x, y] >= max_el * 0.37:
                    qimg_zone.setPixelColor(x, y, QColor(40, 255, 0, 255))
                elif max_el * 0.37 > arr[x, y] >= max_el * 0.36:
                    qimg_zone.setPixelColor(x, y, QColor(10, 255, 0, 255))
                elif max_el * 0.36 > arr[x, y] >= max_el * 0.35:
                    qimg_zone.setPixelColor(x, y, QColor(0, 255, 0, 255))
 
                # голубой
                elif max_el * 0.35 > arr[x, y] >= max_el * 0.245:
                    qimg_zone.setPixelColor(x, y, QColor(0, 255, 40, 255))
                elif max_el * 0.245 > arr[x, y] >= max_el * 0.240:
                    qimg_zone.setPixelColor(x, y, QColor(0, 255, 80, 255))
                elif max_el * 0.240 > arr[x, y] >= max_el * 0.235:
                    qimg_zone.setPixelColor(x, y, QColor(0, 255, 100, 255))
                elif max_el * 0.235 > arr[x, y] >= max_el * 0.23:
                    qimg_zone.setPixelColor(x, y, QColor(0, 255, 120, 255))
                elif max_el * 0.23 > arr[x, y] >= max_el * 0.225:
                    qimg_zone.setPixelColor(x, y, QColor(0, 255, 150, 255))
                elif max_el * 0.225 > arr[x, y] >= max_el * 0.22:
                    qimg_zone.setPixelColor(x, y, QColor(0, 255, 210, 255))
                elif max_el * 0.22 > arr[x, y] >= max_el * 0.215:
                    qimg_zone.setPixelColor(x, y, QColor(0, 255, 240, 255))
                elif max_el * 0.215 > arr[x, y] >= max_el * 0.21:
                    qimg_zone.setPixelColor(x, y, QColor(0, 255, 255, 255))
 
                # темно-голубой
                elif max_el * 0.21 > arr[x, y] >= max_el * 0.19:
                    qimg_zone.setPixelColor(x, y, QColor(0, 220, 255, 255))
                elif max_el * 0.19 > arr[x, y] >= max_el * 0.18:
                    qimg_zone.setPixelColor(x, y, QColor(0, 210, 255, 255))
                elif max_el * 0.18 > arr[x, y] >= max_el * 0.17:
                    qimg_zone.setPixelColor(x, y, QColor(0, 200, 255, 255))
                elif max_el * 0.17 > arr[x, y] >= max_el * 0.16:
                    qimg_zone.setPixelColor(x, y, QColor(0, 190, 255, 255))
                elif max_el * 0.16 > arr[x, y] >= max_el * 0.15:
                    qimg_zone.setPixelColor(x, y, QColor(0, 160, 255, 255))
                elif max_el * 0.15 > arr[x, y] >= max_el * 0.14:
                    qimg_zone.setPixelColor(x, y, QColor(0, 150, 255, 255))
                #     синий
                elif max_el * 0.14 > arr[x, y] >= max_el * 0.13:
                    qimg_zone.setPixelColor(x, y, QColor(0, 130, 255, 255))
                elif max_el * 0.13 > arr[x, y] >= max_el * 0.125:
                    qimg_zone.setPixelColor(x, y, QColor(0, 110, 255, 255))
                elif max_el * 0.125 > arr[x, y] >= max_el * 0.115:
                    qimg_zone.setPixelColor(x, y, QColor(0, 90, 255, 255))
                elif max_el * 0.115 > arr[x, y] >= max_el * 0.11:
                    qimg_zone.setPixelColor(x, y, QColor(0, 70, 255, 255))
                elif max_el * 0.11 > arr[x, y] >= max_el * 0.108:
                    qimg_zone.setPixelColor(x, y, QColor(0, 50, 255, 255))
                elif max_el * 0.108 > arr[x, y] >= max_el * 0.107:
                    qimg_zone.setPixelColor(x, y, QColor(0, 40, 255, 255))
                elif max_el * 0.107 > arr[x, y] >= max_el * 0.106:
                    qimg_zone.setPixelColor(x, y, QColor(0, 30, 255, 255))
                elif max_el * 0.106 > arr[x, y] >= max_el * 0.102:
                    qimg_zone.setPixelColor(x, y, QColor(0, 20, 255, 255))
                elif max_el * 0.102 > arr[x, y] >= max_el * 0.101:
                    qimg_zone.setPixelColor(x, y, QColor(0, 0, 255, 255))
        return qimg_zone
 
 
if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())


Добавлено через 2 минуты
PS. У меня есть мысль, что на основе data можно сделать heatmap через plotly (или чем-то похожим), но никак не получается получить результат идентичный моему коду, т.е. картинку 500 на 200...
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
15.07.2022, 17:11
Ответы с готовыми решениями:

Инвертировать цвета в pandas heatmap
Как инвертировать цвета в pandas heatmap относительно 0. Или по крайней мере сделать черное светлее. скрин здесь: ...

можно ли упростить этот код ,код не мой просто нужно чтобы он был проще)
#include <iostream> #include <cmath> #include <string> #include <cstdlib> #include <ctime> #include <iomanip> #include...

Heatmap на gnuplot
Не знаю, где еще можно разместить эту тему, если что заранее извиняюсь:sorry: Пытаюсь нарисовать температурную карту по матрице...

18
1472 / 827 / 140
Регистрация: 12.10.2013
Сообщений: 5,456
15.07.2022, 17:47
Не проще в поисковике набрать типа heatmap python example?
Выпало такое https://seaborn.pydata.org/gen... atmap.html
1
 Аватар для Михалыч
1011 / 355 / 59
Регистрация: 28.02.2013
Сообщений: 939
15.07.2022, 20:46  [ТС]
Цитата Сообщение от Михалыч Посмотреть сообщение
S. У меня есть мысль, что на основе data можно сделать heatmap через plotly (или чем-то похожим), но никак не получается получить результат идентичный моему коду, т.е. картинку 500 на 200.
Excalibur921, проще, если нужно просто визуализировать, а мне надо что бы получаемая картинка была именно размером в пикселях, такая же как и исходные данные (я ее потом на карту накладываю с прозрачностью). Т.е. если матрица 500 на 200, то и картинка должна быть 500 на 200, что бы:
Цитата Сообщение от Михалыч Посмотреть сообщение
каждому пикселю соответствует какое-то значение data (цвет пикселя (0,0) будет зависеть от data[0,0])
Я пробовал такое сделать plotly, mathplotlib... Выходит немного не то, т.е. я никак не могу получить картинку без полей именно размера 500 на 200, без осей и прочего (отступов, рамок и пр).

Если кто-то сможет сделать по этим данным, что бы на выходе сохранялось изображение аналогичное коду выше, через что-то еще, то я буду очень благодарен)
0
Просто Лис
Эксперт Python
 Аватар для Рыжий Лис
5973 / 3735 / 1099
Регистрация: 17.05.2012
Сообщений: 10,791
Записей в блоге: 9
16.07.2022, 08:40

Не по теме:

Downloading PySide2-5.15.2.1-5.15.2-cp35.cp36.cp37.cp38.cp39.cp310-abi3-manylinux1_x86_64.whl (164.3 MB)

Что-то библиотека дохрена весит



Добавлено через 1 минуту
Не проще картинку в png нарисовать?
0
5516 / 2869 / 571
Регистрация: 07.11.2019
Сообщений: 4,760
16.07.2022, 09:20
Лучший ответ Сообщение было отмечено Рыжий Лис как решение

Решение

Михалыч, попробуйте что-то такое:
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import numpy as np
from PIL import Image
N = 500
M = 200
data = numpy.random.random((N, M))
bins = np.array([0.00, 0.10, 0.15, 0.25, 0.30, 0.40, 0.6, 0.8, 0.95])
palette=np.array([[0, 30, 255, 255], [0, 80, 255, 255],[0, 100, 255, 255], 
                  [0, 255, 255, 255], [20, 255, 255, 255],[100, 100, 255, 255], 
                  [200, 50, 255, 255], [255, 255, 100, 255],[255, 255, 0, 255]]) 
digitize=np.digitize(data, bins, right=True)
digitize = np.expand_dims(digitize, axis=2)
im=np.choose(digitize, palette, mode='clip' )
im=np.uint8(im)
PIL_image = Image.fromarray(np.uint8(im)).convert('RGBA')
PIL_image.save('out_.png')
Я не знаю, как лучше преобразовать np.array в QImage, т.к. практически не работал с PyQt, поэтому воспользовался PIL.
Кстати, палитру можно не забивать в программу, а хранить в виде png файла, размером nx1 пиксель, где n -число цветов.

Добавлено через 15 минут
Михалыч, еще особенность:
для x<=0 - palette[0],
для 0<x<=0.1 - palette[1]
и т. д.
Если ваши данные не лежат в диапазоне 0..1, то нужно произвести их шкалирование (MinMax scaler). Или менять bins на нужные вам.
для тестов можно так проверять что все нормально, а не random
Python
1
data = 0.34*np.ones((N, M))
0.34 - проверочное значение.
2
 Аватар для Михалыч
1011 / 355 / 59
Регистрация: 28.02.2013
Сообщений: 939
16.07.2022, 22:31  [ТС]
u235, благодарю, очень элегантное решение
1
 Аватар для Михалыч
1011 / 355 / 59
Регистрация: 28.02.2013
Сообщений: 939
17.07.2022, 06:38  [ТС]
Лучший ответ Сообщение было отмечено u235 как решение

Решение

Для себя (через QImage):

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import sys
from PySide2.QtGui import QPixmap, QImage
from PySide2.QtWidgets import QMainWindow, QApplication, QLabel, QHBoxLayout, QPushButton, QWidget
import numpy as np
 
# 1. Случайные числа в матрице N на M
N = 50
M = 20
data = np.random.random((N, M))
bins = np.array([0.00, 0.10, 0.15, 0.25, 0.30, 0.40, 0.6, 0.8, 0.95])
palette = np.array([[0, 30, 255], [0, 80, 255], [0, 100, 255],
                    [0, 255, 255], [20, 255, 255], [100, 100, 255],
                    [200, 50, 255], [255, 255, 100], [255, 255, 0]])
 
 
class MainWindow(QMainWindow):
 
    def __init__(self):
        super(MainWindow, self).__init__()
        self.title = "Image Viewer"
        self.setWindowTitle(self.title)
        central_widget = QWidget()
        box = QHBoxLayout()
        self.label = QLabel()
        self.button = QPushButton("Click me")
        self.button.clicked.connect(self.save_heat_map)
        box.addWidget(self.label)
        box.addWidget(self.button)
        central_widget.setLayout(box)
        self.setCentralWidget(central_widget)
 
    def save_heat_map(self):
        digitize = np.digitize(data, bins, right=True)
        digitize = np.expand_dims(digitize, axis=2)
        im = np.choose(digitize, palette, mode='clip')
        im = np.uint8(im)
        h, w, _ = im.shape
        heat_map = QPixmap(QImage(im, w, h, 3 * w, QImage.Format_RGB888))
        heat_map.save('test_output.png')
 
 
if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())
1
5516 / 2869 / 571
Регистрация: 07.11.2019
Сообщений: 4,760
17.07.2022, 06:56
Михалыч, если в 13 строке перед закрывающейся скобкой добавить , dtype='uint8' , то 36 строка будет не нужна и сэкономится память.
Цитата Сообщение от Михалыч Посмотреть сообщение
QImage.Format_RGB888
не уверен, но разве прозрачность не нужна? Может что-то типа: Format_ARGB32?

Добавлено через 7 минут
Михалыч, а, все понял, у вас раньше с палитра с прозрачностью была, а сейчас без. Не обратил внимание.
1
 Аватар для Михалыч
1011 / 355 / 59
Регистрация: 28.02.2013
Сообщений: 939
17.07.2022, 07:13  [ТС]
Спасибо!)
Цитата Сообщение от u235 Посмотреть сообщение
и сэкономится память
Очень полезное замечание
Цитата Сообщение от u235 Посмотреть сообщение
но разве прозрачность не нужна?
Нужна))) Просто не до конца еще разобрался с конструктором QImage, а это QImage.Format_RGB888 единственное что нашел в google из работающих примеров, которые подошли А вектор копания я понял)
Вы мне и так уже времени сэкономили первоначальный вариант на картинках с которыми работаю занимал 10-15 минут и ладно заказчик не требовательный (самому себе предъявлять же не будешь, работает и уже хорошо).
0
5516 / 2869 / 571
Регистрация: 07.11.2019
Сообщений: 4,760
17.07.2022, 09:05
Вот с прозрачностью :
Кликните здесь для просмотра всего текста
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import sys
from PySide2.QtGui import QPixmap, QImage
from PySide2.QtWidgets import QMainWindow, QApplication, QLabel, QHBoxLayout, QPushButton, QWidget
import numpy as np
 
# 1. Случайные числа в матрице N на M
N = 500
M = 200
data = np.random.random((N, M))
bins = np.array([0.00, 0.10, 0.15, 0.25, 0.30, 0.40, 0.6, 0.8, 0.95])
palette = np.array([[0, 30, 255, 255], [0, 80, 255, 255], [0, 100, 255, 255],
                    [0, 255, 255, 255], [20, 255, 255, 255], [100, 100, 255, 255],
                    [200, 50, 255, 255], [255, 255, 100, 255], [255, 255, 0, 255]], dtype='uint8')
palette[:,[0,2]]=palette[:,[2,0]] #swap channel for Format_ARGB32
 
 
class MainWindow(QMainWindow):
 
    def __init__(self):
        super(MainWindow, self).__init__()
        self.title = "Image Viewer"
        self.setWindowTitle(self.title)
        central_widget = QWidget()
        box = QHBoxLayout()
        self.label = QLabel()
        self.button = QPushButton("Click me")
        self.button.clicked.connect(self.save_heat_map)
        box.addWidget(self.label)
        box.addWidget(self.button)
        central_widget.setLayout(box)
        self.setCentralWidget(central_widget)
 
    def save_heat_map(self):
        digitize = np.digitize(data, bins, right=True)
        digitize = np.expand_dims(digitize, axis=2)
        im = np.choose(digitize, palette, mode='clip')
        h, w, _ = im.shape
        #heat_map = QPixmap(QImage(im, w, h, 4 * w, QImage.Format_ARGB32))
        heat_map=QImage(im, w, h, 4 * w, QImage.Format_ARGB32)
        heat_map.save('test_output.png')
 
 
if __name__ == '__main__':
    app = QApplication.instance()
    if app is None: 
        app = QApplication(sys.argv)
    w = MainWindow()
    w.show()
    app.exec_()
    sys.exit()

Qpixmap сохраняется без прозрачности, а QImage - с прозрачностью. И пришлось одной строчкой переставить каналы в палитре.
Еще, если вы зараннее приведете ваши данные float к диапазону 0-255 в uint8 (картинке в оттенках серого), то дальше можно очень быстро применить палитру. Операция называется color look up table (CLUT). см., например в ImageMagick https://imagemagick.org/Usage/color_mods/#clut или в OpenCV cv.LUT().
Успехов вам!
1
 Аватар для Михалыч
1011 / 355 / 59
Регистрация: 28.02.2013
Сообщений: 939
17.07.2022, 16:45  [ТС]
Цитата Сообщение от u235 Посмотреть сообщение
И пришлось одной строчкой переставить каналы в палитре.
Цитата Сообщение от u235 Посмотреть сообщение
palette[:,[0,2]]=palette[:,[2,0]] #swap channel for Format_ARGB32
Именно то из-за чего я простил до не прозрачной картинки) Спасибо рабочий пример и подробное объяснение!
0
5516 / 2869 / 571
Регистрация: 07.11.2019
Сообщений: 4,760
22.08.2022, 21:27
Михалыч, продолжаем ускорять
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import numpy as np
import cv2
 
N = 5000
M = 5000
# тестовые данные в матрице N на M
data=np.tile(np.linspace(0,1,M), (N,1))
# данные в диапазоне 0..1
 
bins = np.array([0.00, 0.10, 0.15, 0.25, 0.30, 0.40, 0.6, 0.8, 0.95])
palette = np.array([[255, 0, 0, 255], [0, 80, 255, 255], [0, 100, 255, 255],
                    [0, 255, 255, 255], [20, 255, 255, 255], [100, 100, 255, 255],
                    [200, 50, 255, 255], [255, 255, 100, 255], [255, 255, 0, 255]], dtype='uint8')
palette[:, [0, 2]] = palette[:, [2, 0]]  # swap channel for Format_ARGB32
 
# вариант с LUT:
data=np.uint8(255*data)
bins=np.uint8(255*bins)
 
# создаем 4-канальные данные для LUT, просто повтор канала
data=cv2.merge([data]*4)
 
gradient=np.digitize(np.arange(256), bins, right=False)-1
gradient = np.expand_dims(gradient, axis=1)
 
palette_cv2 = np.choose(gradient, palette, mode='clip')
palette_cv2=np.expand_dims(palette_cv2 , axis=0)
 
heat_map=cv2.LUT(data, palette_cv2)
 
cv2.imwrite('test_outputLUT.png', heat_map)
Ускорение у меня примерно в 27 раз.
1
 Аватар для Михалыч
1011 / 355 / 59
Регистрация: 28.02.2013
Сообщений: 939
23.08.2022, 15:29  [ТС]
Цитата Сообщение от u235 Посмотреть сообщение
Ускорение у меня примерно в 27 раз.
что мне теперь, совсем на работе не работать? (я обычно сидел и ждал когда посчитает)

Добавлено через 1 час 16 минут
u235, спасибо!) Придется осваивать opencv
0
1472 / 827 / 140
Регистрация: 12.10.2013
Сообщений: 5,456
24.08.2022, 08:59
В приличных мат пакетах тепловая карта строиться одной строкой. Видимо тут еще не эволюционировали до этого. Вообще если нужна скорость то это не к питону т.к. интерпретируемые языки не для этого. Наверняка есть код расчета этого на видеокарте практически в реальном времени. Еще вроде есть компиляция кода.
1
5516 / 2869 / 571
Регистрация: 07.11.2019
Сообщений: 4,760
24.08.2022, 19:05
Цитата Сообщение от Excalibur921 Посмотреть сообщение
В приличных мат пакетах тепловая карта строиться одной строкой.
Тут кастомная тепловая карта, неравномерная в общем случае и с прозрачностью.
Для стандартных палитр действительно можно одной строкой типа:
Python
1
heatmap = cv2.applyColorMap(np.uint8(255 * data), cv2.COLORMAP_JET)
примерно как
Matlab M
1
2
imagesc(data);
colormap jet;
в Matlab.

Михалыч, если у вас bins и palette не меняются, то можно сохранить палитру в png (добавить в конце строку):
Python
1
cv2.imwrite('paletteLUT.png', palette_cv2)
, и тогда код упрощается:
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import numpy as np
import cv2
 
N = 5000
M = 5000
# тестовые данные в матрице N на M
# данные в диапазоне 0..1
data=np.tile(np.linspace(0,1,M), (N,1))
 
# нормализация данных
data = cv2.normalize(src=data, dst=None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)
# создаем 4-канальные данные для LUT, просто повтор канала
data=cv2.merge([data]*4)
# загружаем палитру:
palette_cv2=cv2.imread('paletteLUT.png', cv2.IMREAD_UNCHANGED)
# создание тепловой карты
heat_map=cv2.LUT(data, palette_cv2)
cv2.imwrite('test_outputLUT.png', heat_map)
P.S. с нормализацией осторожно, подразумевается что минимальное значение в данных равно 0, а максимальное 1.
если это не так, то надо использовать другой тип нормализации.

Добавлено через 8 минут
P.S.S. у меня было 0.15 сек, стало 0.10 сек это процесс расчета heatmap без генерации тестовых данных и сохранения результата.
1
Эксперт Python
 Аватар для dondublon
4653 / 2073 / 366
Регистрация: 17.03.2012
Сообщений: 10,183
Записей в блоге: 6
25.08.2022, 11:02
Цитата Сообщение от Excalibur921 Посмотреть сообщение
В приличных мат пакетах тепловая карта строиться одной строкой. Видимо тут еще не эволюционировали до этого.
Тепловая карта строится, matplotlib - одной строкой, не считая импортов. Тут нужно было изображение 1:1 попиксельно, поэтому так.
Цитата Сообщение от Excalibur921 Посмотреть сообщение
Вообще если нужна скорость то это не к питону т.к. интерпретируемые языки не для этого.
Для питона есть numpy, спускает операции на массивах на низкий уровень (С).
1
1472 / 827 / 140
Регистрация: 12.10.2013
Сообщений: 5,456
25.08.2022, 11:07
Если нужна скорость берут уже компилируемый язык типа С++.
Если нужно еще больше скорость то уже спец язык шейдеры и GPU.
0
Эксперт Python
 Аватар для dondublon
4653 / 2073 / 366
Регистрация: 17.03.2012
Сообщений: 10,183
Записей в блоге: 6
25.08.2022, 11:38
Excalibur921, numpy - это и есть С++, легко подключаемый к питону. Большую часть типичных операций он вполне вытягивает, по логике. Ну и другие либы, в которых тоже внутри С++ (scipy etc.). Если он с чем-то не справляется - тогда уж имеет смысл наваять что-то самописное на С++, но это довольно редко может понадобится. Конечно, зависит от задач. Поверьте, я достаточно позанимался числодробилками на питоне, чтобы так утверждать.
Цитата Сообщение от Excalibur921 Посмотреть сообщение
Если нужно еще больше скорость то уже спец язык шейдеры и GPU.
Это уже сложно и имеет свои ограничения по логике - примерно те же, что и для numpy.
1
 Аватар для Михалыч
1011 / 355 / 59
Регистрация: 28.02.2013
Сообщений: 939
25.08.2022, 12:49  [ТС]
Цитата Сообщение от Excalibur921 Посмотреть сообщение
Вообще если нужна скорость то это не к питону т.к. интерпретируемые языки не для этого.
Так я и на С++ могу такое написать, что тоже ждать придется (в смысле качество моего кода будет такое, что С++ не переживет позора, захочет удалиться с моего компа)

Я конечно не занимался много "числодробилками на питоне" как dondublon, но в моем случае в большинстве случаев скорость работы моих программ зависит не от выбора языка или пр., скорее от неверного алгоритма и не рационального применения/не применения библиотек python.

Пока мне помогает выложить свой код на суд более опытных товарищей, это быстрее чем выучить C++

Цитата Сообщение от Excalibur921 Посмотреть сообщение
Наверняка есть код расчета этого на видеокарте практически в реальном времени
Может и я когда-нибудь к этому приду)
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
25.08.2022, 12:49
Помогаю со студенческими работами здесь

highcharts heatmap
Здравствуйте. Можно ли что то подобное сделать с помощью highcharts? Я делаю, но получается только покрытия всех данных. Можно ли как то...

Карты Heatmap
штурмую интернеты в поисках удобной тепловой карты для коммерческого использования, но так что б бесплатно и юристы не натянули. кто-нибудь...

Библиотека plotly, heatmap
Здравствуйте, у меня три вопроса по python-библиотеке plotly. Я составляю тепловую карту (heatmap) и недостаточно понимаю документацию. ...

Pandas. Dataframe. sns.heatmap - Отрисовка результата
Ребята, выручайте. Несколько дней голову ломаю, не могу решить проблему.В питоне я новичок. Код пишу в Notebook Jupyter Вообщем вот...

Создание аналога HeatMap GnuPlot или MatLab
Уважаемые товарищи! Может кто-нибудь подсказать как реализовать в приложении визуализацию получаемых данных. Суть в следующем - имеется...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
19
Ответ Создать тему
Новые блоги и статьи
делаю науч статью по влиянию грибов на сукцессию
anaschu 13.03.2026
прикрепляю статью
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога Финальные проекты на Си и на C++: hello-sdl3-c. zip hello-sdl3-cpp. zip Результат:
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд. Даже если у вас. . .
Модульная разработка через nuget packages
DevAlt 07.03.2026
Сложившийся в . Net-среде способ разработки чаще всего предполагает монорепозиторий в котором находятся все исходники. При создании нового решения, мы просто добавляем нужные проекты и имеем. . .
Модульный подход на примере F#
DevAlt 06.03.2026
В блоге дяди Боба наткнулся на такое определение: В этой книге («Подход, основанный на вариантах использования») Ивар утверждает, что архитектура программного обеспечения — это структуры,. . .
Управление камерой с помощью скрипта OrbitControls.js на Three.js: Вращение, зум и панорамирование
8Observer8 05.03.2026
Содержание блога Финальная демка в браузере работает на Desktop и мобильных браузерах. Итоговый код: orbit-controls-threejs-js. zip. Сканируйте QR-код на мобильном. Вращайте камеру одним пальцем,. . .
SDL3 для Web (WebAssembly): Синхронизация спрайтов SDL3 и тел Box2D
8Observer8 04.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-sync-physics-sprites-sdl3-c. zip На первой гифке отладочные линии отключены, а на второй включены:. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru