![]() |
AW: Orientierungspunkte für die Y-Achse eines Diagramms berechnen
Liste der Anhänge anzeigen (Anzahl: 2)
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:
Eigentlich brauche ich doch nur den YDiv-Wert, oder?
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; Siehe neuer Screenshot und angepasstes Demo im Anhang. |
AW: Orientierungspunkte für die Y-Achse eines Diagramms berechnen
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.
|
AW: Orientierungspunkte für die Y-Achse eines Diagramms berechnen
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.
|
AW: Orientierungspunkte für die Y-Achse eines Diagramms berechnen
Zitat:
|
AW: Orientierungspunkte für die Y-Achse eines Diagramms berechnen
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:
Beispiel (Code oben):
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; 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. |
AW: Orientierungspunkte für die Y-Achse eines Diagramms berechnen
@Michael II
Super, klappt hervorragend!:thumb: |
AW: Orientierungspunkte für die Y-Achse eines Diagramms berechnen
Hallo Harry
Bin froh :-D - und wenn du einen Bug finden solltest, dann bitte PN - Dankeschön. |
AW: Orientierungspunkte für die Y-Achse eines Diagramms berechnen
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:59 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz