GoogleChartsを使って、WordPressブログにレーダーチャートを埋めこむための方法を解説します。
レーダーチャートを使うことで、複数の評価項目を直感的に読みとることができます。
なぜなら、レーダーチャートはデータの大小やバランスを視覚的に表示できるからです。
コードをコピペするだけですぐに使えますので、ブログの用途に合わせてご利用ください。
「どうやってブログに貼り付ければいいかわからない。」
という方は、先にWordPressブログでGoogleChartsを使うための基本をご覧ください。
- レーダーチャートを同一記事内で複数箇所に表示できるようにコードを修正しました。
- 一部のテーマで、レーダーチャート内のフォントサイズが変更できない不具合を修正しました。
レーダーチャートは、クモの巣っぽい見た目のグラフです。
複数の項目のデータを表示し、量の大小を把握しつつ、そのバランスや特徴を見るときなどに使用されます。
一般的には、外にいくほど(レーダーが大きいほど)良いと評価します。
基本のレーダーチャート
ブログでレーダーチャートの用途として想定されるのが、商品やサービスの定量的な評価です。
例えば、価格.comなどでおなじみの満足度をレーダーチャートにしてみます。
- Google Chartsを使ったレーダーチャートの基本デザイン。
- チャートデータの中で、チャートを表示するブロックIDを指定することで、同一記事内でチャートを複数箇所に表示できる。
- 6項目を5点満点で数値化している。
<div style="width: 100%; text-align: center;">
  <div id="radar_1"></div>
</div><div style="width: 100%; text-align: center;">
  <div id="radar_2"></div>
</div><!-- 基本のレーダーチャート -->
<script type="text/javascript">
google.charts.load('upcoming', {
  'packages': ['vegachart']
}).then(loadCharts);
function loadCharts() {
  // レーダーチャートのデータ
  const chartData = [
    ["radar_1","iPhone 12 の満足度", "#B82E2E", [
      ["デザイン", 4.54],
      ["携帯性", 4.31],
      ["レスポンス", 4.80],
      ["画面表示", 4.69],
      ["バッテリー", 4.23],
      ["カメラ", 4.53]
    ]],
    ["radar_1","iPhone 13 の満足度", "#B82E2E", [
      ["デザイン", 4.43],
      ["携帯性", 3.96],
      ["レスポンス", 4.54],
      ["画面表示", 4.49],
      ["バッテリー", 4.37],
      ["カメラ", 4.27]
    ]],
    ["radar_2","iPhone SE(第2世代) の満足度", "#6633CC", [
      ["デザイン", 4.24],
      ["携帯性", 4.67],
      ["レスポンス", 4.64],
      ["画面表示", 4.17],
      ["バッテリー", 3.49],
      ["カメラ", 3.98]
    ]],
    ["radar_2","iPhone SE(第3世代) の満足度", "#6633CC", [
      ["デザイン", 3.71],
      ["携帯性", 4.39],
      ["レスポンス", 4.79],
      ["画面表示", 3.51],
      ["バッテリー", 3.28],
      ["カメラ", 3.45]
    ]],
  ];
  for (var i = 0; i < chartData.length; i++) {
    for (var j = 0; j < chartData[i][3].length; j++) {
      chartData[i][3][j][2] = chartData[i][1];
    }
    addChart(chartData[i][1], chartData[i][3], chartData[i][2], chartData[i][0]);
  }
}
function addChart(title, data, color, chartId) {
  // 値スケール
  const valueScale = [0, 5];
  // 値フォーマット
  const valueFormat = '1';
  // レーダーの枠線の太さ
  const valueStrokeWidth = 1.5;
  // レーダーの領域の不透明度
  const valueOpacity = 0.1;
  // レーダーの値のフォントサイズ
  const valueValtext = 14;
  // レーダーのラベルのフォントサイズ
  const valueLabeltext = 12;
  const dataTable = new google.visualization.DataTable();
  dataTable.addColumn({
    type: 'string',
    'id': 'key'
  });
  dataTable.addColumn({
    type: 'number',
    'id': 'value'
  });
  dataTable.addColumn({
    type: 'string',
    'id': 'category'
  });
  dataTable.addRows(data);
  const options = {
    'vega': {
      "$schema": "https://vega.github.io/schema/vega/v5.json",
      "width": 250,
      "height": 300,
      "autosize": "none",
      "title": {
        "text": title,
        "anchor": "middle",
        "fontSize": 16,
        "dy": -8,
        "dx": {
          "signal": "-width/4"
        },
        "subtitle": ""
      },
      "signals": [{
        "name": "radius",
        "update": "90"
      }],
      "data": [{
          "name": "table",
          "source": "datatable",
        },
        {
          "name": "keys",
          "source": "table",
          "transform": [{
            "type": "aggregate",
            "groupby": ["key"]
          }]
        }
      ],
      "scales": [{
          "name": "angular",
          "type": "point",
          "range": {
            "signal": "[-PI, PI]"
          },
          "padding": 0.5,
          "domain": {
            "data": "table",
            "field": "key"
          }
        },
        {
          "name": "radial",
          "type": "linear",
          "range": {
            "signal": "[0, radius]"
          },
          "zero": true,
          "nice": false,
          "domain": valueScale,
        }
      ],
      "encode": {
        "enter": {
          "x": {
            "signal": "width/2"
          },
          "y": {
            "signal": "height/2 + 20"
          }
        }
      },
      "marks": [{
          "type": "group",
          "name": "categories",
          "zindex": 1,
          "from": {
            "facet": {
              "data": "table",
              "name": "facet",
              "groupby": ["category"]
            }
          },
          "marks": [{
              "type": "line",
              "name": "category-line",
              "from": {
                "data": "facet"
              },
              "encode": {
                "enter": {
                  "interpolate": {
                    "value": "linear-closed"
                  },
                  "x": {
                    "signal": "scale('radial', datum.value) * cos(scale('angular', datum.key))"
                  },
                  "y": {
                    "signal": "scale('radial', datum.value) * sin(scale('angular', datum.key))"
                  },
                  "stroke": {
                    "value": color
                  },
                  "strokeWidth": {
                    "value": valueStrokeWidth
                  },
                  "fill": {
                    "value": color
                  },
                  "fillOpacity": {
                    "value": valueOpacity
                  }
                }
              }
            },
            {
              "type": "text",
              "name": "value-text",
              "from": {
                "data": "category-line"
              },
              "encode": {
                "enter": {
                  "x": {
                    "signal": "datum.x + 14 * cos(scale('angular', datum.datum.key))"
                  },
                  "y": {
                    "signal": "datum.y + 14 * sin(scale('angular', datum.datum.key))"
                  },
                  "text": {
                    "signal": "format(datum.datum.value,'" + valueFormat + "')"
                  },
                  "opacity": {
                    "signal": "datum.datum.value > 0.01 ? 1 : 0"
                  },
                  "align": {
                    "value": "center"
                  },
                  "baseline": {
                    "value": "middle"
                  },
                  "fontWeight": {
                    "value": "bold"
                  },
                  "fill": {
                    "value": color
                  },
                  "fontSize": {
                    "value": valueValtext
                  }
                }
              }
            }
          ]
        },
        {
          "type": "rule",
          "name": "radial-grid",
          "from": {
            "data": "keys"
          },
          "zindex": 0,
          "encode": {
            "enter": {
              "x": {
                "value": 0
              },
              "y": {
                "value": 0
              },
              "x2": {
                "signal": "radius * cos(scale('angular', datum.key))"
              },
              "y2": {
                "signal": "radius * sin(scale('angular', datum.key))"
              },
              "stroke": {
                "value": "lightgray"
              },
              "strokeWidth": {
                "value": 1
              }
            }
          }
        },
        {
          "type": "text",
          "name": "key-label",
          "from": {
            "data": "keys"
          },
          "zindex": 1,
          "encode": {
            "enter": {
              "x": {
                "signal": "(radius + 11) * cos(scale('angular', datum.key))"
              },
              "y": [{
                  "test": "sin(scale('angular', datum.key)) > 0",
                  "signal": "5 + (radius + 11) * sin(scale('angular', datum.key))"
                },
                {
                  "test": "sin(scale('angular', datum.key)) < 0",
                  "signal": "-5 + (radius + 11) * sin(scale('angular', datum.key))"
                },
                {
                  "signal": "(radius + 11) * sin(scale('angular', datum.key))"
                }
              ],
              "text": {
                "field": "key"
              },
              "align": {
                "value": "center"
              },
              "baseline": [{
                  "test": "scale('angular', datum.key) > 0",
                  "value": "top"
                },
                {
                  "test": "scale('angular', datum.key) == 0",
                  "value": "middle"
                },
                {
                  "value": "bottom"
                }
              ],
              "fill": {
                "value": "black"
              },
              "fontSize": {
                "value": valueLabeltext
              }
            }
          }
        },
        {
          "type": "line",
          "name": "twenty-line",
          "from": {
            "data": "keys"
          },
          "encode": {
            "enter": {
              "interpolate": {
                "value": "linear-closed"
              },
              "x": {
                "signal": "0.2 * radius * cos(scale('angular', datum.key))"
              },
              "y": {
                "signal": "0.2 * radius * sin(scale('angular', datum.key))"
              },
              "stroke": {
                "value": "lightgray"
              },
              "strokeWidth": {
                "value": 1
              }
            }
          }
        },
        {
          "type": "line",
          "name": "fourty-line",
          "from": {
            "data": "keys"
          },
          "encode": {
            "enter": {
              "interpolate": {
                "value": "linear-closed"
              },
              "x": {
                "signal": "0.4 * radius * cos(scale('angular', datum.key))"
              },
              "y": {
                "signal": "0.4 * radius * sin(scale('angular', datum.key))"
              },
              "stroke": {
                "value": "lightgray"
              },
              "strokeWidth": {
                "value": 1
              }
            }
          }
        },
        {
          "type": "line",
          "name": "sixty-line",
          "from": {
            "data": "keys"
          },
          "encode": {
            "enter": {
              "interpolate": {
                "value": "linear-closed"
              },
              "x": {
                "signal": "0.6 * radius * cos(scale('angular', datum.key))"
              },
              "y": {
                "signal": "0.6 * radius * sin(scale('angular', datum.key))"
              },
              "stroke": {
                "value": "lightgray"
              },
              "strokeWidth": {
                "value": 1
              }
            }
          }
        },
        {
          "type": "line",
          "name": "eighty-line",
          "from": {
            "data": "keys"
          },
          "encode": {
            "enter": {
              "interpolate": {
                "value": "linear-closed"
              },
              "x": {
                "signal": "0.8 * radius * cos(scale('angular', datum.key))"
              },
              "y": {
                "signal": "0.8 * radius * sin(scale('angular', datum.key))"
              },
              "stroke": {
                "value": "lightgray"
              },
              "strokeWidth": {
                "value": 1
              }
            }
          }
        },
        {
          "type": "line",
          "name": "outer-line",
          "from": {
            "data": "radial-grid"
          },
          "encode": {
            "enter": {
              "interpolate": {
                "value": "linear-closed"
              },
              "x": {
                "field": "x2"
              },
              "y": {
                "field": "y2"
              },
              "stroke": {
                "value": "lightgray"
              },
              "strokeWidth": {
                "value": 1
              }
            }
          }
        }
      ]
    }
  };
  const elem = document.createElement("div");
  elem.setAttribute("style", "display: inline-block; width: 250px; height: 300px; font-size: initial;");
  const chart = new google.visualization.VegaChart(elem);
  chart.draw(dataTable, options);
  document.getElementById(chartId).appendChild(elem);
}
</script>レーダーチャートのカスタマイズ
よく使う設定項目を変数にしてまとめました。
データの種類やデザインにあわせて変更してみてください。
// レーダーチャートのデータ
  const chartData = [
    ["radar_1","iPhone 12 の満足度", "#B82E2E", [
      ["デザイン", 4.54],
      ["携帯性", 4.31],
      ["レスポンス", 4.80],
      ["画面表示", 4.69],
      ["バッテリー", 4.23],
      ["カメラ", 4.53]
    ]],
    ["radar_1","iPhone 13 の満足度", "#B82E2E", [
      ["デザイン", 4.43],
      ["携帯性", 3.96],
      ["レスポンス", 4.54],
      ["画面表示", 4.49],
      ["バッテリー", 4.37],
      ["カメラ", 4.27]
    ]],
    ["radar_2","iPhone SE(第2世代) の満足度", "#6633CC", [
      ["デザイン", 4.24],
      ["携帯性", 4.67],
      ["レスポンス", 4.64],
      ["画面表示", 4.17],
      ["バッテリー", 3.49],
      ["カメラ", 3.98]
    ]],
    ["radar_2","iPhone SE(第3世代) の満足度", "#6633CC", [
      ["デザイン", 3.71],
      ["携帯性", 4.39],
      ["レスポンス", 4.79],
      ["画面表示", 3.51],
      ["バッテリー", 3.28],
      ["カメラ", 3.45]
    ]],
  ];レーダーチャートのデータを指定します。
データの構造とチャートとの対応は下のイラストをご覧ください。

["radar_1","iPhone 12 の満足度", "#B82E2E", [1行目は、チャートを表示するブロックのID、レーダーチャートのタイトル、色を指定します。
コード例に沿って解説します。
“radar_1″がブロックIDです。
「iPhone 12」と「iPhone 13」は、同じブロックで並べて表示させるため同じIDである「radar_1」を割り当てています。
異なるIDを指定することで、同じ記事の中でID毎にDIVブロックを置くことができます。
“iPhone 12の満足度”がレーダーチャートのタイトルです。長すぎると見切れますのでご注意ください。
“#B82E2E”が色です。カラーコードで指定します。
    ["デザイン", 3.71],
    ["携帯性", 4.39],
    ["レスポンス", 4.79],
    ["画面表示", 3.51],
    ["バッテリー", 3.28],
    ["カメラ", 3.45]2行目以降は、チャートのラベルと値を指定します。
この例では項目は6つですが、この部分を行単位で増やしたり減らしたりすることで、項目数を変更することができます。
// 値スケール
const valueScale = [0, 5];レーダーチャートの最小値と最大値を指定します。1つ目の数値が最小値、2つ目の数値が最大値です。
この例では、最小値が「0」、最大値が「5」です。
通常、レーダーチャートの中心はゼロですので、最小値は「0」のままにし、データに合わせて最大値を調整します。

パーセント表示したい場合は、最大値を「1」にすると100%になります。
// 値フォーマット
const valueFormat = '1';値の表示形式を設定します。
この例では、通常の数値形式となります。
パーセント表示したい場合は、’1%’を指定します。
// レーダーの枠線の太さ
const valueStrokeWidth = 1.5;レーダーの枠線の太さを設定します。
単位はピクセルです。

// レーダーの領域の不透明度
const valueOpacity = 0.1;レーダーの領域部分の不透明度を設定します。
「0.0~1.0」までの数値で不透明度を指定します。数値が大きいほど不透明度が高くなり、よりはっきりと表示されます。
- 不透明度: 1 ー 完全に不透明な状態になります。
- 不透明度: 0 ー 完全に透明な状態になります。

不透明度は枠線には適用されません。
// レーダーの値のフォントサイズ
const valueValtext = 14;
// レーダーのラベルのフォントサイズ
const valueLabeltext = 12;値のフォントサイズと、ラベルのフォントサイズをそれぞれ設定します。

レーダーチャートの活用例を紹介します。
レーダーチャートは良くも悪くも存在感があるため、使いどころが難しいです。
比較したい目的に応じた適切な評価項目とデータを用意することが重要です。
能力値のレーダーチャート
人事評価やストレスチェックの結果を視覚的に表現したい場合、レーダーチャートは最適な方法のひとつになります。
この例は、「ギレンの野望」というゲームのキャラクターの能力値を示したものです。
このグラフの設定は以下のとおりです。
  // 値スケール
  const valueScale = [0, 25];
  // 値フォーマット
  const valueFormat = '1';
  // レーダーの枠線の太さ
  const valueStrokeWidth = 3;
  // レーダーの領域の不透明度
  const valueOpacity = 0.5;
  // レーダーの値のフォントサイズ
  const valueValtext = 14;
  // レーダーのラベルのフォントサイズ
  const valueLabeltext = 12;ちなみに、レーダーの3つの色「黄・青・赤」はガンダムのトリコロールカラーを使いました。
色使いに迷った場合は、モビルスーツのカラーリングを参考にしてみてはいかがでしょうか?
 配色パターンはガンダムのカラーリングでキメる|一年戦争編
   配色パターンはガンダムのカラーリングでキメる|一年戦争編  
評価項目の多いレーダーチャート
「チャートデータを編集する」で解説したように、データ項目は増やすことができます。
この例では、12項目をレーダーチャートで表現しています。
食料自給率のデータは、農林水産省WEBサイト「日本の食料自給率」にある「令和2年度食料自給率について」を参照しました。
要素を重ねて表示するレーダーチャート

このレーダーチャートの作り方は、こちらの記事をご覧ください。
 【コピペでGoogleCharts】重ねて表示するレーダーチャートの作り方
   【コピペでGoogleCharts】重ねて表示するレーダーチャートの作り方  
ブログのなかで、レーダーチャートを使っているブロガーさんの記事を紹介します。
たけゆうさん「技術士ノート」
技術士の特化ブログを運営している、たけゆうさん@takeyuublog のブログです。
技術士講座の添削結果をレーダーチャートで表示させています。
ゆーさん「転職逆転人生」
転職のノウハウを発信している、ゆーさん@yusan60857558 のブログです。
レーダーチャートを使って転職ツールをわかりやすく評価しています。
レーダーチャート活用のお手本のような記事ですので、見ておいて損はありませんよ。
レーダーチャートを使うことで、複数の評価項目をわかりやすく表現することができます。
ブログの中にレーダーチャートを使って、ライバルに差をつけましょう。
レーダーチャート以外のグラフの使い方やデザイン集は、以下の記事をご覧ください。
 WordPressブログにグラフを埋めこむためのGoogleChartsの使い方
   WordPressブログにグラフを埋めこむためのGoogleChartsの使い方  



ネット上にはあまりない情報をわかりやすく説明してくださりありがとうございます。レーダーチャートについていくつか質問させてください。
・ラベルと値が重ならないように調整するにはどうすればいいでしょうか?
・項目を5つにしたときに傾かないようにできますか?
見た目が美しいので、ぜひ自分のサイトにも導入したいと思っています。上記の点、教えていただければ幸いです。
コメントありがとうございます。
>・ラベルと値が重ならないように調整するにはどうすればいいでしょうか?
調整方法のひとつとして、ある程度レーダーが小さくなるように「値のスケール」を大きくしてみてはいかがでしょうか?
>・項目を5つにしたときに傾かないようにできますか?
申し訳ありません。
傾きを調整するのは難しそうです。