9

横軸にデータを表示するルーチンを作成します (PHP gd2 を使用しますが、ここでは重要ではありません)。

軸は から始まり、$min$maxひし形を表示します$result。このような画像は、次のように幅 300 ピクセル、高さ 30 ピクセル程度になります。

例
(ソース: testwolke.de )

上記の例では、$min=0$max=3$result=0.6. ここで、意味のあるスケールとラベルを計算する必要があります。たとえば、上の例では、 の点線0 .25 .50 .75 1 1.25 ... up to 3と の数値ラベルがあり0 1 2 3ます。

と の場合$min=-200$max=600点線は に-200 -150 -100 -50 0 50 100 ... up to 600、数値ラベルは にあるはず-200 -100 0 100 ... up to 600です。

と、点線で$min=.02、数字で。$max=5.80.02 .5 1 1.5 2 2.5 ... 5.5 5.8.02 1 2 3 4 5 5.8

点線と数字を配置する場所を配列で関数に明示的に指示しようとしましたが、動作するのは私ではなくコンピューターですよね?!

では、どうやって計算するの???

4

4 に答える 4

7

アルゴリズム (例の値$min=-186$max=+153制限として):

  1. これらの 2 つの制限$minを取り$max、必要に応じてマークします

  2. と の差を計算し$maxます$min$diff = $max - $min
    153 - (-186) = 339

  3. 差の 10 番目の対数を計算$base10 = log($diff,10) = 2,5302

  4. 切り捨て: $power = round($base10)= 2。
    これは、基本単位としての 10 番目の累乗です。

  5. これを計算$stepするには:
    $base_unit = 10^$power= 100;
    $step = $base_unit / 2; (1つにつき2ティックが必要な場合$base_unit)。

  6. $minが で割り切れる場合は計算し$step、そうでない場合は最も近い (切り上げた) ものを取る(
    の場合)$step = 50$loop_start = -150

  7. for ($i=$loop_start; $i<=$max; $i++=$step){ // $i's are your ticks

  8. 終わり

Excel でテストしたところ、非常に良い結果が得られました。機能を増やしたいと思うかもしれません。

たとえば、(ポイント 5)$stepから最初に計算し て$diff、で割り切れる方法で丸めます。
$step = $diff / 4$step$base_unit$step

これにより、(101;201) の間に 4 つのティックがあり、0 から 999 の間$step=25に 39 のステップがあるような状況が回避されます。$step=25

于 2013-02-26T13:34:34.210 に答える
6

ACM Algorithm 463nは、データ ポイントxminとを含む間隔の要求が与えられた場合に、スケールの最小値と最大値、およびスケールの目盛り間の距離の出力 xminp、xmaxp、dist を使用して適切な軸スケールを生成する 3 つの単純な関数を提供しますxmax

  1. Scale1()nおおよその間隔を持ちdist、1、2、または 5 の 10 倍の整数乗である線形スケールを返します。
  2. Scale2()は正確な間隔で線形スケールを与えnます (xminp と xmaxp の間のギャップは によって生成されるギャップよりも大きくなる傾向がありますScale1())。
  3. Scale3()対数目盛を与える.

元の 1973 年の論文はここでオンラインにあり、上記のリンク先のコードよりも詳しい説明が記載されています。

コードは Fortran で書かれていますが、単なる算術計算のセットであるため、解釈して他の言語に変換するのは非常に簡単です。私は自分で PHP を書いたことはありませんが、C によく似ているので、PHP で実行可能なものに近いものを提供するf2cを介してコードを実行することから始めたいと思うかもしれません。

よりきれいなスケールを提供するより複雑な関数がありますが (例: の関数gnuplot)、Scale1()最小限のコードで作業を行う可能性があります。

(この回答は、以前の質問Graph axis calibration in C++に対する私の回答に基づいています)

(編集 - Scale1()Perl で行った実装を見つけました):

use strict;

sub scale1 ($$$) {
  # from TOMS 463
  # returns a suitable scale ($xMinp, $xMaxp, $dist), when called with 
  # the minimum and maximum x values, and an approximate number of intervals
  # to divide into. $dist is the size of each interval that results.
  # @vInt is an array of acceptable values for $dist.
  # @sqr is an array of geometric means of adjacent values of @vInt, which
  # is used as break points to determine which @vInt value to use.
  #
  my ($xMin, $xMax, $n) = @_;
  @vInt = {1, 2, 5, 10};
  @sqr = {1.414214, 3.162278, 7.071068 }
  if ($xMin > $xMax) {
    my ($tmp) = $xMin;
    $xMin = $xMax;
    $xMax = $tmp;
    }
  my ($del) = 0.0002;   # accounts for computer round-off
  my ($fn) = $n;
  # find approximate interval size $a
  my ($a) = ($xMax - $xMin) / $fn;
  my ($al) = log10($a);
  my ($nal) = int($al);
  if ($a < 1) {
    $nal = $nal - 1;
    }
  # $a is scaled into a variable named $b, between 1 and 10
  my ($b) = $a / 10^$nal;
  # the closest permissable value for $b is found)
  my ($i);
  for ($i = 0; $i < $_sqr; $i++) {
    if ($b < $sqr[$i]) last;
  }
  # the interval size is computed
  $dist = $vInt[$i] * 10^$nal;
  $fm1 = $xMin / $dist;
  $m1 = int($fm1);
  if ($fm1 < 0) $m1--;
  if (abs(($m1 + 1.0) - $fm1) < $del) $m1++;
  # the new minimum and maximum limits are found
  $xMinp = $dist * $m1;
  $fm2 = $xMax / $dist;
  $m2 = $fm2 + 1;
  if ($fm2 < -1) $m2--;
  if (abs ($fm2 + 1 - $m2) < $del) $m2--;
  $xMaxp = $dist * $m2;
  # adjust limits to account for round-off if necessary
  if ($xMinp > $xMin) $xMinp = $xMin;
  if ($xMaxp < $xMax) $xMaxp = $xMax;
  return ($xMinp, $xMaxp, $dist);
  }

sub scale1_Test {
  $par = (-3.1, 11.1, 5,
      5.2, 10.1, 5,
      -12000, -100, 9);
  print "xMin\txMax\tn\txMinp\txMaxp,dist\n";
  for ($i = 0; $i < $_par/3; $i++) {
    ($xMinp, $xMaxp, $dist) = scale1($par[3*$i+0], 
    $par[3*$i+1], $par[3*$i+2]);
    print "$par[3*$i+0]\t$par[3*$i+1]\t$par[3*$i+2]\t$xMinp\t$xMaxp,$dist\n";
    }
  }
于 2013-02-25T19:35:01.923 に答える
3

これがまさにあなたが探しているものではないことはわかっていますが、うまくいけば、正しい方向に進むことができます.

$min = -200;
$max = 600;
$difference = $max - $min;
$labels = 10;
$picture_width = 300;
/* Get units per label */
$difference_between = $difference / ($labels - 1);
$width_between = $picture_width / $labels;
/* Make the label array */
$label_arr = array();
$label_arr[] = array('label' => $min, 'x_pos' => 0);
/* Loop through the number of labels */
for($i = 1, $l = $labels; $i < $l; $i++) {
    $label = $min + ($difference_between * $i);
    $label_arr[] = array('label' => $label, 'x_pos' => $width_between * $i);
}
于 2013-02-19T17:55:59.920 に答える
1

$increment = ($max-$min)/$scale簡単な例は、スケールを微調整して、増分がスケールする変数になる行の何かです。それによって除算するため、最大値と最小値が変化すると比例して変化するはずです。その後、次のような関数が作成されます。

$end = false;
while($end==false){
    $breakpoint = $last_value + $increment; // that's your current breakpoint
    if($breakpoint > $max){
        $end = true;
    } 
}

少なくともそれがコンセプトです...問題がある場合はお知らせください。

于 2013-02-26T08:57:54.047 に答える