Einzelnen Beitrag anzeigen

Michael II

Registriert seit: 1. Dez 2012
Ort: CH BE Eriswil
703 Beiträge
 
Delphi 11 Alexandria
 
#15

AW: Orientierungspunkte für die Y-Achse eines Diagramms berechnen

  Alt 15. Mai 2017, 19:42
Der Funktion yIntervallLOG() unten kannst du den minimalen Y Wert und den maximalen Y Werte deiner darzustellenden Zahlenpaare übergeben. (miny, maxy : Extended) - (Negative Werte sind auch OK.)

Du kannst wählen, in wie viele Teile (anzint_min bis anzint_max) die Y Achse ungefähr eingeteilt werden soll. (anzint_min, anzint_max : integer)

Du kannst der Funktion übergeben, welche Zahlentypen du erlauben willst. (Parameter erlaubt: TExtendedArray)

Falls aufgrund der übergebenen Parameter kein Resultat gefunden wird:
Über andereschrittweitenerlaubt:boolean steuerst du, ob zusätzlich getestet werden soll, ob Schrittweiten vom Typ f*10^p, f=1,2,3,4,5,6,7,8,9 möglich sind.

Falls die Funktion keine mögliche Unterteilung findet, dann wird geprüft, ob's mit anzint_min := anzint_min-1 klappt.



Delphi-Quellcode:

uses math;


type TExtendedArray = array of extended;


function yIntervallLOG( miny, maxy : extended; anzint_min, anzint_max : integer;
     erlaubt: TExtendedArray; andereschrittweitenerlaubt : boolean = false ) : TExtendedArray;

var fak_min, fak_max,
    delta, int_min, int_max : extended;
    potmin, potmax, len, i : integer;
    potenz10 : integer;


label nocheinmal;

    procedure check( pot: integer; f : extended );
    // prüfe, ob f*10^pot im Intervall I liegt und damit eine mögliche schrittweite ist
    var wert : extended;
    begin
      wert := f*power(10,pot);
      if ( int_min <= wert ) and ( wert <= int_max ) then
      begin
          SetLength( Result, length(Result)+1 );
          Result[length(Result)-1] := wert;
      end;
    end;

    procedure pot_fak( z : extended; var pot : integer; var f : extended );
    // Berechne die Zerlegung von z: z = f*10^pot
    // IN z - OUT f, pot
    begin
      if ( abs(z) >= 1 ) then
      begin
        pot := trunc(log10( abs(z) ));
        f := z/power(10,pot);
      end
      else
      begin
        pot := trunc(log10( abs(z) ))-1;
        f := z/power(10,pot);
      end;
    end;

begin
  delta := maxy - miny;
  assert( delta > 0 , 'Maximum ' + floattostr(maxy) + ' nicht grösser als Minimum ' + floattostr(miny) );

  nocheinmal:
  // Schrittweite liegt aufgrund der Parameter zwischen int_min und int_max:
  // I:= Intervall [int_min..int_max]
  int_min := delta/anzint_max;
  int_max := delta/anzint_min;

  // Zerlegungen in_min = fak_min*10^potmin, in_max = fak_max*10^potmax bestimmen:
  pot_fak( int_min, potmin, fak_min );
  pot_fak( int_max, potmax, fak_max );

  len := length(erlaubt);

  // Prüfen, ob die erlaubten Vorgaben im Intervall [int_min..int_max] liegen
  for i := 0 to len-1 do
  for potenz10 := potmin to potmax do
    check( potenz10, erlaubt[i] );

  // keine Werte gefunden?
  if ( length(Result) = 0 ) then
  begin
    // falls andere schrittweiten erlaubt:
    // Prüfe, ob n*10^potenz10, für n=1,2,3,4,5,6,7,8,9 möglich ist
    // Prüfe also zum Beispiel auf 300er, 70er, 0.4, 0.07 etc. Schritte...
    if andereschrittweitenerlaubt then
    begin
      for I := 1 to 9 do
      for potenz10 := potmin to potmax do
       check( potenz10, i );
    end;

    // Wenn immer noch keine Resultate gefunden sind, dann erlauben wir ein tieferes anzint_min:
    if ( length(Result) = 0 ) then
    if anzint_min > 1 then
    begin
      dec( anzint_min );
      goto nocheinmal;
    end;
  end;
end;

So rufst du die Funktion auf:

Delphi-Quellcode:
procedure TForm92.Button2Click(Sender: TObject);
var erlaubt, res : TExtendedArray;
    min, max : extended;
    hs : string;
    i : integer;
begin
   setlength( erlaubt, 5 );
   erlaubt[0] := 1;
   erlaubt[1] := 5;
   erlaubt[2] := 2;
   erlaubt[3] := 2.5;
   erlaubt[4] := 7.5;

   min := 0;
   max := 543;
   res := yIntervallLOG( min, max, 8, 16, erlaubt );

   hs := 'min=' + min.ToString + #13#10 +
         'max=' + max.ToString + #13#10;
   hs := hs + 'Mögliche Intervalle:' + #13#10;
   for i := 0 to length(res)-1 do hs := hs + floattostr(res[i]) + #13#10;

   Showmessage( hs);
end;
Beispiel (Code oben):
Du willst y Werte zwischen 0 und 543 darstellen, die y-Achse soll in 8-16 Teile geteilt werden, erlaubt sind Schrittweiten vom Typ 1*10^p, 5*10^p, 2*10^p, 2.5*10^p und 7.5*10^p.

Resultat: 50 (ist vom erlaubten Typ 5*10^5)

Die Funktion gibt jeweils alle möglichen Schrittweiten (Unterteilungen) aus. Zuerst werden Zahlen vom Typ erlaubt[0] ausgegeben, dann vom Typ erlaubt[1], usw..

Beispiel 2:
Wenn du im Beispiel statt 8-16 Teile nun 4-16 Teile erlaubst, dann gibt dir die Funktion die drei möglichen Unterteilungen 100, 50, 75 zurück. (100 zuerst, weil erlaubt[0]=1, dann 50, weil erlaubt[1]=5 und schliesslich noch 75, weil du mit erlaubt[4]=7.5 auch nach Unterteilungen vom Typ 7.5*10^p suchen lässt.)


Beispiel 3:
res := yIntervallLOG( min, max, 5, 16, NIL, true );
sucht nach Unterteilungen der y-Achse vom Typ n*10^p n=1..9.
Michael Gasser

Geändert von Michael II (16. Mai 2017 um 09:00 Uhr)
  Mit Zitat antworten Zitat