AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Algorithmen, Datenstrukturen und Klassendesign Orientierungspunkte für die Y-Achse eines Diagramms berechnen

Orientierungspunkte für die Y-Achse eines Diagramms berechnen

Ein Thema von Harry Stahl · begonnen am 12. Mai 2017 · letzter Beitrag vom 16. Mai 2017
Antwort Antwort
Seite 2 von 2     12
Benutzerbild von Harry Stahl
Harry Stahl

Registriert seit: 2. Apr 2004
Ort: Bonn
2.197 Beiträge
 
Delphi 10.4 Sydney
 
#11

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

  Alt 14. Mai 2017, 19:38
Die von Samso vorgeschlagene Lösung sieht schon sehr gut aus. Habe das mal in den Source gepackt, der sieht nun so aus:
Delphi-Quellcode:
procedure TForm82.Button1Click(Sender: TObject);
var
  L: Integer;
  Val, MaxVal: Extended;

  NPotenz: Integer;
  YDiv, YNorm: Double;
  YResult: Double;

begin
  with chart1 do begin
    series1.clear;
    title.Text.Text := 'Monatliche Umsätze im Jahr 2017';

    Maxval := 0;

    sgUmsatz.cells[0, 0] := 'Monat';
    sgUmsatz.cells[1,0] := 'Betrag';
    sgUmsatz.cells[2,0] := 'Wert Y-Achse';

    for L := 1 to 12 do begin
      sgUmsatz.cells[0, L] := FormatDateTime ('mmm', StrToDate ('01.01.2017') + ((L-1) * 33));
      Val := Random (TButton(sender).tag);
      MaxVal := max (MaxVal, val);
      sgUmsatz.cells[1, L] := Val.ToString;
      series1.Add (StrToFloat (sgUmsatz.cells[1, L]), sgUmsatz.cells[0,L], clGreen);
    end;
  end;

  NPotenz := trunc(Log10(MaxVal));
  YDiv:= IntPower(10, NPotenz);
  YNorm := trunc(MaxVal / YDiv);

  if YNorm<=3
    then
      YResult := YNorm
    else
    if YNorm<=5
    then
      YResult := 5
    else
      YResult := 10;

  // Soll hier nun die selbst errechneten Werte für die Y-Achse ausgeben
  for L := 1 to 10 do begin
    sgUmsatz.cells[2,L] := (L * YDiv).tostring;
  end;

  // Nicht benötigt, oder?
  YResult := YResult * YDiv;
end;
Eigentlich brauche ich doch nur den YDiv-Wert, oder?

Siehe neuer Screenshot und angepasstes Demo im Anhang.
Miniaturansicht angehängter Grafiken
bild-bcf6e9f7-2cf.jpg  
Angehängte Dateien
Dateityp: zip YAxis.zip (56,5 KB, 8x aufgerufen)
  Mit Zitat antworten Zitat
samso

Registriert seit: 29. Mär 2009
430 Beiträge
 
#12

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

  Alt 15. Mai 2017, 07:51
Da liegt ein Missverständnis vor. YDiv hat nichts mit der Einteilung der Y-Achse zu tun. Eventuell komme ich heute Abend dazu, mir Dein Demoprogramm mal vorzunehmen.
  Mit Zitat antworten Zitat
samso

Registriert seit: 29. Mär 2009
430 Beiträge
 
#13

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

  Alt 15. Mai 2017, 08:26
Ist Dein Ziel eine Nachbildung von TChart? Der Maximalwert der Y-Achse ist dort daran orientiert, dass oberhalb der Säule mit dem maximalen Umsatz noch genug Platz sein muss um das zugehörige Monats-Label anzubringen. Da muss dann natürlich die Schriftgröße des Labels, die Größe der Zeichenfläche usw. in der Berechnung berücksichtigt werden.
  Mit Zitat antworten Zitat
Benutzerbild von Harry Stahl
Harry Stahl

Registriert seit: 2. Apr 2004
Ort: Bonn
2.197 Beiträge
 
Delphi 10.4 Sydney
 
#14

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

  Alt 15. Mai 2017, 17:31
Ist Dein Ziel eine Nachbildung von TChart? Der Maximalwert der Y-Achse ist dort daran orientiert, dass oberhalb der Säule mit dem maximalen Umsatz noch genug Platz sein muss um das zugehörige Monats-Label anzubringen. Da muss dann natürlich die Schriftgröße des Labels, die Größe der Zeichenfläche usw. in der Berechnung berücksichtigt werden.
Habe das TChart mal dabei gefügt, damit man eine Orientierung hat, was sinnvolle Zahlen sein könnten. Muss also nicht exakt mit TChart übereinstimmen.
  Mit Zitat antworten Zitat
Michael II

Registriert seit: 1. Dez 2012
Ort: CH BE Eriswil
608 Beiträge
 
Delphi 10.4 Sydney
 
#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
Benutzerbild von Harry Stahl
Harry Stahl

Registriert seit: 2. Apr 2004
Ort: Bonn
2.197 Beiträge
 
Delphi 10.4 Sydney
 
#16

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

  Alt 16. Mai 2017, 00:05
@Michael II

Super, klappt hervorragend!
  Mit Zitat antworten Zitat
Michael II

Registriert seit: 1. Dez 2012
Ort: CH BE Eriswil
608 Beiträge
 
Delphi 10.4 Sydney
 
#17

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

  Alt 16. Mai 2017, 08:55
Hallo Harry

Bin froh - und wenn du einen Bug finden solltest, dann bitte PN - Dankeschön.
Michael Gasser
  Mit Zitat antworten Zitat
Benutzerbild von Harry Stahl
Harry Stahl

Registriert seit: 2. Apr 2004
Ort: Bonn
2.197 Beiträge
 
Delphi 10.4 Sydney
 
#18

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

  Alt 16. Mai 2017, 22:51
Hallo Harry

Bin froh - und wenn du einen Bug finden solltest, dann bitte PN - Dankeschön.
OK, würde ich dann machen (sieht aber nicht so aus, als ob das mal eintreffen sollte).
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:43 Uhr.
Powered by vBulletin® Copyright ©2000 - 2021, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2021 by Daniel R. Wolf