গ্রাফের ওয়াই অ্যাক্সিসের জন্য একটি আকর্ষণীয় লিনিয়ার স্কেল নির্বাচন করা


84

আমি আমাদের সফ্টওয়্যারটিতে একটি বার (বা লাইন) গ্রাফ প্রদর্শন করতে কিছুটা কোড লিখছি। সব ঠিকঠাক হচ্ছে। যে জিনিসটি আমাকে স্ট্যাম্প করেছিল তা হ'ল ওয়াই অক্ষটি লেবেল করা।

কলকারী আমাকে বলতে পারবেন যে তারা ওয়াই স্কেলটি কতটা সূক্ষ্মভাবে লেবেলযুক্ত তা চায় তবে আমি তাদের "আকর্ষণীয়" ধরণের উপায়ে কী লেবেল করব তা নিয়ে আমি আটকা পড়েছি বলে মনে হয়। আমি "আকর্ষণীয়" বর্ণনা করতে পারি না, এবং সম্ভবত আপনিও পারবেন না, তবে আমরা এটি যখন দেখি ঠিক তখনই তা জানি?

সুতরাং যদি তথ্য পয়েন্টগুলি হয়:

   15, 234, 140, 65, 90

এবং ব্যবহারকারী Y অক্ষরে 10 টি লেবেল চেয়েছে, কাগজ এবং পেন্সিলের সাথে সামান্য বিস্ময় প্রকাশ নিয়ে আসে:

  0, 25, 50, 75, 100, 125, 150, 175, 200, 225, 250

সুতরাং সেখানে 10 রয়েছে (0 সহ নয়), শেষটি সর্বোচ্চ মানের (234 <250) এর বাইরেও প্রসারিত, এবং এটি 25 টির একটি "সুন্দর" বর্ধনযোগ্য। যদি তারা 8 টি লেবেল চেয়ে থাকে তবে 30 এর বর্ধিততা দেখতে সুন্দর লাগবে:

  0, 30, 60, 90, 120, 150, 180, 210, 240

নয়টি মুশকিল হত। সম্ভবত মাত্র 8 বা 10 ব্যবহার করেছেন এবং এটিকে যথেষ্ট কাছে কল করা ঠিক হবে। এবং যখন কিছু পয়েন্ট নেতিবাচক হয় তখন কী করবেন?

এক্সেলটি এই সমস্যাটিকে সুন্দরভাবে মোকাবেলা করতে দেখতে পাচ্ছি।

এটিকে সমাধান করার জন্য কেউ কি সাধারণ-উদ্দেশ্যমূলক অ্যালগরিদম (এমনকি কিছু বর্বর শক্তি ঠিক আছে) জানেন? আমাকে তাড়াতাড়ি করতে হবে না, তবে এটি দেখতে সুন্দর লাগবে।


4
এক্সেল তার ওয়াই অক্ষের জন্য সর্বাধিক এবং ন্যূনতম মানগুলি কীভাবে চয়ন করে সে সম্পর্কে এখানে কিছু তথ্য রয়েছে: সমর্থন.microsoft.com/kb/214075
ক্রিস্টোফার অর

নিস বাস্তবায়ন: stackoverflow.com/a/16363437/829571
assylias

উত্তর:


103

অনেক দিন আগে আমি একটি গ্রাফ মডিউল লিখেছি যা এটি দুর্দান্তভাবে কভার করেছে। ধূসর ভরতে খনন করা নিম্নলিখিতগুলি পান:

  • ডেটার নিম্ন এবং উপরের সীমা নির্ধারণ করুন। (বিশেষ ক্ষেত্রে যেখানে সতর্কতা অবলম্বন করুন নীচে আবদ্ধ = উপরের আবদ্ধ!
  • প্রয়োজনীয় পরিমাণ টিক্সের মধ্যে ব্যাপ্তি বিভাজন করুন।
  • টিকের পরিসীমাটিকে দুর্দান্ত পরিমাণে গোল করুন।
  • নিম্ন এবং উপরের সীমাটি সেই অনুযায়ী সামঞ্জস্য করুন।

আপনার উদাহরণটি ধরুন:

15, 234, 140, 65, 90 with 10 ticks
  1. নিম্ন সীমা = 15
  2. উপরের আবদ্ধ = 234
  3. পরিসর = 234-15 = 219
  4. টিক পরিসর = 21.9। এটি 25.0 হওয়া উচিত
  5. নতুন নিম্ন সীমাবদ্ধ = 25 * রাউন্ড (15/25) = 0
  6. নতুন উপরের আবদ্ধ = 25 * রাউন্ড (1 + 235/25) = 250

সুতরাং পরিসীমা = 0,25,50, ..., 225,250

নিম্নলিখিত ধাপগুলি সহ আপনি দুর্দান্ত টিকের পরিসীমা পেতে পারেন:

  1. 10 ^ x দ্বারা ভাগ করুন যাতে ফলাফল 0.1 এবং 1.0 (1 বাদে 0.1 সহ) এর মধ্যে থাকে।
  2. সেই অনুসারে অনুবাদ করুন:
    • 0.1 -> 0.1
    • <= 0.2 -> 0.2
    • <= 0.25 -> 0.25
    • <= 0.3 -> 0.3
    • <= 0.4 -> 0.4
    • <= 0.5 -> 0.5
    • <= 0.6 -> 0.6
    • <= 0.7 -> 0.7
    • <= 0.75 -> 0.75
    • <= 0.8 -> 0.8
    • <= 0.9 -> 0.9
    • <= 1.0 -> 1.0
  3. 10 ^ x দ্বারা গুন করুন।

এই ক্ষেত্রে, 0.29 পেতে 21 10 ^ 2 দ্বারা বিভক্ত। এটি <= 0.25 তাই আমাদের এখন 0.25 রয়েছে। 10 ^ 2 দ্বারা গুণিত এটি 25 দেয়।

8 টি টিক দিয়ে একই উদাহরণটি একবার দেখে নেওয়া যাক:

15, 234, 140, 65, 90 with 8 ticks
  1. নিম্ন সীমা = 15
  2. উপরের আবদ্ধ = 234
  3. পরিসর = 234-15 = 219
  4. টিকের পরিসর = 27.375
    1. ০.২737575 for এর জন্য 10 ^ 2 দ্বারা ভাগ করুন, 0.3 এ অনুবাদ করে যা 30 (10 ^ 2 দিয়ে গুণিত) দেয়।
  5. নতুন নিম্ন আবদ্ধ = 30 * রাউন্ড (15/30) = 0
  6. নতুন উপরের আবদ্ধ = 30 * রাউন্ড (1 + 235/30) = 240

যা আপনি অনুরোধ করেছেন ফলাফল দেয় ;-)।

------ কেডি যোগ করেছেন ------

এখানে কোড যা লুকিং সারণী ইত্যাদি ব্যবহার না করে এই অ্যালগরিদম অর্জন করে ...

double range = ...;
int tickCount = ...;
double unroundedTickSize = range/(tickCount-1);
double x = Math.ceil(Math.log10(unroundedTickSize)-1);
double pow10x = Math.pow(10, x);
double roundedTickRange = Math.ceil(unroundedTickSize / pow10x) * pow10x;
return roundedTickRange;

সাধারণভাবে বলতে গেলে টিকের সংখ্যায় নীচের অংশের টিকটি অন্তর্ভুক্ত থাকে, তাই আসল ওয়াই-অক্ষগুলি বিভাগগুলি টিকের সংখ্যার চেয়ে কম one


4
এই ঠিক সম্পর্কে ছিল। পদক্ষেপ 3, আমাকে এক্স 1 কে হ্রাস করতে হয়েছিল 219 থেকে .1-> 1 এর পরিসীমা পেতে আমাকে 10 ^ 3 (1000) 10 ^ 2 (100) দিয়ে ভাগ করতে হবে না। অন্যথায়, স্পট।
ক্লিনটন পিয়ার্স

4
আপনি 10 ^ x দ্বারা বিভাজক এবং 10 ^ x দ্বারা গুণমান উল্লেখ করুন। এটি লক্ষ করা উচিত যে এক্সটি এই উপায়ে পাওয়া যাবে: 'ডাবল এক্স = ম্যাথ.সিলিং (ম্যাথ.লগ 10 (টিকর্যাঞ্জ));'
ব্রায়ান

4
খুব উপকারী. যদিও বুঝতে পারিনি - 'নতুন লোয়ার বাউন্ড = 30 * রাউন্ড (15/30) = 0' (এটি 30 টি আমার মনে হয় আসবে) এবং আপনি কীভাবে 235 পেয়েছেন 'নতুন আপার বাউন্ড = 30 * রাউন্ডে (1 + 235/30) = 240 '235 এর কোথাও উল্লেখ নেই, এটি 234 হওয়া উচিত
মিউট্যান্ট

4
এটি একটি দুর্দান্ত উত্তর। খুব বেশি প্রশংশিত.
জোয়েল আনায়ের

4
@ জোয়েলআনির আপনাকে ধন্যবাদ একটি স্নিগ্ধ দিনটিকে কিছুটা উজ্জ্বল করে তুলেছে।
টুন ক্রিজে

22

এখানে আমি ব্যবহার করছি একটি পিএইচপি উদাহরণ। এই ফাংশনটি সুন্দর Y অক্ষরের মানগুলির একটি অ্যারে প্রদান করে যা সর্বনিম্ন নূন্যতম এবং সর্বাধিক Y মানগুলিকে অন্তর্ভুক্ত করে। অবশ্যই, এই রুটিনটি X অক্ষের মানগুলির জন্যও ব্যবহৃত হতে পারে।

এটি আপনাকে কতটা টিক্স পছন্দ করতে "পরামর্শ" দিতে সহায়তা করে তবে রুটিনটি যা ভাল দেখাচ্ছে তা ফিরে আসবে। আমি কিছু নমুনা ডেটা যুক্ত করেছি এবং এর জন্য ফলাফলগুলি দেখিয়েছি।

#!/usr/bin/php -q
<?php

function makeYaxis($yMin, $yMax, $ticks = 10)
{
  // This routine creates the Y axis values for a graph.
  //
  // Calculate Min amd Max graphical labels and graph
  // increments.  The number of ticks defaults to
  // 10 which is the SUGGESTED value.  Any tick value
  // entered is used as a suggested value which is
  // adjusted to be a 'pretty' value.
  //
  // Output will be an array of the Y axis values that
  // encompass the Y values.
  $result = array();
  // If yMin and yMax are identical, then
  // adjust the yMin and yMax values to actually
  // make a graph. Also avoids division by zero errors.
  if($yMin == $yMax)
  {
    $yMin = $yMin - 10;   // some small value
    $yMax = $yMax + 10;   // some small value
  }
  // Determine Range
  $range = $yMax - $yMin;
  // Adjust ticks if needed
  if($ticks < 2)
    $ticks = 2;
  else if($ticks > 2)
    $ticks -= 2;
  // Get raw step value
  $tempStep = $range/$ticks;
  // Calculate pretty step value
  $mag = floor(log10($tempStep));
  $magPow = pow(10,$mag);
  $magMsd = (int)($tempStep/$magPow + 0.5);
  $stepSize = $magMsd*$magPow;

  // build Y label array.
  // Lower and upper bounds calculations
  $lb = $stepSize * floor($yMin/$stepSize);
  $ub = $stepSize * ceil(($yMax/$stepSize));
  // Build array
  $val = $lb;
  while(1)
  {
    $result[] = $val;
    $val += $stepSize;
    if($val > $ub)
      break;
  }
  return $result;
}

// Create some sample data for demonstration purposes
$yMin = 60;
$yMax = 330;
$scale =  makeYaxis($yMin, $yMax);
print_r($scale);

$scale = makeYaxis($yMin, $yMax,5);
print_r($scale);

$yMin = 60847326;
$yMax = 73425330;
$scale =  makeYaxis($yMin, $yMax);
print_r($scale);
?>

নমুনা ডেটা থেকে ফলাফল ফলাফল

# ./test1.php
Array
(
    [0] => 60
    [1] => 90
    [2] => 120
    [3] => 150
    [4] => 180
    [5] => 210
    [6] => 240
    [7] => 270
    [8] => 300
    [9] => 330
)

Array
(
    [0] => 0
    [1] => 90
    [2] => 180
    [3] => 270
    [4] => 360
)

Array
(
    [0] => 60000000
    [1] => 62000000
    [2] => 64000000
    [3] => 66000000
    [4] => 68000000
    [5] => 70000000
    [6] => 72000000
    [7] => 74000000
)

আমার বস এতে খুশি হবেন - আমার কাছ থেকেও উঠে পড়ুন ধন্যবাদ ধন্যবাদ !!
স্টিফেন হ্যাজেল

দুর্দান্ত উত্তর! আমি এটিকে সুইফট 4 স্ট্যাকওভারফ্লো.com
পেট্র সাইরোভ

@ স্কট গুথ্রি: ইনপুটগুলি পূর্ণসংখ্যার মতো না হলে এবং অল্প সংখ্যক না হলে এটি দুর্দান্ত, উদাহরণস্বরূপ, যদি yMin = 0.03 এবং yMax = 0.11 হয়।
গ্রেগ

9

এই কোড ব্যবহার করে দেখুন। আমি এটি কয়েকটি চার্টিং দৃশ্যে ব্যবহার করেছি এবং এটি ভাল কাজ করে। এটা খুব দ্রুত।

public static class AxisUtil
{
    public static float CalculateStepSize(float range, float targetSteps)
    {
        // calculate an initial guess at step size
        float tempStep = range/targetSteps;

        // get the magnitude of the step size
        float mag = (float)Math.Floor(Math.Log10(tempStep));
        float magPow = (float)Math.Pow(10, mag);

        // calculate most significant digit of the new step size
        float magMsd = (int)(tempStep/magPow + 0.5);

        // promote the MSD to either 1, 2, or 5
        if (magMsd > 5.0)
            magMsd = 10.0f;
        else if (magMsd > 2.0)
            magMsd = 5.0f;
        else if (magMsd > 1.0)
            magMsd = 2.0f;

        return magMsd*magPow;
    }
}

6

কলারের মতো শব্দগুলি আপনাকে এটির সীমাটি বলতে দেয় না।

সুতরাং আপনি আপনার পয়েন্টগুলি আপনার লেবেল গণনা দ্বারা সুন্দরভাবে বিভাজ্য না হওয়া পর্যন্ত শেষ পয়েন্টগুলি পরিবর্তন করতে মুক্ত।

আসুন "সুন্দর" সংজ্ঞা দিন। যদি লেবেলগুলি বন্ধ থাকে তবে আমি দুর্দান্ত কল করব:

1. 2^n, for some integer n. eg. ..., .25, .5, 1, 2, 4, 8, 16, ...
2. 10^n, for some integer n. eg. ..., .01, .1, 1, 10, 100
3. n/5 == 0, for some positive integer n, eg, 5, 10, 15, 20, 25, ...
4. n/2 == 0, for some positive integer n, eg, 2, 4, 6, 8, 10, 12, 14, ...

আপনার ডেটা সিরিজের সর্বাধিক এবং মিনিট সন্ধান করুন। এই পয়েন্টগুলি কল করুন:

min_point and max_point.

এখন আপনাকে যা করতে হবে তা হ'ল 3 মান:

- start_label, where start_label < min_point and start_label is an integer
- end_label, where end_label > max_point and end_label is an integer
- label_offset, where label_offset is "nice"

যে সমীকরণ ফিট:

(end_label - start_label)/label_offset == label_count

সম্ভবত অনেকগুলি সমাধান রয়েছে, সুতরাং কেবল একটি বেছে নিন। বেশিরভাগ সময় আমি বাজি ধরতে পারি আপনি সেট করতে পারেন

start_label to 0

সুতরাং শুধু পৃথক পূর্ণসংখ্যার চেষ্টা করুন

end_label

অফসেটটি "সুন্দর" না হওয়া পর্যন্ত


3

আমি এখনও এর সাথে লড়াই করছি :)

আসল গেমক্যাট উত্তরটি বেশিরভাগ সময় কাজ করে বলে মনে হয়, তবে প্রয়োজনীয় টিকের সংখ্যা হিসাবে "3 টিক্স" বলে প্লাগ ইন করার চেষ্টা করুন (একই ডাটা মানের জন্য 15, 234, 140, 65, 90) .... এটি মনে হয় এটি 73 এর টিক রেঞ্জ দেয় যা 10 ^ 2 ভাগ করে 0.73 দেয়, যা 0.75 এ মানচিত্র দেয় যা 75 এর 'সুন্দর' টিক রেঞ্জ দেয়।

তারপরে উপরের সীমাটি গণনা করা হচ্ছে: 75 * বৃত্তাকার (1 + 234/75) = 300

এবং নিম্ন সীমা: 75 * রাউন্ড (15/75) = 0

তবে স্পষ্টভাবে যদি আপনি 0 থেকে শুরু করেন এবং 300 এর উপরের সীমানা পর্যন্ত 75 টি ধাপে অগ্রসর হন, আপনি 0,75,150,225,300 দিয়ে শেষ করেন .... যা কোনও সন্দেহজনক নয়, তবে এটি 4 টি টিক (0 সহ নয়) নয় 3 টিক্স প্রয়োজন।

হতাশার সাথে যে এটি সময়ের 100% কাজ করে না .... যা কোথাও কোথাও আমার ভুলের কাছে চলে যেতে পারে!


মূলত ভেবেছিলেন যে সমস্যাটি ব্রায়ানের এক্স ডারাইভ করার পদ্ধতির সাথে সম্পর্কিত কিছু হতে পারে তবে এটি অবশ্যই পুরোপুরি সঠিক।
স্টিলপান্ডারিং

3

টুন ক্রিজ্তের উত্তর বেশিরভাগ সময় কাজ করে। তবে কখনও কখনও এটি অতিরিক্ত সংখ্যক টিক্স উত্পাদন করে। এটি নেতিবাচক সংখ্যাগুলির সাথেও কাজ করবে না। সমস্যার ওভারল পদ্ধতির ক্ষেত্রে ঠিক আছে তবে এটি পরিচালনা করার আরও ভাল উপায় আছে। আপনি যে অ্যালগরিদমটি ব্যবহার করতে চান তা নির্ভর করে আপনি কী পেতে চান তার উপর নির্ভর করবে। নীচে আমি আপনাকে আমার কোডটি উপস্থাপন করছি যা আমি আমার জেএস প্লটিং লাইব্রেরিতে ব্যবহার করেছি। আমি এটি পরীক্ষা করেছি এবং এটি সর্বদা কাজ করে (আশা করি;))। এখানে প্রধান পদক্ষেপগুলি রয়েছে:

  • গ্লোবাল এক্সট্রিমাস এক্সমিন এবং এক্সম্যাক্স পান (আপনি আলগোরিদমে মুদ্রণ করতে চান এমন সমস্ত প্লট ইনলুকড)
  • xMin এবং xMax এর মধ্যে পরিসীমা গণনা করুন
  • আপনার পরিসীমাটির প্রস্থের ক্রম গণনা করুন
  • টিক বিয়োগ বিয়োগের সংখ্যার দ্বারা পরিসীমা বিভাজন করে টিক আকার গণনা করুন
  • এই এক .চ্ছিক। আপনি যদি সর্বত্র মুদ্রিত শূন্য টিক রাখতে চান তবে ধনাত্মক এবং নেতিবাচক টিকের সংখ্যা গণনা করতে আপনি টিক আকার ব্যবহার করেন। টিকের মোট সংখ্যা হবে তাদের যোগফল + 1 (শূন্য টিক)
  • আপনার যদি জিরো টিক অলওয়ে প্রিন্ট করা থাকে তবে এটির দরকার নেই। নিম্ন এবং উপরের সীমা গণনা করুন তবে প্লটটি কেন্দ্র করে রাখতে ভুলবেন না

চল শুরু করি. প্রথমে প্রাথমিক গণনা

    var range = Math.abs(xMax - xMin); //both can be negative
    var rangeOrder = Math.floor(Math.log10(range)) - 1; 
    var power10 = Math.pow(10, rangeOrder);
    var maxRound = (xMax > 0) ? Math.ceil(xMax / power10) : Math.floor(xMax / power10);
    var minRound = (xMin < 0) ? Math.floor(xMin / power10) : Math.ceil(xMin / power10);

আমি ন্যূনতম এবং সর্বাধিক মানগুলিকে 100% নিশ্চিত হতে হবে যে আমার প্লটটি সমস্ত ডেটা কভার করবে। রেঞ্জ হুইটারের লগ 10 ফ্লোর করাও এটি খুব গুরুত্বপূর্ণ, এটি নেতিবাচক নয় এবং পরে 1 টি বিয়োগফল হয়। অন্যথায় আপনার অ্যালগরিদম একের চেয়ে কম সংখ্যার জন্য কাজ করবে না।

    var fullRange = Math.abs(maxRound - minRound);
    var tickSize = Math.ceil(fullRange / (this.XTickCount - 1));

    //You can set nice looking ticks if you want
    //You can find exemplary method below 
    tickSize = this.NiceLookingTick(tickSize);

    //Here you can write a method to determine if you need zero tick
    //You can find exemplary method below
    var isZeroNeeded = this.HasZeroTick(maxRound, minRound, tickSize);

আমি 7, 13, 17 ইত্যাদির মতো টিকগুলি এড়াতে "সুন্দর দেখাচ্ছে টিক্স" ব্যবহার করি। আমি এখানে যে পদ্ধতিটি ব্যবহার করি তা খুব সহজ। দরকার পড়লে জিরো টিক দেওয়াও ভাল। প্লটটি আরও বেশি পেশাদার দেখায়। আপনি এই উত্তরের শেষে সমস্ত পদ্ধতি খুঁজে পাবেন।

এখন আপনি উপরের এবং নিম্ন সীমা গণনা করতে হবে। এটি শূন্য টিকের সাহায্যে খুব সহজ তবে অন্য ক্ষেত্রে আরও কিছুটা প্রচেষ্টা দরকার। কেন? কারণ আমরা প্লটটি উপরের এবং নিম্ন সীমাতে সুন্দরভাবে কেন্দ্র করতে চাই। আমার কোডটি দেখুন কিছু ভেরিয়েবলগুলি এই স্কোপের বাইরে সংজ্ঞায়িত করা হয় এবং এর মধ্যে কয়েকটি হ'ল একটি অবজেক্টের বৈশিষ্ট্য যেখানে পুরো উপস্থাপিত কোড রাখা হয়।

    if (isZeroNeeded) {

        var positiveTicksCount = 0;
        var negativeTickCount = 0;

        if (maxRound != 0) {

            positiveTicksCount = Math.ceil(maxRound / tickSize);
            XUpperBound = tickSize * positiveTicksCount * power10;
        }

        if (minRound != 0) {
            negativeTickCount = Math.floor(minRound / tickSize);
            XLowerBound = tickSize * negativeTickCount * power10;
        }

        XTickRange = tickSize * power10;
        this.XTickCount = positiveTicksCount - negativeTickCount + 1;
    }
    else {
        var delta = (tickSize * (this.XTickCount - 1) - fullRange) / 2.0;

        if (delta % 1 == 0) {
            XUpperBound = maxRound + delta;
            XLowerBound = minRound - delta;
        }
        else {
            XUpperBound =  maxRound + Math.ceil(delta);
            XLowerBound =  minRound - Math.floor(delta);
        }

        XTickRange = tickSize * power10;
        XUpperBound = XUpperBound * power10;
        XLowerBound = XLowerBound * power10;
    }

এবং এখানে আমি আগে উল্লেখ করেছি এমন পদ্ধতি রয়েছে যা আপনি নিজের দ্বারা লিখতে পারেন তবে আপনি খনি ব্যবহার করতে পারেন

this.NiceLookingTick = function (tickSize) {

    var NiceArray = [1, 2, 2.5, 3, 4, 5, 10];

    var tickOrder = Math.floor(Math.log10(tickSize));
    var power10 = Math.pow(10, tickOrder);
    tickSize = tickSize / power10;

    var niceTick;
    var minDistance = 10;
    var index = 0;

    for (var i = 0; i < NiceArray.length; i++) {
        var dist = Math.abs(NiceArray[i] - tickSize);
        if (dist < minDistance) {
            minDistance = dist;
            index = i;
        }
    }

    return NiceArray[index] * power10;
}

this.HasZeroTick = function (maxRound, minRound, tickSize) {

    if (maxRound * minRound < 0)
    {
        return true;
    }
    else if (Math.abs(maxRound) < tickSize || Math.round(minRound) < tickSize) {

        return true;
    }
    else {

        return false;
    }
}

এখানে আরও একটি জিনিস রয়েছে যা এখানে অন্তর্ভুক্ত নেই। এটি "সুন্দর দেখার সীমা"। এগুলি নিম্ন সীমানা যা "সুন্দর দেখাচ্ছে টিক্স" এর সংখ্যার অনুরূপ are উদাহরণস্বরূপ, একই টিক আকারের সাথে 6 এ শুরু হওয়া প্লট থাকার চেয়ে টিক সাইজের 5 দিয়ে নিম্ন বাউন্ডটি 5 দিয়ে শুরু করা ভাল। তবে এটি আমার বরখাস্ত আমি আপনাকে ছেড়ে দিচ্ছি।

আশা করি এটা সাহায্য করবে. চিয়ার্স!


2

এই উত্তরটি সুইফট 4 হিসাবে রূপান্তরিত করেছে

extension Int {

    static func makeYaxis(yMin: Int, yMax: Int, ticks: Int = 10) -> [Int] {
        var yMin = yMin
        var yMax = yMax
        var ticks = ticks
        // This routine creates the Y axis values for a graph.
        //
        // Calculate Min amd Max graphical labels and graph
        // increments.  The number of ticks defaults to
        // 10 which is the SUGGESTED value.  Any tick value
        // entered is used as a suggested value which is
        // adjusted to be a 'pretty' value.
        //
        // Output will be an array of the Y axis values that
        // encompass the Y values.
        var result = [Int]()
        // If yMin and yMax are identical, then
        // adjust the yMin and yMax values to actually
        // make a graph. Also avoids division by zero errors.
        if yMin == yMax {
            yMin -= ticks   // some small value
            yMax += ticks   // some small value
        }
        // Determine Range
        let range = yMax - yMin
        // Adjust ticks if needed
        if ticks < 2 { ticks = 2 }
        else if ticks > 2 { ticks -= 2 }

        // Get raw step value
        let tempStep: CGFloat = CGFloat(range) / CGFloat(ticks)
        // Calculate pretty step value
        let mag = floor(log10(tempStep))
        let magPow = pow(10,mag)
        let magMsd = Int(tempStep / magPow + 0.5)
        let stepSize = magMsd * Int(magPow)

        // build Y label array.
        // Lower and upper bounds calculations
        let lb = stepSize * Int(yMin/stepSize)
        let ub = stepSize * Int(ceil(CGFloat(yMax)/CGFloat(stepSize)))
        // Build array
        var val = lb
        while true {
            result.append(val)
            val += stepSize
            if val > ub { break }
        }
        return result
    }

}

ইনপুটগুলি পূর্ণসংখ্যার মতো না হয় এবং ছোট সংখ্যা না হলে এটি দুর্দান্ত, উদাহরণস্বরূপ, যদি yMin = 0.03 এবং yMax = 0.11 হয়।
গ্রেগ

1

এটি যদি আপনি 10 টি পদক্ষেপ + শূন্য চান তবে এটি একটি কবজির মতো কাজ করে

//get proper scale for y
$maximoyi_temp= max($institucion); //get max value from data array
 for ($i=10; $i< $maximoyi_temp; $i=($i*10)) {   
    if (($divisor = ($maximoyi_temp / $i)) < 2) break; //get which divisor will give a number between 1-2    
 } 
 $factor_d = $maximoyi_temp / $i;
 $factor_d = ceil($factor_d); //round up number to 2
 $maximoyi = $factor_d * $i; //get new max value for y
 if ( ($maximoyi/ $maximoyi_temp) > 2) $maximoyi = $maximoyi /2; //check if max value is too big, then split by 2

1

ES5 জাভাস্ক্রিপ্টে যার যার প্রয়োজন এটির জন্য, কিছুটা কুস্তি চালাচ্ছিলেন, তবে এটি এখানে:

var min=52;
var max=173;
var actualHeight=500; // 500 pixels high graph

var tickCount =Math.round(actualHeight/100); 
// we want lines about every 100 pixels.

if(tickCount <3) tickCount =3; 
var range=Math.abs(max-min);
var unroundedTickSize = range/(tickCount-1);
var x = Math.ceil(Math.log10(unroundedTickSize)-1);
var pow10x = Math.pow(10, x);
var roundedTickRange = Math.ceil(unroundedTickSize / pow10x) * pow10x;
var min_rounded=roundedTickRange * Math.floor(min/roundedTickRange);
var max_rounded= roundedTickRange * Math.ceil(max/roundedTickRange);
var nr=tickCount;
var str="";
for(var x=min_rounded;x<=max_rounded;x+=roundedTickRange)
{
    str+=x+", ";
}
console.log("nice Y axis "+str);    

টুন ক্রিজ্তেজের দুর্দান্ত উত্তরের ভিত্তিতে।


1

এই সমাধানটি আমি পেয়েছি এমন জাভা উদাহরণের ভিত্তিতে তৈরি ।

const niceScale = ( minPoint, maxPoint, maxTicks) => {
    const niceNum = ( localRange,  round) => {
        var exponent,fraction,niceFraction;
        exponent = Math.floor(Math.log10(localRange));
        fraction = localRange / Math.pow(10, exponent);
        if (round) {
            if (fraction < 1.5) niceFraction = 1;
            else if (fraction < 3) niceFraction = 2;
            else if (fraction < 7) niceFraction = 5;
            else niceFraction = 10;
        } else {
            if (fraction <= 1) niceFraction = 1;
            else if (fraction <= 2) niceFraction = 2;
            else if (fraction <= 5) niceFraction = 5;
            else niceFraction = 10;
        }
        return niceFraction * Math.pow(10, exponent);
    }
    const result = [];
    const range = niceNum(maxPoint - minPoint, false);
    const stepSize = niceNum(range / (maxTicks - 1), true);
    const lBound = Math.floor(minPoint / stepSize) * stepSize;
    const uBound = Math.ceil(maxPoint / stepSize) * stepSize;
    for(let i=lBound;i<=uBound;i+=stepSize) result.push(i);
    return result;
};
console.log(niceScale(15,234,6));
// > [0, 100, 200, 300]


0

প্রশ্নোত্তর জন্য ধন্যবাদ, খুব সহায়ক। গেমক্যাট, আমি ভাবছি যে আপনি কীভাবে টিকের পরিসরটি বৃত্তাকার করতে হবে তা নির্ধারণ করছেন।

টিক পরিসর = 21.9। এটি 25.0 হওয়া উচিত

অ্যালগরিদমভাবে এটি করতে, বৃহত্তর সংখ্যার জন্য এই স্কেলটি সুন্দরভাবে তৈরি করতে উপরের অ্যালগরিদমে যুক্তি যুক্ত করতে হবে? উদাহরণস্বরূপ 10 টিকের সাথে, যদি পরিসীমাটি 3346 হয় তবে টিকের পরিসরটি 334.6 এ মূল্যায়ন করবে এবং নিকটতম 10 এর সাথে গোল করে 340 দিবে যখন 350 সম্ভবত ভাল লাগবে।

আপনি কি মনে করেন?


@ গেমক্যাটের উদাহরণে, 334.6 => 0.3346, যা 0.4 এ যেতে হবে। সুতরাং টিকের পরিসরটি আসলে 400 হবে, যা একটি দুর্দান্ত সংখ্যা।
ব্রায়ান

0

@ গেমক্যাটের অ্যালগরিদমের ভিত্তিতে, আমি নিম্নলিখিত সহায়ক শ্রেণি তৈরি করেছি

public struct Interval
{
    public readonly double Min, Max, TickRange;

    public static Interval Find(double min, double max, int tickCount, double padding = 0.05)
    {
        double range = max - min;
        max += range*padding;
        min -= range*padding;

        var attempts = new List<Interval>();
        for (int i = tickCount; i > tickCount / 2; --i)
            attempts.Add(new Interval(min, max, i));

        return attempts.MinBy(a => a.Max - a.Min);
    }

    private Interval(double min, double max, int tickCount)
    {
        var candidates = (min <= 0 && max >= 0 && tickCount <= 8) ? new[] {2, 2.5, 3, 4, 5, 7.5, 10} : new[] {2, 2.5, 5, 10};

        double unroundedTickSize = (max - min) / (tickCount - 1);
        double x = Math.Ceiling(Math.Log10(unroundedTickSize) - 1);
        double pow10X = Math.Pow(10, x);
        TickRange = RoundUp(unroundedTickSize/pow10X, candidates) * pow10X;
        Min = TickRange * Math.Floor(min / TickRange);
        Max = TickRange * Math.Ceiling(max / TickRange);
    }

    // 1 < scaled <= 10
    private static double RoundUp(double scaled, IEnumerable<double> candidates)
    {
        return candidates.First(candidate => scaled <= candidate);
    }
}

0

ন্যূনতম এবং সর্বাধিক মানের মধ্যে সীমা খুব কম হলে উপরের অ্যালগরিদমগুলি ক্ষেত্রে বিবেচনা করে না। এবং এই মানগুলি শূন্যের থেকে অনেক বেশি হলে কী হবে? তারপরে, আমাদের শূন্যের চেয়ে বেশি মানের সাথে y- অক্ষ শুরু করার সম্ভাবনা রয়েছে। এছাড়াও, গ্রাফের উপরের বা নীচের দিকে সম্পূর্ণরূপে আমাদের লাইনটি এড়াতে আমাদের এটিকে কিছুটা "শ্বাস নিতে বায়ু" দিতে হবে।

এই কেসগুলি কভার করার জন্য আমি উপরের কোডটি (পিএইচপি তে) লিখেছি:

function calculateStartingPoint($min, $ticks, $times, $scale) {

    $starting_point = $min - floor((($ticks - $times) * $scale)/2);

    if ($starting_point < 0) {
        $starting_point = 0;
    } else {
        $starting_point = floor($starting_point / $scale) * $scale;
        $starting_point = ceil($starting_point / $scale) * $scale;
        $starting_point = round($starting_point / $scale) * $scale;
    }
    return $starting_point;
}

function calculateYaxis($min, $max, $ticks = 7)
{
    print "Min = " . $min . "\n";
    print "Max = " . $max . "\n";

    $range = $max - $min;
    $step = floor($range/$ticks);
    print "First step is " . $step . "\n";
    $available_steps = array(5, 10, 20, 25, 30, 40, 50, 100, 150, 200, 300, 400, 500);
    $distance = 1000;
    $scale = 0;

    foreach ($available_steps as $i) {
        if (($i - $step < $distance) && ($i - $step > 0)) {
            $distance = $i - $step;
            $scale = $i;
        }
    }

    print "Final scale step is " . $scale . "\n";

    $times = floor($range/$scale);
    print "range/scale = " . $times . "\n";

    print "floor(times/2) = " . floor($times/2) . "\n";

    $starting_point = calculateStartingPoint($min, $ticks, $times, $scale);

    if ($starting_point + ($ticks * $scale) < $max) {
        $ticks += 1;
    }

    print "starting_point = " . $starting_point . "\n";

    // result calculation
    $result = [];
    for ($x = 0; $x <= $ticks; $x++) {
        $result[] = $starting_point + ($x * $scale);
    }
    return $result;
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.