diff --git a/.gitignore b/.gitignore index f1538dd..db20e63 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ staged res.md dist *.spec -build \ No newline at end of file +build +!colorbar.ipynb \ No newline at end of file diff --git a/colorbar.ipynb b/colorbar.ipynb new file mode 100644 index 0000000..43a0afe --- /dev/null +++ b/colorbar.ipynb @@ -0,0 +1,165 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[0.050383, 0.029803, 0.527975, 1. ],\n", + " [0.063536, 0.028426, 0.533124, 1. ],\n", + " [0.075353, 0.027206, 0.538007, 1. ],\n", + " ...,\n", + " [0.944152, 0.961916, 0.146861, 1. ],\n", + " [0.941896, 0.96859 , 0.140956, 1. ],\n", + " [0.940015, 0.975158, 0.131326, 1. ]], shape=(256, 4))" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "import matplotlib as mpl\n", + "import numpy as np\n", + "\n", + "mpl.colormaps[\"plasma\"](np.linspace(0, 1, 256))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from matplotlib.colors import ListedColormap\n", + "import numpy as np\n" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/tmp/ipykernel_4058693/3103424214.py:42: UserWarning: set_ticklabels() should only be used with a fixed number of ticks, i.e. after set_ticks() or using a FixedLocator.\n", + " ax.set_xticklabels([format_spec % val for val in ax.get_xticks()])\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from matplotlib.colorbar import ColorbarBase\n", + "\n", + "\n", + "def create_colorbar(get_color, vmin=0, vmax=1, width=8, height=0.8, dpi=100, num_samples=256, \n", + " title=None, format_spec=\"%.2f\"):\n", + " \"\"\"\n", + " 创建自定义colorbar\n", + " \n", + " 参数:\n", + " get_color: 颜色映射函数,接受vmin-vmax之间的值,返回(r,g,b,a)颜色元组\n", + " vmin: colorbar最小值\n", + " vmax: colorbar最大值\n", + " width: 图像宽度\n", + " height: 图像高度\n", + " dpi: 图像分辨率\n", + " num_samples: 颜色采样数量\n", + " title: colorbar标题\n", + " format_spec: 刻度格式化字符串\n", + " \"\"\"\n", + " # 创建图形\n", + " fig, ax = plt.subplots(figsize=(width, height), dpi=dpi)\n", + " \n", + " # 生成颜色样本\n", + " colors = []\n", + " for i in range(num_samples):\n", + " # 计算实际值\n", + " value = vmin + (vmax - vmin) * (i / (num_samples - 1))\n", + " r, g, b, a = get_color(value)\n", + " colors.append((r, g, b, a))\n", + " \n", + " # 创建自定义colormap\n", + " custom_cmap = ListedColormap(colors)\n", + " \n", + " # 直接创建colorbar\n", + " ColorbarBase(ax, \n", + " cmap=custom_cmap,\n", + " orientation='horizontal',\n", + " norm=plt.Normalize(vmin, vmax))\n", + " \n", + " # 设置刻度数量和格式\n", + " ax.locator_params(nbins=5) # 设置大约5个刻度\n", + " ax.set_xticklabels([format_spec % val for val in ax.get_xticks()])\n", + " \n", + " # 设置标题(如果提供)\n", + " if title:\n", + " ax.set_title(title)\n", + " \n", + " # 调整布局\n", + " plt.tight_layout()\n", + " \n", + " return fig\n", + "\n", + "def get_color(value):\n", + " if value == 0:\n", + " return (0, 0, 0, 0)\n", + " result = mpl.colormaps[\"hot\"](value)\n", + " _res = tuple([int(255 * x) for x in result])\n", + " r, g, b, a = _res\n", + " # return (r, g, b, a)\n", + " return (result[0], result[1], result[2], value*3)\n", + "\n", + "create_colorbar(get_color, vmax=0.3, width=5)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "vertex", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/src/__init__.py b/src/__init__.py index ce67d09..8fcdc0a 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -2,6 +2,7 @@ from io import BytesIO from flask import Blueprint, request, send_file from src.plot import create_heatmap, find_centroids +from src.process_data import get_all_heat_points from src.read_tar import TarGet @@ -30,6 +31,19 @@ def render(): return send_file(buff, mimetype='image/png') +@tc_module.route("/render/heatpoint") +def get_points(): + path = request.args.get('path') + day = request.args.get('day') + tar = TarGet(path) + data = tar.read_dtcp() + data_this_day = data["data"][:, :, int(day)] + + result = get_all_heat_points(data_this_day, (0, -35)) + + return result + + @tc_module.route("/metadata/centroids") def get_centroids(): path = request.args.get('path') @@ -39,7 +53,11 @@ def get_centroids(): data_this_day = data["data"][:, :, int(day)] centords = find_centroids(data_this_day) - return centords + + def mapper(data): + x, y = data + return x, y-35 + return list(map(mapper, centords)) @tc_module.route("/metadata/tc") diff --git a/src/plot.py b/src/plot.py index 9722c1b..32aeb8b 100644 --- a/src/plot.py +++ b/src/plot.py @@ -2,15 +2,18 @@ import numpy as np from PIL import Image from scipy import ndimage +import matplotlib as mpl + +COLOR_MAPS = mpl.colormaps -def find_centroids(image): +def find_centroids(image, offset_result=(0, 0)): """ 找出图像中所有联通区域的重心 Args: image: 2D numpy array,值为0或非0 - + offset_result: 重心坐标的偏移量,用于将重心坐标转换为原始图像坐标 Returns: list of tuples: [(y1,x1), (y2,x2), ...] 表示每个联通区域的重心坐标 """ @@ -30,13 +33,15 @@ def find_centroids(image): centroid_y = np.average(y_coords, weights=weights) centroid_x = np.average(x_coords, weights=weights) - centroids.append((centroid_y, centroid_x)) + offset_x, offset_y = offset_result + + centroids.append((centroid_y + offset_y, centroid_x + offset_x)) return centroids def create_heatmap(data, - colormap='hot', + colormap='plasma', flip_vertical=False, flip_horizontal=False, rotate_90=0, @@ -47,7 +52,7 @@ def create_heatmap(data, 参数: data: 2D numpy array,值应该在0-1之间 - colormap: 颜色映射方案,目前支持'hot' + colormap: 颜色映射方案,目前支持'plasma' flip_vertical: 是否垂直翻转 flip_horizontal: 是否水平翻转 rotate_90: 顺时针旋转的90度次数 (0, 1, 2, 或 3) @@ -78,28 +83,25 @@ def create_heatmap(data, image = Image.new('RGBA', (width, height), (0, 0, 0, 0)) # 创建颜色映射 - if colormap == 'hot': - # 红色到黄色的渐变 - # 非线性变换,使得低值更容易区分。 使用 sqrt(x) 作为映射函数 - def get_color(value): - # 首先把原value从0~0.1映射到0~1。如果value大于0.1,就直接取1 - value = min(value / 0.4, 1) - if np.isnan(value): - return (0, 0, 0, 0) - r = int(min(255, np.sqrt(value) * 256)) - g = int(max(0, min(255, np.sqrt(value) * 256 - 256))) - return (r, g, 0, int(value * 255)) - # def get_color(value): - # if np.isnan(value): - # return (0, 0, 0, 0) - # r = int(min(255, value * 510)) - # g = int(max(0, min(255, value * 510 - 255))) - # return (r, g, 0, int(value * 255)) + if type(colormap) == str: + mapper = COLOR_MAPS[colormap] + if mapper is None: + raise ValueError('Invalid colormap name') + def get_color(value): + if value == 0: + return (0, 0, 0, 0) + result = mapper(value) + _res = tuple([int(255 * x) for x in result]) + r, g, b, _ = _res + return (r, g, b, min(int(value * 255 * 3), 255)) + else: + get_color = colormap # 填充像素 pixels = image.load() for y in range(height): for x in range(width): - pixels[x, y] = get_color(data[y, x]) + pixels[x, y] = get_color( + data[y, x]) return image diff --git a/src/process_data.py b/src/process_data.py index e69de29..e8d39e8 100644 --- a/src/process_data.py +++ b/src/process_data.py @@ -0,0 +1,31 @@ +from dataclasses import dataclass +from typing import List +import numpy as np + + +@dataclass +class HeatPoint: + lng: float + lat: float + count: int + + +def get_all_heat_points(data: np.ndarray, offset=(0, 0)) -> List[HeatPoint]: + """ + # filter all points that has value greater than 0 + + data: 2D numpy array + offset: tuple, the offset of the data + """ + # first, we need to filter all points that has value greater than 0 + + points = [] + for i in range(data.shape[0]): + for j in range(data.shape[1]): + if data[i, j] > 0: + if data[i, j] > 0: + points.append( + HeatPoint(lng=float(j+offset[1]+0.1), lat=float(i+offset[0]+0.1), count=int(data[i, j]*256+1))) + else: + continue + return list(filter(lambda d: d.count > 0, points))