# Google Apps Script 勉強会資料
この資料は、2020年4月25日に中泉雄登によって作成された。
更新:2020年4月26日
更新:2020年4月29日
以下では、Google Apps ScriptをGAS(読み方がガス)とする。
## 0. GAS勉強会の概要
### 0.1 ゴール・やりたいこと
- 何かプロダクトを作りたい
- 日報管理ツール
- 目標管理ツール
- ビジネスの予行演習で使えるようにする
- データ収集
### 0.2 日程
- 日曜午前
<br>
## 1. GASの基礎知識
### 1.1 GASとは
- [Google](https://www.google.co.jp/)社が提供するプログラミング言語
- JavaScriptベースで作られている
- 全く一緒ということではなく、Webページを作成するなどはできない
### 1.2 GASの特徴
- Google Appsと連携できること
- 連携できるGoogle Apps
- Gmail
- Google Calender
- Google Hangout
- Google Document
- Google Spreadsheet
- Google Forms
- Google Slides
- Google Sites
- Google Map
- Google Language
- Google社のクラウドサーバーで動いている。メリットは以下の通り。
- 環境構築がいらない
- 定期実行が容易
### 1.3 GASに必要なもの
- Googleアカウント
- ブラウザ
- インターネットに接続できるPC
<br>
## 2. GASの使い方
### 2.1 GASの始め方
1. スプレッドシートを開く
2. スプレッドシートのメニューから、スクリプトエディタを選択する

3. エディタが起動する

<br>
### 2.2 プロジェクトとスクリプト
#### スクリプト
GASで記述されたプログラムのこと。上の画像を例にとると、コード.gsになる。
#### プロジェクト
プロジェクトとは、単一もしくは複数のスクリプトで構成されたもの。
##### スタンドアロンスクリプト
プロジェクト自体を直接Googleドライブに保存されたもの。
* 他の人に見つからないからいい。
##### コンテナバインドスクリプト
スプレッドシートなどに紐づく形で保存されたもの。**基本こちらを使うことになる(で多分問題ない)。**
<br>
### 2.3 ログ
GASにはスクリプトの動作を確認するために、ログという機能がある。ログ機能は、以下のように使う。
1. **```Logger.log(値);```を記入する**
今回はこのように記入してみる。
```javascript:log.gs
function myFunction() {
Logger.log("Hello world");
}
```
2. **スクリプトを保存する**
それっぽいボタンを押して保存する。(その際にプロジェクト名を要求される。今回は"GAS勉強会"にする。)

3. **スクリプトを実行する**
それっぽいボタンを押して実行する

4. **ログを確認する**
ログ自身は、エディタのメニューの[表示]->[ログ]から確認できる。


## 3. 基本構文
### 3.1 基本形
GASの基本形は、以下の通り。文末にセミコロンを忘れない。
```javascript=
function 関数名 () {
処理;
}
```
<br>
### 3.2 変数の宣言
変数を定義する際、変数を宣言してから代入する場合と、宣言と代入を同時に行う場合がある。
```javascript=
function myFunction() {
// 変数を宣言してから代入する場合
var a;
a = 10;
Logger.log(a); // 10
// 宣言と代入を同時に行う場合
var b = "GAS";
Logger.log(b); // "GAS"
}
```
<br>
### 3.3 変数と定数
- 変数:上書きが可能。定義する際に ```var``` を用いる。
- 定数:上書きが不可能。定義する際に ```const``` を用いる。
```javascript=
function myFunciton() {
// 変数
var x = 10;
x = 14;
Logger.log(x); // 14
// 定数
const y = 5;
y = 50;
Logger.log(y); // 5
}
```
<br>
### 3.4 データ型
| データ型 | 説明 | 例 |
| -------- | -------- | -------- |
| 数値型(Number) | 整数値や浮動小数点。 | 5, 1.08 |
| 文字列型(String) | 文字列。ダブルクオーテーション(")などで囲む。 | "GAS", 'test' |
| 真偽値 | 真と偽のどちらかの値をとるデータ型。 | true, false |
| null | 値がないことを表す値 | null |
| 配列型(Array) | インデックスをキーとするデータの集合 | [1,2,3], ["array", true] |
| オブジェクト型(Object) | プロパティをキーとするデータの集合 | {apple:"りんご", banana:"バナナ"}, {x:10, y:20, z:30} |
<br>
### 3.5 配列
配列は、複数のデータの集合。それぞれのデータには番号が振られていて、1番最初のデータは**0**でアクセスすることができる。アクセスの仕方は、配列名[インデックス]。
```javascript=
function myFunction() {
var array = [25, 30, 35, 40];
Logger.log(array[2]); // 35
}
```
要素を指定して、代入することも可能。
```javascript=
function myFunction() {
var array = [25, 30, 35, 40];
array[2] = 10;
Logger.log(array); // [25, 30, 10, 40]
}
```
#### 2次元配列
2次元配列は、配列の要素が配列のことをさす。アクセスの仕方は、基本的に1次元のものと変わらない。
```javascript=
function myFunction() {
var arrays = [[1,2,3],[4,5,6],[7,8]];
Logger.log(arrays[0]); // [1,2,3]
// 要素の配列の中身を取得するには、2回アクセスすればいい
var array = arrays[1];
Logger.log(array[2]); // 6
Logger.log(arrays[1][2]); // 6
}
```
<br>
### 3.6 オブジェクト
オブジェクトは、複数のデータの集合。配列の場合は要素にアクセスするためにインデックスを用いたが、オブジェクトはプロパティを用いる。アクセスの仕方は、オブジェクト名['プロパティ']、もしくはオブジェクト名.プロパティ。
```javascript=
function myFunction {
var person = {name:"Bob", sex:"male", age:10};
Logger.log(person.name); // "Bob"
Logger.log(person['Bob']); // "Bob"
}
```
プロパティを指定して、代入することも可能。
```javascript=
function myFunction() {
var person = {name:"Bob", sex:"male", age:10};
person.name = "Kevin";
Logger.log(person.name); // "Kevin"
person['age'] = 20;
Logger.log(person['age']); // 20
}
```
<br>
## 4. 制御構文
### 4.1 if 文
条件分岐をするときに用いられるのが、```if```文。GAS(JavaScript)の形は、以下の通り。
```javascript=
function myFunction() {
var age = 15;
if (age < 20) {
Logger.log("お酒は飲んではいけません。"); // お酒は飲んではいけません。
}
}
```
複数の条件を使いたいときは、```if...else```や、```else if```を使う。
```javascript=
function myFunction() {
var x = 12;
if (x <= 5) {
Logger.log("xは5以下です");
} else if (x <= 10) {
Logger.log("xは10以下です");
} else {
Logger.log("xは10より大きいです");
}
// "xは10より大きいです"
}
```
<br>
### 4.2 比較演算子と論理演算子
#### **比較演算子**
```if```文などの条件式で使う、比較のための演算子のことを、比較演算子という(例:<など)。今回は一部を紹介。
| 演算子 | 説明 |
| -------- | -------- |
| == | 等しいかどうかを調べるときに使う |
| != | 等しいくないかどうかを調べるときに使う |
<br>
#### **論理演算子**
```if```文などの条件式で、複数の条件式を使えるようにする演算子のことを、論理演算子という。
| 演算子 | 説明 |
| -------- | -------- |
| && | かつ |
| \|\| | または |
| ! | 否定 |
具体的な使い方は、以下の通り。
```javascript=
var x = 5, y = 10;
if (x >= 5 && y >= 5) {
Logger.log("xもyも5異常です。")
}
```
<br>
### 4.3 for文
繰り返し処理を行いたいときに使うのが```for```文。繰り返し処理を行う、他の方法として```while```がある。今回は省略する。
```javascript=
function myFunction() {
var array = [25, 30, 35, 40];
for (var i = 0; i < array.length; i++) {
Logger.log(array[i]);
}
}
```
#### for...of と for...in
```for```文では、上記の方法以外で繰り返し処理を行うことが可能。
```javascript=
function myFunction() {
// 配列の場合
var array = [25, 30, 35, 40];
for (var num of array) {
Logger.log(num);
}
// オブジェクトの場合
var fruits = {apple:"りんご", banana:"バナナ"}
for (var kudamono in fruits) {
Logger.log(kudamono);
}
for (var kudamono in fruits) {
Logger.log(fruits[kudamono]);
}
}
```
<br>
## 5. 関数
### 5.1 GASの関数
GASは最初からmyFunctionという関数が用意されているが、他の関数を定義することが可能。新たに宣言する関数の基本形は、以下の通り。
#### **引数を取らない場合**
```javascript=
function 関数名 () {
処理;
}
```
具体例
```javascript=
function myFunction() {
hello(); // Hello
}
function hello() {
Logger.log("Hello");
}
```
#### **引数をとる場合**
```javascript
function 関数名 (引数1,引数2,...) {
処理;
return 戻り値;
}
```
具体例
```javascript=
function myFunction() {
Logger.log(add_number(3,4)); // 7
}
function add_number(x,y) {
return x + y;
}
```
### 5.2 グローバル領域
関数外の領域を、グローバル領域という。ここに記述された内容は、関数内に記述されたものより先に実行される。
```javascript=
Logger.log("1番");
function myFunction() {
Logger.log("2番");
}
Logger.log("3番");
```
実行結果
``1番 ``
``3番 ``
``2番``
## 6. スプレッドシート
### 6.1 スプレッドシートを取得する
スプレッドシートを取得する方法は、以下の3つ。
- アクティブなスプレッドシートを取得する
- URLを指定して取得する
- IDを指定して取得する
<br>
具体例
```javascript=
// コンテナバインドスクリプトであれば、これで取得できる
var spreadsheet_1 = SpreadsheetApp.getActiveSpreadsheet();
// URLを使って取得できる
var url = 'https://docs.google.com/spreadsheets/d/xxxxxx/edit#gid=0';
var spreadsheet_2 = SpreadsheetApp.openByUrl(url);
// IDを使って取得できる
var id = 'xxxxxx';
var spreadsheet_3 = SpreadsheetApp.openByID(id);
```
取得したスプレッドシートを使い、シートを取得することができる。
```javascript=
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
// シート名で取得する
var sheet = spreadsheet.getSheetByName('シート名');
// 複数のシートを取得する
// データは配列型
var sheets = spreadsheet.getSheets();
```
スプレッドシート->シートの順に取得するのは、あまり良くないらしい。
一気に取得する方法が以下。
```javascript
// アクティブなシートを取得する
var active_sheet = SpreadsheetApp.getActiveSheet();
```
<br>
### 6.2 シートのデータ範囲を取得する
シートのデータ範囲を取得する際は ```getRange()``` を使う。
```javascript=
// データ範囲を取得するために、アドレスを使う場合
// アドレスは、A2のような行列のインデックスを組み合わせたもの
sheetオブジェクト.getRange(アドレス)
// データ範囲を取得するために、行番号、列番号を使う場合
sheetオブジェクト.getRange(行番号,列番号[,行数,列数])
```
具体例
```javascript=
function myFunction() {
var sheet = SpreadsheetApp.getActiveSheet();
// セルを指定
Logger.log(sheet.getRange('A2').getA1Notation()); // A2
Logger.log(sheet.getRange(2,1).getA1Notation()); // A2
// 範囲を指定
// アドレスを使う場合は、'左上のセルのアドレス:右下のセルのアドレス'で指定する
Logger.log(sheet.getRange('A2:C4').getA1Notation()); // A2:C4
Logger.log(sheet.getRange(2,1,3,3).getA1Notation()); // A2:C4
// 行と列全体を指定
Logger.log(sheet.getRange('A:A').getA1Notation()); // A:A
Logger.log(sheet.getRange(1,1).getA1Notation()); // '1:1'
}
```
<br>
範囲はわからないけど、データ範囲全体を取得したい場合は```getDataRange()```を使う。
```javascript=
sheetオブジェクト.getDataRange()
```
<br>
最終行や最終列の番号を取得する方法もある。
```javascript=
function myFunction() {
var sheet = SpreadsheetApp.getActiveSheet();
Logger.log(sheet.getName()); // シート1
// データがある最終行の番号を取得
var row = sheet.getLastRow();
Logger.log(row); // 4.0
// データがある最終列の番号を取得
var column = sheet.getLastColumn();
Logger.log(column); // 3.0
}
```
### 6.3 値を取得・入力する
今回は[以下のシート](https://docs.google.com/spreadsheets/d/1X4WIEfjsR-SDuDvZTRYfVT_HaXfHDZpCYu8kqxmgV4o/edit?usp=sharing)を使い、実践してみる。

#### **値を取得する際は、```getValue()/getValues()```を使う**
値を取得する際は、データを取得する範囲を指定して、```getValue()/getValues()```を使う。
- ```getValue()``` : データが1つ
- ```getValues()``` : データが複数
<br>
具体例
```javascript=
function myFunction() {
var sheet = SpreadsheetApp.getActiveSheet();
Logger.log(sheet.getName()); // 有名人
// セルのデータを取得するときは getValue() を用いる
Logger.log(sheet.getRange('A2').getValue()); // 田中みな実
// 指定した範囲のデータを取得するときは getValues() を使用する
Logger.log(sheet.getRange('A3:C4').getValues()); // [[白間美瑠, female, 22.0], [野田洋次郎, male, 34.0]]
}
```
<br>
#### **値を入力する際は、```setValue()/setValues()```を使う**
値を取得する際は、データを取得する範囲を指定して、```setValue()/setValues()```を使う。
- ```setValue()``` : データが1つ
- ```setValues()``` : データが複数
<br>
具体例
```javascript=
function myFunction() {
var sheet = SpreadsheetApp.getActiveSheet();
Logger.log(sheet.getName()); // 有名人
// セルにデータを入力するときは setValue() を用いる
sheet.getRange('A5').setValue('落合陽一');
Logger.log(sheet.getRange('A5').getValue()); // 落合陽一
// 指定した範囲にデータを入力するときは setValues() を使用する
sheet.getRange('B5:C5').setValues([['male', 32]]);
Logger.log(sheet.getRange('A5:C5').getValues()); // [[[落合陽一, male, 32.0]]
}
```
### 6.4 シートに行を追加する
```Sheetオブジェクト.appendRow()```で行を追加することができる。
<br>
具体例
```javascript
function myFunction() {
var sheet = SpreadsheetApp.getActiveSheet();
Logger.log(sheet.getName()); // 有名人
// データを追加する
sheet.appendRow(['井口理', 'male', 26]);
// 式も代入できる
sheet.appendRow([null, null, '=AVERAGE(C2:C6)']);
}
```
### 6.5 セル範囲を並び替える
`Rangeオブジェクト.sort(列番号)`で並べ替えることができる。
```javascript=
function myFunction() {
var sheet = SpreadsheetApp.getActiveSheet();
Logger.log(sheet.getName()); // 有名人
// 範囲を取得する
var range = sheet.getRange('A2:C6');
// 年齢を降順で並び替え
range.sort([
{column: 3, ascending: false}
]);
}
```
**sort前↓**

**sort後↓**

## 7. Gmailを使う
### 7.1 メールを送る
メールは以下のやり方で送ることができる
```javascript=
GmailApp.sendEmail(宛先,件名,本文[,オプション])
```
具体的なやり方を見てみる。
```javascript=
function myFunction () {
var subject = 'GAS勉強会の件'; // 件名
var text = '各位 \n' + // 本文
'\n' + // \n -> 改行を表す
'お疲れ様です。\n' +
'5/17(日) 10時より、GAS勉強会を開催します。\n' +
'\n' +
'中泉';
var to = ['nakaizumi@example.com', // 宛先は、配列等で決められる
'yuto@example.com' ];
GmailApp.sendEmail(
to,
subject,
text,
{
name: 'GAS勉強会管理人' // 送信者名
}
);
}
```
## 8. カレンダー
### 8.1 カレンダーを取得する
カレンダーの取得の仕方
- ID(メールアドレスがほとんど)で取得
- デフォルトカレンダーを取得する
- 所有・閲覧しているカレンダーの一覧を取得
```javascript=
function myFunction() {
// デフォルトのカレンダーを取得する
var calendar = CalendarApp.getDefaultCalendar();
// IDで取得する
// var calendar = CalendarApp.getCalendarById('YOUR_CALENDER_ID');
// 所有しているカレンダー一覧を取得する
// var calendars = CalendarApp.getAllOwnedCaledars();
// アクセス可能なカレンダー一覧を取得する
// var calendars = CalendarApp.getAllCalendars();
// カレンダーのタイトルを表示する
Logger.log(calendr.getName());
}
```
### 8.2 カレンダーの予定を取得する
カレンダーの予定を取得する方法は2種類ある。
- 期間を指定して、その期間内の予定を取得する
``` Calederオブジェクト.getEvents(開始日時,終了日時[,オプション])```
- ある特定の日の予定を取得する
``` Calederオブジェクト.getEventsForDay(日付[,オプション])```
具体的なスクリプト
```javascript=
function myFunction() {
// カレンダーを取得
var calender = CalenderApp.getDefaultCalender();
// 今日の予定を取得
var events = calendar.getEventsForDay(new Date('2020/05/24'));
// イベントのタイトルと開始時間を表示する
// forEach 構文
// 配列に使える
// 使うには、値とインデックス、元の配列といった3つの仮引数が必要
events.forEach(function (event, index, array) {
// タイトルを表示
Logger.log(event.getTitle());
// 開始時間を表示
Logger.log(event.getStartTime());
});
}
```
## 9. イベントとトリガー
### 9.1 2種類のトリガー
GASには、指定した日時、スプレッドシートを編集したとき、フォームを投稿した時といった**イベント**に合わせて自動的にスクリプトを実行させる**トリガー**という機能がある。
トリガーは、大きく分けて2種類ある。
- シンプルトリガー : 関数名でスクリプトを作成する
- インストーラブルトリガー : エディタのトリガー画面から発動させるイベントの内容と関数を設定する
### 9.2 シンプルトリガー
シンプルトリガーは以下の5種類。
- スプレッドシート、ドキュメントなどを開いた時に実行される
- スプレッドシートの値を変更した時に実行される
- スプレッドシートなどにアドオンをインストールした時に実行される
- Webアプリケーションにアクセスがあった時、またはGETリクエストがあった時に実行される
- WebアプリケーションにPOSTリクエストがあった時に実行される
### 9.3 インストーラブルトリガー
インストーラブルトリガーは以下の5種類。
- 起動時
- 編集時
- 値の変更時
- フォーム変更時
- 時間主導型
#### 時間で実行してみる
実行した、その時の時間をスプレッドシートのセルに記入するスクリプトを例に出してみた。
時間を扱うためには、Momentライブラリを使う。Momentライブラリは、Dateオブジェクトを扱いやすくしたもの。GASにはライブラリがあるが、使い方が結構独特。
**ライブラリの使い方**
1. エディタ画面のタブのリソースから、ライブラリを選択する

2. 追加したいライブラリのプロジェクトキーを入力して、追加する
`Momentライブラリのプロジェクトキー:MHMchiX6c1bwSqGM1PZiW_PxhMjh3Sh48`

**Momentライブラリでできること**
- 日時を好きなフォーマットで表示すること
- 日時の演算(足し算、引き算など)
- 日時の比較
時間で実行する時に使うスクリプト
```javascript=
function myFunction() {
// 現在時刻を取得する
var now = Moment.moment(); // 今の時間を取得
// var ex = Moment.moment('2020-05-24'); // こういう使い方もある
var now_formatted = now.format('YYYY-MM-DD HH:mm'); // 任意の形にできる
// シートを取得する
var sheet = SpreadsheetApp.getActiveSheet();
// 範囲を指定する
var cell = sheet.getRange('E1');
// 現在時刻をセルに記入する
cell.setValue(now_formatted);
}
```
**時間実行の仕方**
1. エディタ画面の時計のようなアイコンをクリック¥

2. 右下の"トリガーを追加"をクリック

3. "イベントソースの選択"から"時間主導型"を選ぶ

4. "時間ベースのトリガーのタイプ選択"から"特定の日時"を選ぶ

5. 日時を入力して、保存する

## 10. 本日のまとめ
### 10.1 その日の予定が毎朝メールで送られるようにする
そのためには
1. その日の予定を取得する
2. その予定をメールで送る
3. 1と2を、毎朝定期実行する
スクリプトはこんな感じ(多分)
```javascript=
function myFunction() {
// 本日の日時を取得
var today = Moment.moment().format('YYYY/MM/DD');
// デフォルトのカレンダーを取得する
var calendar = CalendarApp.getDefaultCalendar();
// 本日の予定を取得する
var events = calendar.getEventsForDay(new Date(today));
// メールの本文を作成する
var text = today + "の予定です\n" +
"\n" +
"---------------------------" +
"\n";
events.forEach(function (event, index, array) {
var event_text = "時間 : " + event.getStartTime() + "\n" +
"名前 : " + event.getTitle() + "\n" +
"\n" +
"---------------------------" +
"\n";
// ベースの文と結合
text = text + event_text;
});
// 件名を作成
var subject = today + "の予定";
// メールを送信する
GmailApp.sendEmail(
['YOUR_MAIL_ADDRESS'],
subject,
text
);
}
```
これが書けたら、時計のようなボタンを押してトリガー画面を開く。
開いたら、トリガーを追加->時間主導型->日付ベースのタイマー->朝らへんを指定で完成かな。
## 参考
### LINE bot
中泉が作成したLINE botについて簡単にまとめた。GASを勉強した日に作ったので、ゴミゴードなのはお許しを。
#### **概要**
- [厚労省のデータ](https://www.mhlw.go.jp/stf/seisakunitsuite/bunya/0000164708_00001.html)から、茨城県の感染者数等を送信するもの。[JSON](https://www.stopcovid19.jp/data/covid19japan.json)。

- LINE関連のトークンとかは、[ここ](https://developers.line.biz/console/)で諸々登録すればいける。[LINE諸々の参考記事](https://qiita.com/oimo23/items/11a0c38bbe1e297fb611)。
#### **スクリプト**
```javascript=
function SEND_MESSAGE() {
// get COVID-19 data from json
var COVID19_URL = 'https://www.stopcovid19.jp/data/covid19japan.json';
var json = UrlFetchApp.fetch(COVID19_URL).getContentText();
var json_data = JSON.parse(json);
// json_data.lastUpdate -> date
// json_data.area[7] -> Ibaraki
var update_date = json_data.lastUpdate;
var num_patients = json_data.area[7].npatients;
var num_deaths = json_data.area[7].ndeaths;
var data_arr = [update_date, num_patients, num_deaths];
// identify spreadsheet
var spreadsheet_id = 'YOUR_SPREADSHEET_ID';
var spreadsheet = SpreadsheetApp.openById(spreadsheet_id);
// append array data
spreadsheet.appendRow(data_arr);
// message
var date_message_ver = Utilities.formatDate(new Date(update_date), 'JST', 'MM月dd日');
var message = "【" + date_message_ver + "の感染者情報】\n" + "総感染者数:" + num_patients + "人\n" + "総死者数:" + num_deaths + "人";
//Logger.log(message);
// URL and token
var access_token = 'YOUR_TOKEN';
var user_id = 'YOUR_LINEDEVELOPERS_ID';
var line_url = 'https://api.line.me/v2/bot/message/push';
var options = {
"headers": {
"Content-Type": "application/json; charset=UTF-8",
'Authorization': 'Bearer ' + access_token,
},
"method": "post",
"payload": JSON.stringify({
"to": user_id,
"messages": [{
"type": "text",
"text": message,
}]
})
};
// send
UrlFetchApp.fetch(line_url, options);
}
```
## はじめに
昨年の5月に名古屋に来て東海の冬を初め体感している真っ最中なのですが、結構雪が降るんだなという印象を受けました。そこで今回は気象庁のデータを使って、降雪の状況を可視化していきたいと思います。
## 使用したデータ
今回使用したデータは、気象庁の[過去の気象データ検索](https://www.data.jma.go.jp/obd/stats/etrn/index.php)から名古屋の観測地点の12月の降水量、12月の最深積雪のデータを過去10年分取得しました。それぞれ整形し、CSVファイルとして保存しました。12月のデータを使用しているのは、僕が12月しか経験していないからです笑
## 結果
今回はRを使ってグラフを描画し、内容をみていきたいと思います。スクリプトをこちらに記載します。
```r=
# パッケージの読み込み
library(tidyverse)
# 降水量のデータの読み込み
data_p <- read_csv("./precipitation_dec.csv")
# 最深積雪量のデータの読み込み
data_d <- read_csv("./deepest_snowfall_dec.csv")
# グラフの描画
# 降水量のグラフ
g_p <- ggplot(data_p, aes(x=year, y=precipitation)) +
geom_bar(stat = "identity") +
theme_gray(base_family = "Osaka") +
xlab("年") +
ylab("降水量") +
ggtitle("12月の名古屋の降水量")
# 最深積雪量
g_p <- ggplot(data_p, aes(x=year, y=deepest_snowfall)) + # データの指定
geom_bar(stat = "identity") + # 棒の追加
theme_gray(base_family = "Osaka") + # フォントを指定
xlab("年") + # x軸のラベルを指定
ylab("最深積雪量") + # y軸のラベルを指定
ggtitle("12月の名古屋の最深積雪量") # タイトルを指定
g_p
g_d
```