不改变相对位置的前提下把点散开1

实际问题:有一堆数据点,知道它们的横纵坐标,横纵坐标的范围不在一个数量级。这些点最终展示到可视化界面时(每个点上还写了文字说明),一些离得太近的点相互叠加没办法看。需要在不改变这些点的相对位置的情况下让离得太近的点散开(最终的结果用于概览,不表示精确的输出)。
横纵坐标范围不是同一个数量级,所以需要分别扩散。
初始思路:曲线投影然后拉长。
3步思路
思路如上图,三个点经过三次变换,离右侧点近的点和它的距离拉远了,离右侧点远的点距离未发生改变。先找到聚集的一堆点的中心,然后按这样变换,离中心近的点距离会拉开,离中心远的点距离基本不会变。

import math
from matplotlib import pyplot as plt

def find_mid(numlist):
    """求数组的中位数"""
    idx = len(numlist)//2
    mid_num = sorted(numlist)[idx]
    return mid_num

def find_max_distance(aimpoint, points):
    """找离指定点最远的点和指定点之间的长度"""
    max_distance = max(abs(aimpoint-p) for p in points)
    return max_distance

def circle_to_shortline(aimpoint, pa, radius, cycles):
    """把弧上的点投影到短线上
    :param aimpoint: 中位点, 位置固定;
    :param pa: 要以中位点为参照重排的点;
    :param radius: 圆半径;
    """
    arc_len = abs(aimpoint - pa)    # 两点间的距离, 即变圆后的弧长
    arc_angle = arc_len / radius    # 变圆后该点和中位点之间的弧度
    shortline_len = math.sin(arc_angle) * radius    # 到直线投影的长度
    
    # 伸长的小段距离
    # r/maxd = sl/ll  =>  ll = maxd*sl/r = sl*pi/2
    move_len = (shortline_len * math.pi / 2 - arc_len) / cycles
    
    if pa < aimpoint:
        b_x = pa - move_len
    else:
        b_x = pa + move_len
    return b_x

def scatter_x(xdata, cycles):
    """扩散点
    :param xdata(list): 横坐标列表;
    :param cycles(int): 扩散次数;
    """
    aimpoint = find_mid(xdata)
    
    max_distance = find_max_distance(aimpoint, xdata)
    circle_radius = 2 * max_distance / math.pi
    
    new_xdata = []
    for pa in xdata:
        x = circle_to_shortline(aimpoint, pa, circle_radius, cycles)
        new_xdata.append(x)
    return new_xdata

def main(xdata, ydata):
	# 方便判断每个点的位置变化所以加了颜色(使用的数据为95个点)
    colors = ['#{0:0>2}{0:0>2}FF'.format(i) for i in range(95)]
    cycles = 0
    while cycles < 20:
        aimpoint_x = find_mid(xdata)
        aimpoint_y = find_mid(ydata)
        plt.axis([-2, 2, -20, 20])
        plt.scatter(xdata, ydata, c=colors)
        plt.scatter([aimpoint_x], [aimpoint_y], marker='D')
        plt.savefig(f'ok{cycles}.png')
        plt.clf()
        xdata = scatter_x(xdata, cycles+1)
        ydata = scatter_x(ydata, cycles+1)
        cycles += 1

使用这次的点进行测试:
扩散前的点聚集在一块
扩散19次后的点

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值