<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>CTAPbIu_MABP&#039;s BLOG &#187; applet</title>
	<atom:link href="http://mabp.kiev.ua/tag/applet/feed/" rel="self" type="application/rss+xml" />
	<link>http://mabp.kiev.ua</link>
	<description>энтузиазм = 1/опыт © Старый Мавр</description>
	<lastBuildDate>Sat, 12 May 2012 07:40:54 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2</generator>
		<item>
		<title>Дата Пасхи</title>
		<link>http://mabp.kiev.ua/2009/04/17/date-of-easter/</link>
		<comments>http://mabp.kiev.ua/2009/04/17/date-of-easter/#comments</comments>
		<pubDate>Fri, 17 Apr 2009 09:57:06 +0000</pubDate>
		<dc:creator>CTAPbIu_MABP</dc:creator>
				<category><![CDATA[JAVA]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[algorithms]]></category>
		<category><![CDATA[applet]]></category>

		<guid isPermaLink="false">http://mabp.kiev.ua/?p=1061</guid>
		<description><![CDATA[Попалась мне как-то на глаза цитата с баша (из бездны) "Пасха рассчитывается по формуле Гаусса: a = [(19 * [Y / 19] + 15) / 30], где Y - год, [] - остаток от деления; b = [(2 * [Y / 4] + 4 * [Y / 7] + 6 * a + 6) / [...]]]></description>
			<content:encoded><![CDATA[<p>Попалась мне как-то на глаза цитата с баша (из бездны)</p>
<pre>
"Пасха рассчитывается по формуле Гаусса:
a = [(19 * [Y / 19] + 15) / 30], где Y - год, [] - остаток от деления;
b = [(2 * [Y / 4] + 4 * [Y / 7] + 6 * a + 6) / 7];
Если (a + b) > 10, то Пасха будет (a + b - 9) апреля ст. стиля, в противном случае — (22 + a + b) марта ст. стиля. Дата Пасхи может попадать в период от 22 марта до 25 апреля по ст. стилю (от 4 апреля до 8 мая по н. стилю)."
Гаусс не только великий ученый но и священный математик =)
</pre>
<span id="more-1061"></span>
<p>Я, как известно, человек не очень религиозный, но меня это заинтересовало. Тем более что паска не за горами. Алгоритм уже есть, осталось только его реализовать, а это всего пару строчек кода. Затык был только один - преход с Юлианского календаря на Григорианский. Согласно википедии переход на <a href="http://ru.wikipedia.org/wiki/Григорианский_календарь" rel="nofollow external">Григорианский календарь</a> был произведен папой римским Григорием XIII 4 октября 1582. Но не все поддержали эту инициативу и переход длился 346 лет с 1582 по 1928 год. Вот это нихуясебе не могли договориться! Но поскольку Пасхой заведует папа то я решил что моментом перехода будет считаться 1582 год, Пасха в котором была по "старому" стилю.</p>
<p>Чтобы алгоритм с цифрами не смотрелся совсем одиноко я оформил небольшой апплет, который высчитывает Пасху в нашей эре, тоесть время до рождества не доступно, да и собственно не нужно, потому что Пасху тогда не отмечали. Сначала вы посмотрите код, а потом сможете посчитать когда была Пасха например в год вашего рождения.</p>

<pre><code class="java">
package ua.kiev.mabp;

import java.applet.Applet;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.util.Date;
import java.text.SimpleDateFormat;

/**
 * Created by IntelliJ IDEA.
 * User: CTAPbIu_MABP
 * Date: 17.04.2009
 * Time: 10:15:29
 */

public class Easter extends Applet  implements ActionListener {

    private String date;
    private TextField tf;

    public void init() {
        setSize(300,100);
        String year = new SimpleDateFormat("yyyy").format(new Date());
        date = calculate(Integer.parseInt(year));
        tf = new TextField (year, 20);
        add(tf);
        Button btn = new Button("Calculate!");
        btn.addActionListener(this);
        add(btn);
    }

    public void paint(Graphics g) {
        g.drawString(date, 40, 50);
    }

    public void actionPerformed(ActionEvent event) {
        String year = tf.getText().replaceAll("[^\\d]","");
        tf.setText(year);
        date = !year.isEmpty() ? calculate(Integer.parseInt(year)) : "Enter valid year, please!";
        repaint();
    }

    public static String calculate(int year){

        int a = (19 * (year % 19) + 15) % 30;
        int b = ( 2 * (year % 4) + 4 * (year % 7) + 6 * a + 6) % 7;

        int oldDate = (a + b) > 9 ? (a + b - 9) : (22 + a + b);
        String oldMonth = (a + b) > 9 ? " april" : " march";

        int newDate;
        String newMonth;
        if((a + b) > 9){ // апрель
            newDate = oldDate + 13 > 30 ? oldDate + 13 - 30 : oldDate + 13;
            newMonth = oldDate + 13 > 30 ? " may" : " april";
        }else{ // март
            newDate = oldDate + 13 > 31 ? oldDate + 13 - 31 : oldDate + 13;
            newMonth = oldDate + 13 > 31 ? " april" : " march";
        }
        return year > 1582 ? newDate + newMonth : oldDate + oldMonth;
    }
}
</code></pre>

<p>Итак смотрите что у меня получилось в результате:</p>

<div style="text-align:center">
<APPLET CODEBASE="/content/source/" CODE= "ua.kiev.mabp.Easter" archive="Easter.jar" WIDTH="300" HEIGHT="100" ALT="Java не включена!">
</APPLET>
</div>]]></content:encoded>
			<wfw:commentRss>http://mabp.kiev.ua/2009/04/17/date-of-easter/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Цепи Маркова</title>
		<link>http://mabp.kiev.ua/2009/01/27/markovs-chains/</link>
		<comments>http://mabp.kiev.ua/2009/01/27/markovs-chains/#comments</comments>
		<pubDate>Mon, 26 Jan 2009 22:06:26 +0000</pubDate>
		<dc:creator>CTAPbIu_MABP</dc:creator>
				<category><![CDATA[JAVA]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[algorithms]]></category>
		<category><![CDATA[applet]]></category>

		<guid isPermaLink="false">http://mabp.kiev.ua/?p=537</guid>
		<description><![CDATA[Я что-то не особо любил учиться в школе, потом в институте, а сейчас в институте ничему не учат, приходишь два раза в год сдаёшь сессию и не заморачиваешься - заочный в общем. Тяжелее всего мне в школе давалась вышка и физика. Все, кто мне говорил, что вышка нужна для программирования посылались на хуй не задумываясь. [...]]]></description>
			<content:encoded><![CDATA[<p>Я что-то не особо любил учиться в школе, потом в институте, а сейчас в институте ничему не учат, приходишь два раза в год сдаёшь сессию и не заморачиваешься - заочный в общем. Тяжелее всего мне в школе давалась вышка и физика. Все, кто мне говорил, что вышка нужна для программирования посылались на хуй не задумываясь. Да на хуй вышка нужна быдлокодеру на <a href="http://mabp.kiev.ua/category/programming/html/">HTML</a> и <a href="http://mabp.kiev.ua/category/programming/php/">PHP</a>?! :D. Но вот не такое уже и большое время назад я понял, что было бы неплохо знать, о чем идет речь, когда читаешь статью о программировании. Все началось наверное когда я прочел об алгоритме сортировки <a href="http://ru.wikipedia.org/wiki/Быстрая_сортировка" rel="nofollow external">quicksort</a>. Потом мне как-то на глаза попалась заметка <a href="http://andrew-vasilkov.livejournal.com/38626.html" rel="nofollow external">Пылесос Kirby не удаляет пыль Фату с ковра Серпинского</a>, естественно полез узнавать что это такое :) Где-то посреди поисков нашел фразу "Пылесос Kirby не удаляет <a href="http://ru.wikipedia.org/wiki/Пыль_Фату" rel="nofollow external">пыль Фату</a> с <a href="http://ru.wikipedia.org/wiki/Ковёр_Серпинского" rel="nofollow external">ковра Серпинского</a> просыпанную из <a href="http://ru.wikipedia.org/wiki/Бутылка_Клейна" rel="nofollow external">бутылку Клейна</a>", еще один умный термин в копилку. Кстати больше никогда не буду упоминать бутылку Клейна в разговоре, не с моим талантом объяснять людям, что это такое. И одним из последних мне на глаза попался <a href="http://blog.nihilogic.dk/2008/09/mandelbrot-in-less-than-128-bytes-of.html" rel="nofollow external">фрактал Мандельброта</a>. Так вот к чему это я так долго веду... К тому что я в рамках собственного ликбеза и наполнения блога статьями по Java написал реализацию <a href="http://ru.wikipedia.org/wiki/Цепь_Маркова" rel="nofollow external">цепей Маркова</a>, а все вышесказанное плавно подводило к тому что это граф из высшей математики.</p>
<span id="more-537"></span>
<p>Мне тут уже мягко намекали что реализации этого алгоритма есть уже на всех языках программирования, потому что он используется (использовался?) для генерации дорвеев. Я не спорю, но это была неплохая возможность потренироваться, и добавить контента на сайт. Большую часть времени написания данного чуда составило аж никак не программирование и не высшая математика, а попытки настроить <a href="http://mabp.kiev.ua/tag/applet/">applet</a> так, чтоб эта зараза могла открывать локальные файлы. предупреждение об этом вы видели когда загрузили страницу и согласились, или не согласились, тогда вам нужно нажать ctrl+r.</p>
<p>Описания того как при помощи цепей Маркова генерировать тексты в сети полно, но я рискну повториться. Берем исходный осмысленный текст и раскладываем его на последовательности, для примера я взял скороговорку:</p>
<pre>Ехал Грека через реку.
Видит Грека в реке рак.
Сунул в реку руку Грека.
Рак за руку Грека - цап. </pre>
<br />
<p>После разложения она выглядит так:</p>
<br />
<pre>{
ехал=[грека],
грека=[через, в], 
через=[реку], 
реку=[видит, руку], 
видит=[грека], 
в=[реке, реку], 
реке=[рак], 
сунул=[грека], 
руку=[греку, рак]
рак=[за],
за=[руку], 
греку=[цап], 
}</pre>
<br />
<p>У нас получился массив слов, с парами которые могут идти после этих слов. Теперь задача обратная взять любое слово и начать строить из него  цепочку в которой каждое слово имело бы себе пару из списка. Я попробую построить без программы самую длинную цепочку не проходя дважды по одним и тем же комбинациям, начнем с несчастного Греки.</p>
<br />
<pre>Грека через реку видит Грека в реке рак за руку Греку цап.</pre>
<br />
<p>Смысла конечно в предложении не много, и от оригинала не сильно отличается, просто у нас очень короткий исходный текст. Посмотрев на этот набор слов мы удостоверились что все слова по парно стыкуются по падежам, и похожи на реальный текст. Но из 4 строчек много не нагенеришь, я тут давеча взял на lib.ru Войну и Мир (500 кб) и попробовал нагенерить пару страниц оттуда, получаются весьма забавные перлы! Но как правильно заметил один человек в Войну и Мир слово "кондиционер" не впихнешь. А еще, я надеюсь, это все таки он написал <a href="http://blog.promosite.ru/comments.php?336" rel="nofollow external">статью</a>, о том как отличить текст нагенеренный из <s>4 строчек</s> 30 килобайт исходного текста до целого мегабайта.</p>
<p>Так, пока вы не разочаровались в алгоритме, я думаю пора привести его реализацию и дать с ним поиграться, а то все убегут не дочитав до конца. Вот исходный код с небольшим количеством комментариев:</p>
<br />
<pre><code class="java">
package ua.kiev.mabp;

/**
 * Created by IntelliJ IDEA.
 * User: CTAPbIu_MABP
 * Date: 26.01.2009
 * Time: 21:04:28
 */

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.DataInputStream;
import java.io.BufferedInputStream;

import java.awt.Button;
import java.awt.Dimension;
import java.awt.FileDialog;
import java.awt.Frame;
import java.awt.TextArea;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import java.applet.Applet;


public class MarkovChainApplet extends Applet implements ActionListener {

    public void init() {
        // Порисуем :)
        setSize(300,150);
        Button btn = new Button("Select file!");
        btn.addActionListener(this);
        add(btn);
        add(new TextArea(5,30));
    }

    public void actionPerformed(ActionEvent event) {

        // Получаем файл
        FileDialog fd = new FileDialog(new Frame(), "Please choose a file:", FileDialog.LOAD);
        fd.setVisible(true);
        File file = new File(fd.getDirectory() + fd.getFile());
        System.out.println("Reading file " + fd.getDirectory() + fd.getFile());

        // Читаем файл
        String filestring = null;
        try {
            DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));

            try {
                byte[] infile = new byte[dis.available()];
                filestring = new String(infile, 0, dis.read(infile));
            } catch (IOException e) {
                System.out.println("File read error...");
                e.printStackTrace();
            }
            // Если нажали на кнопку "Отмена"
        } catch (FileNotFoundException e) {
            System.out.println("File not found...");
            e.printStackTrace();
        }

        // Файл был пустой
        if (filestring != null &#038;& filestring.length() &gt; 0) {

            // Причесываем текст
            String text = filestring.toLowerCase()
                    // Переводим все в нижний регистр, убираем цифры, спецсимволы и лишнии пробелы
                    .replaceAll("[\\d\\(\\)\\[\\]\\{\\}'\"\\*$\\\\\\/^~_,:;%@#&#038;|+=—-]", "")
                    .replaceAll("\\s+", " ");

            // Составляем карту
            Map&lt;String, Set&lt;String&gt;&gt; markovMap = new HashMap&lt;String, Set&lt;String&gt;&gt;();
            String[] sentenses = text.split("[\\.\\?!]\\s?");
            for (int i = 0, j = sentenses.length; i &lt; j; i++) {
                String[] words = sentenses[i].split(" ");
                for (int k = 0, l = words.length - 1; k &lt; l; k++) {
                    if (markovMap.containsKey(words[k])) {
                        markovMap.get(words[k]).add(words[k + 1]);
                    } else {
                        markovMap.put(words[k], new HashSet&lt;String&gt;(Arrays.asList(words[k + 1])));
                    }
                }
            }

            // Строим последовательности
            List&lt;LinkedList&lt;String&gt;&gt; prepared = new ArrayList&lt;LinkedList&lt;String&gt;&gt;();
            Random random = new Random();
            // генерируем 10 предложений
            for (int s = 0; s &lt; 10; s++) {
                ArrayList&lt;String&gt; keys = new ArrayList&lt;String&gt;(markovMap.keySet());
                String prev = keys.get(random.nextInt(keys.size()));
                LinkedList&lt;String&gt; sentense = new LinkedList&lt;String&gt;(Arrays.asList(prev));
                for (Set&lt;String&gt; next = markovMap.get(prev);
                     // по 10-20 слов в каждом
                     next != null &#038;& !next.isEmpty() &#038;& sentense.size() &lt; 10 + random.nextInt(10);
                     next = markovMap.get(prev)) {
                    List list = Arrays.asList(next.toArray());
                    prev = (String) list.get(random.nextInt(list.size()));
                    sentense.add(prev);
                }
                prepared.add(s, sentense);
            }

            // Генерируем из последовательностей текст
            StringBuilder generatedText = new StringBuilder();
            for (LinkedList&lt;String&gt; sentense : prepared) {
                if (sentense.size() &gt; 5) {
                    for (String words : sentense) {
                        generatedText.append(" ").append(words);
                    }
                    generatedText.append(".");
                }
            }

            // Выводим на экран
            ((TextArea) getComponent(1)).setText(generatedText.toString());
        }
    }
}
</code></pre>
<br />
<p>Я сегодня такой добрый, что даже покажу как это все скомпилить так чтобы не вылазила ошибка? о том что апплет не имеет доступа в файловой системе. Следующий код можно сохранить как *.bat:</p>
<br />
<pre><code>
javac path/to/your/package/ClassNameApplet.java
jar cf cna.jar path/to/your/package/ClassNameApplet.class
keytool -genkey -keystore YOU_SITE_NAME.YOUR_DOMAIN -keyalg rsa -dname "CN=YOUR_NAME, OU=, O=, L=, ST=, C=" -alias YOUR_NAME -validity 3600 -keypass YOUR_PASSWORD -storepass YOUR_PASSWORD
jarsigner -keystore YOU_SITE_NAME.YOUR_DOMAIN -storepass YOUR_PASSWORD -keypass YOUR_PASSWORD -signedjar ClassNameApplet.jar cna.jar YOUR_NAME 
</code></pre>
<br />
<p>Ну и конечно же дам поиграться результатом. Еще раз напомню если вы при загрузке страницы нажали на большом алерте с надписью "Do you want to run the application?" кнопку "нет" то сейчас нужно нажать ctrl+r и на повторно вылезшем алерте нажать "да", иначе кина не будет. Если алерт повторно не вылез, то к сожалению, скорее всего придется закрыть браузер и открыть повторно.</p>
<br />
<div style="text-align:center">
<applet codebase="/content/source/" code="ua.kiev.mabp.MarkovChainApplet" archive="MarkovChainApplet.jar" height="150" width="300" alt="Java не включена!"></applet>
</div>]]></content:encoded>
			<wfw:commentRss>http://mabp.kiev.ua/2009/01/27/markovs-chains/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>JFreeChart: StackedXYBarChart</title>
		<link>http://mabp.kiev.ua/2008/05/28/jfreechart-stackedxybarchart/</link>
		<comments>http://mabp.kiev.ua/2008/05/28/jfreechart-stackedxybarchart/#comments</comments>
		<pubDate>Wed, 28 May 2008 16:13:23 +0000</pubDate>
		<dc:creator>CTAPbIu_MABP</dc:creator>
				<category><![CDATA[JAVA]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[applet]]></category>

		<guid isPermaLink="false">http://mabp.localhost/?p=219</guid>
		<description><![CDATA[Так получается что по работе я все дальше отхожу от JavaScript в сторону Java. Я в принципе я рад, но дело в том, что писать становиться все сложнее, потому что показывать какие-то мелкие части большой системы не имеет никакого смысла, их зачастую нельзя даже использовать повторно. Но вот недавно мне пришлось использовать библиотеку под названием [...]]]></description>
			<content:encoded><![CDATA[<p>Так получается что по работе я все дальше отхожу от <a href="http://mabp.kiev.ua/programming/javascript/">JavaScript</a> в сторону <a href="http://mabp.kiev.ua/programming/java/">Java</a>. Я в принципе я рад, но дело в том, что писать становиться все сложнее, потому что показывать какие-то мелкие части большой системы не имеет никакого смысла, их зачастую нельзя даже использовать повторно. Но вот недавно мне пришлось использовать библиотеку под названием JFreeChart и о ней я сейчас расскажу.</p>
<p>Библиотека очень приятная на ощупь! Прекрасная демка, скачиваешь загрузчик, который сам тянет все примеры, смотришь, все хорошо, до того момента пока не переходишь на закладку "исходный код", а там с тебя просят за исходники заплатить. Простите, но это жлобство, мало того, что сама библиотека платная, так еще и исходники примеров платные. Первая мысль - декомпилировать, а вторая поискать в Google, который с радостью отдает все исходники по названию примера?. Пошаманив немного я изобразил то, что требовалось. Но об этом чуть позже.</p>
<p>В принципе примеры сделаны очень грамотно, но как всегда есть одно но, то что требуется сделать проблематично просмотреть, поскольку создается новый график без каких либо методов вывода себя. Вот в первом примере я и покажу как легко отображать график для его отладки при создании, для этого отнаследуюсь от фрейма и буду выдавать всплывающее окошко с картинкой. Кстати у этого окошка есть настройки и тултипы, которых лишены все остальные примеры.</p>
<span id="more-219"></span>

<pre><code class="java">
package ua.mabp.kiev;

/**
 * Created by IntelliJ IDEA.
 * User: mabp
 * Date: 27.05.2008
 * Time: 23:18:42
 */

import java.awt.*;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import javax.swing.*;

import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.NumberTickUnit;
import org.jfree.chart.labels.StandardXYItemLabelGenerator;
import org.jfree.chart.labels.StandardXYToolTipGenerator;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.StackedXYBarRenderer;
import org.jfree.data.time.TimeTableXYDataset;
import org.jfree.data.time.Year;
import org.jfree.data.xy.TableXYDataset;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.RectangleInsets;
import org.jfree.ui.RefineryUtilities;
import org.jfree.ui.VerticalAlignment;


public class StackedXYBarChartFrame extends ApplicationFrame {

    /**
     * Создаёт новый фрейм с графиком
     * @param title Заголовок окна
     */
    public StackedXYBarChartFrame(String title) {
        super(title);
        // Создаём новый график
        JFreeChart chart = createChart(createDataset());
        // На панеле
        ChartPanel chartPanel = new ChartPanel(chart);
        // С размерами 450*450
        chartPanel.setPreferredSize(new Dimension(450, 450));
        // И ползунками если необходимо
        JScrollPane sp = new JScrollPane(chartPanel);
        sp.setPreferredSize(new Dimension(500, 500));
        sp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        setContentPane(sp);
    }

    /**
     * Наполняет Set данными для построения графика
     * @return Данные для построения
     */
    private static TableXYDataset createDataset() {
        // Типа данные
        TimeTableXYDataset dataset = new TimeTableXYDataset();
        dataset.add(new Year(2002), 1000, "Blue");
        dataset.add(new Year(2003), 1100, "Blue");
        dataset.add(new Year(2002), 0, "Red");
        dataset.add(new Year(2003), 50, "Red");
        return dataset;
    }

    /**
     * Создаёт новый график по данным
     * @param dataset данные для построения
     * @return график
     */
    private static JFreeChart createChart(TableXYDataset dataset) {

        // OX - ось абсцисс
        // задаем название оси
        DateAxis domainAxis = new DateAxis("Year");
        // Показываем стрелочку вправо
        domainAxis.setPositiveArrowVisible(true);
        // Задаем отступ от графика
        domainAxis.setUpperMargin(0.2);

        // OY - ось ординат
        // Задаём название оси
        NumberAxis rangeAxis = new NumberAxis("Color");
        // Задаём величину деления
        rangeAxis.setStandardTickUnits(NumberAxis.createStandardTickUnits());
        rangeAxis.setTickUnit(new NumberTickUnit(200));
        // Показываем стрелочку вверх
        rangeAxis.setPositiveArrowVisible(true);


        // Render
        // Создаем стопковый (не знаю как лучше перевести) график
        // 0.02 - расстояние между столбиками
        StackedXYBarRenderer renderer = new StackedXYBarRenderer(0.02);
        // без рамки
        renderer.setDrawBarOutline(false);
        // цвета для каждого элемента стопки
        renderer.setSeriesPaint(0, Color.blue);
        renderer.setSeriesPaint(1, Color.red);
        // Задаём формат и текст подсказки
        renderer.setBaseToolTipGenerator(new StandardXYToolTipGenerator("{0} : {1} = {2} tonnes", new SimpleDateFormat("yyyy"), new DecimalFormat("#,##0")));
        renderer.setSeriesItemLabelGenerator(0, new StandardXYItemLabelGenerator());
        renderer.setSeriesItemLabelGenerator(1, new StandardXYItemLabelGenerator());
        // Делаем её видимой
        renderer.setSeriesItemLabelsVisible(0, true);
        renderer.setSeriesItemLabelsVisible(1, true);
        // И описываем её шрифт
        renderer.setSeriesItemLabelFont(0, new Font("Serif", Font.BOLD, 10));
        renderer.setSeriesItemLabelFont(1, new Font("Serif", Font.BOLD, 10));

        // Plot
        // Создаем область рисования
        XYPlot plot = new XYPlot(dataset, domainAxis, rangeAxis, renderer);
        // Закрашиваем
        plot.setBackgroundPaint(Color.white);
        // Закрашиваем сетку
        plot.setDomainGridlinePaint(Color.white);
        plot.setRangeGridlinePaint(Color.white);
        // Отступ от осей
        plot.setAxisOffset(new RectangleInsets(0D, 0D, 10D, 10D));
        plot.setOutlinePaint(null);

        // Chart
        // Создаем новый график
        JFreeChart chart = new JFreeChart(plot);
        // Закрашиваем
        chart.setBackgroundPaint(Color.white);
        // Перемещаем легенду в верхний правый угол
        chart.getLegend().setPosition(RectangleEdge.RIGHT);
        chart.getLegend().setVerticalAlignment(VerticalAlignment.TOP);

        return chart;
    }

    public static void main(String[] args) {
        // Создаем новый фрейм
        StackedXYBarChartFrame demo = new StackedXYBarChartFrame("JFreeChart: StackedXYBarChart");
        demo.pack();
        // И показываем
        RefineryUtilities.centerFrameOnScreen(demo);
        demo.setVisible(true);
    }

}

</code></pre>

<p>Я надеюсь, я достаточно продокументировал код, что бы было понятно, что я делаю. В результате его выполнения получаем всплывающее окошко с графиком, все хорошо, быстро и удобно, но нам все-таки нужен график и, скорее всего мы будем его либо показывать в браузер, либо сохранять в файл, значит, нам нужно сделать так, чтобы его можно было передать в OutputStream. Для выброса в поток и записи в файл предусмотрены две утилиты, каждая из которых умеет работать с двумя форматами PNG и JPEG, GIF - платный формат :(. Так вот тут есть косяк при сохранении в JPEG почему-то график окрашивается в розовый цвет. лечение от этого бага я не нашел, да особо и не искал так как PNG меня вполне устраивал. Итак, выбрасываем в поток:</p>

<pre><code class="java">
package ua.mabp.kiev;

/**
 * Created by IntelliJ IDEA.
 * User: mabp
 * Date: 27.05.2008
 * Time: 23:18:42
 */

import java.awt.*;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;

import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.NumberTickUnit;
import org.jfree.chart.labels.StandardXYItemLabelGenerator;
import org.jfree.chart.labels.StandardXYToolTipGenerator;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.StackedXYBarRenderer;
import org.jfree.data.time.TimeTableXYDataset;
import org.jfree.data.time.Year;
import org.jfree.data.xy.TableXYDataset;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.RectangleInsets;
import org.jfree.ui.VerticalAlignment;

public class StackedXYBarChartPNG extends JFreeChart {


    /**
     * Создаёт новый график по данным
     * @param dataset данные для построения
     */
    public StackedXYBarChartPNG(TableXYDataset dataset) {
        super(new XYPlot());

        // OX
        DateAxis domainAxis = new DateAxis("Month");
        domainAxis.setPositiveArrowVisible(true);
        domainAxis.setUpperMargin(0.2);

        // OY
        NumberAxis rangeAxis = new NumberAxis("Tonnes");
        rangeAxis.setStandardTickUnits(NumberAxis.createStandardTickUnits());
        rangeAxis.setTickUnit(new NumberTickUnit(200));
        rangeAxis.setPositiveArrowVisible(true);

        // Render
        StackedXYBarRenderer renderer = new StackedXYBarRenderer(0.02);
        renderer.setDrawBarOutline(false);
        renderer.setSeriesPaint(0, Color.blue);
        renderer.setSeriesPaint(1, Color.red);
        renderer.setBaseToolTipGenerator(new StandardXYToolTipGenerator("{0} : {1} = {2} tonnes", new SimpleDateFormat("yyyy"), new DecimalFormat("#,##0")));
        renderer.setSeriesItemLabelGenerator(0, new StandardXYItemLabelGenerator());
        renderer.setSeriesItemLabelGenerator(1, new StandardXYItemLabelGenerator());
        renderer.setSeriesItemLabelsVisible(0, true);
        renderer.setSeriesItemLabelsVisible(1, true);
        renderer.setSeriesItemLabelFont(0, new Font("Serif", Font.BOLD, 10));
        renderer.setSeriesItemLabelFont(1, new Font("Serif", Font.BOLD, 10));

        // Plot
        XYPlot plot = getXYPlot();
        plot.setDataset(dataset);
        plot.setDomainAxis(domainAxis);
        plot.setRangeAxis(rangeAxis);
        plot.setRenderer(renderer);
        plot.setBackgroundPaint(Color.white);
        plot.setDomainGridlinePaint(Color.white);
        plot.setRangeGridlinePaint(Color.white);
        plot.setAxisOffset(new RectangleInsets(0D, 0D, 10D, 10D));
        plot.setOutlinePaint(null);

        // Chart
        setBackgroundPaint(Color.white);
        getLegend().setPosition(RectangleEdge.RIGHT);
        getLegend().setVerticalAlignment(VerticalAlignment.TOP);
    }
    
    /**
     * Наполняет Set данными для построения графика
     * @return Данные для построения
     */
    private static TableXYDataset createDataset() {
        TimeTableXYDataset dataset = new TimeTableXYDataset();
        dataset.add(new Year(2002), 1000, "Blue");
        dataset.add(new Year(2003), 1100, "Blue");
        dataset.add(new Year(2002), 0, "Red");
        dataset.add(new Year(2003), 50, "Red");
        return dataset;
    }

    /**
     * Создает и сохраняет график
     * @param args ничего не передается
     */
    public static void main(String[] args) {
        // строим график
        JFreeChart chart = new StackedXYBarChartPNG(createDataset());
        chart.setBorderVisible(false);
        chart.setAntiAlias(true);

        // выбрасывем в поток
        try {
            // например в файл
            OutputStream stream = new FileOutputStream("chart.png");
            ChartUtilities.writeChartAsPNG(stream, chart, 500, 500);
        } catch(IOException e) {
            System.err.println("Failed to render chart as png: "+ e.getMessage());
            e.printStackTrace();
        }
    }

}

</code></pre>

<p>Две основные функции не поменялись, единственно что из конструктора можно выкинуть все что касается тултипов так как они естественно не работают.</p>

<p>Поменялся PSVM он теперь приспособлен для обработки графика внешними методами. Файлик chart.png можно будет найти в корне проекта и посмотреть, что получилось. Но было бы некрасиво столько написать и не дать посмотреть на результат, возможно, кто-то не может собрать проект, а кто-то просто не хочет, поэтому я завернул все это хозяйство в апплет и сделал из этого третий пример. Он получился самым легким из-за отсутствия всех дополнительных методов, есть только один метод для рисования имплементирующий функционал апплета.</p>


<pre><code class="java">
package ua.mabp.kiev;

/**
 * Created by IntelliJ IDEA.
 * User: mabp
 * Date: 27.05.2008
 * Time: 23:18:42
 */
import java.applet.Applet;
import java.awt.*;
import java.text.SimpleDateFormat;
import java.text.DecimalFormat;

import org.jfree.data.xy.TableXYDataset;
import org.jfree.data.time.TimeTableXYDataset;
import org.jfree.data.time.Year;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.NumberTickUnit;
import org.jfree.chart.renderer.xy.StackedXYBarRenderer;
import org.jfree.chart.labels.StandardXYToolTipGenerator;
import org.jfree.chart.labels.StandardXYItemLabelGenerator;
import org.jfree.chart.JFreeChart;
import org.jfree.ui.RectangleInsets;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.VerticalAlignment;

public class StackedXYBarChartApplet extends Applet {

    /**
     * Наполняет Set данными для построения графика
     * @return Данные для построения
     */
    private static TableXYDataset createDataset() {
        TimeTableXYDataset dataset = new TimeTableXYDataset();
        dataset.add(new Year(2002), 1000, "Blue");
        dataset.add(new Year(2003), 1100, "Blue");
        dataset.add(new Year(2002), 0, "Red");
        dataset.add(new Year(2003), 50, "Red");
        return dataset;
    }

    /**
     * Создаёт новый график по данным
     * @param dataset данные для построения
     * @return график
     */
    private static JFreeChart createChart(TableXYDataset dataset) {

        // OX
        DateAxis domainAxis = new DateAxis("Month");
        domainAxis.setPositiveArrowVisible(true);
        domainAxis.setUpperMargin(0.2);

        // OY
        NumberAxis rangeAxis = new NumberAxis("Tonnes");
        rangeAxis.setStandardTickUnits(NumberAxis.createStandardTickUnits());
        rangeAxis.setTickUnit(new NumberTickUnit(200));
        rangeAxis.setPositiveArrowVisible(true);

        // Render
        StackedXYBarRenderer renderer = new StackedXYBarRenderer(0.02);
        renderer.setDrawBarOutline(false);
        renderer.setSeriesPaint(0, Color.blue);
        renderer.setSeriesPaint(1, Color.red);
        renderer.setBaseToolTipGenerator(new StandardXYToolTipGenerator("{0} : {1} = {2} tonnes", new SimpleDateFormat("yyyy"), new DecimalFormat("#,##0")));
        renderer.setSeriesItemLabelGenerator(0, new StandardXYItemLabelGenerator());
        renderer.setSeriesItemLabelGenerator(1, new StandardXYItemLabelGenerator());
        renderer.setSeriesItemLabelsVisible(0, true);
        renderer.setSeriesItemLabelsVisible(1, true);
        renderer.setSeriesItemLabelFont(0, new Font("Serif", Font.BOLD, 10));
        renderer.setSeriesItemLabelFont(1, new Font("Serif", Font.BOLD, 10));

        // Plot
        XYPlot plot = new XYPlot(dataset, domainAxis, rangeAxis, renderer);
        plot.setBackgroundPaint(Color.white);
        plot.setDomainGridlinePaint(Color.white);
        plot.setRangeGridlinePaint(Color.white);
        plot.setAxisOffset(new RectangleInsets(0D, 0D, 10D, 10D));
        plot.setOutlinePaint(null);

        // Chart
        JFreeChart chart = new JFreeChart(plot);
        chart.setBackgroundPaint(Color.white);
        chart.getLegend().setPosition(RectangleEdge.RIGHT);
        chart.getLegend().setVerticalAlignment(VerticalAlignment.TOP);

        return chart;

    }

    /**
     * Вот тут вся фишка апплета
     * @param g Графика
     */
    public void paint(Graphics g){
        JFreeChart chart = createChart(createDataset());
        chart.draw((Graphics2D)g, getBounds());
    }
}
</code></pre>

<p>Итак смотрим что получилось в результате:</p>
<div style="text-align:center">

<APPLET CODEBASE="/content/source/StackedXYBarChart/" CODE="ua.kiev.mabp.StackedXYBarChartApplet" archive= "jfc.jar,jcommon-1.0.12.jar,jfreechart-1.0.9.jar" WIDTH="450" HEIGHT="450" ALT="Java не включена!"></APPLET>

</div>
]]></content:encoded>
			<wfw:commentRss>http://mabp.kiev.ua/2008/05/28/jfreechart-stackedxybarchart/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

