[Java] 83 Swing 21 JEditorPaneハイパーリンク・クリック後のHTMLファイル作成 各tableの設定

HTMLの各tableにidを付けて色設定等を変えてみました。

同じ文字列(class=”dataframe”)をそれぞれ違う文字列(id=”tableA”他)に変えるには、このような野暮ったい方法しか思いつきませんでした。

pandasではtableの線が2重線なので1重線にして色を付けました。

<CSVファイルの読み込み以降>

try:
    df2 = pd.read_csv(racefile_path,encoding="shift_JIS")
except UnicodeDecodeError:
    df2 = pd.read_csv(racefile_path,encoding="UTF-8")

# df2を3つのtableに分割
dfA = df2[['1 日付','2 開催','3 レース','4 レース名','5 条件','6 コース','7 天候','8 馬場状態','9 発走時刻']]
dfB = df2[['着順','枠番','馬番','馬名','性齢','斤量','騎手','タイム','着差','通過','上り','単勝','人気','馬体重','調教師','馬主','賞金(万円)']]

dfB2 = dfB[:-3]
dfC = dfB[-2:]
print(dfC)

dfC2 = dfC[['着順','枠番']]
print(dfC2)

# dfAのデータ行のみ抽出
row_num = len(df2)-3
print(row_num)

# データ行以外の行番号をリスト化
row_list = [row for row in range(0,row_num + 3) if not row==row_num]
print(row_list)

dfA2 = dfA.drop(dfA.index[row_list])
dfA3 = dfA2.rename(columns={'1 日付': '日付','2 開催': '開催','3 レース': 'レース','4 レース名': 'レース名','5 条件': '条件','6 コース': 'コース','7 天候': '天候','8 馬場状態': '馬場状態','9 発走時刻': '発走時刻'})

dfB3 = dfB2.fillna('')
print(dfB3.dtypes)

try:
    dfB3['着順'] = pd.to_numeric(dfB3['着順'], downcast='signed')
except Exception as e:
    print(e)

dfB3['枠番'] = pd.to_numeric(dfB3['枠番'], downcast='signed')
dfB3['馬番'] = pd.to_numeric(dfB3['馬番'], downcast='signed')
dfB3['人気'] = pd.to_numeric(dfB3['人気'], downcast='signed')
print(dfB3.dtypes)

html_string = '''
<html>
    <head>
        <meta charset="UTF-8">
        <title>{raceID}</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <div class="container">
            {tableA}
            {tableB}
            {tableC}
        </div>
    </body>
</html>
'''

with open(html_file,'w') as f:
    f.write(html_string.format(tableA=dfA3.to_html(index=False),tableB=dfB3.to_html(index=False),tableC=dfC2.to_html(index=False,header=False),raceID=raceID))

with open(html_file,'r') as f:
    html = f.read()

htmlH = html.split('<table border="1" class="dataframe">')[0]
htmlA = html.split('<table border="1" class="dataframe">')[1]
htmlB = html.split('<table border="1" class="dataframe">')[2]
htmlC = html.split('<table border="1" class="dataframe">')[3]

htmlA2 = '<table id="tableA" border="1" style="border-collapse: collapse; border-color: #add8e6">' + htmlA
htmlB2 = '<table id="tableB" border="1" style="border-collapse: collapse; border-color: #ffb6c1">' + htmlB
htmlC2 = '<table id="tableC" border="1" style="border-collapse: collapse; border-color: #f0e68c">' + htmlC

html_new = htmlH + htmlA2 + htmlB2 + htmlC2

with open(html_file,'w') as f:
    f.write(html_new)
body {
    background-color: #f0f8ff;
}
th {
    text-align: center;
    }
.container {
    display: block;
}
#tableA{
    background-color: #ffffe0;
    margin: 15px 5px 15px 5px;
}
#tableB{
    background-color: #e0ffff;
    margin: 15px 5px 15px 5px;
}
#tableC{
    background-color: #7fffd4;
    margin: 15px 5px 15px 5px;
}

[Java] 82 Swing 20 JEditorPaneハイパーリンク・クリック後のHTMLファイル作成 table列のデータ型変更

もう一息のところまで出来ました。

データ型の変更でastype関数が効かないため、to_numeric関数を使いました。to_numeric関数の取り扱いはドキュメントを読まないと分かりませんでした。中級者向けでしょうか。

あとは2番目のtableのいくつかの列を右寄せにして一応完成になります。

各tableにIDを付けて2番目だけ書式設定する必要がありますが、少し工数が掛かりそうなので次回以降の記事で紹介します。

このアプリを作り上げてきて、ようやく実用に耐えるレベルに達したように思います。インターネット接続が従量制だった頃であれば、どれだけコストが浮いたことでしょう。

<CSVファイルの読み込み以降>

try:
    df2 = pd.read_csv(racefile_path,encoding="shift_JIS")
except UnicodeDecodeError:
    df2 = pd.read_csv(racefile_path,encoding="UTF-8")

# df2を複数のTableに分割
dfA = df2[['1 日付','2 開催','3 レース','4 レース名','5 条件','6 コース','7 天候','8 馬場状態','9 発走時刻']]
dfB = df2[['着順','枠番','馬番','馬名','性齢','斤量','騎手','タイム','着差','通過','上り','単勝','人気','馬体重','調教師','馬主','賞金(万円)']]

dfB2 = dfB[:-3]
dfC = dfB[-2:]
print(dfC)

dfC2 = dfC[['着順','枠番']]
print(dfC2)

# dfAのデータ行のみ抽出
row_num = len(df2)-3
print(row_num)

# データ行以外の行番号をリスト化
row_list = [row for row in range(0,row_num + 3) if not row==row_num]
print(row_list)

dfA2 = dfA.drop(dfA.index[row_list])
dfA3 = dfA2.rename(columns={'1 日付': '日付','2 開催': '開催','3 レース': 'レース','4 レース名': 'レース名','5 条件': '条件','6 コース': 'コース','7 天候': '天候','8 馬場状態': '馬場状態','9 発走時刻': '発走時刻'})

dfB3 = dfB2.fillna('')
print(dfB3.dtypes)

# 中(止)、除(外)、取(消)への対応
try:
    dfB3['着順'] = pd.to_numeric(dfB3['着順'], downcast='signed')
except Exception as e:
    print(e)

dfB3['枠番'] = pd.to_numeric(dfB3['枠番'], downcast='signed')
dfB3['馬番'] = pd.to_numeric(dfB3['馬番'], downcast='signed')
dfB3['人気'] = pd.to_numeric(dfB3['人気'], downcast='signed')
print(dfB3.dtypes)

html_string = '''
<html>
    <head>
        <meta charset="UTF-8">
        <title>{raceID}</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <div class="container">
            {tableA}
            {tableB}
            {tableC}
        </div>
    </body>
</html>.
'''

with open(html_file,'w') as f:
    f.write(html_string.format(tableA=dfA3.to_html(index=False),tableB=dfB3.to_html(index=False),tableC=dfC2.to_html(index=False,header=False),raceID=raceID))

[Java] 81 Swing 19 JEditorPaneハイパーリンク・クリック後のHTMLファイル作成 table分割

CSVファイル由来のTableを3つに分割し、縦に並べたHTMLファイルを作成しました。

大分見栄えが良くなりました。あともう少しです。

CSVデータを簡単にHTMLにしてくれるpandasは本当に頼りになるツールです。他のスクリプト言語でpandasに相当するものは存在するのでしょうか。

<CSVファイルの読み込み以降>

try:
    df2 = pd.read_csv(racefile_path,encoding="shift_JIS")
except UnicodeDecodeError:
    df2 = pd.read_csv(racefile_path,encoding="UTF-8")

# df2を複数のTableに分割
dfA = df2[['1 日付','2 開催','3 レース','4 レース名','5 条件','6 コース','7 天候','8 馬場状態','9 発走時刻']]
dfB_pre = df2[['着順','枠番','馬番','馬名','性齢','斤量','騎手','タイム','着差','通過','上り','単勝','人気','馬体重','調教師','馬主','賞金(万円)']]

dfB = dfB_pre[:-3]
dfC_pre = dfB_pre[-2:]
print(dfC_pre)

dfC = dfC_pre[['着順','枠番']]
print(dfC)

# dfAのデータ行のみ抽出
row_num = len(df2)-3
print(row_num)

# データ行以外の行番号をリスト化
row_list = [row for row in range(0,row_num + 3) if not row==row_num]
print(row_list)

dfA2 = dfA.drop(dfA.index[row_list])

html_string = '''
<html>
    <head>
        <meta charset="UTF-8">
        <title>{raceID}</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <div class="container">
            {tableA}
            {tableB}
            {tableC}
        </div>
    </body>
</html>.
'''

with open(html_file,'w') as f:
    f.write(html_string.format(tableA=dfA2.to_html(index=False),tableB=dfB.to_html(index=False),tableC=dfC.to_html(index=False,header=False),raceID=raceID))

[Java] 80 Swing 18 JEditorPaneハイパーリンク・クリック後のHTMLファイル作成 CSS他

Python外部プログラムによりCSVファイルを2つのtableに分割し、これらを縦に並べたHTMLファイルにしました。レイアウトはCSSファイルで設定しています。

ここからheaderの数字やNaNを削除、小数を整数化、列幅設定など体裁を整えていきます。

JavaScriptのElectronでCSSを少し学んだことがここで役に立ちました。

import glob,csv,re
import pandas as pd

paths = glob.glob('/*.csv')
paths2 = sorted(paths)
csvfile = paths2[-2]

df = pd.read_csv(csvfile,encoding='UTF-8')

race_count = len(df)
print("レース数 " + str(len(df)))

list_raceID = df['raceID'].tolist()

pathsB = glob.glob('/*.html')
pathsB2 = sorted(pathsB)
html_file = pathsB2[-1]

# ファイル名からレース番号を抽出
race_num = html_file.split(".")[0][-3:]
print(race_num)

raceID = list_raceID[int(race_num) -1]
print(raceID)

# racefileパスを作成する
year = raceID[1:5]
course = raceID[5:7]
kai =  raceID[7:9]
racefile = "race" + raceID[1:] + ".csv"
racefile_path = f"/race/{year}/{course}/{kai}/{racefile}"

try:
    df2 = pd.read_csv(racefile_path,encoding="shift_JIS")
except UnicodeDecodeError:
    df2 = pd.read_csv(racefile_path,encoding="UTF-8")

# df2を2つに分割
dfA = df2[['1 日付','2 開催','3 レース','4 レース名','5 条件','6 コース','7 天候','8 馬場状態','9 発走時刻']]
dfB = df2[['着順','枠番','馬番','馬名','性齢','斤量','騎手','タイム','着差','タイム指数','通過','上り','単勝','人気','馬体重','調教タイム','厩舎コメント','備考','調教師','馬主','賞金(万円)']]

# dfAのデータ行番号を算出
row_num = len(df2)-3
print(row_num)

# データ行以外の行番号をリスト化
row_list = [row for row in range(0,row_num + 3) if not row==row_num]
print(row_list)

# データ行以外を削除
dfA2 = dfA.drop(dfA.index[row_list])

html_string = '''
<html>
    <head>
        <meta charset="UTF-8">
        <title>{raceID}</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <div class="container">
            {tableA}
            {tableB}
        </div>
    </body>
</html>.
'''

with open(html_file,'w') as f:
    f.write(html_string.format(tableA=dfA2.to_html(index=False),tableB=dfB.to_html(index=False),raceID=raceID))
body {
    background-color: #f0f8ff;
}
table {
    margin: 30px 10px 30px 10px;
}
.container {
    display: block;
}
.dataframe{
    background-color: #fffacd;
}

[Java] 79 Swing 17 JEditorPaneハイパーリンク・クリック後のHTMLファイル作成 Python外部プログラム

前回の続きです。

Java-Swingアプリにて選択したレース結果のHTMLファイルを作成するPythonコードです。作成されたHTMLファイルは前回記事にあるMainクラスによりブラウザに表示されます。

このコードではCSVファイルの全内容がtableになるため、適宜加工が必要になります。tableを分割するなどして整形してから、cssファイルで徐々に見栄えを良くしていくつもりです。

import glob
import pandas as pd

paths = glob.glob('/*.csv')
paths2 = sorted(paths)
csvfile = paths2[-2]

df = pd.read_csv(csvfile,encoding='UTF-8')

race_count = len(df)
print("レース数 " + str(len(df)))

list_raceID = df['raceID'].tolist()

pathsB = glob.glob('/race/*.html')
pathsB2 = sorted(pathsB)
html_file = pathsB2[-1]

# 空ファイル名からレース番号を抽出(Javaとの連携箇所)
race_num = html_file.split(".")[0][-3:]
print(race_num)

raceID = list_raceID[int(race_num) -1]
print(raceID)

# racefileパスを作成する
year = raceID[1:5]
course = raceID[5:7]
kai =  raceID[7:9]
racefile = "race" + raceID[1:] + ".csv"
racefile_path = f"/race/{year}/{course}/{kai}/{racefile}"

print(f"year {year}")
print(f"course {course}")
print(f"kai {kai}")
print(f"racefile {racefile}")
print(f"racefile_path {racefile_path}")

df2 = pd.read_csv(racefile_path,encoding="shift_JIS")

html_string = '''
<html>
    <head><meta charset="UTF-8">
    <title>TEST</title>
    </head>
    <body>
        {table}
    </body>
</html>.
'''

with open(html_file,'w') as f:
    f.write(html_string.format(table=df2.to_html(index=False)))

[Java] 78 Swing 16 JEditorPaneハイパーリンク・クリック後のHTMLファイル作成 Mainクラス

[Java] 75 Swing 15の続きです。

Mainクラスから外部プログラムを実行してレース結果HTMLファイルを作成します。

今回はMain.javaの内容を載せます。自製のProcessExecutor.exec()メソッドでコンソールからPythonコードを実行します。

    // PAGE_CENTER設定
		editorPane = new JEditorPane();
		contentPane.add(editorPane, BorderLayout.CENTER);
		editorPane.setContentType("text/html");
		editorPane.setEditable(false);
		editorPane.setBackground(new Color(0xf0f8ff));
		editorPane.addHyperlinkListener(new HyperlinkListener() {
            @Override
            public void hyperlinkUpdate(HyperlinkEvent e) {
		        if (HyperlinkEvent.EventType.ACTIVATED.equals(e.getEventType())) {
		        	String race_html_pre = e.getURL().toString();
		        	System.out.println("race_html " + race_html_pre);

		        	String race_html = race_html_pre.substring(5);
		        	StringBuilder HTMLcode = new StringBuilder();
		        	HTMLcode.append("<table>" + "</table>");

		        	// /raceディレクトリのインスタンスを作成する
		        	File dir = new File("/race/");

		            // listFilesメソッドを使用して一覧を取得する
		            File[] list = dir.listFiles();

		            // 一覧のファイルを全て削除する
		            for(int i=0; i<list.length; i++) {
		            	File file = new File(list[i].toString());
						      file.delete();
		            }

		        	// 空HTMLファイルの作成
		            try{
		                File file = new File(race_html);
		                FileWriter filewriter = new FileWriter(file);
		                filewriter.write(HTMLcode.toString());
		                filewriter.close();}
		            catch(IOException e0){
		                System.out.println(e0);
		            }

		            // クリックしたレースのHTMLファイルを作成して上書きする(外部プログラム)
		            String type = "race";
		            try {
		                ProcessExecutor.exec(type);
					 } catch (Exception e1) {
		                e1.printStackTrace();
			        }

		            Desktop desktop = Desktop.getDesktop();
		            try {
		                desktop.browse(e.getURL().toURI());
		            } catch (IOException e2) {
		                e2.printStackTrace();
		            } catch (URISyntaxException e2) {
		                e2.printStackTrace();
		            }
		        }
		    }
        });

[Java] 77 ディレクトリ内ファイルを全て削除する

メモ書きしておきます。

// 対象ディレクトリのインスタンスを作成する
File dir = new File("対象ディレクトリのパス");

// listFilesメソッドでファイル一覧を取得する
File[] list = dir.listFiles();

// ファイルを全て削除する
for(int i=0; i<list.length; i++) {
    File file = new File(list[i].toString());
    file.delete();
}

[Java] 76 カタカナをローマ字に変換 ICU4J

[macOS catalina 10.15.7]

DesktopクラスでHTMLファイルを読み込む際、ファイル名に日本語が含まれているとエラーになります(macOS起因の可能性あり)。その場合はファイル名をエンコードするか、日本語をローマ字に変換して対処します。

調べていたらICU4Jという変換ツールを見つけたのでGitHubからjarファイルをダウンロードして試してみました。C言語版もあります。ICUはInternational Components for Unicodeの略で、このプロジェクトにはMicrosoftの社員が関わっているようです。

注意点としては、長音が含まれるとマクロンという横棒付きになりHTML読み取り時にエラーになります。一旦平仮名に変換してからローマ字に変換すると ā→aa となってうまくいきました。

日本語をエンコードすると意味が分からなくなるので躊躇していましたが、このツールでローマ字化して解決しました。今後も重宝しそうです。

import com.ibm.icu.text.Transliterator;

<中略>

Transliterator transliterator = Transliterator.getInstance("Katakana-Latin");
String name_latin = transliterator.transliterate(name);
System.out.println("競走馬名直接ローマ字 " + name_latin);

Transliterator transliterator2 = Transliterator.getInstance("Katakana-Hiragana");
String name_hira = transliterator2.transliterate(name);
System.out.println("競走馬名ひらがな " + name_hira);

Transliterator transliterator3 = Transliterator.getInstance("Hiragana-Latin");
String name_latin2 = transliterator3.transliterate(name_hira);
System.out.println("競走馬名ローマ字 " + name_latin2);
--------------------------------------------------

出力
--------------------------------------------------
競走馬名直接ローマ字 shafuriyāru
競走馬名ひらがな しゃふりやある
競走馬名ローマ字 shafuriyaaru

[Java] 75 Swing 15 JEditorPaneハイパーリンク・クリック後の動作

EditorPaneのハイパーリンク・クリック後の動作についてコードを追記しました。

リンク先のHTMLファイルは、JavaのクラスあるいはPythonの外部プログラムで作成します。

外部プログラムを使う場合、HTMLファイルのパスを渡すすべがないので、空のHTMLファイルを作成した後、Pythonのglobメソッドとsorted関数でファイルを見つけ出し加工します。

    // PAGE_CENTER設定
		editorPane = new JEditorPane();
		contentPane.add(editorPane, BorderLayout.CENTER);
		editorPane.setContentType("text/html");
		editorPane.setEditable(false);
		editorPane.setBackground(new Color(0xf0f8ff));
		editorPane.addHyperlinkListener(new HyperlinkListener() {
            @Override
            public void hyperlinkUpdate(HyperlinkEvent e) {
		        if (HyperlinkEvent.EventType.ACTIVATED.equals(e.getEventType())) {
		        	String race_html_pre = e.getURL().toString();
		        	System.out.println("race_html_pre " + race_html_pre);
              
                  // HTMLファイルパスの"file:"を削除
		        	String race_html = race_html_pre.substring(5);
		        	StringBuilder HTMLcode = new StringBuilder();
		        	HTMLcode.append("<table>" + "</table>");
		        	
		        	// 空HTMLファイルの作成
		            try{
		                File file = new File(race_html);
		                FileWriter filewriter = new FileWriter(file);
		                filewriter.write(HTMLcode.toString());
		                filewriter.close();}
		            catch(IOException e0){
		                System.out.println(e0);
		            }

               // ここでリンク先のHTMLファイルを作成する

		            Desktop desktop = Desktop.getDesktop();
		            try {
		                desktop.browse(e.getURL().toURI());
		            } catch (IOException e1) {
		                e1.printStackTrace();
		            } catch (URISyntaxException e1) {
		                e1.printStackTrace();
		            }
		        }
		    }
        });

[Java] 74 Swing 14 JEditorPaneのハイパーリンクHTML作成

前回の続きです。

早速ハイパーリンク付きのHTMLファイルを作成するコードを書きました。

実際はリンク先のHTMLファイルはまだ作られておらず、リンクをクリックすると同時にSQL検索(あるいはSQL登録前の元ファイル検索)してレースHTMLをPythonにて作成します。

出走レース番号を付番するためにJRAの最大出走回数記録を調べたところ、1986年以降生まれではハートランドヒリュの127戦でした。したがってゼロ埋めは3桁に設定しています。

        // ベタ書きHTMLの文字列インスタンスを作成
        StringBuilder HTMLcode = new StringBuilder();

        // 現在日時の文字列インスタンスを作成
        Date dateObj = new Date();
        SimpleDateFormat format = new SimpleDateFormat( "yyMMddHHmmss" );
        String now = format.format( dateObj );

        // 競走馬名を取得
        String name = nameAndID4.get(0);
        System.out.println("競走馬名 " + name);

        Integer count = 0;
        HTMLcode.append("<table" + " " + "border='1'" + " " + "class='dataframe'>" + "<thead><tr>");
        for (ArrayList<String> raceList: raceListConSorts){
            if (count == 0){
                for (int i = 0 ; i < raceList.size() ; i++){
                    HTMLcode.append("<th>" + raceList.get(i) + "</th>");}
                HTMLcode.append("</tr></thead><tbody>");
                HTMLcode.append("<tr>");
                count = count + 1;}

            else{
                for (int i = 0 ; i < raceList.size() ; i++){
                	if (i == 4) {
                		String race_html = String.format("/%s_%s_%03d.html",now,name,count);
                		HTMLcode.append("<td>");
                		HTMLcode.append("<a href='" + race_html + "'>" + raceList.get(i) + "</a>");
                		HTMLcode.append("</td>");
                	}
                	else {
                    HTMLcode.append("<td>" + raceList.get(i) + "</td>");
                    }
                }
                HTMLcode.append("</tr>");
                count++;
            }
        }
        HTMLcode.append("</tbody></table>");

        // HTMLファイル名を作成
        String filename = String.format("/%s_%s.html",now,name);

        // HTMLファイルの作成
        try{
            File file = new File(filename);
            FileWriter filewriter = new FileWriter(file);
            filewriter.write(HTMLcode.toString());
            filewriter.close();}
        catch(IOException e){
            System.out.println(e);
        }