feat: fix positions
This commit is contained in:
parent
a501342700
commit
35fe44339a
3
.gitignore
vendored
3
.gitignore
vendored
@ -7,4 +7,5 @@ staged
|
||||
res.md
|
||||
dist
|
||||
*.spec
|
||||
build
|
||||
build
|
||||
!colorbar.ipynb
|
||||
165
colorbar.ipynb
Normal file
165
colorbar.ipynb
Normal file
@ -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": [
|
||||
"<Figure size 500x80 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"execution_count": 35,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAeoAAABFCAYAAACFUKW1AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAACU9JREFUeJzt3U9IVO0XwPEzajMT+TcCJ8HUkJcgCiNRXPSHX0YLoRZFiyBqUy3alVCQ5SJIMSEhWgVRtEgqpBaFGFIbsYKwP6SIhYuCRmhRJqWWc97Fr5n3zswzo1dn9FG/H4ibzz1z7nOf53hP2mQeVVUBAABWyljoCQAAgMRo1AAAWIxGDQCAxWjUAABYjEYNAIDFaNQAAFiMRg0AgMWy5uMi4+PjMjk5OR+XAgBg3ni9XvH7/Wm9Rtob9fj4uJSVlUkwGEz3pQAAmFeBQECGh4fT2qzT3qgnJyclGAzKp0+fJCcnR0REVFXCPxAt9mgaSxavqiIzzBHJ9V9Q1NH0epnm2mrIEffD3pLch3ENpouJiTNe25Ajdixq7ZzXMb02wbVN8aa1k+nmEROT9H6deUw5EuVNsjemuZrWzjTHZDmcuTxJat50LnbMFOecS9y5RPsVzjPDecTFO2KN+5vgXKKxuPuZQbw4Po+N9x1zzrk3Ho1fkwxDjvDfC5rqIi6HSCSHaS1MNWmah4TzzGA9jfHhe3TOwzkW/ngmOQx1ZMohzhzhnEnio8b+HsPzyDTlMKxr3Fo7980wFndNZx5TfIL8sXszpir/CwZlcnJycTfqsNzcXHsadYKCX5BGnWAs6f0kiZ91o55mPWPPyXQ5Yu5NpptHeDzJfGI/yRKuXYL1iZpPzFxMc032h6Jp8xtyzblRm8Ycc5m3Ru0YW9BGnSiH4X5M8c77mXOjVkODcM4hyV7GnktJozaNhZMZ5pO2Rm3IkeHM8feY9kadYG/m2qglFJL5wJvJAACwGI0aAACL0agBALAYjRoAAIvRqAEAsBiNGgAAi9GoAQCwGI0aAACL0agBALAYjRoAAIvRqAEAsBiNGgAAi9GoAQCwGI0aAACL0agBALAYjRoAAIvRqAEAsBiNGgAAi9GoAQCwGI0aAACL0agBALAYjRoAAItlzdeFRkdHRVVFRERVo37vPJrGksWrqsgMc0Ry/RcUdTS9Xqa5thpyOPMkOpdsrtPeT0yc8dqGHLFjUWvnvI7ptQmubYo3rZ1MN4+YmKT368xjypEob5K9Mc3VtHamOSbL4czlSVLzpnOxY6Y451ziziXar3CeGc4jLt4Ra9zfBOcSjcXdzwzixfF5bLzvmHPOvfFo/JpkGHKEv4ox1UVcDpFIDtNamGrSNA8J55nBehrjw/fonIdzLPzxTHIY6siUQ5w5wjmTxEeN/T2G55FpymFY17i1du6bYSzums48pvgE+WP3ZiwmX7qkvVGrqmRnZ0txcXG6LwUAwLzKzs6O/wIgxdLeqD0ej4yNjcmnT58kNzc33ZfDEjY6OirFxcXUEuaEOkKqhGvJ4/FMHzwH8/at79zcXD4pkBLUElKBOsJiwZvJAACwGI0aAACLpb1R+3w+aWxsFJ/Pl+5LYYmjlpAK1BFSZb5qyaPpfrsaAACYNb71DQCAxWjUAABYjEYNAIDFaNQAAFiMRg0AgMVm1aivXbsmpaWl4vf7pbq6Wl6+fJk0/t69e7Jhwwbx+/2yadMmefz4cdR5VZULFy7I2rVrZeXKlVJbWytDQ0OzmRoWETd19P79e9m/f7+UlpaKx+ORtra2OefE0uFm369fvy7btm2TgoICKSgokNra2rh4nknLk5s66ujokMrKSsnPz5dVq1ZJRUWF3L59OyomZXWkLrW3t6vX69UbN27o+/fv9dixY5qfn68jIyPG+J6eHs3MzNSWlhbt7+/XhoYGXbFihb579y4S09zcrHl5efrgwQN98+aN7t27V8vKyvTXr19up4dFwm0dvXz5Uuvr6/XOnTsaCAT0ypUrc86JpcHtvh86dEivXbumfX19OjAwoEePHtW8vDz9/PlzJIZn0vLjto6ePn2qHR0d2t/frx8+fNC2tjbNzMzUzs7OSEyq6sh1o66qqtKTJ09GPp6amtKioiJtamoyxh88eFDr6uqixqqrq/XEiROqqhoKhTQQCOjly5cj5799+6Y+n0/v3LnjdnpYJNzWkVNJSYmxUc8lJxavue77nz9/NCcnR2/duqWqPJOWq1Q8P7Zs2aINDQ2qmto6cvWt78nJSXn16pXU1tZGxjIyMqS2tlZ6e3uNr+nt7Y2KFxHZs2dPJH54eFiCwWBUTF5enlRXVyfMicVtNnW0EDlhv1Ts+8+fP+X379+yevVqEeGZtBzNtY5UVbq7u2VwcFC2b98uIqmtI1eN+uvXrzI1NSWFhYVR44WFhRIMBo2vCQaDSePDRzc5sbjNpo4WIifsl4p9P3PmjBQVFUUeqDyTlp/Z1tH3798lOztbvF6v1NXVydWrV2X37t0ikto6mrf/5hIAbNPc3Czt7e3y7Nkz8fv9Cz0dLDI5OTny+vVrGRsbk+7ubjl16pSsX79edu7cmdLruPqKes2aNZKZmSkjIyNR4yMjIxIIBIyvCQQCSePDRzc5sbjNpo4WIifsN5d9b21tlebmZunq6pLNmzdHxnkmLT+zraOMjAwpLy+XiooKOX36tBw4cECamppEJLV15KpRe71e2bp1q3R3d0fGQqGQdHd3S01NjfE1NTU1UfEiIk+ePInEl5WVSSAQiIoZHR2VFy9eJMyJxW02dbQQOWG/2e57S0uLXLx4UTo7O6WysjLqHM+k5SdVz49QKCQTExMikuI6cvXWM/3/W9h9Pp/evHlT+/v79fjx45qfn6/BYFBVVQ8fPqxnz56NxPf09GhWVpa2trbqwMCANjY2Gv95Vn5+vj58+FDfvn2r+/bt459CLHFu62hiYkL7+vq0r69P165dq/X19drX16dDQ0MzzomlyW0tNTc3q9fr1fv37+uXL18iv378+BEVwzNpeXFbR5cuXdKuri79+PGj9vf3a2trq2ZlZen169cjMamqI9eNWlX16tWrum7dOvV6vVpVVaXPnz+PnNuxY4ceOXIkKv7u3bv6zz//qNfr1Y0bN+qjR4+izodCIT1//rwWFhaqz+fTXbt26eDg4GymhkXETR0NDw+riMT92rFjx4xzYulyU0slJSXGWmpsbIzE8ExantzU0blz57S8vFz9fr8WFBRoTU2Ntre3R+VLVR3x/1EDAGAxftY3AAAWo1EDAGAxGjUAABajUQMAYDEaNQAAFqNRAwBgMRo1AAAWo1EDAGAxGjUAABajUQMAYDEaNQAAFvsXykTRcs9n4VcAAAAASUVORK5CYII=",
|
||||
"text/plain": [
|
||||
"<Figure size 500x80 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"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
|
||||
}
|
||||
@ -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")
|
||||
|
||||
48
src/plot.py
48
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
|
||||
|
||||
@ -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))
|
||||
Loading…
x
Reference in New Issue
Block a user