Moin!
Was ich eigentlich noch besseer fände wäre eine ganz standardisiert Skala, halt bei 1798-2178
1750
1800
1850
...
2150
2200
Davon hatte ich ja geredet, bevor es zu diesem Intermezzo kam. :)
Du mußt ein paar Dinge festlegen, bevor du loslegen kannst:
1. Wieviele Teilstriche soll es auf der Skala geben? Meine Annahme waren 10 Stück. Ok, dank des "off-by-one"-Problems ist diese Zahl gelogen: Es sind nicht 10 Teilstriche, sondern 11, und diese haben 10 Zwischenräume.
Normiert: 0,0 - 0,1 - 0,2 - 0,3 - 0,4 - 0,5 - 0,6 - 0,7 - 0,8 - 0,9 - 1,0
Wenn du auf Viertel und nicht auf Zehntel teilen willst, hast du logischerweise nur fünf Teilstriche und entsprechend vier Zwischenräume.
Normiert: 0,0 - 0,25 - 0,5 - 0,75 - 1,0
Die Wahl der Teilstriche hängt entscheidend davon ab, wie es als Grafik aussieht. Eines steht dabei aber fest: Du hast mindestens zwei Teilstriche - einen unten und einen oben als Begrenzungen der Skala:
Normiert: 0,0 - 1,0
Und die Anzahl der Teilstriche richtet sich danach, wie gut sich die zur Verfügung stehenden Pixel aufteilen lassen. 100 Pixel sind gut auf 10 Intervalle aufteilbar, und auch auf 4 Intervalle lassen sie sich gut verteilen. Bedenke, dass du in beiden Fällen 101 Pixel benötigst, um oben drüber noch eine Abschlußlinie für den obersten Strich zeichnen zu können, denn ein Intervall besteht aus einem Pixel Linie und 9 Pixeln Leere - zusammen 10 Pixel. Für 10 Intervalle sind das 100 Pixel - und der 101.ste Pixel ist die Linie oben drüber.
Wenn du dein Intervall dritteln willst, empfiehlt es sich zum Beispiel, ein Intervall genau 33 Pixel groß zu machen, was bei 99 Pixeln endet - der 100.ste Pixel ist dann die Abschlusslinie. Auf diese Weise sparts du dir die Drittelbrüche.
Das sind aber alles Dinge, die du vorher manuell festlegen solltest. Zehntel und Fünftel sind miteinander Kompatibel, und auch Viertel passen da gut ins Raster rein. Achtel gehen schon schwieriger, weil sie bei 100 Pixeln Höhe 12,5 Pixel hohe Intervalle erfordern würden. Andere Teilungen sind ziemlich undenkbar, ohne dass du die Höhe der Grafik immer anpassen mußt.
Sofern du weißt, welche Teilung die Skala haben soll, hast du gewisse Grafikgrundparameter schon mal geklärt. :)
Jetzt muss der Wertebereich transferiert werden.
Ich hatte erwähnt, dass die Differenz zwischen Minimum und Maximum auf irgendein Raster passen muß. Die Differenz im Beispiel ist 397 gewesen (oder so ähnlich), du hättest also die Wahl, die Skala auf 400 Einheiten festzulegen, oder auf 500 Einheiten. Bei anderen Konstellationen hast du möglicherweise die Wahl, auf 25 Einheiten zu skalieren (und dann z.B. nur 5 Intervalle zu nutzen), oder auf 50, oder 100, oder auf 10.000. Versuche, dafür eine einheitliche Regel zu finden. Wie findet man die kleinste Zahl, die größer ist als die Differenz, aber trotzdem gerade?
Empfehlenswert könnte diese Zahlenreihe "passender Skalierungen" sein:
50, 100, 500, 1000, 5000, 10000, 50000...
Allerdings: Wenn du jeweils leicht über eine Grenze drübergehst (Differenz: 510), dann wird sofort eine Skalierung genommen, die die auszugebende Grafik auf nur die Hälfte des Verfügbaren Platzes reduziert. Es ist also evtl. besser, feinere Abstufungen zuzulassen:
25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000, 7500, 10000...
Das Minimum dürfte unter Umständen sogar noch zu hoch gegriffen sein - es sei denn, wir rechnen in Cent. 25 Euro Mindestumfang der Skala ist jedenfalls noch etwas grob für kleine Beträge, 25 Cent hingegen vollkommen ausreichend - da würde ich dann sogar erst bei 100 Cent beginnen.
Ok, werden wir etwas konkreter: Mit welcher Formel bildet man diese Werte? Denn es ist irgendwie sinnvoll, entweder mit einer Schleife diese Zahlenwerte nacheinander zu berechnen und beim ersten, der größer als die Differenz zwischen Min und Max ist, anzuhalten. Noch besser wäre eine Funktion, welche als Argument die Differenz erhält, und als Ergebnis das passende übergreifende Intervall erhält.
Eine mathematische Formel für die Zahlenreihe wird vermutlich schwierig zu entwickeln sein, aber als PHP-Funktion könnte das hier hilfreich sein:
function get_scale_range($minrange)
{
$minrange = abs($minrange); // Wenn sich die Differenz mal verrechnet und negativ ist - besser das Vorzeichen weghauen
$raster = 25; // Rasterwert: 25xx, 50xx, 75xx, 100xx
$potenz = 0; // Start bei 10^0 = 1
$step = 1; // Hilfsvariable, die die Schritte in einem Wertebereich mitzählt.
$range = 25; // Startwert
while ($range < $minrange)
{
$step++;
if ($step % 4 == 0) // Alle vier Erhöhungsschritte
{
$potenz++; // die Zehnerpotenz erhöhen
}
$range = $range + $raster * 10 ^ $potenz
}
return $range;
}
Die Funktion ist ungetestet, sollte aber grob das erledigen, was du willst: Sie erstellt dir einen Skalierung, die deine Differenz umfasst. Ich habe darauf verzichtet, den Rasterwert 25 als Parameter zu übergeben, weil davon auch der Modulo-Wert von $step abhängt - die Funktion ist maßgeschneidert auf die Anforderung. Man sollte nie zu allgemein programmieren, wenn es nicht notwendig ist.
Der Rest ist noch etwas Rechenkram: Du kennst deine Skalierung der Achse, also kennst du auch den Wert eines Teilstrichintervalls: Skalierung geteilt durch Anzahl Intervalle - also teilen durch 10.
Du suchst jetzt eine "runde" Zahl kleiner als dein Minimum, welche als Startpunkt deiner Skala dienen kann.
Auch hier kann "Modulo"-Rechnen ziemlich gut helfen, weil es den unnötigen, krummen "Rest" deines Minimums wegnimmt.
int($min / ($range/10)) * ($range/10) = Startwert der Skala
Erklärung:
$range/10 ergibt die Einteilung der Teilstriche im Bereich der Skala - und natürlich außerhalb.
Wenn ich das Minimum durch die Teilstrichintervalle teile, weiß ich, wieviele Teilstriche auf der Skala _ab Null_ ich auftragen muß, um $min zu markieren. Wenn ich mit int() den Nachkommaanteil abschneide, erhalte ich die Teilstriche, die von $min _vollständig_ abgedeckt werden - der letzte, nur teilweise ausgenutzte Teilstrich entfällt.
Multipliziere ich das Ganze wieder mit dem Intervall eines Teilstrichs, bin ich wieder im Bereich meiner ursprünglichen Skala, und kenne den Wert des Teilstrichs, der sich direkt unter dem Minimum befindet. :)
Auf den Startwert addierst du ggf. den Skalabereich, um den Endwert zu erhalten - das sollte aber nicht zwingend nötig sein.
- Sven Rautenberg
"Bei einer Geschichte gibt es immer vier Seiten: Deine Seite, ihre Seite, die Wahrheit und das, was wirklich passiert ist." (Rousseau)