import pandas as pd
import folium
from folium import plugins
import random
from nicegui import ui
import os
import webbrowser
from pathlib import Path
def generate_mock_data():
locations = []
base_lat = 23.122373
base_lon = 113.268027
for i in range(100):
lat = base_lat + random.uniform(-0.1, 0.1)
lon = base_lon + random.uniform(-0.1, 0.1)
locations.append({'lat': lat, 'lon': lon})
return pd.DataFrame(locations)
def generate_heatmap_html():
data = generate_mock_data()
heatmap1 = folium.Map(
location=[23.122373, 113.268027],
zoom_start=10,
control_scale=True,
tiles='http://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}',
attr='© <a href="http://ditu.amap.com/">高德地图</a>'
)
folium.Marker(
[23.122373, 113.268027],
popup='<i>中心点</i>',
icon=folium.Icon(icon='cloud', color='green')
).add_to(heatmap1)
if 'lat' in data.columns and 'lon' in data.columns:
heat_data = [[row["lat"], row["lon"]] for index, row in data.iterrows()]
heatmap_layer = plugins.HeatMap(heat_data)
heatmap1.add_child(heatmap_layer)
else:
print("错误:数据中缺少 lat 或 lon 列")
print("数据列名:", data.columns.tolist())
temp_file = 'temp_heatmap.html'
heatmap1.save(temp_file)
return temp_file
@ui.page('/')
def main():
ui.label('热力图可视化').classes('text-2xl font-bold')
def show_heatmap():
html_file = generate_heatmap_html()
webbrowser.open(f'file://{os.path.abspath(html_file)}')
ui.notify(f'热力图已生成并打开:{html_file}')
ui.button('生成并查看热力图', on_click=show_heatmap).classes('mt-4')
data = generate_mock_data()
ui.label(f'模拟数据点数量:{len(data)}').classes('mt-4')
ui.label('前 5 行数据预览:').classes('mt-4')
columns = [
{'name':'index','label':'Index','field':'index'},
{'name':'lat','label':'纬度','field':'lat'},
{'name':'lon','label':'经度','field':'lon'}
]
rows = [
{'index': i,'lat': row['lat'],'lon': row['lon']}
for i,(idx, row) in enumerate(data.head().iterrows())
]
ui.table(columns=columns, rows=rows).classes('w-full')
if __name__ in {"__main__","__mp_main__"}:
ui.run(title='热力图可视化应用', port=8080, reload=True)
import pandas as pd
import folium
from folium import plugins
import random
from nicegui import ui
import os
import webbrowser
from pathlib import Path
import numpy as np
import base64
from io import BytesIO
def generate_mock_data():
locations = []
base_lat = 23.122373
base_lon = 113.268027
for i in range(100):
lat = base_lat + random.uniform(-0.1, 0.1)
lon = base_lon + random.uniform(-0.1, 0.1)
value = random.uniform(1, 100)
locations.append({'lat': lat, 'lon': lon, 'value': value})
return pd.DataFrame(locations)
def generate_heatmap_base64():
data = generate_mock_data()
heatmap1 = folium.Map(
location=[23.122373, 113.268027],
zoom_start=10,
control_scale=True,
tiles='http://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}',
attr='© <a href="http://ditu.amap.com/">高德地图</a>',
style='background-color: #4B0082;'
)
folium.Marker(
[23.122373, 113.268027],
popup='<i>中心点</i>',
icon=folium.Icon(icon='cloud', color='green')
).add_to(heatmap1)
for idx, row in data.iterrows():
svg_bar_html = create_svg_bar(row['value'])
bar_width = 9
bar_height = max(int(row['value']/5)*6, 30)+4
if bar_height < 34:
bar_height = 34
icon = folium.DivIcon(
html=svg_bar_html,
icon_size=(bar_width, bar_height),
icon_anchor=(bar_width // 2, bar_height // 2)
)
folium.Marker(
[row['lat'], row['lon']],
icon=icon,
popup=f"数值:{row['value']:.2f}"
).add_to(heatmap1)
add_smooth_color_legend(heatmap1)
map_html = heatmap1._repr_html_()
return map_html
def create_svg_bar(value):
width = 5
height = max(int(value / 5)*6, 30)
border_width = 2
svg_width = width + 2 * border_width
svg_height = height + 2 * border_width
gradient_id = f"grad_{int(value * 100)}"
gradient_html = f'''
<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient x1="0%" y1="100%" x2="0%" y2="0%">
'''
num_steps = 20
for i in range(num_steps + 1):
stop_value = (i / num_steps) * value
color = get_smooth_color_by_value(stop_value)
offset = i / num_steps
gradient_html += f'<stop offset="{offset * 100}%" stop-color="{color}" />\n'
gradient_html += f'''
</linearGradient>
</defs>
<rect x="{border_width}" y="{border_width}" fill="url(#{gradient_id})" stroke="yellow" stroke-width="{border_width}"/>
</svg>
'''
return gradient_html
def get_smooth_color_by_value(value):
normalized_value = min(max(value / 100.0, 0), 1)
hue = normalized_value * 300
h = hue / 60.0
c = 1.0
x = c * (1 - abs(h % 2 - 1))
if 0 <= h < 1:
r, g, b = c, x, 0
elif 1 <= h < 2:
r, g, b = x, c, 0
elif 2 <= h < 3:
r, g, b = 0, c, x
elif 3 <= h < 4:
r, g, b = 0, x, c
elif 4 <= h < 5:
r, g, b = x, 0, c
else:
r, g, b = c, 0, x
r = int(r * 255)
g = int(g * 255)
b = int(b * 255)
return f'#{r:02x}{g:02x}{b:02x}'
def add_smooth_color_legend(m):
legend_html = '''
<div>
<p><b>数值范围</b></p>
<div>
'''
for i in range(100, 0, -1):
color = get_smooth_color_by_value(i)
legend_html += f'<div token interpolation>{color}; border: 0.5px solid black;'></div>'
legend_html += '''
</div>
<div>
<span>0</span>
<span>50</span>
<span>100</span>
</div>
</div>
'''
m.get_root().html.add_child(folium.Element(legend_html))
# 创建 NiceGUI 界面
@ui.page('/')
def main():
ui.label('拉长版平滑过渡七彩条形图').classes('text-2xl font-bold')
# 显示地图
def show_map():
map_html = generate_heatmap_base64()
# 使用 ui.html 显示地图,添加 sanitize=False 参数
ui.html(map_html, sanitize=False).classes('w-full h-screen')
# 显示地图按钮
ui.button('显示地图', on_click=show_map).classes('mt-4')
# 显示数据信息
data = generate_mock_data()
ui.label(f'模拟数据点数量:{len(data)}').classes('mt-4')
# 显示前几行数据
ui.label('前 5 行数据预览:').classes('mt-4')
# 使用正确的 ui.table 语法
columns = [
{'name':'index','label':'Index','field':'index'},
{'name':'lat','label':'纬度','field':'lat'},
{'name':'lon','label':'经度','field':'lon'},
{'name':'value','label':'数值','field':'value'}
]
rows = [
{'index': i,'lat': row['lat'],'lon': row['lon'],'value': row['value']}
for i,(idx, row) in enumerate(data.head().iterrows())
]
ui.table(columns=columns, rows=rows).props('dense flat bordered').classes('w-full')
# 启动应用
if __name__ in {"__main__","__mp_main__"}:
ui.run(title='拉长版平滑过渡七彩条形图应用', port=8080, reload=False)