# Balkendiagramm zeichnen



## Ruderer1993 (11. Aug 2011)

Hallo
ich habe folgendes Problem:
Ich habe ein Array, dessen Zahlen mithilfe des BubbleSort Algorithmus sortiert werden. 
Nun würde ich gerne die Zahlen als Balkendiagramm ausgeben, sowohl unsortiert , als auch sortiert. Da ich noch nie wirklich grafisch in Java gearbeitet habe hoffe ich das mir hier jemand helfen kann.

Zum besseren Verständnis zeige ich mal hier meinen Code:

```
import java.io.*;
import java.util.Random;

public class BubbleSort {
 
	public static void main(String[] args) throws IOException {
        String text;
		//erstelle ein Array das wir sortieren
		int intArray[] = new int[6];
		
		Random zufall = new Random();
        for (int i=0; i<6; i++)
        intArray[i] = zufall.nextInt(1000);

 
		//gebe die Zahlen des Array aus bevor der Sortierung
		System.out.println("Array vor der Sortierung");
		for(int i=0; i < intArray.length; i++){
			System.out.print(intArray[i] + " ");
		}
 
		//sortiere das Array mit dem Bubblesort
		bubbleSort(intArray);
 
		System.out.println("");
 
		//gebe das Array nach dem Sortieren aus
		System.out.println("Array nach dem Bubblesort");
		for(int i=0; i < intArray.length; i++){
			System.out.print(intArray[i] + " ");
}
		
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
    System.out.println("\n\nGeben sie c ein um die Konsole zu leeren");
text = input.readLine();
if (text.equals("c")) {
System.out.println("\f"); 
 
	}

}
 
	private static void bubbleSort(int[] intArray) {
 
		/*
		 * berlegung: 2 nebeneinander stehende Zahlen werden berprft, falls die Reihenfolge falsch ist
		 * werden sie getauscht und die nchsten werden verglichen, bis man alle Zahlen durchlaufen hat
		 * 
		 * Bubble Sort Schritte:
		 * 
		 * 1. Vergleiche Array[0] und Array[1]
		 * 2. Falls array[0] > array [1] tausche sie.
		 * 3. Vergleiche array[1] & array[2]
		 * 4. Falls array[1] > array[2] tausche sie.
		 * ...
		 * 5. Vergleiche array[n-1] & array[n]
		 * 6. Falls [n-1] > array[n] dann tausche sie.
		 * 
		 * Nach diesen Schritten haben wir das gr§te Element am letzten Index
		 * 
		 * Wiederhole die selben Schritte fr array[1] bis array[n-1]
		 *  
		 */
 
		int n = intArray.length; 
		int temp = 0;
 
		for(int i=0; i < n; i++){ //n Durchläufe, mehr werden nicht benötigt
			for(int j=1; j < (n-i); j++){
 
				if(intArray[j-1] > intArray[j]){
					//tausche die Elemente - Dreieckstausch
					temp = intArray[j-1];
					intArray[j-1] = intArray[j];
					intArray[j] = temp;
				}
 
			}
		}
 
	}
}
```

Vielen Dank im Voraus !


----------



## AlexSpritze (11. Aug 2011)

Wie soll das Balkendiagramm ausgegeben werden? Direkt auf dem Bildschirm mittels eines JFrames oder einfach nur in eine PNG-Bilddatei geschrieben werden. Hier kann dir nur jemand helfen, wenn du konkrete Fragen stellst.


----------



## Ruderer1993 (11. Aug 2011)

OK sry daran hatte ich nicht gedacht, ich würde es gerne in einem JFRame ausgeben lassen.
Ich habe auch schon etwas gefunden, also ein JFRame das ein Balkendiagramm ausgibt :
Einfache Diagramme mit Java AWT – Boxis Webdev-Blog

aber das Problem was ich hier habe ist folgendes:
ich habe eine Methode public void bubblesort. Bei dem oben gezeigten Beispiel wir der Maximale Wert errechnet. Ich dachte mir ersetzte ich die Methode die den maximalen Wert errechnet einfach mit meinem BubbleSort Algorithmus und es läuft. 
Das geht aber nicht, weil ich eine Methode habe mit void und im Beispiel eine Methode ohne void also mit Rückgabewert verwendet wird. Nun das will nicht klappen !


----------



## chalkbag (11. Aug 2011)

siehe link: JFreeChart

Vielleicht leichter, als selbst das Lineal in die Hand zu nehmen. Beispiele sind auf der Seite.


----------



## AlexSpritze (11. Aug 2011)

Wenn du deine bubbleSort-Methode noch auf double Arrays erweiterst und unbedingt das Beispiel aus deinem Link nehmen willst, kannst du das so machen:
(Du musst wie gesagt, noch deine bubbleSort Funktion einfügen)


```
import java.awt.Color;
import java.awt.event.*;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.util.Random;

public class HistoFarbig extends Frame {

    // Fensterbreite
    public static final int FRAME_WIDTH  = 640;

    // Fensterhoehe
    public static final int FRAME_HEIGHT = 480;

    // Fenstertitel
    public static final String APP_TITLE = "Histogramm";

    // Die Messreihe, ein Array von double-Zahlen.
    double[] zahlen = null;
    Color[] farben  = {
        Color.black,
        Color.blue,
        Color.cyan,
        Color.gray,
        Color.magenta,
        Color.green,
        Color.red,
    };
    static Frame f1 = null;

    private static void bubbleSort(double[] array){
    .... // Hier deine Methode
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
      double doubleArray[] = new double[6];
        
        Random zufall = new Random();
        for (int i=0; i<6; i++)
        doubleArray[i] = zufall.nextDouble()*60;
      
      HistoFarbig f1 = new HistoFarbig(doubleArray);
        f1.setTitle(APP_TITLE);
        f1.setSize(FRAME_WIDTH, FRAME_HEIGHT);
        f1.setVisible(true);

        // "WindowListener" setzen, damit wenigstens der Close-Button
        // eine Funktion (System.exit(0)) hat. Alle anderen Methoden
        // _muessen_ auch implementiert werden, haben hier aber keine
        // Funktion.
        f1.addWindowListener(new WindowListener() {
            public void windowOpened(WindowEvent e) {}
            public void windowIconified(WindowEvent e) {}
            public void windowDeiconified(WindowEvent e) {}
            public void windowDeactivated(WindowEvent e) {}
            public void windowClosing(WindowEvent e) { System.exit(0); }
            public void windowClosed(WindowEvent e) {}
            public void windowActivated(WindowEvent e) {}
        });
        
        double[] sortedDoubleArray = new double[doubleArray.length];
        System.arraycopy(doubleArray, 0, sortedDoubleArray, 0, doubleArray.length);
        bubbleSort(sortedDoubleArray);
        
      HistoFarbig f2 = new HistoFarbig(sortedDoubleArray);
        f1.setTitle(APP_TITLE);
        f1.setSize(FRAME_WIDTH, FRAME_HEIGHT);
        f1.setVisible(true);

        // "WindowListener" setzen, damit wenigstens der Close-Button
        // eine Funktion (System.exit(0)) hat. Alle anderen Methoden
        // _muessen_ auch implementiert werden, haben hier aber keine
        // Funktion.
        f1.addWindowListener(new WindowListener() {
            public void windowOpened(WindowEvent e) {}
            public void windowIconified(WindowEvent e) {}
            public void windowDeiconified(WindowEvent e) {}
            public void windowDeactivated(WindowEvent e) {}
            public void windowClosing(WindowEvent e) { System.exit(0); }
            public void windowClosed(WindowEvent e) {}
            public void windowActivated(WindowEvent e) {}
        });
    }
    
    public HistoFarbig(double[] arr){
      this.zahlen=arr;
    }

    public void paint (Graphics g) {
        super.paint(g);

        // Double, um ohne Rundungsfehler rechnen zu koennen:
        double frameWidth  = new Double(this.getWidth());
        double frameHeight = new Double(this.getHeight());

        Graphics2D g2 = (Graphics2D) g;

        // Die maximale Breite, die ein Rechteck des Charts haben soll:
        // Die Gesamtbreite gleichmaessig auf die Anzahl der Zahlen
        // aufgeteilt und davon 60%.
        double width  = frameWidth / zahlen.length * .6;
        double xSpace = ( frameWidth / zahlen.length - width ) / 2;

        // Die maximale Hohe, die ein Rechteck des Charts haben soll:
        // 90% der Gesamthoehe
        double maxHeight = frameHeight * .90;

        // Messwertreihe durchgehen und Balkengrafiken aufbauen
        for (int i = 0; i < zahlen.length; i++) {

            // Einfaerben
            g2.setColor(farben[i]);

            // Hoehe des zu erstellenden Balken in Pixel. Der aktuelle _Wert_
            // wird mit dem groessten Wert innerhalb des Array in Beyiehung
            // gesetzt und der entstandene Faktor anschliessend mit "maxHeight"
            // auf seine finale Groesse gestreckt.
            double height = zahlen[i] / max(zahlen) * maxHeight;

            // xPos soll die horizontale Position sein, an der der Balken
            // erstellt werden soll. Die Position leitet sich aus der aktuellen
            // Balkenzahl ab, die in Verhaeltnis zur Balkenanzahl gebracht wird:
            // Balken 3 von 5 muesste in der Mitte der Chartflaeche aufgebaut
            // werden. Der entstandene Faktor mit "frameWidth" gestreckt.
            double xPos = new Double(i) / new Double(zahlen.length) * frameWidth + xSpace ;

            // Die vertikale Position, an der der Balken erstellt werden soll.
            double yPos = frameHeight - height;

            // Ein Rechteck wird anhand seiner X-Position, Y-Position, Breite und
            // Hoehe erstellt.
            Rectangle2D.Double r = new Rectangle2D.Double( xPos , yPos, width, height);

            // Balken zeichnen: "fill()" statt "draw()", damit das Rechteck ausgemalt
            // und nicht nur umrandet ist.
            g2.fill(r);
        }
    }

    /**
     * Liefert die groesste Zahl aus dem uebergebenen Zahlenarray zurueck.
     * @param double[] array
     * @return double maxValue
     */
    private double max ( double[] array ) {
        double maxValue = 0;
        for (int i = 0; i < array.length; i++) {
            if ( array[i] > maxValue ) {
                maxValue = array[i];
            }
        }
        return maxValue;
    }
}
```


----------



## Ruderer1993 (11. Aug 2011)

Hm danke erstmal aber wenn ich die Lösung dort nehme und dann meinen bubbleSort Algorithmus implementiere und dann in dieser Zeile:

```
double height = zahlen[i] / max(zahlen) * maxHeight;
```
Die Methode max mit bubbleSort ersetze, dann bekomme ich die Meldung das dort kein void Typ erlaubt ist !


----------



## AlexSpritze (11. Aug 2011)

Ruderer1993 hat gesagt.:


> Hm danke erstmal aber wenn ich die Lösung dort nehme und dann meinen bubbleSort Algorithmus implementiere und dann in dieser Zeile:
> 
> ```
> double height = zahlen[i] / max(zahlen) * maxHeight;
> ...



Das ergibt auch wenig Sinn, die Methode bubbleSort sortiert dir direkt das Array, ohne dir irgendwelchen Rückgabewert zu liefern. Welcher wäre da auch sinnvoll? Höchstens noch das Array ansich, aber du kannst dnan in der Codezeile keine Zahl durch ein Array teilen.

Du sortierst das Array und rufst dann max auf mit dem sortierten Array als Übergabeparameter.

PS: Die Methode max dient an der Stelle auch nur um die Balken so zu skalieren, dass sie nicht über den Bildschirmrand schießen. Darum solltest du da eigentlich nichts ändern müssen.


----------



## Ruderer1993 (11. Aug 2011)

EDIT:
Schon ok habs nun


----------



## Ruderer1993 (11. Aug 2011)

Ok nun klappt alles soweit aber ich habe noch eine zweite Frage, könnte man darum nun auch so eine Art Koordinaten System zeichnen ? Oder zumindest die Zahlen, die sortiert werden so unterhalb oder in die Balken schreiben. Man könnte ja quasi 6 Labels nehmen sie richtig positionieren und dann die Werte dort ausgeben lassen, aber wenn man eine Funktion einbauen wollte in der der Anwender die Arraygröße bestimmen kann, würde dieser Weg ja schonmal nicht gehen. Daher denke ich das es bestimmt noch bessere Wege gibt, jemand eine Idee ?


----------



## AlexSpritze (11. Aug 2011)

Die Möglichkeiten die obiges Codebeispiel bietet sind sehr gering. Wenn du nicht wirklich alles selbst programmieren willst, empfehle auch ich JFreeChart, damit kannst du dann fast alles abdecken, was dir so einfällt.


----------



## Ruderer1993 (11. Aug 2011)

Hm habe noch nie mir JFreeChart gearbeitet, kann man sich das wie in Objektive-C (sry kenne mich damit wesentlich besser aus) mit den Frameworks vorstellen. Also ist das quasi so eine externe Library die ich implementieren muss ?

Würde es lieber normal lösen, kann man denn nicht die Werte einfach in oder unter die Balken Schreiben ?


----------



## AlexSpritze (11. Aug 2011)

Hm, es gibt bestimmt einige Tutorials zu JFreeChart. Im Endeffekt ist bindest du diese Bibliothek als JAR in dein Projekt ein und rufst entsprechende Befehle der dortigen API auf und bekommst das gewünschte Diagramm, dass du dann anzeigen oder speichern kannst. Einfach mal googlen. Es ist eigentlich immer besser schon fertige Libraries zu benutzen, als alles selbst programmieren zu wollen.

Trotzdem kannst du mit 

```
//Graphics2D g2 = ...;
      g2.drawString("Text", 12, 34);
```
das Wort Text beginnend an der Pixelposition (12,34) schreiben. Musst halt ein wenig probieren, wo du der Text genau erscheinen soll. Das Codestück findet dann Verwendung in der For-Schleife, wo du auch auf das zahlenArray zugreifst.


----------



## chalkbag (11. Aug 2011)

Die Frage hatte hier sogar schon mal einer, und es gibt super viele Beispiele welche dir bestimmt helfen.

http://www.java-forum.org/buecher-tutorials-links/77954-tutorial-fuer-jfreechart.html

p.s. nicht den Guide zum kaufen sonder die Beispiele unter java2s.com


----------



## Ruderer1993 (11. Aug 2011)

Ja hatte den Thread gesehen, damals kam man in dem Thread aber zu keiner wirklichen Lösung.
Ich habe nun die Ausgabe wie folgt gemacht : 

```
g1.drawString((""+String.valueOf(zahlen[0]).substring(0, String.valueOf(zahlen[0]).toString().indexOf(".") + 3)),33,475);
            g1.drawString((""+String.valueOf(zahlen[1]).substring(0, String.valueOf(zahlen[1]).toString().indexOf(".") + 3)),135,475);
            g1.drawString((""+String.valueOf(zahlen[2]).substring(0, String.valueOf(zahlen[2]).toString().indexOf(".") + 3)),240,475);
            g1.drawString((""+String.valueOf(zahlen[3]).substring(0, String.valueOf(zahlen[3]).toString().indexOf(".") + 3)),345,475);
            g1.drawString((""+String.valueOf(zahlen[4]).substring(0, String.valueOf(zahlen[4]).toString().indexOf(".") + 3)),455,475);
            g1.drawString((""+String.valueOf(zahlen[5]).substring(0, String.valueOf(zahlen[5]).toString().indexOf(".") + 3)),520,475);
            g1.setColor(Color.black);
```

Aber irgendwie verschwindet der allerletzte String hinter dem Diagramm. Also das Diagramm liegt dann über dem String, bei den anderen liegt der String über dem Diagramm, wieso ?!

EDIT: Schon ok ich hab erst den String gezeichnet und dann den letzten Balken, wodurch der String "überschrieben" wurde, habs jetzt geändert.


----------



## chalkbag (11. Aug 2011)

Ruderer1993 hat gesagt.:


> Ja hatte den Thread gesehen, damals kam man in dem Thread aber zu keiner wirklichen Lösung.



Das Vogella Beispiel ist doch ganz ok (wie jedes Vogella Beispiel)


```
JFreeChart chart = createChart(createDataset());
		final ChartComposite frame = new ChartComposite(parent, SWT.NONE,
				chart, true);
				
private JFreeChart createChart(CategoryDataset dataset) {

		JFreeChart chart = ChartFactory.createBarChart("Bar Chart", // chart
				// title
				"Labels", // domain axis label
				"Values", // range axis label
				dataset, // data
				PlotOrientation.VERTICAL, // orientation
				true, // include legend
				true, // tooltips?
				false // URLs?
				);

		CategoryPlot plot = (CategoryPlot) chart.getPlot();
		plot.setBackgroundPaint(Color.lightGray);
		plot.setDomainGridlinePaint(Color.white);
		plot.setDomainGridlinesVisible(true);
		plot.setRangeGridlinePaint(Color.white);
		return chart;

	}
	
	
	private CategoryDataset createDataset() {
		DefaultCategoryDataset dataset = new DefaultCategoryDataset();

		// row keys...
		String series1 = "First";
		String series2 = "Second";

		// column keys...
		String category1 = "Label 1";
		String category2 = "Label 2";
		String category3 = "Label  3";

		dataset.addValue(1.0, series1, category1);
		dataset.addValue(4.0, series1, category2);
		dataset.addValue(3.0, series1, category3);

		dataset.addValue(5.0, series2, category1);
		dataset.addValue(7.0, series2, category2);
		dataset.addValue(6.0, series2, category3);

		return dataset;
	}
```

Aber ok, war ja nur ein Vorschlag. Manche Sachen schreib ich auch lieber selber :joke:


----------

