You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现mpld3生成的HTML图表标记点随缩放动态调整大小?

问题描述

我写了一段Python脚本,用Matplotlib生成不同哈希算法与字符串长度的平均哈希时间对比图,再通过mpld3转成交互式HTML。目前图表里的标记点在HTML缩放时大小不变,想优化体验:

  • 标记点随缩放级别动态调整:放大时缩小,缩小时放大
  • 解决放大到最大级别时标记点不再继续缩小的问题
现有代码
import hashlib
import random
import string
import time
import matplotlib.pyplot as plt
import multiprocessing
import os
from datetime import datetime
import mpld3

algorithms = ['sha1', 'sha256', 'sha3_256']
string_lengths = [10, 25, 50, 75, 100]
num_samples = 50000
random_seed = 42
random.seed(random_seed)
custom_colors = ['#1f77b4', '#FFD700', '#2ca02c']

def generate_random_string(length):
    characters = string.ascii_letters + string.digits
    return ''.join(random.choice(characters) for _ in range(length))

def hash_string(input_string, algorithm):
    hash_func = hashlib.new(algorithm)
    hash_func.update(input_string.encode())
    return hash_func.hexdigest()

def hash_and_measure_avg_time(args):
    algorithm, random_strings = args
    num_samples = len(random_strings)
    
    start_time = time.time_ns()
    
    [hash_string(s, algorithm) for s in random_strings]
    
    end_time = time.time_ns()

    total_time = end_time - start_time
    return total_time / num_samples

def main():
    for i in range(10):
        num_cpus = multiprocessing.cpu_count()
        cpu_count = os.cpu_count()

        print(f"\nUsing {num_cpus} CPU cores for analysis")
        print(f"Number of CPU cores available: {cpu_count}")

        random_strings = {}
        for length in string_lengths:
            random_strings[length] = [generate_random_string(length) for _ in range(num_samples)]

        results = {}
        timestamp = datetime.now().strftime("%m-%d-%Y-%H-%M-%S")
        results_folder = f"results_{timestamp}"
        os.makedirs(results_folder, exist_ok=True)

        for algorithm in algorithms:
            results[algorithm] = {}

            print(f"\nTesting hashing algorithm: {algorithm}")
            with multiprocessing.Pool(processes=num_cpus) as pool:
                args = [(algorithm, random_strings[length]) for length in string_lengths]
                results_list = pool.map(hash_and_measure_avg_time, args)

            for length, result in zip(string_lengths, results_list):
                results[algorithm][length] = result

            time.sleep(1)

        plt.figure(figsize=(10, 6))
        for i, (algorithm, avg_times) in enumerate(results.items()):
            avg_times = [avg_times[length] for length in string_lengths]
            plt.plot(
                string_lengths,
                avg_times,
                marker='o',
                markersize=4,
                label=algorithm,
                color=custom_colors[i]
            )

        plt.title('Average Hashing Time vs. String Length')
        plt.xlabel('String Length')
        plt.ylabel('Average Hashing Time (ns)')
        plt.legend()
        plt.grid(True)

        interactive_plot = mpld3.fig_to_html(plt.gcf())
        plot_filename = f"c_result_{timestamp}.html"
        with open(os.path.join(results_folder, plot_filename), 'w') as html_file:
            html_file.write(interactive_plot)

if __name__ == "__main__":
    print("\n----- Welcome to the Hashing Performance Benchmark -----")
    main()
当前缩放效果

未缩放时

未缩放时的图表

缩放后

缩放后的图表

最大缩放级别

最大缩放级别的图表

解决方案

要实现标记点随缩放动态调整,需要给mpld3添加自定义JavaScript插件,监听缩放事件并调整标记点大小,同时设置大小限制避免过度缩小。

修改步骤:

  1. 在Python代码中,替换生成交互式HTML的部分,添加自定义插件:

将原来的interactive_plot = mpld3.fig_to_html(plt.gcf())替换为以下代码:

# 注册动态调整标记点大小的自定义插件
plugins = [mpld3.plugins.connect(plt.gcf(), mpld3.plugins.Plugin(
    "dynamicmarkersize",
    {},
    js_code="""
var DynamicMarkerSize = function(fig, props){
    var markers = fig.canvas.querySelectorAll(".mpld3-marker");
    var originalRadius = [];
    // 保存每个标记点的原始半径
    markers.forEach(function(marker){
        originalRadius.push(parseFloat(marker.getAttribute("r")));
    });

    // 设置标记点的最小/最大半径限制
    var minRadius = 1;
    var maxRadius = 8;

    // 监听缩放事件
    fig.plugins.zoom.on("zoom", function(){
        var scale = fig.zoom.scale;
        markers.forEach(function(marker, idx){
            // 根据缩放比例反向调整半径
            var newRadius = originalRadius[idx] / scale;
            // 限制半径范围,避免过度缩小或放大
            newRadius = Math.max(minRadius, Math.min(maxRadius, newRadius));
            marker.setAttribute("r", newRadius);
        });
    });
};

mpld3.register_plugin("dynamicmarkersize", DynamicMarkerSize);
"""
))]

# 生成带插件的交互式HTML
interactive_plot = mpld3.fig_to_html(plt.gcf(), plugins=plugins)

效果说明:

  • 缩放时,标记点半径会根据当前缩放比例反向调整:放大(scale>1)时缩小半径,缩小(scale<1)时放大半径
  • 通过minRadius和maxRadius限制标记点的尺寸范围,解决最大缩放时标记点过度缩小的问题,同时避免缩小时标记点过大遮挡内容

内容的提问来源于stack exchange,提问作者user22734651

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 21:34:53