Graphen generieren
Andreas Korthaus
- programmiertechnik
Hallo!
ich bin gerade dabei eine mini-auktion zu erstellen, dafür soll es auch eine graphische Auswertungs-Möglichkeit des Bietverlaufs geben.
Ich kenne natürlich die bekannten libs wie jpgraph..., aber das ist alles nicht flexibel genug, also muß ich es wohl oder über selbst schreiben. Da frage ich mich jetzt, womit ich das am besten mache. Als Server-Programmiersprache soll PHP dienen(nur zur Not PERL -> gibt es hierfür vielleicht ein Modul?).
Ich überlege eigentlich in 3 Richtungen:
1. Erstellung eines png "onTheFly", in das ich dann dem Bietverlauf entsprechend Pixel/Linien eintrage
2. SVG
3. HTML(<div>'s)
Es soll ein Graph erstellt werden, der alle eingegangenen Gebote im Zeitverlauf(x-achse) und mit der Höhe(y-achse) darstellt.
Auf den ersten Blick hört sich das da so an, als könnten das die bekannten Tools doch, aber ich habe ein Problem:
Jeder Bieter soll eine eigene Farbe bekommen, um so _alle_ Gebote in den Graphen einfügen zu können, also Bieter 1 ist blau, Bieter 2 ist rot, dann zeichne ich alle Gebote der Bieter mit entsprechenden Farben in den Graphen ein. Die Bestgebote sollen dann mit Linien verbunden werden und bilden so die Kurve.
Wie mache ich das am besten? SVG stört mich am meisten, da kaum jemand dieses plugin hat. Mit HTML ist es IMHO seh schwierig, vor allem wenn es in den verschiedenen Browsern 100%ig gleich dargestellt werden muß.
Also bleibt nur noch das Generieren von png's. Kennt jemand vielleicht doch noch eine Bibliothek, mit der ich das evtl. realisiern könnte? Oder ein PERL-Modul?
Und noch ein konzeptionelles Problem, das mit den verschiedenen Farben ist ja schön und gut, nur was wen ich 20, 30 oder 50 Bieter habe? Hat jemand ne Idee wie man die Bieter dann noch auseinanderhalten könnte?
Viele Grüeß
Andreas
Hallo,
Wie mache ich das am besten? SVG stört mich am meisten, da kaum jemand dieses plugin hat.
Naja, immerhin besteht durchaus die Moeglichkeit, diesen Zustand zu verbessern, wenn man Anwendungen schafft, die es den Leuten als lohnend nahelegen, sich ein Plugin zu installieren ...
Wenn es bei Deiner Anwendung nur um eine optionale Grafik geht, dann versuche doch mal ein Stueck Zukunft ;-). Vielleicht hilft Dir http://www.datenverdrahten.de/svglbc/ dabei.
BTW: Du koenntest ja auch mal etwas in Richtung dynamisches Flash mit PHP versuchen (Stichwort: MING-Bibliothek).
MfG, Thomas
Moin!
Ich kenne natürlich die bekannten libs wie jpgraph..., aber das ist alles nicht flexibel genug, also muß ich es wohl oder über selbst schreiben.
Du kennst die Grafik-Funktionen von PHP? Die nutzen die gdlib (seit PHP 4.3 ist die gdlib sogar in einer speziellen Fassung bei PHP mit dabei und kann noch ein paar Features mehr).
Was ist an der Möglichkeit, im Prinzip jeden einzelnen Pixel setzen zu können, unflexibel? Natürlich mußt du einen größeren Aufwand treiben, wenn das grafische Ergebnis toll designt aussehen soll - aber wenn es um immer wiederkehrende Elemente mit einigen variablen Eintragungen geht, kannst du genausogut die Grundelemente in einem Grafikprogramm erstellen und als Grafikdatei ablegen, und sie dann bei Bedarf als Grundlage für das zu erstellende Bild wieder laden.
Auf den ersten Blick hört sich das da so an, als könnten das die bekannten Tools doch, aber ich habe ein Problem:
Jeder Bieter soll eine eigene Farbe bekommen, um so _alle_ Gebote in den Graphen einfügen zu können, also Bieter 1 ist blau, Bieter 2 ist rot, dann zeichne ich alle Gebote der Bieter mit entsprechenden Farben in den Graphen ein. Die Bestgebote sollen dann mit Linien verbunden werden und bilden so die Kurve.
Du hast das schon mal manuell erstellt und findest es übersichtlich? Mir scheint, da kommen ziemlich viele Farben in ziemlich wildem Durcheinander ins Spiel, und man sieht am Ende gar nichts. Naja, ist nur meine Befürchtung, muß der Realität nicht entsprechen. Nur wenn 30 oder mehr Bieter auftreten, dann wird es in der Grafik eng.
Also bleibt nur noch das Generieren von png's. Kennt jemand vielleicht doch noch eine Bibliothek, mit der ich das evtl. realisiern könnte? Oder ein PERL-Modul?
Das PHP-Interface zur gdlib ist für dein Vorhaben gut geeignet. Allerdings brauchst du (und das wurde unlängst im Forum diskutiert) natürlich mathematische Grundlagen, um die Grafikausgabe auch vernünftig programmieren zu können. Vom Himmel fällt sie nämlich nicht. Ich stehe selbst allerdings auch erst am Anfang der Anwendung der gdlib.
Und noch ein konzeptionelles Problem, das mit den verschiedenen Farben ist ja schön und gut, nur was wen ich 20, 30 oder 50 Bieter habe? Hat jemand ne Idee wie man die Bieter dann noch auseinanderhalten könnte?
Unwichtige Bieter ausblenden oder ausgrauen würde helfen.
- Sven Rautenberg
Hallo!
Du kennst die Grafik-Funktionen von PHP?
jepp, vom höernsagen/lesen, habe es aber noch nicht verwendet.
Die nutzen die gdlib (seit PHP 4.3 ist die gdlib sogar in einer speziellen Fassung bei PHP mit dabei und kann noch ein paar Features mehr).
Muß mal schauen. Kann man damit auch "schön schreiben", also wenn ich in Arial einen Text reinschreibe das der nicht so pixelig aussieht wie in den vielen Graphen die man manchsmal so sieht?
Was ist an der Möglichkeit, im Prinzip jeden einzelnen Pixel setzen zu können, unflexibel?
Mit Bibliotheken meinte ich jpgraph & Co. Sicher ist gdlib das flexibelste was es gibt. Aber eben nicht "mal eben so" einzubauen, das auch ansehentliche Grafiken bei rauskommen.
Natürlich mußt du einen größeren Aufwand treiben, wenn das grafische Ergebnis toll designt aussehen soll - aber wenn es um immer wiederkehrende Elemente mit einigen variablen Eintragungen geht, kannst du genausogut die Grundelemente in einem Grafikprogramm erstellen und als Grafikdatei ablegen, und sie dann bei Bedarf als Grundlage für das zu erstellende Bild wieder laden.
Das sowieso, am meisten sorgen mache ich mir pber die "Pixelikeit" das es so aussieht wie "billigschrott". Wobei ich ein wenig Angst habe, denn es gibt ja einige Klassen hierfür, und die meisten sehen wirklich schlimm aus!
Auf den ersten Blick hört sich das da so an, als könnten das die bekannten Tools doch, aber ich habe ein Problem:
Jeder Bieter soll eine eigene Farbe bekommen, um so _alle_ Gebote in den Graphen einfügen zu können, also Bieter 1 ist blau, Bieter 2 ist rot, dann zeichne ich alle Gebote der Bieter mit entsprechenden Farben in den Graphen ein. Die Bestgebote sollen dann mit Linien verbunden werden und bilden so die Kurve.
Du hast das schon mal manuell erstellt und findest es übersichtlich?
habe ich nicht.
Mir scheint, da kommen ziemlich viele Farben in ziemlich wildem Durcheinander ins Spiel, und man sieht am Ende gar nichts.
die Gefahr sehe ich auch.
Das PHP-Interface zur gdlib ist für dein Vorhaben gut geeignet. Allerdings brauchst du (und das wurde unlängst im Forum diskutiert) natürlich mathematische Grundlagen, um die Grafikausgabe auch vernünftig programmieren zu können. Vom Himmel fällt sie nämlich nicht.
Klar, aber da sehe ich nicht das Problem. Wenn ich z.B. eine Grafik mit 100 x 100 Pixeln erstelle, kann ich ja ganz genau berechnen was wo angezeigt werden soll, ich definiere einen Anzeigebereich für x- und y-Achse, und Rechne die Daten aus dem theoretischen Koordinatensystem(wie in der Schule) um in mein 100 x 100 Koordinaten-System. Ich muß es wohl einfach mal probieren...
Unwichtige Bieter ausblenden oder ausgrauen würde helfen.
Das ist gut! Ich fang wohl einfach mal an ;-)
Danke und viele Grüße
Andreas
Moin!
Klar, aber da sehe ich nicht das Problem. Wenn ich z.B. eine Grafik mit 100 x 100 Pixeln erstelle, kann ich ja ganz genau berechnen was wo angezeigt werden soll, ich definiere einen Anzeigebereich für x- und y-Achse, und Rechne die Daten aus dem theoretischen Koordinatensystem(wie in der Schule) um in mein 100 x 100 Koordinaten-System. Ich muß es wohl einfach mal probieren...
Unwichtige Bieter ausblenden oder ausgrauen würde helfen.
Das ist gut! Ich fang wohl einfach mal an ;-)
Genau. Einfach mal probieren. Das schlimmste Problem wird sein, die gdlib zu integrieren, sollte dein PHP (bzw. das PHP, was letztendlich die Ausgabe erledigen soll), die gdlib nicht kennen.
Ansonsten: Testen. Probieren. Erfahrungen sammeln.
Bedenke auch, dass einige der gd-Funktionen in PHP nicht in allen gd-Versionen zur Verfügung stehen. Beispielsweise (was ich vermißt habe) gibts imagerotate() erst seit PHP 4.3.0. :)
Außerdem kann man das Vorhandensein der Grafikfunktionen nicht immer dynamisch über function_exists() korrekt abfragen - auch wenn die Funktion tatsächlich nicht existiert, wird aufgrund von Bugs manchmal bzw. in bestimmten Versionen von PHP trotzdem true zurückgegeben. Im Bugfix-Report von PHP 4.3.0 wurde jedenfalls davon gesprochen, IIRC.
- Sven Rautenberg
Hallo Sven!
Also, habe doch glatt mal gestartet, als Vorlage diente mir ein IX-Artikel: http://www.heise.de/ix/artikel/2002/05/078/ habe das mit der Ping-Statistik einfach mal ausgebaut, halt Rechtecke für an der Stelle jedes Eintrages, eine Durschschnittslinie, bisher eigentlich recht problemlos, und erstaunlich einfach.
Das einzige was mit jetzt Kopfzerbrechen bereitet ist das schreiben von Text. Wie es aussieht kann man mit http://www.php3.de/manual/de/function.imagechar.php lediglich einzelne Buchstaben schreiben. Gibt es keien Möglichkeit einen ganzen String zu schreiben? Denn sonst kann ich keine Proportionalschrift wie Arial verwenden. Ist die einzige Möglichkeit den Text buchtabenweise mit jeweils entsprechenden Koordinaten zu generieren? Na gut, dafür könnte ich mir ne Funktion schreiben, die das alles macht, oder gibt es da noch eine Methode die ich noch nicht kenne?
Und nochwas, ich überlege gerade, wie ich sinnvollerweise eine Skala implemementiere. Am besten wäre natürlich eine Skala mit schönen geraden Schritten, also 10,20,30, oder 2040, 2060, 2080, 2100...
das ist halt immer unterschiedlich, je nach Wertebereich, in denen die Werte liegen. Ich würde mir jetzt den max-wert und den min-wert ermitteln, vielleicht beide jeweils +/- 10 %, dann sagen wir mal der höchte Wert ist 2187 und der niedrigste 1790. Das Problem ist jetzt, wei kome ich an schön gerade Werte? Die Grafik hat jetzt 100 Pixel in der höhe, dann wäre 2187 + 10% der max-Wert, und 1790 -10% der min-wert. In die Grafik soll dann eine Skala mit den Werten
1700, 1800, 1900, 2000, 2100, 2200 eingefügt werden, aber wie kommeich jetzt an die Zahlen? Zwischen meinen oben errechneten min/max werten liegen dann etwas über 500 Punkte. Wie komme ich jetzt auf diese zahlen, so dass es auch mit ganz anderen Zahlen vergleichbar funktioniert? Ich wüßte zwar Teil-Lösungen, so dass man z.B. durch 100 teilt und und dann eine absolute Zahl bildet udn wieder mit 100 multipliziert, aber das bringt mich erstmal nicht viel weiter.
Wenn es keine so geraden Zahlen sein müßten würde ich einfach vorher festlegen weiviele Skaleneinträge ich möchte, die Differenz wz. min/max durch diese Zahl -1 dividieren, und dann indem ich die mon-zahl um jeweils dieses ergebnis erhöhe bekomme ich die Einträge.
Wie bekomme ich das beides jetzt zusammen?
Viele Grüße
Andreas
Moin!
Das einzige was mit jetzt Kopfzerbrechen bereitet ist das schreiben von Text. Wie es aussieht kann man mit http://www.php3.de/manual/de/function.imagechar.php lediglich einzelne Buchstaben schreiben. Gibt es keien Möglichkeit einen ganzen String zu schreiben?
Doch. Die Funktion heißt imagettftext(), erfordert das Vorhandensein der passenden TTF-Schriftart und außerdem noch das Vorhandensein der Freetype-Bibliothek. Wie gut die Ergebnisse sind, kann ich aber noch nicht sagen - ich hab's noch nicht ausprobiert.
Und nochwas, ich überlege gerade, wie ich sinnvollerweise eine Skala implemementiere. Am besten wäre natürlich eine Skala mit schönen geraden Schritten, also 10,20,30, oder 2040, 2060, 2080, 2100...
Du hast idealerweise eine Skala, bei denen zwischen zwei Teilstrichen immer gleich viele Pixel liegen, damit die Grafik schön regelmäßig aussieht.
Davon unabhängig mußt du das Problem betrachten, welche Zahlenwerte du an die Skala ranschreibst. :)
das ist halt immer unterschiedlich, je nach Wertebereich, in denen die Werte liegen. Ich würde mir jetzt den max-wert und den min-wert ermitteln, vielleicht beide jeweils +/- 10 %, dann sagen wir mal der höchte Wert ist 2187 und der niedrigste 1790. Das Problem ist jetzt, wei kome ich an schön gerade Werte? Die Grafik hat jetzt 100 Pixel in der höhe, dann wäre 2187 + 10% der max-Wert, und 1790 -10% der min-wert. In die Grafik soll dann eine Skala mit den Werten
1700, 1800, 1900, 2000, 2100, 2200 eingefügt werden, aber wie kommeich jetzt an die Zahlen? Zwischen meinen oben errechneten min/max werten liegen dann etwas über 500 Punkte. Wie komme ich jetzt auf diese zahlen, so dass es auch mit ganz anderen Zahlen vergleichbar funktioniert? Ich wüßte zwar Teil-Lösungen, so dass man z.B. durch 100 teilt und und dann eine absolute Zahl bildet udn wieder mit 100 multipliziert, aber das bringt mich erstmal nicht viel weiter.
Wie du siehst: Mathematik ist zu Recht elementarer Bestandteil von Informatik. ;)
Dein Problem ist übrigens nicht trivial. Da haben sich schon andere Leute die Zähne dran ausgebissen.
Wie ich oben andeutete: Du kannst natürlich dein Raster mit den Teilstrichen fest vorgeben. Den Verfügbaren Platz von ungefähr 100 Pixeln (ungefähr deshalb, weil exakt 100 Pixel wahrscheinlich nicht auf 10 Teilstriche aufteilbar sind) teilst du immer fest auf.
Dann rechnest du aus, bei welchem Minimum der Graph beginnen soll, und beschriftest die Achse unten entsprechend. Analog dazu behandelst du das Maximum. Als Resultat erhälst du eine Grafik, die von 1790 bis 2187 geht und den verfügbaren Platz voll ausnutzt.
Wenn das nicht dein Wunsch ist, dann mußt du runden. Ich würde nicht soweit gehen, und grundsätzlich oben und unten 10% Abstand lassen - das engt deinen Grafikspielraum unnötig ein, kosten also nur Platz. Besser ist: Analysiere, welche nächste Stufe in dem gewünschten Achsenraster deine Min/Max-Werte erfordern, und nimm die.
Natürlich gibts auch da wieder Erfordernisse. Wenn du bei 10 Teilstrichen bleiben willst, mußt du das Intervall zwischen Min und Max erstmal sinnvoll auf die Achse verteilen. Dein Beispiel schwankt zwischen 1790 und 2187 - eine Differenz von 397. Du musst sehen, was dafür am besten paßt: Ein Achsenumfang von 400 oder 500? Entsprechend hast du dann den maximalen Bereich von 1687 bis 2290 (bei 500 Umfang - jeder Teilstrich ist 50), in dem die Grafik passen soll. Ich hab mal vom Min und Max jeweils 500 in die gegenüberliegende Richtung gerechnet.
Das bedeutet: Das untere Ende deiner Skala liegt zwischen 1687 und 1790, und das obere Ende der Skala liegt zwischen 2187 und 2290. Jetzt mußt du "nur noch" einen Wert finden, bei dem das untere und das obere Ende auf glatten Werten landen und exakt 500 auseinanderliegen. Naja, mit menschlichem Auge dürfte das oben leicht sein: 2200 wäre gut. Entsprechend würde das untere Ende bei 1700 liegen.
Umgekehrt betrachtet könnte man (50 ist der Teilstrichabstand) auch bei 1750 starten und bei 2250 enden. Das mußt du in einer Funktion selber entscheiden.
Und erst jetzt kommt deine Funktion und transformiert den Wertebereich von 1750 bis 2250 auf den Pixelbereich von 0 bis 100 Pixel (was insgesamt 101 Pixel sind).
- Sven Rautenberg
Hallo!
Wirklich nicht so einfach das ganze, aber ich glaube mit Deiner Hilfe habe ich eine Idee:
ich schreibe das mal so grob als "pseudeo-programm" (Richtung PHP ;-)
//Ausgangswert
$min = 1790;
$max = 2187;
// Differenz
$diff = $max - $min;
$diff_prozent = $diff / $max;
$absolut_max = $max + 0,1 * $diff;
$absolut_min = $min - 0,1 * $diff;
$diff_max = $absolut_max - $absolut_min;
// Ermittlung einer Zahl mit möglichst vielen Nullen am Ende zw. $max und $absolut_max
for($i=1, $i < count_chars($absolut_max), $i++) {
$temp = substr($absolut_max,0,-$i).str_repeat ( "0", $i);
if ($temp>$max) {
$max_gerundet = $temp;
} else {
break;
}
}
// Ermittlung einer Differenz mit möglichst vielen Nullen am Ende zw. $diff_max und $diff
for($i=1, $i < count_chars($diff_max), $i++) {
$temp = substr($diff_max ,0,-$i).str_repeat ( "0", $i);
if ($temp>$diff) {
$opt_diff = $temp;
} else {
break;
}
}
$schritte = abs($opt_diff/10);
// Erstelle einen Array mit den einzelnen Skala-Werten
for($i=0, $i < 10, $i++) {
skala_array[]=$max_gerundet - $i * $schritte;
}
Was sagst Du dazu? Wie könnte man das noch verbessern?
Viele Grüße
Andreas
Hallo Andreas,
nur ein paar Gedanken zu Deinen Überlegungen
ich schreibe das mal so grob als "pseudeo-programm" (Richtung PHP ;-)
// Differenz
$diff = $max - $min;
$diff_prozent = $diff / $max;
Bitte bei Prozent noch mit 100 multiplizieren :-)
$absolut_max = $max + 0,1 * $diff;
$absolut_min = $min - 0,1 * $diff;
Tipp: Rechne überall und immer mit Integerwerten, dann ist z.B. der Modulo-Operator Dein Freund, damit kannst Du viele Nullen finden...
// Ermittlung einer Zahl mit möglichst vielen Nullen am Ende zw. $max und $absolut_max
for($i=1, $i < count_chars($absolut_max), $i++) {
...
}
Mach so was mit Rechenoperationen, nicht mit Stringoperationen
// Ermittlung einer Differenz mit möglichst vielen Nullen am Ende zw. $diff_max und $diff
Ist das gleiche Problem: Suche eine Zahl mit möglichst vielen Nullen zwischen zwei anderen Zahlen => Mach _eine_ Funktion draus
Was sagst Du dazu? Wie könnte man das noch verbessern?
HTH
Gruss,
Vinzenz
Hallo Vinzenz!
$diff_prozent = $diff / $max;
Bitte bei Prozent noch mit 100 multiplizieren :-)
Den Teil brauche ich eh nicht ;-)
$absolut_max = $max + 0,1 * $diff;
$absolut_min = $min - 0,1 * $diff;Tipp: Rechne überall und immer mit Integerwerten, dann ist z.B. der Modulo-Operator Dein Freund, damit kannst Du viele Nullen finden...
Wie denn? Wenn ich 10 % addieren will dann kann ich nicht mit Integer-Werten rechnen, entweder ich Teile durch einen Wert, oder ich Multipliziere mit einer Dezimal-Zahl.
Und wie soll ich mit Modulo eine solche Zahl finden? Die Methode die ich angewendet habe würde z.B. bei Zahlen zw. 100.000 und 250.000 maximal 5 Schleifendruchläufe benötigen. Wenn Du aber alle Zahlen durchgehst, und jede Zahl mit Modulo überprüfst, dann brauchst Du 150.000 Durchläufe!
Oder geht das auch ohen Schleife, nur mit Rechenoperationen? Ich könnte mir da nichts vorstellen.
// Ermittlung einer Zahl mit möglichst vielen Nullen am Ende zw. $max und $absolut_max
for($i=1, $i < count_chars($absolut_max), $i++) {
...
}Mach so was mit Rechenoperationen, nicht mit Stringoperationen
Und wie?
// Ermittlung einer Differenz mit möglichst vielen Nullen am Ende zw. $diff_max und $diff
Ist das gleiche Problem: Suche eine Zahl mit möglichst vielen Nullen zwischen zwei anderen Zahlen => Mach _eine_ Funktion draus
stimmt, aber soweit bin ich noch gar nicht gewesen, mir geht es erstmal ums Prinzip, später werde ich das sicher so machen.
Was sagst Du dazu? Wie könnte man das noch verbessern?
HTH
wie meinen?
Viele Grüße
Andreas
Hallo Andreas,
$absolut_max = $max + 0,1 * $diff;
$absolut_min = $min - 0,1 * $diff;
Tipp: Rechne überall und immer mit Integerwerten, dann ist z.B. der Modulo-Operator Dein Freund, damit kannst Du viele Nullen finden...
Wie denn? Wenn ich 10 % addieren will dann kann ich nicht mit Integer-Werten rechnen, entweder ich Teile durch einen Wert, oder ich Multipliziere mit einer Dezimal-Zahl.
Caste auf Integer ...
$absolute_max = (int) ($max + 0,1 * $diff);
Das was Du hinter dem Komma verlierst, sollte unbedeutend sein, insbesondere, wenn Du als Grundeinheit Cent nimmst...
Und wie soll ich mit Modulo eine solche Zahl finden? Die Methode die ich angewendet habe würde z.B. bei Zahlen zw. 100.000 und 250.000 maximal 5 Schleifendruchläufe benötigen. Wenn Du aber alle Zahlen durchgehst, und jede Zahl mit Modulo überprüfst, dann brauchst Du 150.000 Durchläufe!
Oder geht das auch ohen Schleife, nur mit Rechenoperationen? Ich könnte mir da nichts vorstellen.
Nein, natürlich nimmst Du eine Schleife:
ungefähr so:
$max_nullen = $obergrenze;
$divisor = 10;
while ( $max_nullen - ($max_nullen % $divisor) > $untergrenze ) {
$max_nullen -= $maxnullen % $divisor;
$divisor *= 10;
}
<kein_php mathe="ja">
$obergrenze > $untergrenze > 0
</kein_php>
stimmt, aber soweit bin ich noch gar nicht gewesen, mir geht es erstmal ums Prinzip, später werde ich das sicher so machen.
Nein! Fang' gleich damit an.
Gruss,
Vinzenz
HallO!
Caste auf Integer ...
$absolute_max = (int) ($max + 0,1 * $diff);
Du meinst:
$absolute_max = (int($max + 0,1 * $diff));
oder wie habe ich das zu verstehen? Oder vielleicht besser abs() oder round()?
Das was Du hinter dem Komma verlierst, sollte unbedeutend sein, insbesondere, wenn Du als Grundeinheit Cent nimmst...
Nein, natürlich nimmst Du eine Schleife:
ungefähr so:
$max_nullen = $obergrenze;
$divisor = 10;while ( $max_nullen - ($max_nullen % $divisor) > $untergrenze ) {
$max_nullen -= $maxnullen % $divisor;
$divisor *= 10;
}
Ah ja, das sieht in der Tat etwas besser aus ;-)
Aber geht das eigentlich auch anders herum? Also dass ich vin meiner Untergrenze langsam hochgehe? Wäre doch eigentlich eh logischer, oder?
Also sowas:
$max_nullen = $untergrenze
$divisor = 10;
while ( $max_nullen + ($divisor - $max_nullen % $divisor) < $obergrenze ) {
$max_nullen += $divisor - $maxnullen % $divisor;
$divisor *= 10;
}
$max_nullen müsste jetzt den gewünschten Wert enthalten.
Den Spezialfall, dass es keine Zahl dazwischen gibt, lasse ich Dir als Fingerübung ;-)
Voraussetzung ist selbstverständlich, dass gilt:
Vielleicht einfach "wenn $max_nullen == $untergrenze und $max_nullen != $obergrenze, dann ($untergrenze + $obergrenze)/2"
$obergrenze > $untergrenze > 0
logisch.
Danke Dir!
Grüße
Andreas
Hallo Andreas,
Caste auf Integer ...
$absolute_max = (int) ($max + 0,1 * $diff);
Du meinst:
$absolute_max = (int($max + 0,1 * $diff));
Nein, ich meine schon:
(int) ($max + ... )
Der Cast-Operator bedeutet, dass der Typ des Ausdrucks hinter dem Cast-Operator auf den angegebenen Typ umgewandelt wird, ggf. mit Verlust an Information.
Zur Quelle: Rasmus Lerdorf, Programming PHP
Und der sollte es wissen ;-)
oder wie habe ich das zu verstehen? Oder vielleicht besser abs() oder round()?
Könntest Du bestimmt auch verwenden, auf die Nachkommastellen sollte es wirklich nicht ankommen.
Ah ja, das sieht in der Tat etwas besser aus ;-)
Danke.
Aber geht das eigentlich auch anders herum? Also dass ich vin meiner Untergrenze langsam hochgehe? Wäre doch eigentlich eh logischer, oder?
Also sowas:
$max_nullen = $untergrenze
$divisor = 10;while ( $max_nullen + ($divisor - $max_nullen % $divisor) < $obergrenze ) {
$max_nullen += $divisor - $maxnullen % $divisor;
$divisor *= 10;
}
Ja, das sollte funktionieren
Gruss,
Vinzenz
HallO!
Was ich eigentlich noch besseer fände wäre eine ganz standardisiert Skala, halt bei 1798-2178
1750
1800
1850
...
2150
2200
Könnte man das auch irgendwie abilden? Das es in allen Bereichen funktioniert? Also von 1er Schritten auf 5er auf 10er auf 50er auf 100er auf 500er...? ODer meint Ihr das ließe sich nicht auf _alle_ Zahlenbereiche anwenden? Eigentlich schon, oder?
Grüße
Andreas
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
Hi Sven!
Davon hatte ich ja geredet, bevor es zu diesem Intermezzo kam. :)
tut mir Leid ;-)
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.
Das ist jetzt die Frage wie rum ich das ganze ausrechne. Ich hatte auch daran gedacht mich weniger auf das Intervall zu fixieren, eher auf die absoluten Werte, um so eine ganz "loose" Skala zu bekommen, nur mit den 4-5 wichtigen Werten in der Region. Wobei das glaube ich nur so wie Du beschreiben hast geht, denn wenn ich das Intervall nicht habe kann ich keinen sinnvollen Startwert festlegen, ich denke es ist schon OK. Ich probiere es sobald mein GD mit jpegs hier lokal läuft ;-)
Eine mathematische Formel für die Zahlenreihe wird vermutlich schwierig zu entwickeln sein, aber als PHP-Funktion könnte das hier hilfreich sein:
Das hatte ich oben auch gemerkt :-)
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;
}
Es hat zwar den ein oder anderen moment gedauert bis ich es dann verstanden hatte, aber danach war ich um so begeisterter, nicht schlecht - wobei es IMHO ^ in PHP nicht gibt, aber da gibt es ne Funktion(pow() oder so ähnlich?)
Du suchst jetzt eine "runde" Zahl kleiner als dein Minimum, welche als Startpunkt deiner Skala dienen kann.
Meinst Du mit rund eine die in das 25er Raster passt?
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
int() gibt es nicht in php, nur intval(), abs(), round() und (int). Wobei ich bei allen diesen Dingen Angst habe, denn (INT) 10*(0.1 + 0.7) //=7!
Aber sonst sieht das sehr gut und sehr logisch aus!
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. :)
Ein netter Trick! Ganz ehrlich - auf solche Sachen wäre ich selbst nie gekommen, auch die Funktion, guck Dir dagegen mal mein "Gemurkse" mit Sting-Funkitonen an.... tse, tse, tse
Vielen Dank für die Hilfe, ich denke hiermit ist alles klar, jetzt muß ich es nur noch schaffen jpeg-Support in PHP mit einzukompilieren(s.o. im Forum), naja.
Viele Grüße
Andreas
Moin!
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;
}
Es hat zwar den ein oder anderen moment gedauert bis ich es dann verstanden hatte, aber danach war ich um so begeisterter, nicht schlecht - wobei es IMHO ^ in PHP nicht gibt, aber da gibt es ne Funktion(pow() oder so ähnlich?)
Tja, das sind (du erinnerst dich vielleicht an mein Posting </archiv/2003/1/34091/#m185660>) alles noch "Reste" von meiner Programmierweise. Da ich die Funktion nicht getestet habe, habe ich logischerweise auch nicht recherchiert, welche Funktionen es wirklich gibt. Du weißt, was gemeint ist - "showing the usefulness of this function is left as an exercise to the reader". ;)
Du suchst jetzt eine "runde" Zahl kleiner als dein Minimum, welche als Startpunkt deiner Skala dienen kann.
Meinst Du mit rund eine die in das 25er Raster passt?
Naja, 25er, oder 250er, oder so ähnlich - je nach Wertebereich. :)
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
int() gibt es nicht in php, nur intval(), abs(), round() und (int). Wobei ich bei allen diesen Dingen Angst habe, denn (INT) 10*(0.1 + 0.7) //=7!
Du brauchst aber keine Angst zu haben - solltest du jedenfalls erstmal nicht. Denn um was geht es bei dieser Formel? Sie soll Ganzzahlen produzieren! Also ist ein Computer genau das Richtige zum Rechnen. :)
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. :)
Ein netter Trick! Ganz ehrlich - auf solche Sachen wäre ich selbst nie gekommen, auch die Funktion, guck Dir dagegen mal mein "Gemurkse" mit Sting-Funkitonen an.... tse, tse, tse
"Sting"-Funkitonen - netter Verschreiber. :) Oder war das dein String-Gemurkse?
Vielen Dank für die Hilfe, ich denke hiermit ist alles klar, jetzt muß ich es nur noch schaffen jpeg-Support in PHP mit einzukompilieren(s.o. im Forum), naja.
Ich würde Grafiken immer mit PNG ausgeben (hilfsweise mit GIF, aber das ist normalerweise ja nicht verfügbar). Das, was du planst, erfordert feine Linien und nicht wahnsinnig viele Farben - also ist JPEG genau falsch. Es sei denn, du brauchst das für andere Dinge.
- Sven Rautenberg
HAllo!
Tja, das sind (du erinnerst dich vielleicht an mein Posting </archiv/2003/1/34091/#m185660>) alles noch "Reste" von meiner Programmierweise. Da ich die Funktion nicht getestet habe, habe ich logischerweise auch nicht recherchiert, welche Funktionen es wirklich gibt. Du weißt, was gemeint ist - "showing the usefulness of this function is left as an exercise to the reader". ;)
ich wollte es auch nur der Vollständigkeit halber bemerkt haben.
(INT) 10*(0.1 + 0.7) //=7!
Du brauchst aber keine Angst zu haben - solltest du jedenfalls erstmal nicht. Denn um was geht es bei dieser Formel? Sie soll Ganzzahlen produzieren! Also ist ein Computer genau das Richtige zum Rechnen. :)
Anscheinend ja nicht, sonst gäbe obiges Beispiel doch 8! Wer sagt mir das ich dabei nicht auch auf so einen Wert wie oben stoße?
"Sting"-Funkitonen - netter Verschreiber. :) Oder war das dein String-Gemurkse?
ups :-)
Ich würde Grafiken immer mit PNG ausgeben (hilfsweise mit GIF, aber das ist normalerweise ja nicht verfügbar). Das, was du planst, erfordert feine Linien und nicht wahnsinnig viele Farben - also ist JPEG genau falsch. Es sei denn, du brauchst das für andere Dinge.
Stimmt, das habe ich an der Ping-Statistik aus dem IX Artikel gesehen. PNG unterstützen ja alle 4er Versionen der Browser, also sollte das auch möglich sein. Danke Dir!
Grüße
Andreas
Hi Andreas,
(INT) 10*(0.1 + 0.7) //=7!
Du brauchst aber keine Angst zu haben ...
Anscheinend ja nicht, sonst gäbe obiges Beispiel doch 8! Wer sagt mir das ich dabei nicht auch auf so einen Wert wie oben stoße?
genau das Wissen um die Extremfälle der numerischen Berechnung (aufgrund der verlustbehafteten Konvertierung zwischen dezimal und float) ist es, was ich von Dir eingefordert hatte: In diesem Falle nimmt man nun mal round() und nicht floor(), weil man dann gegen 7.999999999 gefeit ist.
Viele Grüße
Michael
Hi Andreas,
$potenz = 0; // Start bei 10^0 = 1
while ($range < $minrange)
{
$potenz++; // die Zehnerpotenz erhöhen
}
Es hat zwar den ein oder anderen moment gedauert bis ich es dann verstanden hatte, aber danach war ich um so begeisterter, nicht schlecht - wobei es IMHO ^ in PHP nicht gibt, aber da gibt es ne Funktion(pow() oder so ähnlich?)
Du kannst statt dessen einfach eine Variable $faktor mit 1 initialisieren und pro Schleifendurchgang mit 10 multiplizieren. $potenz selbst brauchst Du ja gar nicht - Sven hat seine Formel nur "schön mathematisch" aussehen lassen.
Wobei ich bei allen diesen Dingen Angst habe, denn (INT) 10*(0.1 + 0.7) //=7!
Elementare Kenntnisse über (hier: numerische) Mathematik _sind_ hilfreich. Da gab es neulich so einen Thread zu diesem Thema ... ;-)
Ein netter Trick! Ganz ehrlich - auf solche Sachen wäre ich selbst nie gekommen
Deine Aufgabe ist aber gar nicht mal untypisch für das Programmieren: Du versuchst, das System in Deiner Aufgabenstellung zu finden (indem Du mehr und mehr von dieser Aufgabenstellung in Regeln, Bedingungen, Formeln etc. ausdrückst - beispielsweise die Zahl der Elemente in Deinen Intervallen und die Bedingungen der Teilbarkeit für "schöne" Koordinatenwerte), dieses dann in einen Algorithmus umzusetzen, und zuletzt den Algorithmus in eine konkrete Programmiersprache zu codieren (was Sven hier teilweise abstrahiert hat, weil es für den Erkenntnisprozeß nicht mehr notwendig war). Der erste Teil erfordert Abstraktionsfähigkeit (das ist etwas für die Mathematiker), der zweite Kreativität (das ist etwas für die Künstler), der dritte saubere handwerkliche Arbeit (das ist etwas für die Arbeiter).
Viele Grüße
Michael
Hallo!
Du kannst statt dessen einfach eine Variable $faktor mit 1 initialisieren und pro Schleifendurchgang mit 10 multiplizieren. $potenz selbst brauchst Du ja gar nicht - Sven hat seine Formel nur "schön mathematisch" aussehen lassen.
man will die ganze Mathematik ja nicht "um sonst" gelernt haben ;-)
Wobei ich bei allen diesen Dingen Angst habe, denn (INT) 10*(0.1 + 0.7) //=7!
Elementare Kenntnisse über (hier: numerische) Mathematik _sind_ hilfreich. Da gab es neulich so einen Thread zu diesem Thema ... ;-)
Was ist "numerische" Matehmatik? Das Problem besteht doch wohl darin, dass sich bstimmte Zaheln nicht alsbinär-Code abbileden lassen, so z.B. 1/3. DAher entstehen beim Rechnen mit sochen float-zahlen ganz minimale Abweichungen, die normalerweise nicht zu sehen sind, halt nur in Spezialfällen. Nur verstehe ich das obige Beispiel nicht - was ist daran schwer abszubilden? Vermutlich ergibt 0.1 + 0.7 = 0.7999999999, und das * 10 ist dann 7.99999999 und das als INT ist 7. Aber wieso? Wieso ist 0.1 + 0.7 nicht einfach 0.8? Kann man Dezimalzahlen grundsätzlich nicht 100% korrekt binär abbilden? Wieso speichern Programmiersprachen keien INT-Werte Kombiniert mit der Potenz? Also bei 0.7 einfach 7 * 10 ^-1 ? Man rechnet einfach mit den INT-Werten und ermittelt am Ende dann zusätzlich die 10er Potenz? Und wieso werden die .9999999 nirgendwo angezeigt wenn sie doch existieren?
Der erste Teil erfordert Abstraktionsfähigkeit (das ist etwas für die Mathematiker), der zweite Kreativität (das ist etwas für die Künstler), der dritte saubere handwerkliche Arbeit (das ist etwas für die Arbeiter).
Also sind Informatiker nichts anderes als hart arbeitende Künstler mit guten Mathematikkentnissen? ;-)
Grüße
Andreas
Hi Andreas,
Elementare Kenntnisse über (hier: numerische) Mathematik _sind_ hilfreich. Da gab es neulich so einen Thread zu diesem Thema ... ;-)
Was ist "numerische" Matehmatik? Das Problem besteht doch wohl darin, dass sich bstimmte Zaheln nicht alsbinär-Code abbileden lassen, so z.B. 1/3. DAher entstehen beim Rechnen mit sochen float-zahlen ganz minimale Abweichungen, die normalerweise nicht zu sehen sind, halt nur in Spezialfällen.
Eben - _das_ ist Numerische Mathematik. ;-)
Nur verstehe ich das obige Beispiel nicht - was ist daran schwer abszubilden? Vermutlich ergibt 0.1 + 0.7 = 0.7999999999, und das * 10 ist dann 7.99999999 und das als INT ist 7. Aber wieso? Wieso ist 0.1 + 0.7 nicht einfach 0.8? Kann man Dezimalzahlen grundsätzlich nicht 100% korrekt binär abbilden?
Nein. Und das zu verstehen, ist auch Numerische Mathematik.
Was ist denn so eine Binärzahl? Eine endliche (!) binäre Ziffernfolge.
Ob die als Vor- oder als Nachkommastellen interpretiert werden, ist egal - die Wertemenge ist nun mal auf 2 hoch (Anzahl der verwendeten Bits für die Mantisse) Kombinationen beschränkt.
Und innerhalb dieser Menge erlaubter Werte liegt 0.8 nun mal leider nicht - Du müßtest in der Lage sein, es durch die Summe beliebiger Terme aus [0.5, 0.25, 0.125, ...] darzustellen, und das wird Dir nicht gelingen, weil diese Liste eben nur endlich lang ist - so lang, wie Du Bits für die Mantisse spendierst.
Wieso speichern Programmiersprachen keien INT-Werte Kombiniert mit der Potenz?
Tun sie doch. Allerdings teilen sie diese INT-Werte vorher durch 2 hoch (Anzahl der verwendeten Bits für die Mantisse). Das ändert nichts an der Anzahl der darstellbaren Zahlen - allerdings sehr wohl an der konkreten Menge, wie Du am Beispiel von 0.8 siehst.
Also bei 0.7 einfach 7 * 10 ^-1 ? Man rechnet einfach mit den INT-Werten und ermittelt am Ende dann zusätzlich die 10er Potenz?
Versuche mal, das in ein real existierendes Schaltwerk zu übersetzen ... es hat schon seine Gründe, wieso Computer mit Binärzahlen arbeiten und nicht mit Dezimalzahlen.
Außerdem würdest Du bei Dezimalzahlen Platz verschenken. Wenn schon ein Exponent, dann einer zur Basis 16 ...
Und wieso werden die .9999999 nirgendwo angezeigt wenn sie doch existieren?
Weil Du das durch die Verwendung von INT() verboten hast?
Der erste Teil erfordert Abstraktionsfähigkeit (das ist etwas für die Mathematiker), der zweite Kreativität (das ist etwas für die Künstler), der dritte saubere handwerkliche Arbeit (das ist etwas für die Arbeiter).
Also sind Informatiker nichts anderes als hart arbeitende Künstler mit guten Mathematikkentnissen? ;-)
Informatiker sind vor allem gute Mathematiker mit hinreichend viel Kreativität und harten Arbeitern in Rufweite. (Ich habe nichts gegen Programmierer - jeder sollte einen haben. ;-)
Viele Grüße
Michael
Hallo Andreas,
Was ich eigentlich noch besseer fände wäre eine ganz standardisiert Skala, halt bei 1798-2178
1750
1800
...
2150
2200
Könnte man das auch irgendwie abilden? Das es in allen Bereichen funktioniert? Also von 1er Schritten auf 5er auf 10er auf 50er auf 100er auf 500er...? ODer meint Ihr das ließe sich nicht auf _alle_ Zahlenbereiche anwenden? Eigentlich schon, oder?
Klar, auch das läßt sich erreichen. Ich hab's nicht mehr in Erinnerung, ob nicht Sven Dir schon etwas in der Richtung vorgeschlagen hat.
Vorgehensweise in etwa so:
Anzahl der möglichen Schritte ist bekannt, da Deine Grafik eine bestimmte Größe hat.
Differenz von Maximalwert und Minimalwert geteilt durch Anzahl der Schritte gibt Dir den Einstiegspunkt in Deine Schrittweite. Diese muss grösser sein als der berechnete Wert
Beispiel:
Start : 1798
Ende : 2178
Schritte: 10
2178 - 1798 = 380
380 / 10 = 38
=> Schrittweite ist 50, da nächstgrößere zulässige Schrittweite.
Dann ggf. noch das angezeigte Intervall so symmetrisch wie möglich wählen.
So in etwa könnte das klappen.
Gruss,
Vinzenz
Das einzige was mit jetzt Kopfzerbrechen bereitet ist das schreiben von Text. Wie es aussieht kann man mit http://www.php3.de/manual/de/function.imagechar.php lediglich einzelne Buchstaben schreiben. Gibt es keien Möglichkeit einen ganzen String zu schreiben? Denn sonst ...
zumindest das hat sich erledigt ;-)
Grüße
Andreas
Hallo Andreas & Co.,
jetzt wurde ja schon eine ganze Menge geantwortet. Trotzdem möchte ich versuchen, mich auch noch "einzumischen", weil ich das Problem interessant finde. Vorab: ich kenne mich in PHP nicht aus, deswegen schreibe ich die Formeln in einer "Mischung aus Mathematik und Klartext".
Und nochwas, ich überlege gerade, wie ich sinnvollerweise eine Skala implemementiere.
Ich würde das so angehen:
Gegeben ist ein Minimalwert und ein Maximalwert der Gebote. Daraus errechnet sich die Differenz der Gebote. Da der kleinste Balken immer noch eine Mindesthöhe > 0 haben soll, muss vom Minimalwert noch ein bestimmter Wert abgezogen werden. Damit dieser Wert in der Grafik immer gleichhoch erscheint, muss er proportional zur *Differenz* sein, da die Differenz ja auf eine bestimmte Pixelhöhe "gezerrt" wird. Wenn das Minimalgebot und das Maximalgebot also sehr unterschiedlich sind, wird "viel Geld" auf kleinem Raum dargestellt. Ein Pixel in der Grafik repräsentiert also mehr Cents, als wenn sich die Gebote kaum im Preis unterscheiden würden. Daher stellt auch der Platz, der unter dem letzten Gebot zur Ästhetik freigelassen werden soll, mehr Geld dar. Es muss also mehr vom Minimalwert abgezogen werden, als wenn die Gebote sehr nahe beieinander liegen würden. (Ich hoffe, das kann man jetzt verstehen.)
Gegeben: maxwert, minwert; # Werte des höhsten und niedrigsten Gebots
Gesucht:
einheit, # "runde" Zahl von Euro zwischen zwei Markierungen auf der y-Achse
intervallanz, # Anzahl der Intervalle, in die die y-Achse eingeteilt werden soll
# (ungefähr 10)
maxwert, minwert # "gerundeter" Maximal- und Minimalwert auf der y-Achse des Diagramms
minwert = minwert - (maxwert-minwert)*0.1; # unten 10% Platz lassen
if (minwert < 0) minwert = 0; # Minimalwert soll nie kleiner als 0 sein.
differenz = maxwert - minwert; # Achtung: kann 0 werden, wenn nur ein Gebot vorhanden
Diese Differenz soll jetzt in 10 "runde" Intervalle eingeteilt werden. Hier ergibt sich das Problem aus der Definition von "rund". Ich würde das einmal so bezeichnen: Die Differenz soll in Intervalle eingeteilt werden, bei denen im Dezimalsystem nur die erste Ziffer ungleich 0 sein darf. Aus 2345 würde also 2000, aus 465 würde 500 und aus 9821 würde 10000. Der "Rundungsfehler" ist also relativ zur Ausgangszahl gering gehalten. (Wenn das noch zu grob ist, kannst du dir ja überlegen, ob du nicht den ersten beiden Stellen erlaubst, ungleich 0 zu sein. Also 2345 --> 2300, 465 --> 470 und 9821 --> 9800. In diesem Fall müsstest du potenz im folgenden code durch 10 teilen.)
Dann könnte man so "runden":
potenz = 10 ^ abrunden(log(nichtrund)); # zu rundender Wert sollte ungleich 0 sein
ersteZiffer = runden(nichtrund/potenz); # Kann Werte von 1-10 annehmen (nicht 0);
rund = ersteZiffer*potenz;
Wobei:
Du würdest also die weiter oben errechnete Differenz durch 10 teilen und das Ergebnis dieses Quotientens anschließend wie oben runden. Das gerundete Ergebnis möchte ich jetzt "Einheit" nennen. Eine Einheit gibt an, wie viel Euro zwischen zwei Markierungen auf der y-Achse liegen.
einheit = differenz/10;
potenz = 10 ^ abrunden(log(einheit)); # zu rundender Wert sollte ungleich 0 sein
ersteZiffer = runden(einheit/potenz); # Kann Werte von 1-10 annehmen (nicht 0);
einheit = ersteZiffer*potenz;
Anschließend solltest du nocheinmal überprüfen, ob es wirklich sinnvoll ist, die Skala in genau 10 Intervalle aufzuteilen. Unter bestimmten Bedingungen kann es nämlich sein, dass durch das Runden eine Aufteilung in 9 oder 11 Intervalle sinvoller ist. Die Anzahl der Intervalle, in die die Skala zerteilt werden soll, nenne ich "inntervallanz":
intervallanz = aufrunden(differenz/einheit); # einheit sollte ungleich 0 sein
Wobei aufrunden(wert) das Runden auf die nächsthöhere ganze Zahl sein soll.
Daraus errechnet sich ein neuer Wert für die Differenz aus dem Maximal- und Minimalwert: Die Differenz stellt jetzt den Geldbereich dar, der auf der y-Achse angezeigt wird. Sie errechnet sich also so:
differenz = intervallanz * einheit;
Jetzt musst du noch den Maximalwert so setzen, dass er ein Vielfaches von potenz ist, aber nicht kleiner und auch nur möglichst wenig größer wird:
maxwert = aufrunden(maxwert/potenz)*potenz; # potenz ist ungleich 0
Der Minimalwert errechnet sich dann wie folgt:
minwert = maxwert - differenz; # minwert sollte nie kleiner als 0 werden
Wenn ich jetzt nichts übersehen habe, sollte gelten:
differenz = maxwert - minwert = einheit * intervallanz;
Außerdem sollte der Maximalwert nicht kleiner und der Minimalwert nicht größer geworden sein.
Bitte sagt mir, wenn euch ein Denkfehler auffällt. Ich habe das nämlich noch nicht getestet, könnte mir aber vorstellen, dass es so in etwa funktioniert.
Das ganze noch mal zusammengeschrieben:
#----------------------------------------------------------
minwert = minwert - (maxwert-minwert)*0.1; # unten 10% Platz lassen
if (minwert < 0) minwert = 0; # Minimalwert soll nie kleiner als 0 sein.
differenz = maxwert - minwert; # Achtung: kann 0 werden, wenn nur ein Gebot vorhanden
einheit = differenz/10;
potenz = 10 ^ abrunden(log(einheit)); # zu rundender Wert sollte ungleich 0 sein
ersteZiffer = runden(einheit/potenz); # Kann Werte von 1-10 annehmen (nicht 0);
einheit = ersteZiffer*potenz;
intervallanz = aufrunden(differenz/einheit); # einheit sollte ungleich 0 sein
differenz = intervallanz * einheit;
maxwert = aufrunden(maxwert/potenz)*potenz; # potenz ist ungleich 0
minwert = maxwert - differenz; # minwert sollte nie kleiner als 0 werden
#----------------------------------------------------------
Robert