Kleinsten und größten Wert einer ArrayList ermitteln

Manche Zahlen und Objekte speichere ich in einer ArrayList. Hier kann man relativ leicht Objekte hinzufügen (.add()) oder entfernen (.remove()). In diesem Artikel beschreibe ich, wie man den größten und den kleinsten Wert (Minumum und Maximum) einer ArrayList bestimmt.

Für eine ArrayList<Integer>

Am einfachsten ist die Bestimmung des Minimums und des Maximums bei einer Liste von Objekten mit einer natürlichen Reihenfolge, wie z.B. Integer-Zahlen. In dem Falle kann man die statischen Methoden max() und min() der Collections-Klasse verwenden. Je nachdem wie die Liste aufgebaut ist, kann es allerdings auch effizientere Wege geben (siehe Stackoverflow und Zparacha-Blog).

ArrayList<Integer> liste = new ArrayList<Integer>();
liste.add(100);
liste.add(200);
liste.add(110);
liste.add(99);
 
System.out.println("Maximum: " + Collections.max(liste));
System.out.println("Minimum: " + Collections.min(liste));

Vollständiges Beispiel:

package de.fenon.test;
 
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
 
/**
 * Beispiel: Kleinsten und größten Wert in einer ArrayList finden.
 * @author fenon.de
 */
public final class HauptProgramm {
  /** Zahl der Messungen. */
  static final Integer STICHPROBE = 10;
  /** Maximalwert. */
  static final Integer MAXIMUM = 10;
  /** Seed des Zufallszahlen-Generators. */
  static final Integer SEED = 1234567891;
 
  /**
   * Privater Konstruktor.
   * Dadurch kann kein Objekt der Klasse "Hauptprogramm" erzeugt werden.
   */
  private HauptProgramm() {}
 
  /**
   * main()-Methode.
   * @param args - Parameter der Kommandozeile.
   */
  public static void main(final String[] args) {
    ArrayList<Integer> liste = new ArrayList<Integer>();
    // Erzeuge zufällige Messwerte
    Random generator = new Random(SEED);
    for (int i = 0; i < STICHPROBE; i++) {
      liste.add(generator.nextInt(MAXIMUM));
    }
    // Gib die Messwerte aus
    for (Integer element:liste) {
      System.out.println(element);
    }
    // Gib Kleinsten und Größten Wert aus
    System.out.println("Maximum: " + Collections.max(liste));
    System.out.println("Minimum: " + Collections.min(liste));
 
  } // ENDE: main()
 
} // ENDE: HauptProgramm

Für eine ArrayList mit komplexeren Objekten

Man kann allerdings auch den minimalen und maximalen Wert eigener/komplexerer Objekte bestimmen. Im folgenden Beispiel habe ich eine Liste von Objekten des eigenen Typs Website. Mit Hilfe eines Comparators (hier: VergleicheHits) kann festgelegt werden, wie die Objekte verglichen werden sollen. Im Beispiel werden die Website-Objekte dann anhand ihrer Zugriffzahlen verglichen.

Klasse: Website

package de.fenon.Website;
 
/**
 * Informationen über Webseite.
 * @author fenon.de
 */
public class Website {
  /** Zahl der Besucher der Website. */
  private Integer hits;
 
  /**
   * Konstruktor.
   * @param besuche - Zahl der Besucher.
   */
  public Website(final Integer besuche) {
    this.setHits(besuche);
  } // ENDE: Konstruktor
 
  /**
   * Gibt die Besucherzahl der Webseite aus.
   * @return Zahl der Besucher der Website.
   */
  public final Integer getHits() {
    return hits;
  } // ENDE: getHits()
 
  /**
   * Setze die Besucherzahl der Webseite.
   * @param besuche - Zahl der Besucher.
   */
  public final void setHits(final Integer besuche) {
    this.hits = besuche;
  } // ENDE: setHits()
 
} // ENDE: Website

Comparator: VergleicheHits

package de.fenon.Website;
 
import java.util.Comparator;
 
/**
 * Vergleiche Website-Objekte anhand ihrer Hits.
 * @author fenon.de
 */
public class VergleicheHits implements Comparator<Website> {
  /** Konstruktor. */
  public VergleicheHits() {}
 
  @Override
  public final int compare(final Website a, final Website b) {
    if (a.getHits() < b.getHits()) {
      return -1;
    } else if (a.getHits().equals(b.getHits())) {
      return 0;
    } else {
      return 1;
    }
  } // ENDE: compare()
 
} // ENDE: VergleicheHits

Das Beispiel

package de.fenon.test;
 
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
 
import de.fenon.Website.VergleicheHits;
import de.fenon.Website.Website;
 
/**
 * Beispiel: Kleinsten und größten Wert in einer Liste finden.
 * @author fenon.de
 */
public final class HauptProgramm {
  /** Zahl der Messungen. */
  static final Integer STICHPROBE = 10;
  /** Maximalwert. */
  static final Integer MAXIMUM = 10;
  /** Seed des Zufallszahlen-Generators. */
  static final Integer SEED = 1234567891;
 
  /**
   * Privater Konstruktor.
   * Dadurch kann kein Objekt der Klasse "Hauptprogramm" erzeugt werden.
   */
  private HauptProgramm() {}
 
  /**
   * main()-Methode.
   * @param args - Parameter der Kommandozeile.
   */
  public static void main(final String[] args) {
    ArrayList<Website> seiten = new ArrayList<Website>();
    // Erzeuge zufällige Messwerte
    Random generator = new Random(SEED);
    for (int i = 0; i < STICHPROBE; i++) {
      seiten.add(new Website(generator.nextInt(MAXIMUM)));
    }
    // Gib die Messwerte aus
    for (Website element:seiten) {
      System.out.println("Hits: " + element.getHits());
    }
    // Gib Kleinsten und Größten Wert aus.
    // Mit einem anderen Getter könnte man z.B. den Namen der Website ausgeben.
    System.out.println(
      "Maximum: "
      + Collections.max(seiten, new VergleicheHits()).getHits()
      );
    System.out.println(
      "Minimum: "
      + Collections.min(seiten, new VergleicheHits()).getHits()
      );
  } // ENDE: main()
 
} // ENDE: HauptProgramm

Screenshot einer kompletten Webseite machen.

Manchmal möchte man einen Screenshot (Bildschirmfoto) von einer kompletten Webseite erstellen. Oftmals sind Webseiten aber größer als der im Browserfenster dargestellte Bereich. Dadurch kann man die Homepage nicht mit dem im Betreibssystem integrierten Screenshot-Programm „ablichten“ und speichern, da diese nur den aktuell dargestellten Bereich abfotografieren.

Bildschirmfoto vom 2013-08-23 02:09:18
Oftmals sind Webseiten größer als der aktuell im Browser dargestellte Bereich. Daher kann man nicht ohne Weiteres ein Foto der gesamten Seite erstellen (hier ist der untere Bereich abgeschnitten).
Browser Add-ons ermöglichen es, eine Webseite in ihrer vollen Größe "abzulichten".
Browser Add-ons ermöglichen es, eine Webseite in ihrer vollen Größe „abzulichten“.

Für den Browser Firefox gibt es diverse Add-Ons, die in der Lage sind komplette Webseiten abzulichten. Awesome Screenshot Plus und Fireshot (Fireshot ist nicht für Linux verfügbar) bieten darüber hinaus die Möglichkeit, das erstellte Bildschirmfoto vor dem Speichern zu bearbeiten.

Das Firefox Add-On "Awesome Screenshot Plus" ermöglicht es auch unter Linux ein Bildschirmfoto eine kompleten Webseite (oder auch Teilen davon) zu erstellen. Im Anschluss kann das Foto direkt bearbeitet werden
Das Firefox Add-On „Awesome Screenshot Plus“ ermöglicht es (auch unter Linux!) ein Bildschirmfoto einer kompletten Webseite (oder auch Teilen davon) zu erstellen. Im Anschluss kann das Foto direkt bearbeitet werden.

 

Leidenschaftliche Karotten

Es ist ganz schön schwer einen Titel für die folgenden Bilder zu finden. „Porno mit Gemüse“, „Möhren Minne„, „Karotten Kopulation“, „Amors Wurzeln“ oder „Schmutzige Sachen, die Möhren so machen“. Im Prinzip sind es einfach zwei Karotten, die sich gern hatten – bis zum 25.09.2013. An jenem Mittwoch Abend habe ich beide an ihrem Kopfschmuck aus der Erde unseres Gartens in Göttingen gezogen und damit das Schäferstündchen jäh beendet. Bis dahin wusste ich allerdings auch nicht, was Möhren in der Dunkelheit so alles treiben.

Querformat_4854

Querformat_4856

Hochformat_4838

Hochformat_4858

Querformat_4849

Querformat_4857

Querformat_4859

Lustiges Obst und Gemüse gibt es auch hier:

Die Version installierter Pakete im Terminal herausfinden

Kürzlich sollte ich einem Administrator die Version der VMware-Tools mitteilen, die auf meiner virtuellen Maschine installiert waren. Allerdings war (und ist) mir kein Befehl bekannt, mit dem ich diese Informationen direkt von Programmen des Paketes erhalten kann. Es ist aber möglich, die Version des installierten Paketes über den Debian Paketmanager (dpkg) zu ermitteln (UbuntuUsers-Forum).

Dazu lässt man sich zunächst (mit Hilfe von dpkg) eine Liste von Kurzbeschreibungen aller installierten Pakete ausgeben. Mit Hilfe von grep lässt man allerdings nur diejenigen Zeilen anzeigen, in denen der Namen des Paketes vorkommt (in meinem Falle open-vm-tools):

dpkg -l | grep open-vm-tools

In der Ausgabe kann man dann die Version ablesen:

ii  open-vm-tools  2012.05.21-724730-0ubuntu2  i386  tools and components for VMware guest systems (CLI tools)

In meinem Falle konnte der Administrator die virtuelle Maschine problemlos über den vSphere-client neu starten.

Meine TeXstudio-Makros

TeXstudio wurde erstellt, um die Arbeit mit LaTeX zu vereinfachen. Eine Möglichkeit ist die Verwendung sogenannter Makros (oder Macros). Mit der Hilfe von Markos kann man umfangreiche Anweisungen ausführen lassen oder LaTeX-Anweisungen in den Quelltext einfügen. In diesem Artikel liste ich solche Markos auf, die ich derzeit verwende. Weitere Möglichkeiten von Makros werden im Handbuch von TeXstudio beschrieben.

Makros können in TeXstudio unter Makros / Makros bearbeiten verwaltet werden. Ich benutze Makros vor allem um LaTeX-Anweisungen direkt beim Tippen in meinen Quelltext einfügen zu lassen. Dazu dienen Auslöseimpulse (Trigger) und deren Abkürzungen (Abbreviations). Legt man z.B. ein Makro mit dem Trigger BILD an, so wird nach der Eingabe von BILD dieser Text durch den definierten LaTeX-Text ersetzt.

Beispiel für die ein benutzerdefiniertes Makro in TeXstudio. Nach dem speichern des Markos werden die Zeichenketten \bild und BILD beim Tippen automatisch durch den angegebenen LaTeX-Text ersetzt.
Beispiel für die ein benutzerdefiniertes Makro in TeXstudio. Nach dem speichern des Markos werden die Zeichenketten \bild und BILD beim Tippen automatisch durch den angegebenen LaTeX-Text ersetzt.

Makro: Bild einfügen

Nach der Eingabe von \bild oder BILD, werden diese Zeichenketten durch LaTeX-Befehle zum Einbinden eines Bildes ersetzt. Damit die unten stehenden Befehle funktionieren, muss in der Präambel das Paket graphicx eingebunden werden (z.B. \usepackage[pdftex]{graphicx}).

Name: Bild einfügen
Trigger: BILD
Abbreviation: \bild
LaTeX-Text:
\begin{figure}
\includegraphics[width=\textwidth]{Bilder/todo.jpg}
\caption{\textbf{XXX.}
XXX.
}
\label{Fig:XXX}
\end{figure}

Makro: Tabelle einfügen

Nach der Eingabe von \tabelle oder TABELLE, werden diese Zeichenketten durch LaTeX-Befehle für eine Tabelle ersetzt. Damit die unten stehenden Befehle funktionieren, müssen in der Präambel zwei Pakete eingebunden werden:

  • \usepackage{tabularx} – Tabelle, die automatisch an die Breite der Seite angepasst werden kann (über ein X bei der Angabe der Ausrichtung innerhalb der Tabelle).
  • \usepackage{booktabs} – Für die Befehle \toprule, \midrule und \bottomrule.
Name: Tabelle einfügen
Trigger: TABELLE
Abbreviation: \tabelle
LaTeX-Text:
\begin{table}
\caption{TabellenTitel}
\label{Tab:Parameter}
\begin{tabularx}{\textwidth}{ llX }
	\toprule
	Parameter & Typical value & Meaning\\
	\midrule
	$XXX$ & $XXX$ & XXX.\\
	$XXX$ & $XXX$ & XXX.\\
	\bottomrule
\end{tabularx}
\end{table}

Weitere Informationen zu Triggern

Trigger werden als Reguläre Ausdrücke interpretiert. Daher können sie deutlich mehr, als nur eine zu ersetzende Zeichenkette definieren:

Wenn dieser Triggertext in einem tex-Dokument geschrieben wird, so wird durch das aktuelle Makro ersetzt.

Wenn der Trigger mit (?<=etwas) anfängt, so passiert dies nur wenn "etwas" vor den restlichen Teil des Triggers geschriben wurde. Da der Triggertext kein einfacher Suchtext, sondern eine regulärer Suchausdruck ist, kann (?<=\S) verwendet werden, um Ersetzungen nach einem Wort und (?<=\s|^) um Ersetzungen vor einem Wort auszulösen. Man kann den speziellen Wert ?txs-start verwenden, um das Skript bei txs start zu starten.

Linientypen, Symbole und Farben in R-Plots

R bietet verschiedene Möglichkeiten, seine Datenreihen in Plots unterscheidbar zu machen. Dazu gibt man in den Plot-Befehlen den zu ändernden Parameter, sowie einen Zahlenwert an. Ich vergesse allerdings immer, welche Zahl zu welcher Farbe oder zu welchem Linientyp gehört. Daher liste ich in diesem Artikel Zahlenwerte für folgende Parameter auf:

  1. Typen von Linien (lty).
    Beispiel: plot(c(1:10), type="o", lty=3).
  2. Farben (col).
    Beispiel: plot(c(1:10), type="o", col=4).
  3. Typen von Punkten / Sybole (pch; point character).
    Beispiel: plot(c(1:10), type="o", pch=5).

Linientypen

In R gibt es sechs verschiedene Typen von Linien. Die Zahlen für die Linientypen werden mit einer Periode von sechs „recycled“. Dadurch entspricht der Typ sieben (7) wieder dem Typen eins (1), eine Linie vom Typ acht (8) sieht aus wie eine Linie vom Typen zwei (2) und so weiter. Für jeden der Linien-Typen gibt es auch einen Namen (siehe auch Beschreibung des Parameters lty in der R-Hilfe zu par(): ?par):

  • 0: „blank“; unsichtbare Linie (=> wird nicht gezeichnet)
  • 1: „solid“
  • 2: „dashed“
  • 3: „dotted“
  • 4: „dotdash“
  • 5: „longdash“
  • 6: „twodash“
In R gibt es sechs verschiedene Typen von Linien, hier abwechselnd in rot und grün dargestellt. Jeder der Linientypen ist in 3 verschiedenen Größen (lwd=1-3) dargestellt. Die Werte für die Linientypen wiederholen sich in einer Periode von sechs. Daher entspricht die Angabe lty=7 der Angabe lty=1, die Angabe lty=8 entspricht der Angabe lty=2, und so weiter.
In R gibt es sechs verschiedene Typen von Linien, hier abwechselnd in rot und grün dargestellt. Jeder der Linientypen ist in 3 verschiedenen Größen (lwd=1-3) dargestellt. Die Werte für die Linientypen wiederholen sich in einer Periode von sechs. Daher entspricht die Angabe lty=7 der Angabe lty=1, die Angabe lty=8 entspricht der Angabe lty=2, und so weiter.

Das oben stehende Bild habe ich mit folgendem Code erzeugt:

1
2
3
4
5
6
7
8
# 6 Linientypen
png("linientypen.png")
par(mar=c(0,4,0,0)+.1, cex=1.5)
plot(1,1, type="n", ylim=c(0, 7), xaxt="n", xlab="", ylab="Linentyp (lty)", las=1)
abline(h=c(0:7),     lty=c(0:7), lwd=3, col=c(2,3))
abline(h=c(0:7)-0.2, lty=c(0:7), lwd=2, col=c(2,3))
abline(h=c(0:7)-0.4, lty=c(0:7), lwd=1, col=c(2,3))
dev.off()

Farben

In der Standard-Palette von R befinden sich acht verschiedene Farben. Dazu kommt noch der Wert 0, bei dem die Hintergrundfarbe als Farbe verwendet wird. Die Farben werden mit einer Periode von acht „recycled“. Durch diese fortlaufende Wiederholung, entspricht die Farbe neun (9) der Farbe eins (1), die Farbe zehn (10) wieder der Farbe zwei (2) und so weiter. Anstatt einer Zahl kann man auch direkt den RGB-Farbwert angeben (z.B. plot(1, 1, col="#000000") anstatt plot(1, 1, col=1) ). Weitere Details gibt es im Bereich „Color Specification“ in der R-Hilfe zu den Grafik-Parametern (?par).

In R gibt es acht verschiedene Farben. Hinzu kommt der Wert 0, bei dem die Hintergrundfarbe als Farbe verwendet wird (siehe diagonale Linie). Mit einer Periodenlänge von 8, werden die Farben wiederholt (wiederholte Farben sind mit einer dünnen Linie dargestellt).
In R gibt es acht verschiedene Farben. Hinzu kommt der Wert 0, bei dem die Hintergrundfarbe (hier: #eeeeee) als Farbe verwendet wird (siehe diagonale Linie). Mit einer Periodenlänge von 8, werden die Farben wiederholt (wiederholte Farben sind mit einer dünnen Linie dargestellt).

Für das vorangegangene Bild habe ich folgenden Code verwendet:

1
2
3
4
5
6
7
# 8 LinienFarben
png("linienfarben.png")
par(mar=c(0,4,0,0)+.1, cex=1.5, bg="#eeeeee")
plot(1,1, type="n", ylim=c(0, 11), xlim=c(0, 11), xaxt="n", xlab="", ylab="Linenfarbe (col)", las=1, lab=c(1,11,0))
abline(h=c(0:11), lty=1, lwd=c(rep(10,9), rep(1,9)), col=c(0:11))
abline(a=0, b=1, lwd=10, col=0)
dev.off()

Punkttypen / Symbole

Um den Punkttyp zu definieren, kann entweder ein einzelnes Zeichen oder eine Zahl angeben werden. In der Hilfe zum Befehl par() (?par oder ?graphics::par) steht dazu:

Note that only integers and single-character strings can be set as a graphics parameter (and not NA nor NULL)

Eine detaillierte Liste gibt es in der R-Hilfe zur Funktion points() (?points; Bereich „‚pch‘ values“). Hier eine kurze Zusammenfassung:

  • Zeichen 018: S-kompatible Vektor Symbole
  • Zeichen 1925: Weitere R Vektor Symbole. Die Zeichen 2125 können mit Hilfe von bg innerhalb des plot-Befehls (hier: points()) eingefärbt werden. Achtung: Die Angabe von bg innerhalb von points() hat hier eine andere Auswirkung als die Angabe von bg innerhalb von par() (z.B. par(bg="#ff00ff")). Durch letzteres setzt man die Hintergrundfarbe der gesamten Plot-Fläche.
  • Zeichen 2631: Werden ignoriert
  • Zeichen 32127: ASCII Zeichen

In der folgenden Grafik werden die die ersten 26 Zeichen dargestellt (+ zwei negative Werte).

Punkt-Typen für "pch"-Werte von -2 bis +25. Der Innernraum der Zeichen 21 bis 25 wurde durch die Angabe " bg='red' " innerhalb des Befehls "points()" rot eingefärbt.
Punkt-Typen für „pch“-Werte von -2 bis +25. Der Innernraum der Zeichen 21 bis 25 wurde durch die Angabe “ bg=’red‘ “ innerhalb des Befehls „points()“ rot eingefärbt.

Das oben stehende Bild wurde mit folgenden Befehlen erzeugt:

1
2
3
4
5
6
7
8
9
# 25 Punkt-Typen
png("punkttypen.png")
par(mar=c(0,4,0,0)+.25, cex=1.5)
plot(1, 1, type="n", ylim=c(-2, 25), xlim=c(0, 10), xaxt="n", xlab="", ylab="Punkttyp (pch)", las=1, lab=c(2,15,0))
abline(h=c(-2:25), lty=3, lwd=1, col="#cccccc")
for (typ in -2:25) {
  points(x=c(0:10), y=c(rep(typ,11)), pch=typ, bg="red")
}
dev.off()

JavaScript-Datei im Theme-Editor sichtbar machen

Wer JavaScript-Dateien in seinem WordPress-Blog verwenden möchte, der möchte diese Dateien eventuell auch über den eingebauten Theme-Editor bearbeiten. Das Problem ist allerdings, dass der Theme-Editor solche Dateien nicht auflistet die in Unterverzeichnissen liegen oder deren Dateinamen nicht auf .css oder .php enden. In diesem Artikel zeige ich eine Möglichkeit, dieses Problem in drei Schritten zu umgehen.

  1. Verschiebe die Datei aus dem Unterverzeichnis direkt in das Wurzelverzeichnis deines Themes oder Child-Themes.
  2. Ändere die Endung der Datei auf .php.
  3. Schreibe zu Beginn der Datei folgenden PHP-Befehl:
    <?php
    header("Content-type: text/javascript; charset=UTF-8");
    ?>

    Mit diesem Befehl sendet PHP an den Browser, dass es sich um eine JavaScript-Datei handelt. Wenn vom Server keine (oder falsche) Informationen über den Inhalt der Datei gesendet würden, dann würde insbesondere Firefox diese Datei ignorieren. Solltest Du beim Erstellen der JavaScript-Datei einen anderen Zeichensatz als UTF-8 verwendet haben, musst Du die Angabe das charset entsprechend ändern.

Gerade mit Referenz-Steigung in einen doppelt logarithmischen Plot in R eintragen

Ich stelle viele meiner Daten in Plots mit zwei logarithmischen Achsen dar. Oftmals kommt es in solchen Plots auf die Steigung der Kurve an, also den Exponenten eines Power laws. In solchen Fällen zeichne ich, zusätzlich zu den Daten, eine oder mehrere Geraden mit einer Referenz-Steigung ein. Dadurch kann der Betrachter abschätzen, in welchen Bereichen die Daten eher zu der einen oder der anderen Steigung tendieren. Ich fand es allerdings immer sehr mühsam diese Steigungen einzuzeichnen. Grund: Ein Teil der Anfangs- oder Endkoordinaten musste im logarithmischen Raum berechnet werden. Daher habe ich mir eine Funktion geschrieben, die mir anhand einer Anfangs-Koordinate, der Steigung, sowie einem Teil der Endkoordinate, den fehlenden Wert berechnet und die Referenz-Gerade in den Plot einzeichnet.

  1. Zunächst generiere ich Daten, die im doppelt-logarithmischen Plot eine Gerade ergeben:
    x = 1:1000
    y = x^-1.5
  2. Diese werden dann mit schön formatierten Achsen geplottet, wie im Artikel „Logarithmische Achsen in R-Plots formatieren“ beschrieben.
    library(package = "sfsmisc")
    #png("log-gerade.png", width=480, height=360)
    #par(cex =1.5, mar=c(4,4,0,0)+.01)
     
    plot(x, y, log="xy", xaxt="n", yaxt="n")
    sfsmisc::eaxis(side=1, at=10^c(0:3))
    sfsmisc::eaxis(side=2, at=10^c(-4,-2,0))
     
    #dev.off()
    Darstellung einer Potenz-Funktion in einem Plot mit zwei logarithmischen Achsen.
    Darstellung einer Potenz-Funktion in einem Plot mit zwei logarithmischen Achsen.
  3. Der Exponent der von mir verwendeten Potenzfunktion ist -1.5. Daher ist auch die Steigung der Geraden m = -1.5. Nun möchte ich zusätzlich eine Gerade mit der Steigung m = -1 in den Plot eintragen. Diese soll bei am Punkt (x1 = 101, y1 = 10-1) beginnen. Enden soll die Gerade bei x2 = 2*102. Gesucht ist also die Y-Koordinate des Endpunktes (y2).

    Nun kann man:

    1. Alle vorhandenen x- und y-Werte logarithmieren (da beide Achsen logarithmisch sind).
    2. Diese Werte können in die Gleichung für die Berechnung der Steigung eingesetzt werden.
    3. Nun muss die Gleichung nach x2 aufgelöst werden (oder: die Gleichung auflösen lassen).
    4. Im Anschluss muss der x2-Wert in den Exponenten genommen werden.
    5. Über den Plot-Befehl kann nun eine Gerade zwischen den beiden Punkten (x1, y1) und (x2, y2) eingezeichnet werden.

    Diese Vorgehensweise habe ich in der Funktion refline() zusammengefasst:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    
    refline <- function(x1=NA, y1=NA, x2=NA, y2=NA, m=1, add=T, ...) {
      # Welchen Achsen (des letzten plots) sind logarithmisch?
      logX = par("xlog")
      logY = par("ylog")
     
      # Werte der logarithmischen Achsen umrechnen
      if(!is.na(x1) && logX) {x1 = log(x1)}
      if(!is.na(x2) && logX) {x2 = log(x2)}
      if(!is.na(y1) && logY) {y1 = log(y1)}
      if(!is.na(y2) && logY) {y2 = log(y2)}
     
      # Bestimmung der fehlenden Variablen
      if(is.na(x1)) {
        x1 = (y1 - y2 + m * x2) / m
        print("X1 wird berechnet")
      } else if(is.na(x2)) {
        x2 = (y2 - y1 + m * x1) / m
        print("X2 wird berechnet")
      } else if(is.na(y1)) {
        y1 = y2 + m * (x1 - x2)
        print("Y1 wird berechnet")
      } else if(is.na(y2)) {
        y2 = y1 + m * (x2 - x1)
        print(paste("Y2 wird berechnet", y2))
      }
     
      # Werte der logarithmischen Achsen umrechnen
      if(!is.na(x1) && logX) {x1 = exp(x1)}
      if(!is.na(x2) && logX) {x2 = exp(x2)}
      if(!is.na(y1) && logY) {y1 = exp(y1)}
      if(!is.na(y2) && logY) {y2 = exp(y2)}
     
      # Einzeichnen
      if(add) {
        lines(x=c(x1, x2), y=c(y1, y2), ...)
      }
     
      # Ausgabe
      data.frame(
        x1, y1, x2, y2, m
        , xmin=min(x1, x2), xmax=max(x1, x2)
        , ymin=min(y1, y2), ymax=max(y1, y2)
      )
    }

    Die Besonderheiten der Funktion refline() sind:

    • Es wird automatisch die fehlende Koordinate bestimmt.
    • Es wird erkannt, welche der Achsen logarithmisch sind.
    • Wichtige Werte der Geraden werden bei Aufruf zurückgegeben. Im Anschluss können sie verwendet werden, z.B. um Texte an die Enden der Geraden zu schreiben.
    • Die Gerade wird (auf Wunsch: add=T) in den vorigen Plot eingetragen.
    • Grafik-Parameter werden an den Plot-Befehl weitergeleitet (...).

    Nun kann refline() genutzt werden, um die oben genannte Gerade (sowie eine weitere Gerade) in den Plot einzuzeichnen. Die Variablen rl1 und rl2 dienen dazu, die Anfangs- und End-Punkte zu speichern. Mit den gespeicherten Werten werden Anschluss die Texte positioniert.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    #png("log-gerade_2.png", width=480, height=360)
    #par(cex =1.5, mar=c(4,4,0,0)+.01)
     
    plot(x, y, log="xy", xaxt="n", yaxt="n")
    sfsmisc::eaxis(side=1, at=10^c(0:3))
    sfsmisc::eaxis(side=2, at=10^c(-4,-2,0))
     
    rl1 = refline(x1=1e1, y1=1e-1, x2=2e2, m=-1, col="red")
    text(x=rl1$x2, y=rl1$y2, labels=paste0(" Slope: ", rl1$m), adj=0, col="red")
     
    rl2 = refline(x1=8e0, y1=1e-2, x2=1e2, m=-2, col="blue")
    text(x=rl2$x2, y=rl2$y2, labels=paste0(" Slope: ", rl2$m), adj=0, col="blue")
     
    #dev.off()
    Darstellung einer Potenzfunktion mit einer Steigung von -1.5. Zusätzlich wurden Referenz-Steigungen von -1 und -2 eingezeichnet.
    Darstellung einer Potenzfunktion mit einer Steigung von -1.5. Zusätzlich wurden Referenz-Steigungen von -1 und -2 eingezeichnet.
  4. Hinweis: Als Parameter für die Funktion refline() muss ein vollständiges und ein unvollständiges Koordinaten-Tupel, sowie die gewünschte Steigung angegeben werden. Der Punkt (x2, y2) muss dabei nicht immer rechts vom Punkt (x1, y1) liegen. Vielmehr hängt es von den gewählten Werten ab, wie die Punkte zueinander liegen. Die Werte x1 und y1 bestimmen gemeinsam immer den einen Punkt und die Werte x2 und y2 gemeinsam den anderen Punkt.
  5. Wie ich oben bereits erwähnt habe, funktioniert die Berechnung des fehlenden Punktes der Gerade auch in Plots mit zwei linearen, oder nur einer logarithmischen Achse:
    Im Falle z.B. einer logarirhmischen Y-Achse werden dann nur die Y-Koordinaten logarithmiert. Hier einige Beispiele:

    # Linear
    plot(x, y)
    r1 = refline(x1=0, x2=500, y1=1, m=-0.0005, col="blue")
    text(x=r1$xmax, y=r1$ymin, labels=paste0(" Steigung: ", r1$m), adj=0)
     
    # Y-logarithmisch
    plot(x, y, log="y", yaxt="n")
    sfsmisc::eaxis(side=2, at=10^c(-4,-2,0))
    r2 = refline(x1=10, x2=500, y1=1, m=-0.002, col="red")
    text(x=r2$xmax, y=r2$ymin, labels=paste0(" Steigung: ", r2$m), adj=0)

Zeichenketten in R zusammenfügen

Das Zusammenfügen von Zeichenketten (Konkatenieren von Strings) ist eine Standard-Aufgabe in allen Programmiersprachen. Auch bei der Programmierung in R wird die Funktion benötigt, wenn man z.B. Text dynamisch erzeugen lassen, oder den Wert einer Variablen an einen Text anfügen möchte. Die Funktion, die diese Aufgabe in R übernimmt, ist meiner Meinung nach etwas außergewöhnlich benannt. Mit diesem Artikel möchte ich mich selbst daran erinnern, dass sie paste() heißt.

Hier ein paar Beispiele, wie Zeichenketten (Strings) in verschiedenen Programmiersprachen zusammengefügt werden:

R
Die Funktion, mit der in R Strings zusammengefügt werden, heißt paste() (vom englischen „paste“ für „zusammenkleben“). Beispiel:

daten = c(1:10)
plot(daten, main=paste("Plot von",length(daten),"Werten."))

Mit der Funktion paste() werden durch Kommata getrennte Werte zusammengefügt. Dabei wird jedesmal ein Leerzeichen eingefügt. Wenn man die Zeichenketten ohne Leerzeichen zusammenfügen möchte, kann man entweder den Parameter sep="" setzen, oder die Funktion paste0() verwenden:

paste(sep="", "eins", "zwei") == paste0("eins", "zwei")
Java
In Java können Zeichenketten mit dem +-Operator verkettet werden:

String var = "eins";
var = var + "zwei" + "drei";
System.out.println(var);

oder mit dem +=-Operator:

String text = "Anfang";
text += "Ende";
System.out.println(text);

Sollte man sehr häufig Strings zusammenfügen, so empfiehlt sich die Verwendung eines StringBuffer-Objektes mit der Methode append() (siehe auch ChuckAndWayne-Blog):

StringBuffer b = new StringBuffer();
for (int i = 0; i<1000000; i++) {
	b.append("langer Text\n");
}
System.out.println(b);
bash
In der Bash können Variablen und Strings einfach direkt nacheinander geschrieben werden, um sie zusammenzufügen.

a="A"
b=$a"b"
echo $b
 
c="${b}c"
echo $c
 
echo $c "Bei echo können" "Leerzeichen zwischen" "den Strings sein."
 
d=$a$b
echo $d

Die bash unterstützt auch den +=-Operator:

c="Vorne"
c+=Hinten
echo $c

Für weitere Details siehe StackOverflow.

Um ganze Dateien zusammenzufügen, kann man den Befehl cat verwenden:

echo -e "Zeile 1, Datei 1\nZeile 2, Datei 1" > datei1.txt
echo -e "Zeile 1, Datei 2\nZeile 2, Datei 2" > datei2.txt
cat datei1.txt datei2.txt
PHP
In PHP können Strings mit Hilfe von . oder .= zusammengefügt werden:

<?php
$text = "Mein Text ";
$text .= "wird immer" . " " . "länger!";
echo $text;
?>
JavaScript
In JavaScript können Strings, ähnlich wie in Java, mit Hilfe des + und des +=-Operators aneinander gehängt werden:

<script>
var msg = "Nachricht";
msg += " wird";
msg = msg + " immer" + " länger";
alert(msg + "!");
</script>
C#
In C# können Strings mit Hilfe der Funktionen string.concat and string.join zusammengefügt werden. Siehe dazu den Blog von Alex James Brown.

Logarithmische Achsen in R-Plots formatieren

Im Gegensatz zu gnuplot, werden in R-Plots die logarithmische Achsen nicht sehr schön formatiert. Das Paket SFSmisc schafft hier Abhilfe. In diesem Artikel beschreibe ich Schritt für Schritt, wie man ansehnliche logarithmische Achsen für R-Plots erstellt.

  1. Als Beispiel sollen Daten geplottet werden, die in einem doppelt logarithmischen Plot eine Gerade ergeben:
    x = 1:1000
    y = x^-1.5
  2. Nun werden diese Daten mit dem Befehl plot() in einem Koordinatensystem mit logarithmischer X- und Y-Achse (log="xy") dargestellt:
    plot(x, y, log="xy")

    Dabei kann man erkennen, dass es keine kleinen Striche zur Unterteilung der Bereiche zwischen den einzelnen Größenordnungen gibt:

    Plot mit logarithmischen Achsen. Standardmäßig werden keine Striche zwischen den Größenordnungen eingezeichnet.
    Plot mit logarithmischen Achsen. Standardmäßig werden keine Striche zwischen den Größenordnungen eingezeichnet.
  3. Es ist aber durchaus üblich, den Bereich zwischen zwei Größenordnungen mit 8 kleinen Strichen zu unterteilen. Diese Striche zeigen an, an welchen Stellen 20%, 30%, 40%, 50%, 60%, 70%, 80% oder 90% der folgenden Größenordnung erreicht wurden. Um das in R zu bewerkstelligen, muss zunächst das Paket SFSmisc installiert werden (siehe dazu auch: Funktion aus einem bestimmten R-Paket laden):
    # Installation
    install.packages("sfsmisc", dependencies=T)
    # Paket laden
    library(package = "sfsmisc")
  4. Im Anschluss plotten wir die Daten erneut, aber ohne dabei die Achsen zu beschriften (xaxt="n", yaxt="n"). Die Beschriftung der Achsen wird im Anschluss mit Hilfe des Befehls eaxis() aus dem Paket SFSmisc hinzugefügt:
    plot(x, y, log="xy", xaxt="n", yaxt="n")
    sfsmisc::eaxis(side=1)   # X-Achse
    sfsmisc::eaxis(side=2)   # Y-Achse

    Im neuen Plot sind nun auf jedenfall acht Striche zur Unterteilung einer Größenordnung zu sehen:

    Erstellt man die Achsen eines Plots mit Hilfe des Befehls eaxis() aus dem Paket SFSmisc, so wird der Bereich zwischen zwei Größenordnungen in neun Teile unterteilt. Eventuell werden aber nicht nur die Zahlen für die Größenordnungen eingetragen, sondern auch für dazwischen liegende Werte (hier z.B. 5, 50 und 500).
    Erstellt man die Achsen eines Plots mit Hilfe des Befehls eaxis() aus dem Paket SFSmisc, so wird der Bereich zwischen zwei Größenordnungen in neun Teile unterteilt. Eventuell werden aber nicht nur die Zahlen für die Größenordnungen eingetragen, sondern auch für dazwischen liegende Werte (hier z.B. 5, 50 und 500).

    In diesem Beispiel wurde nicht explizit angegeben, welche Zahlen auf den Achsen zu sehen sein sollen. Daher sind nicht nur die Größenordnungen, sondern auch Werte dazwischen, als Zahlen eingetragen.

  5. Daher kann man nun noch explizit angeben, welche Zahlen sichtbar sein sollen (at=)
    plot(x, y, log="xy", xaxt="n", yaxt="n")
    sfsmisc::eaxis(side=1, at=10^c(0:3))
    sfsmisc::eaxis(side=2, at=10^c(-4,-2,0))

    In diesem Plot wurden nur Zahlen für die Größenordnungen angegeben. Auf der X-Achse wurde jede, auf der Y-Achse nur jede zweite Größenordnung mit einer Zahl versehen.
    In diesem Plot wurden nur Zahlen für die Größenordnungen angegeben. Auf der X-Achse wurde jede, auf der Y-Achse nur jede zweite Größenordnung mit einer Zahl versehen.