برنامه نویسی

بهینه سازی عملکرد نمودار خط با الگوریتم LTTB

هنگام کار با مجموعه داده های بزرگ ، ارائه تمام نقاط در یک نمودار خط می تواند باعث ایجاد مشکلات قابل توجهی شود. به عنوان مثال ، ترسیم 50،000 نقطه داده به طور مستقیم می تواند مرورگر را تحت الشعاع قرار داده و نمودار را پاسخگو نباشد. ابزارهایی مانند AmCharts و Apexcharts با چنین مجموعه داده هایی می جنگند ، در حالی که Echarts عملکرد بهتری دارد اما هنوز برای مجموعه داده های بسیار بزرگ بهینه نشده است.

برای پرداختن به این موضوع ، من Echarts را با بزرگترین الگوریتم مثلث سه سطل (LTTB) ترکیب کردم. LTTB یک الگوریتم کاهش دهنده است که ضمن حفظ ساختار بصری مجموعه داده ، نقاط داده را کاهش می دهد.

در این پست ، من توضیح خواهم داد که چگونه الگوریتم LTTB گام به گام کار می کند و نمونه ای از کاهش 10 امتیاز به 4 است. برای هر مرحله ، کد مربوطه ، توضیحات و تحولات داده حاصل را درج می کنم.

کد الگوریتم LTTB
در اینجا کد کامل الگوریتم LTTB وجود دارد:

export function lttb(data: Point[], threshold: number): Point[] {
  const dataLength = data.length;
  if (threshold >= dataLength || threshold === 0) {
    return data; // No downsampling needed
  }

  const sampled: Point[] = [];
  let sampledIndex = 0;
  const bucketSize = (dataLength - 2) / (threshold - 2);
  let a = 0; // Start point
  let nextA = 0;

  sampled[sampledIndex++] = data[a]; // Add the first point

  for (let i = 0; i < threshold - 2; i++) {
    let avgX = 0;
    let avgY = 0;
    let avgRangeStart = Math.floor((i + 1) * bucketSize) + 1;
    let avgRangeEnd = Math.floor((i + 2) * bucketSize) + 1;
    avgRangeEnd = avgRangeEnd < dataLength ? avgRangeEnd : dataLength;
    const avgRangeLength = avgRangeEnd - avgRangeStart;

    for (; avgRangeStart < avgRangeEnd; avgRangeStart++) {
      avgX += data[avgRangeStart].x;
      avgY += data[avgRangeStart].y;
    }

    avgX /= avgRangeLength;
    avgY /= avgRangeLength;

    let rangeOffs = Math.floor((i + 0) * bucketSize) + 1;
    const rangeTo = Math.floor((i + 1) * bucketSize) + 1;
    const pointAX = data[a].x;
    const pointAY = data[a].y;

    let maxArea = -1;

    for (; rangeOffs < rangeTo; rangeOffs++) {
      const area = Math.abs(
        (pointAX - avgX) * (data[rangeOffs].y - pointAY) -
        (pointAX - data[rangeOffs].x) * (avgY - pointAY)
      );
      if (area > maxArea) {
        maxArea = area;
        nextA = rangeOffs;
      }
    }

    sampled[sampledIndex++] = data[nextA]; // Add the most important point
    a = nextA;
  }

  sampled[sampledIndex++] = data[dataLength - 1]; // Add the last point

  return sampled;
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

مثال: کاهش 10 امتیاز به 4 امتیاز
ما با استفاده از الگوریتم LTTB ، مجموعه داده های زیر 10 امتیاز را به 4 امتیاز کاهش خواهیم داد:

مجموعه داده اصلی

const data = [
  { x: 1, y: 10 },
  { x: 2, y: 20 },
  { x: 3, y: 15 },
  { x: 4, y: 25 },
  { x: 5, y: 30 },
  { x: 6, y: 20 },
  { x: 7, y: 40 },
  { x: 8, y: 35 },
  { x: 9, y: 45 },
  { x: 10, y: 50 }
];
const threshold = 4; // Reduce to 4 points
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

مرحله 1: نکته اول را اضافه کنید

sampled[sampledIndex++] = data[a]; // Add the first point
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

✅ الگوریتم همیشه با اضافه کردن اولین نقطه داده شروع می شود. این تضمین می کند که مجموعه داده های downsampled به درستی شروع می شود.

📊 نتیجه داده شده:

sampled = [
  { x: 1, y: 10 }
];
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

مرحله 2: اندازه سطل را محاسبه کنید

const bucketSize = (dataLength - 2) / (threshold - 2);
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

size اندازه سطل تعیین می کند که چه تعداد نقطه داده در هر “سطل” قرار می گیرد. در این مورد:


باکتری کردن=دیتاجت2آستانه2=10242=4\ text {bucketsize} = \ frac {\ text {datal طول} – 2} {\ text {آستانه} – 2} = \ frac {10 – 2} {4 – 2} = 4

بنابراین ، هر سطل حاوی 4 نقطه داده است.

مرحله 3: سطل اول (نقاط 2-5)

let avgX = 0;
let avgY = 0;
let avgRangeStart = Math.floor((i + 1) * bucketSize) + 1;
let avgRangeEnd = Math.floor((i + 2) * bucketSize) + 1;
avgRangeEnd = avgRangeEnd < dataLength ? avgRangeEnd : dataLength;
const avgRangeLength = avgRangeEnd - avgRangeStart;

for (; avgRangeStart < avgRangeEnd; avgRangeStart++) {
  avgX += data[avgRangeStart].x;
  avgY += data[avgRangeStart].y;
}

avgX /= avgRangeLength;
avgY /= avgRangeLength;
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

✅ الگوریتم میانگین نقطه اول سطل را محاسبه می کند (امتیاز 2-5). این کار با جمع بندی آنها انجام می شود x وت y ارزش ها و تقسیم بر تعداد امتیاز.


aygx=2با3با4با54=3.5\ text {avgx} = \ frac {2 + 3 + 4 + 5} {4} = 3.5


با ابست=20با15با25با304=22.5\ text {avgy} = \ frac {20 + 15 + 25 + 30} {4} = 22.5

مرحله 4: مهمترین نکته را پیدا کنید

let rangeOffs = Math.floor((i + 0) * bucketSize) + 1;
const rangeTo = Math.floor((i + 1) * bucketSize) + 1;
const pointAX = data[a].x;
const pointAY = data[a].y;

let maxArea = -1;

for (; rangeOffs < rangeTo; rangeOffs++) {
  const area = Math.abs(
    (pointAX - avgX) * (data[rangeOffs].y - pointAY) -
    (pointAX - data[rangeOffs].x) * (avgY - pointAY)
  );
  if (area > maxArea) {
    maxArea = area;
    nextA = rangeOffs;
  }
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

✅ الگوریتم نقطه ای را در سطل مشخص می کند که بزرگترین مثلث را با میانگین نقطه و نقطه قبلاً انتخاب شده تشکیل می دهد.

برای این سطل ، (2،20) بزرگترین منطقه را دارد

sampled = [
  { x: 1, y: 10 },
  { x: 2, y: 20 }
];
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

مرحله 5: سطل دوم (نقاط 6-9)

این الگوریتم فرآیند را برای سطل دوم (نقاط 6-9) تکرار می کند ، محاسبات:

مهمترین نکته در این سطل (6 ، 20) است.


aygx=6با7با8با94=7.5\ text {avgx} = \ frac {6 + 7 + 8 + 9} {4} = 7.5


با ابست=20با40با35با454=35\ text {avgy} = \ frac {20 + 40 + 35 + 45} {4} = 35

داده های به روز شده:

sampled = [
  { x: 1, y: 10 },
  { x: 2, y: 20 },
  { x: 6, y: 20 }
];
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

مرحله ششم: آخرین نکته را اضافه کنید

sampled[sampledIndex++] = data[dataLength - 1]; // Add the last point
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

✅ الگوریتم همیشه با اضافه کردن آخرین نقطه به پایان می رسد.

📊 داده های نهایی:

sampled = [
  { x: 1, y: 10 },
  { x: 2, y: 20 },
  { x: 6, y: 20 },
  { x: 10, y: 50 }
];
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

پایان
با ترکیب Echarts با الگوریتم LTTB ، من توانستم مجموعه داده های خود را به طور کارآمد کاهش دهم و عملکرد نمودار را به میزان قابل توجهی بهبود دهم. اگر با مجموعه داده های بزرگ کار می کنید ، این روش راهی عالی برای تعادل عملکرد و دقت بصری است. به من اطلاع دهید که آیا این رویکرد را امتحان کرده اید یا تکنیک های دیگری برای اشتراک گذاری دارید!

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا