アップルスクリプト:半年後の月末

全然使い道が思いつかないんだけど、半年後の月の月末はアップルスクリプトでどうするのか、気になってしまった。weeks、days という便利な関数があるのに months は無いんだよなあ。


set myDate to (current date)
set newDate to myDate + (1 * days) –date “2016年6月25日土曜日 14:42:29”
set newDate to myDate + (1 * weeks) –date “2016年7月1日金曜日 14:43:13”
set newDate to myDate + (1 * hours) –date “2016年6月24日金曜日 15:43:56”
set newDate to myDate + (20 * minutes) –date “2016年6月24日金曜日 15:05:04”


months を数字にして数を足していくと、年末を超えるような場合でも年数がうまく繰り上がってくれない。うまい方法があるのかもしれないけど、見つけられなかった。ぼくはナンバーズを使うことが多いので、ナンバーズの関数を使うのが普通だろうけど。あえてアップルスクリプトで考えてみた。ボケ防止、出来上がりは、初心者ですからね、ご容赦を。

たとえば、下のようにある列の日付のフォーマットを指定しておく。

名称未設定_2.jpg

 

セルA2に適当な日付を入れる。半年後の月末の日付を求めたい。

名称未設定_2.jpg


tell application “Numbers”
— 「”」が標準のコードと違ってペーストされている
activate
tell table 1 of sheet 1 of document 1
set myDate to the value of cell “A2”
— 「”」をつかわなければ “A2” のかわりに cell 1 of row 2
set myMonth to month of myDate
set myMonth to myMonth * 1 + 7 — 7 は7ヶ月後、「* 1」はこの場合なくてもいい
set newYear to (year of myDate) + myMonth div 12
set newMonth to myMonth mod 12
set day of myDate to 1 — ここでは関係無いけど、128以上で破綻
set year of myDate to newYear
set month of myDate to newMonth
set myDate to myDate – (1 * days)
set the value of cell “A3” to myDate
— 「”」がスクリプトエディターでは打ち直さないとエラーになる
end tell
end tell


だいぶ長くなってしまうけど、もっといい方法があるのかもしれない。

名称未設定_2.jpg

あ、もっと先の日付を試せば、ちゃんと年も繰り上がる。

set day of … to 127  vs  128。127まではちゃんと年も繰り上がるのに。0、-1 も受け付けてくれない


set myDate to date “2016年10月10日月曜日 0:00:00”
set day of myDate to 127
myDate –date “2017年2月4日土曜日 0:00:00”

set myDate to date “2016年10月10日月曜日 0:00:00”
set day of myDate to 128
myDate –date “2016年5月25日水曜日 0:00:00”


 

ついでにこれくらいアップルスクリプト

ペーストするだけだと、不十分な時があるので、プチ整形が必要になることがある。下の図でワーファリンの投与量は漸減しているのではなく、右の表の1行目の日付で減量、2行目の日付でさらに減量していることになるので、左側の下のグラフは階段状になってくれると嬉しい。

pre

表の方で、減量した日付をその下に行を新しく加えて複製、PT-INRも複製、ワーファリンは新しい投与量を下の行よりコピーペーストすると

post

このようになって、より実情を反映する。

アップルスクリプト初心者は考えた。表data でワーファリンの量を最初の行からチェックしていき、次の行のワーファリンの量と異なっていれば、新しい行を下に作る。そこに日付、検査値は古いものを複製、薬の量はより新しい日付のものを下の行より複製する。日付は「次の日」にするのが本当かもしれない。でも、グラフにすると、差は分からないくらいだ。薬の量が空白になったら終了。


tell application “Numbers”
activate
try
tell table 1 of sheet 1 of document 1

repeat with i from 2 to 49 — 49 は適当に大きめに選んだ数字。
set nowDataC to the value of cell 3 of row i
set nextDataC to the value of cell 3 of row (i + 1)

if nextDataC is equal to missing value then exit repeat

if nowDataC ≠ nextDataC then
set nowDataA to the value of cell 1 of row i
set nowDataB to the value of cell 2 of row i

add row below row i

set value of cell 1 of row (i + 1) to nowDataA
set value of cell 2 of row (i + 1) to nowDataB
set value of cell 3 of row (i + 1) to nextDataC

set nowDataC to nextDataC

end if
end repeat
end tell
end try
end tell


今回は repeat の勉強と、何も入っていないセルの値は missing value で “” でも null でもないということを学んだ。あたりまえだけど row も index で指定できるのになかなか気付かず苦労した。

ここでは無視したけど、1日後の日付を計算するのがなかなかわからなかった。


tell application “Numbers”
activate
tell table 1 of sheet 1 of document 1
set oldDate to the value of cell “A2”
set newDate to oldDate + (1 * days)
set value of cell “A3” to newDate
end tell
end tell


セル A2 に入っている日付の1日後をセル A3 へ入れる。days、weeks はできるけど、months、years という関数?は無いみたいだ。300日後も、年、月が連動して計算される。興味深いことに、Numbers の側で指定した日付のフォーマットがそのまま利用できる。month が June とかでなく、数字で指定してあれば、そのまま数字が採用される。

 

これだけアップルスクリプト:ファイルメーカーからナンバーズ

ファイルメーカーのデータをナンバーズで処理できたらいいなあとずっと思っていた。アップルスクリプトを使えればなんとかなるのかなとは思っていたけど、難しそうで調べていなかった。ところが意外と簡単にできることが分かった。ファイルメーカーのグラフは思ったようにデザインできないからね。あ、ボクが知らないだけかも。

ファイルメーカーのデータをクリップボードにコピーしておく。データは tab で区切られ、レコードは return で区切られていて、手動ではナンバーズのあるセルにペーストすると、レコードが行ごとにペーストされる類のものだ。クリップボードにコピーするのはファイルメーカーのスクリプトでできるし、アップルスクリプトを組み込めるようにもなっている。ボクはアップルスクリプト、初心者だから間違っているかもしれないけど、一応無事に動いているので、結果オーライだろう。

データをテンプレートで作ってあるファイルの、決まったセルにコビーするなら、下のスクリプトでできた。document、sheet、table の名前は自分の作ったテンプレートで違ってくるかもしれない。


tell application “Numbers”
activate

— create a default document, styled with a template
make new document with properties ¬
{document template:template “テンプレートの名前”}

tell front document to tell sheet 1 to tell table 1
set selection range to cell “ペーストしたい起点となるセル。例:A1”
end tell

tell application “System Events” to keystroke “v” using ¬
{command down, shift down, option down}

end tell


今まで手動でやっていたこれだけを自動でやってくれるのを見るだけで感激だけど、名前と年齢もついでに入力してもらいたくなる。上のデータと一緒にペーストしても良かったけど、もう一度ファイルメーカーのスクリプトに戻り、名前と年齢を return で区切って一つのフィールドに入れて、このフィールドををクリップボードにコピーしてから、下のアップルスクリプトを実行してもらった。return で区切られたデータは paragraph で順番を指定して取り出せる。


tell application “Numbers”
activate
tell front document to tell sheet 1 to tell table 1

set value of cell “ペーストしたいセル。例:A1” to paragraph 1 of (the clipboard)
set value of cell “ペーストしたいセル。例:C1” to paragraph 2 of (the clipboard)

end tell
end tell


かなり手際よくデータが視覚化出来て気持ちが良い。ファイルメーカーをナンバーズと組み合わせるとかなりグレードアップした感じがする。

クリップボードはよく分からない。paragraph 1 of とか付けると、() をつけてなかったり、the が無かったりするとうまく実行できない。文法的に何かあるんだろうね。


set value of cell “A1” to the clipboard


というのはうまくいくんだなあ。いろいろ分からないことがあるけれど、最低限のことはできそうだ。

 

TTRレポート:アップルスクリプトの練習

この前、TTR の計算方法について書いて、役に立たないだろうと思ったけど、レポートをファイルメーカーから Numbers にわたして、簡単に作れる。AppleScript の練習でやってみると面白い。もっと早くAppleScript やってればよかったなあ。

ファイルメーカーのデータをクリップボードにコピーするようにスクリプトを組んで、AppleScript で Numbers にわたしてもらう。ファイルメーカーのグラフはちょっと傾向を確認するくらいはいいけど、なかなか思うようなスタイルにできない。最新バージョンもそんなに変わっていないみたいだ。よく見てないけど。

名称未設定

このままだとワーファリンのグラフが不自然だ。これも AppleScript で整形できるんだねえ。血圧のデータなんかは、単純だから、もっと簡単にできるだろう。MONTH 関数を使えば、季節による変動なんかも簡単にグラフにできる。これは Numbers の方に備わっている関数だけど。

名称未設定_2

相手に渡すのは右側のテーブルを二つ除いた部分にすればいい。グラフの Y 軸をすこしマニュアルで指定しなければいけないことがあるかもしれないが、自動的に出来上がるのを見てるとおもしろい。AppleScript ってすごい。私の作った AppleScript をのせても、同じことを考えている人はいないだろうから、無駄だろうな。AppleScript に関連するサイトってものすごくたくさんあって、素晴らしいものが多い。自分のやろうと思うことをそういうサイトを参考にする方が何倍もいいだろう。

filemaker のデータを numbers へ

filemaker のデータを numbers へ渡すのに、ボタンひとつのクリックでできないかなあと思っていた。AppleScript が使えればできそうだけど、良くわからなかった。YouTube の macmost というビデオが参考になった。

あ、numbers できるんだ。だけど、簡単なことしかわからない。このビデオから、numbers での AppleScript を詳しく解説したサイトが紹介されていた。まだ全部読んでないので、どれくらいのことまでできるのかは分からないけど、AppleScript に対するアレルギーがなくなりそうだ。

とりあえず僕のやりたいことは、ファイルメーカー側の tab で区切られたデータを clipboard にコピーしておいて、numbers でテンプレートから新しいファイルを作り、決まったテーブルの決まったセルに clipiboard の内容をペーストする、っていうことだ。

参考になったサイトがあといくつか。

  1. Apple Support Communities
  2. ArcAcid
  3. AppleScript: Beginner’s Tutorial

ファイルメーカーのスクリプトに AppleScript を記述して、上記のことができるところまでは行き着けた。ファイルメーカーのデータを clipboard にコピーした状態で、numbers のテンプレートのファイルの名前と、目的のシート、テーブル、セル(例では A2)を指定するようにして… うまくいったみたい。まだ、一つ一つの意味を理解しているとは言えないけど。


tell application “Numbers”
activate
try

set thisTemplateName to “テンプレートのファイルの名前”

make new document with properties ¬
{document template:template thisTemplateName“テンプレートのファイルの名前”}

tell front document to tell sheet 1 to tell table 1
set selection range to cell “A2”
end tell

tell application “System Events” to keystroke “v” using ¬
{command down, shift down, option down}

end try
end tell


System Events は version 12 だとエラーになってしまう。(あれ、12でもできるぞ。 AppleScript の処理に差があるなんて変だもんね、)15 の試用版だとうまくいく。日曜大工みたいにファイルメーカーを使っている分には、12 で十分だったんだけどなぁ。14 が安くなっているかと探してみたけど、15 と変わらないくらいだ。一か所、7,000 円で売っているサイトが有ったけど、思いっきり怪しい。購入したという経験を書いた記事が一個、見つかったけど、こっちも負けずに怪しい。もう少しマシなサイトも有ったけど、こちらはファイルメーカーを扱っていなかった。

numbers : 数える

gacco の問題で、ヒストグラムを作るのかと思ってしまったが、条件によって数を数える、という問題でちょっと混乱してしまった。

A/Bテストの設計に従い、会員データから想定ターゲット世帯を無作為に600サンプル抽出し、AとBに300サンプルずつ割り付けて調査を実施しました。

購入意向は、購入したい(5点)/やや購入したい(4点)/どちらともいえない(3点)/やや購入したくない(2点)/購入したくない(1点)の5段階で意向調査を実施し、スコア化したものとする。

簡単にするとサンプルはこんな具合になる。

1.jpg

ここで問題には必要なかったが、ヒストグラムを作るにはどうしようかと思ったけど、「A」「B」別にして列にしないと、index と frequency では無理かもしれない。「購入意向」が数字になっているが、もともとは「購入したい」などに置き換えられる、なんて言ったっけ、名義変数だっけ、そういう風にも取れるデータで連続変数とはちょっと趣が違う。でも、まあこういう数量の変数があるかもしれない。

条件付きで個数を数える関数があるので、これを下のように使えば数えられる。

2.jpg

購入意向が連続した量だったらどうしよう。この例では必要ないけど、下のような条件を加えてやればいいみたいだ。最後の『+1』が区間の幅になる。

6.jpg

問題には「A」と「B」の「購入意向」の平均値を求めさせるものがあったけど、こちらは averageif(s) 関数だ。

5.jpg

はじめの方の問題では割合も計算しなくては答えられないものもあった。

4.jpg

numbers には、エクセルのような、誘導してくれるようなものは少ないが、gacco の問題に出るような基本的なことには、簡単に対応できそうな実力は備わっている。gacco の講座のビデオで見ている限りでしか言えないけど、エクセルより UI は洗練されているような気がする。

 

numbers : クロス集計表

今週の gacco の問題で、クロス集計に関するものが有った。

教養娯楽費について、「住居の所有関係」を表側(行)、「就業・非就業の別」を表頭(列)、としたクロス集計を行い、世帯当たりの1か月の平均値を算出しました。「持ち家」の「就業」の教養娯楽費の集計値として正しいものを、次の(1)~(4)のうちから一つ選びなさい。

下のようなデータ。

dummydata_A_csv-2.jpg

クロス集計表は、エクセルでは設定に答えれば作れて行けて便利そうに見える。集計表を作るのを別にして、設問の「世帯当たりの1か月の、「持ち家」の「就業」の教養娯楽費の平均値を算出」するだけなら numbers は簡単だ。

前のバージョンまでは categorize という機能があったけど、新しいバージョンでは探しても見つからない。それはそれで、まず「住居」の列を選んで「⋁」マークをクリックしていって「持ち家」でフィルターをかける。

dummydata_A_csv-2.jpg

次に同じようにして「就業」の列から「就業」でフィルターをかける。この状態で「教養娯楽費」の T 列をクリックすれば、一番下に

dummydata_A_csv-2.jpg

合計、平均値、最大、最小、空白でない行の数が、即座に表示され、問題の答えは得られる。COUNTA にはヘッダ行も含まれているが、平均値の算出にはヘッダ行を除いた数で算出している。ちょっとややこしい。右の⚙マークから他の関数も表示できる。

クロス集計表を作るにはエクセルのようには出来ないけど、そんな機能はいらないのじゃないかな。問題に従ってヘッダ行を作る。ヘッダのタイトルはデータの表からコピーペーストするのが間違いがない。最初のセルに、平均値を求める関数を入れる。

Banners_and_Alerts_と_dummydata_A_csv-2_と_dummydata_A_csv-2.jpg

ここで関数の引数が指示されるので、

dummydata_A_csv-2_と_dummydata_A_csv-2.jpg

固定する列や行を考えて上のように決定。答えの数字のフォーマットを指定して、

dummydata_A_csv-2.jpg

行や列の合計、行パーセントを計算、表示させれば下のようになる。

dummydata_A_csv-2.jpg

クロス集計表をつくるのは、エクセルみたいな機能がなくても、手数は同じくらいしかかからないので、numbers では用意してないのだろう。変に複雑にならないから、こっちの方がいいかもしれない。

numbers : 数式を最後の行までコピーする : filling down a column without dragging over every cell

 

今週の gacco の課題に、100 行以上のデータが資料としてついていた。

dummydata_B_csv_numbers

背広服の支出に関して、後方12ヶ月の移動平均を求める問題だったので、背広服の列の前に、年月の列を複製(これは必須じゃない…というか、日付の間隔が一定なので、無用ですかね)、後方には移動平均を計算するための列を挿入した。

Untitled

計算式を V13 に入れる。さて、これを V 列の最後までいれたい。V13 のセルを最後の行までドラッグしてコピーすればいいんだけど、100 行もあるのでは、できないことはないけど、バカらしい。1000 行だったらどうすればいい。

dummydata_B_csv_numbers.jpg

下のように V13 のセルを ⌘ と c でなくてもいいけど、選択してコピーする。

Untitled

V をクリックして  V 列を選択する。

Untitled

選択した状態で、⌘と v でペーストする。⌘と v でなくて、メニューから選んでもいいけど。


追記:ヘッダが選ばれているので、以下の流れは当然と言えば当然。⌘キーを押しながら、V 列のヘッダをクリックすれば、データだけのセルが選ばれる。この状態にしておけば、以下のように、ヘッダに赤い三角が表示されることはない。

V13、V12 でもいいけど、 を選択して、⌘ と shift キーを押しながら ↓ 矢印をおせば、目的の範囲が正確に選択できる。


 

Untitled

そうすると、計算式が列の最後の行までコピーされる。上の方の赤い三角形のセルの範囲を選ぶのは簡単だから、選んで delete すれば出来上がり。この時、一つ注意しなければいけないのが、オリジナルのセルの一つ上も計算してしまっている。これはヘッダ行もデータが入っているとして、計算しているのだろう。この辺が残念。

Untitled

Untitled

さて、ヘッダ列の A 列と元になるデータの列と移動平均を計算した列を選んで折れ線グラフを選択して、

Untitled

Untitled

スタイルをすこしいじれば、

dummydata_B.jpg

こんなグラフであることがわかる。エクセルの移動平均を選んで作っていくのは、ややこしい気がする。numbers の方が、何をやっているのか考えながらやっているので、シンプルでいい。そんな難しい作業ではないから。

関数はドラッグしてペーストしないと、引数がうまく調整されないイメージを持っていたけど、単にペーストするだけで、引数もちゃんと機能してくれるんだ。…考えてみれば、つまらない。orz まあ、それに気がついただけでも収穫とするかな。