韜晦日記

韜晦日記

Rietveldよりもプログラミングメインになりつつある

Rietveld解析初心者による備忘録とつぶやき

空白を含むファイルパスを変数として扱う方法

年の瀬に年末エントリーを書こうと思っていたのに…。 それは明日にでもかこう。

exeファイルを実行したい。

どうも。久しぶりのVBAに関する記事です。
VBAで実行ファイルを実行したい際にはWshShellオブジェクトRunメソッドを使いますよね。
この時、実行したいファイルのパスを与えなければなりません。
しかし、ファイルパスに空白が含まれていると正しく実行できず、二重引用符で囲む必要があります。

例えば
C:\Program Files\FOGE.exe
を実行したいときは以下のように書きます。

Dim ShellObject As Object
Set ShellObject = CreateObject("WScript.Shell")
ShellObject.Run """C:\Program Files\FOGE.exe"""

このファイルパスをプログラム上に直接書き込まずに変数として取得して使用したい場合は少し工夫が必要です。

取得したいファイルパスがA1セルに入力されているとします。 するとファイルパスは以下のように取得しますね。

Dim filePath as String
filePath = Cells(1, 1) 'あるいはRange("A1")でもいいけど

そして取得したファイルパスに引用符を文字列として付けたいのですが、普通にダブルコーテーションで囲って文字列を結合しようとしても意味がありません。

Dim filePath as String
filePath = """ & Cells(1, 1)  & """

Debug.Print filePath
' " & Cells(1, 1)  & "
' 上のように出力されてしまう。

このような場合は文字コードを直接指定してあげるとよさそうです。

Dim filePath as String
filePath = Chr(34) & Cells(1, 1)  & Chr(34)

Debug.Print filePath
' "C:\Program Files\FOGE.exe"
' これでおっけー

複数の引数を渡して実行する方法

おまけ

実行ファイルFOGE.exeに加えて引数Arg1, Arg2を与えたいとします。 これらのファイルも空白含んでいるとして、次のようにするといいでしょう。

filePath = Chr(34) & Cells(1, 1) & Chr(34)
Arg1 = Chr(34) & Cells(2, 1) & Chr(34)
Arg2 = Chr(34) & Cells(3, 1) & Chr(34)

Dim ShellObject As Object
Set ShellObject = CreateObject("WScript.Shell")
ShellObject.Run filePath & " " & Arg1 & " " & Arg2

以上です。

MendeleyへのExportでブロックされる時の対処法

論文をScience DirectからMendeleyに直接ダウンロードする

Science DirectにはMendeleyに直接論文をダウンロードできる機能があります。 この辺の連携がしっかりしていないと、一度Science Directで論文をダウンロードしてからMendeleyのソフトを立ち上げてインポートする必要があります。

この面倒な作業が、Science Direct - Menedely間ではボタン一つで連携が取れるのです。 しかし、実際に使ってみるとアンチウイルスソフトにブロックされてしまいました。 Macでは有名なセキュリティソフトに「avast!」があると思いますが、こちらを利用しているとMendeleyにエクスポートする際にブロックされてしまします。

今回はその対処法を描いてみます。

対処方法

  1. アバストを開きます。

    f:id:tanisuke_str:20181227202509j:plain:w200
    アバストを開く

  2. 左にある設定タブをクリック
    シールド内にあるウェブシールドの設定をクリック

    f:id:tanisuke_str:20181227202541j:plain:w600
    ウェブシールドの設定画面を開く

  3. 除外するサーバーとしてプラスボタンをクリックして
    サーバー : https
    サービス : www.mendeley.com
    と指定する。

    f:id:tanisuke_str:20181227202651j:plain:w600
    サーバーを追加
    これで大丈夫です。
    ただ、仮にmendeley経由でウィルスが流入しても監視対象外となるので、その辺は自己責任です。
    以上。

Shellメモ

メモ用の走り書きだし正確性や可読性については勘弁してほしい。

$@, $*, "$@", "$*"の違い

引数に与えられる位置パラメータについて。

shell, bashなどではコマンドラインから実行する際に、引数は位置パラメータに設定される。
これを使って引数をプログラムに与えることが出来るののだ。また引数として(-oとか-hの様な)オプションを与えることも出来るようになる。
もっともオプションを使えるようにするためにはコマンドラインの入力を解析するためにプログラムは複雑になる。
こんな時はオプション解析コマンド getoptsを使えばかなり楽になるが、ここでは関係ないためこの辺にとどめておく。

閑話休題
この位置パラメータについて、具体的にかくとこんな感じだ。

コマンド 説明
$0 コマンドラインで実行されたファイルのファイルパスかコマンド
$1~$n コマンドラインで入力された引数を先頭から順番に格納してる
$# コマンドラインで入力された引数の総数を表す。
$@ コマンドラインで入力された引数の全てが格納される
$* $@と同じだが" "で囲んだ時の挙動が"$@"と違う

こんな感じだ、と言われてもピンとこないと思うので試してみる。
ここで実行するshellのファイルはtest.shとする。
また実行するtest.shはカレントディレクトリに配置されているものとする。
まずは与えられた引数がどのように格納されているかみる。

$0と$1 ~ $nについて

#!/bin/sh
echo $0
echo $1
echo $2
echo $3
echo $4

上記のtest.shを次のように実行すればこのように出力される。

$ sh test.sh aa bb cc
test.sh
aa
bb
cc

ここでshはshellを実行する宣言みたいなもの。
test.shは実行するファイル
aa bb ccが引数となる。
正しくはtest.shも引数である。多分
この時、コマンドラインに与えられた引数は3つのみなのに、echo $4としているため、出力の最後は空白行となっている。
このようにコードに書いた$nと引数が一致しなくてもプログラムはエラーを吐かないので注意が必要。

$10以上の時

また、$nの整数 nは基本的にはなんぼでもいけるが、$10以降は$10と分けて認識されてしまうため問題が生じる。
試しにやってみる。

#!/bin/sh
echo $10
echo ${10}
$ sh test.sh aa bb cc dd ee ff gg hh ii jj
aa0
jj

このように$10だと第一引数のaaと、$10の認識されなかった0が出力されてしまう。
この対策として${n}として{ }で囲うことで正しく出力されていることがわかる。

$@と$*について

この2つの挙動は同じである。
試しにやってみる。

#!/bin/sh
echo "\$@ -> $@"
echo "\$* -> $*"

これはこの様な結果になる。

$ sh test.sh aa bb cc dd ee ff gg hh ii jj
$@ -> aa bb cc dd ee ff gg hh ii jj
$* -> aa bb cc dd ee ff gg hh ii jj

同じですね。 もっと言えば、引数全てがスペース区切りで繋げられた状態で返されると認識しているといいかもしれない。

"$@"と"$*"について

試しにやってみる。

#!/bin/sh
echo "\$@ -> "$@""
echo "\$* -> "$@""

これはこの様な結果になる。

$ sh test.sh aa bb cc dd ee ff gg hh ii jj
$@ -> aa bb cc dd ee ff gg hh ii jj
$* -> aa bb cc dd ee ff gg hh ii jj

$@$*の時と同じ様に見える。
ここで$#setを使って引数の挙動を観察してみる。

#!/bin/sh
set -- "$@"
echo "$@"
echo $#

set -- "$*"
echo "$*"
echo $#
$ sh test.sh aa bb cc dd ee ff gg hh ii jj
aa bb cc dd ee ff gg hh ii jj
10
aa bb cc dd ee ff gg hh ii jj
1

$@の場合、setを通っても引数の数は10のまま変わない。
これに対して$*の場合は全て一つの引数としてまとめられたことがわかる。

したがって、この二つは引数全体を一つのパラメータとして扱う場合と引数を個別のパラメータとして扱う場合に使い分けることが出来る。
単に引数をLogとして出力する場合なんかは"$*"を使えば良い。

また、補足になるが引数を" "で囲んだ場合は囲まれた中身が1つのパラメータとして認識される。

#!/bin/sh
echo $#
echo $@
$ sh test.sh aa bb "cc dd"
3
aa bb cc dd

$@と"$@"の違い

この2つの違いは引数を" "で囲んだ部分がある場合に" "内を1つの引数として認識するかどうかである。 試しにやってみる。

echo $#
set -- $@
echo "$@"
echo $#

set -- "$@"
echo "$@"
echo $#
$ sh test.sh aa bb "cc dd"
3
aa bb cc dd
4
aa bb cc dd
4

実行時は" "で囲まれた部分が1つの引数として認識されている。
しかし、$@setしなおすと" "が無視されて引数が3から4に増えたことがわかる。 したがってsetする場合やforで値を取り出す場合に注意が必要である。 試しにforで引数を取り出してみる。

echo \$@
for i in $@; do
  echo ${i}
done

echo ""
echo "\$@"
for i in "$@"; do
  echo ${i}
done

echo ""
echo "\$*"
for i in "$*"; do
  echo ${i}
done
$sh test.sh aa bb "cc dd"

$@
aa
bb
cc
dd

"$@"
aa
bb
cc dd

"$*"
aa bb cc dd

ExchangeCharCo

この様に、$@の場合は" "を無視されていることがわかる。
また、"$*"では引数が1つにまとめられている事もわかる。

位置パラメータの再設定

プログラム内で位置パラメータを再設定することはできない。 例えば以下の様に再設定しようとしてもエラーが吐かれて終わる。

#!/bin/sh
$1=jj

位置パラメータを変更したい場合にはsetを用いる。

#!/bin/sh
echo $1 $2
set kk ll
echo $1 $2
$ sh test.sh aa bb
aa bb
kk ll

バラ星雲とコーン星雲

f:id:tanisuke_str:20181210130320j:plain
バラ星雲とコーン星雲

Photoshopを導入後初の天体写真

先日、僕もついにPhotoshopを導入する運びとなりました。
運びとなりました。と仰々しく書いていますが、ただ年間1万円近くの利用料金を払ってPhotoshopをインストールしただけですけどね。
それにしても、買い切り型よりもサブスクリプション型の方がなんとなく購入するまで構えてしまいがちです。

さて、Photoshopを導入したのはいいものの、ここ最近観測に行けていません。
不憫に思ったのか、Photoshop練習用にと師匠が撮影データを送ってきてくれました。
対称星はバラ星雲とコーン星雲です。また、見難いですがカタツムリ星雲も写っています。

色々と書きたいこともありますが、あまり時間がないので今日は成果報告として画像を上げるだけにします。
なんの面白みもない記事ですみません。
Photoshopでの画像処理法についてはまたいつかあげようと思います。

Mixhostのサーバー障害で記事が消えた時の対処法

事の発端

先日からレンタルサーバーのMixhostにてサーバー障害が発生していたようです。

Mixhostのサーバーは復旧したようですが、サーバーのデータが1週間前に巻き戻しされブログなどの記事も消されてしまったようです。
これによって今朝からTwitterではプチ騒動になっている模様。

僕自身、このサーバーを使っていないのであまり詳しくは把握していませんが、これの対処法について書きたいと思います。

問題と対処法

  • 問題
    Mixhostデータベースのデータが1週間程度前の状態に戻された。
    その結果、12月1日から12月9日までのブログ記事等は消滅。

  • 対処法
    サーバーから記事が消えてしまっても、Googleによってクロールされていればキャッシュが作成されているはず。 このキャッシュデータにアクセスして削除された記事を復旧する。 support.google.com

以上となります。

具体的な方法

※ 僕はMixhostを使っていないので画像などははてなブログになっています。

  1. まず自分のWebサイトをGoogleで検索します。

  2. 写真矢印の部分をクリックするとキャッシュと表示されるのでそこをクリック。

    f:id:tanisuke_str:20181210123836j:plain:w600
    矢印の部分をクリックすると「キャッシュ」と表示される

  3. すると削除以前のブログページを開くことができますので、削除された記事のタイトルをコピーしておきます。
    f:id:tanisuke_str:20181210124657j:plain:w600

  4. コピーしたブログタイトルをGoogleで再び検索します。
    2番と同様に検索結果からキャッシュページを表示します。

これで削除されたページが見れるようになるはずです。
記事が削除されても、キャッシュから復旧できればあとはコピペするなりして元に戻せるのではないかと思います。

Plotlyをオンラインで使う方法 | Plotly徹底解説

オンラインプロット

PlotlyではFreeアカウントを取得することでオンライン上で作成したグラフの編集、保存が可能になります。 オンラインプロットでは自分のアカウント上にグラフを保存するため、アカウント登録が必要です。
そしてグラフをプロットするにはAPIキーというのを取得する必要があります。非常に簡単に出来るので心配ありません。
Freeアカウントでは公開状態でグラフが保存されますが、年会費を支払うことでプライベート保存が可能になります。
詳細は次の料金プランについての説明を見てください。

APIキーの取得

オンライン上にプロットする為にはAPIキーを取得する必要があります。
APIキーはAPI Keyページから設定できるはずです。

f:id:tanisuke_str:20181110185434j:plain:w600
APIキーの表示画面
正しくリンクが飛ばない場合は、自分のアカウントからSettings > API Keysとクリックしてください。
初めてAPIを設定する方は API Keyの下にある部分のRegenerate Keyをクリックして保存します。
生成されたAPIキーは念のため人に見られない安全な場所に保存しておいてください。
一度登録してしまえばあとはあまり使うことはありません。

APIキーの登録

APIキーはPythonを使ってコマンドラインから設定できます。
あるいはAPIキー登録ようのpythonファイルを作成して実行してもいいかもしれません。

$ python
>>> import plotly
>>> plotly.tools.set_credentials_file(username='DemoAccount', api_key='lr1c37zw81')

usernameのDemoAccountapi_keyのlr1c37zw81を自分のものと置き換えます。 また、.credentialsファイルの設定からも行なえます。

  1. Finedrを開き > 移動 > フォルダへ移動(⬆︎⌘G)とメニューバーから選択。
  2. ~/.plotly/と入力
  3. .credentialsファイルを開き、usernameとapi_keyの部分に記入
  4. 保存して閉じる。

pythonAPIキーを登録した場合は、こちらのファイルが書き換えられているはずです。
APIキーに問題がありそうな場合はこちらのファイルを見直すか、新たにAPIキーを発行して登録し直すといいかもしれません。

オンラインプロットの公開範囲

プロットするデータが第三者などに閲覧されては困る場合、公開範囲に気を使わなければなりません。
Plotlyでは3つの公開範囲が用意されています。

種類 説明
Public 誰でもグラフを閲覧することが可能です。あなたのアカウントプロフィール上に、そして検索エンジンの結果にも表示されます。そしてPlotlyにログインすることなく閲覧が可能です。
Private あなただけがグラフを閲覧できます。この設定によってPlotlyのフィード上、あなたのアカウントプロフィール上、そして検索エンジンの検索結果に表示されなくなります。
このグラフを閲覧するにはあなたがPlotlyアカウントにログインする必要があります。また、他のPlotlyユーザーに対して個人的に公開も可能ですが、相手もログインする必要があります。
Secret 与えられたシークレットリンクを持つ人は誰でもグラフを見れます。WebページやIPython notebookに埋め込んだ場合も誰でも見ることができます。また閲覧にログインは不要です。しかしながらPrivateと同様に検索結果などには表示されません。

公開範囲を設定する場合はPython上で以下のように実行します。

import plotly
plotly.tools.set_config_file(world_readable=False, sharing='private')
#↓はデフォルトの設定
plotly.tools.set_config_file(world_readable=True, sharing='public')

また、公開範囲はプロット時に指定することもできます。
plot()のなかでsharing='private'と入力するだけです。

import plotly.plotly as py
import plotly.graph_objs as go

pass # プロットのための処理
# 系列データの設定
data = [trace0, trace1]

#グラフのプロット
# sharingで公開範囲の設定をする。
py.plot(data, filename = 'basic-line' \
  , auto_open=True, sharing='private')

オンラインプロットで描画

グラフのオンラインプロットにはplotly.plotlyの中のメソッドを用います。
公式ドキュメントではimport plotly.plotly as pyとして利用しています。
そしてオンラインプロットにはpy.plotpy.iplotの2つのメソッドが用意されています。
違いは以下のようになります。

  • py.plot : 任意のURLを返し、オプションで指定することでブラウザ上にグラフを表示します。
  • py.iplot : エディタ上に直接プロットすることができます。

どちらで実行してもPlotlyアカウント上に保存されます。

ということで、とりあえず考えなしに以下のコードを実行して見てください。

import plotly.plotly as py
import plotly.graph_objs as go

# 各系列のデータを設定
trace0 = go.Scatter(
x=[1, 2, 3, 4],
y=[10, 15, 13, 17]
)
trace1 = go.Scatter(
x=[1, 2, 3, 4],
y=[16, 5, 11, 9]
)
data = [trace0, trace1]

py.plot(data, filename = 'basic-line', auto_open=True)

自分のアカウントが開き、以下のようなグラフが表示されるかと思います。

因みに、py.plotメソッドではプロット時の設定をオプションで与えることができます。
上ではfilenameで保存するファイル名、auto_openでグラフの表示・非表示の設定を行なっています。
auto_openではTrueの時は自動的にブラウザを起動しグラフを表示しますが、Falseだとグラフを保存したURLを返してくれます。

,またAPIキーの設定などが済んでいないとエラーが生じるので注意してください。 エラーは以下のような内容で出るかと思います。

#APIキーが指定されていない時
Make sure that you're logged in as ユーザー名.
Need help? Please try searching Plotly's <a href='http://stackoverflow.com/questions/tagged/plotly'>Stack Over
flow channel</a>.

#APIキーとユーザー名が指定されていない時
Aw, snap! We didn't get a username with your request.
Don't have an account? https://plot.ly/api_signup
Questions? accounts@plot.ly

といった感じ今回は簡単な使い方説明に留めておきました。
Plotlyではかなり凝ったレイアウトにすることができるのでそちらも紹介していきます。
レイアウトの参考にはデモ記事を参照してください。
tanisukestr.hatenablog.com

Plotlyをオフラインで使う方法 | Plotly徹底解説

ここではオフラインで描画する方法について説明します。
オフラインモードでは以下の2つのやり方でグラフを描画できます。

  • ファイルを実行し、ブラウザ上に表示
  • エディタであるAtomやjupyterの画面上に表示

またオフラインでプロットする場合、Plotlyのアカウント取得やAPIキーの設定はする必要はありません。
しかし、のちにオンライン上でグラブ編集したり保存するためにはアカウントが必要になるので登録(無料)することをお勧めします。

ではやって行きます。

普通にプロットする

オフラインで描画するために以下の2つをインポートします。

# import plotly.plotly as py <- オンライン用
import plotly.offline as offline # <- オフライン用
import plotly.graph_objs as go

プロットする場合は

offline.plot(data, filename = 'basic-line', auto_open=True)

となります。以下のプログラムをコピペして実行してみてください。

# 以下の2つをインポート
import plotly.offline as offline
import plotly.graph_objs as go

trace0 = go.Scatter(
x=[1, 2, 3, 4],
y=[10, 15, 13, 17]
)
trace1 = go.Scatter(
x=[1, 2, 3, 4],
y=[16, 5, 11, 10]
)
data = [trace0, trace1]

# オフラインでプロット
offline.plot(data, filename = 'basic-line', auto_open=True)

ここで、offline.plotの引数にあるauto_openTrueとすると、作成したグラフを自動的にブラウザで表示してくれます。
auto_open=Falseとするとグラフは表示されず生成したファイルのパスを返します。
何れにしてもHTMLファイルが生成され、再度表示することが可能になります。
デフォルトの設定はTrueとなっています。

Atom, jupyter notebookで描画する

基本的には前節で説明したやり方と変わりありませんが、4点ほど違いがあります。

  • import文の後ろにoffline.init_notebook_mode()を追加
  • offline.plot()ではなくoffline.iplot()を使う
  • HTMLファイルは出力されない。
  • auto_openは使えない。(エディタ上で直接見るので当然ですね。)

その他は基本的に同じはずです。

offline.init_notebook_mode()について*1

これはデフォルトでoffline.init_notebook_mode(connected=False)となり、ブラウザに必要なライブラリ(plotly.js)を読み込みます。
常にオフラインで実行する場合はoffline.init_notebook_mode()とします。
しかし、この方法だとファイルにplotly.jsを直接読み込むことになるのでファイルサイズが数メガバイト増加します。

試しに以下のコードを使ってjupyter notebookのファイルサイズの変化をみてみます。

# 以下の2つをインポート
import plotly.offline as offline
import plotly.graph_objs as go

offline.init_notebook_mode(connected=False)

trace0 = go.Scatter(
x=[1, 2, 3, 4],
y=[10, 15, 13, 17]
)
trace1 = go.Scatter(
x=[1, 2, 3, 4],
y=[16, 5, 11, 10]
)
data = [trace0, trace1]

# オフラインでプロット
offline.iplot(data, filename = 'basic-line')

このコードでconnected=Falseconnected=Trueを切り替えると

  • Trueの時  : 5 KB
  • Falseの時 : 5.9 MB

と、ファイルサイズが増加することがわかります。 一時的にでもインターネットに接続できる場合や、ファイルサイズを小さくしたい場合にはTrueを選べば良いと思います。