
太陽系の惑星は、今どんな並びになっている?
「今日の太陽系」は、水星・金星・地球・火星・木星・土星・天王星・海王星の現在位置を、太陽系を上から見下ろしたような図で表示するScriptableウィジェットです。
惑星が太陽のまわりを回っているのはもちろん知っていても、「じゃあ今この瞬間、実際にどんな並びになってるんやろ?」と思ったのが作ったきっかけです。
現在の惑星配置だけでなく、地球から各惑星までの距離や、今もっとも地球に近い惑星、太陽までの距離なども確認できます。
外部APIから現在位置を取得しているのではなく、JPL(NASAジェット推進研究所)が公開している惑星の軌道要素をもとに、現在の日付と時刻からScriptable内で惑星の位置を計算しています。
そのため表示される位置や距離は観測機関が提供するリアルタイムの精密値ではなく、惑星のおおよその配置や距離を楽しむためのものです。
ウィジェットの表示内容
現在の日付と軌道要素から惑星位置を近似計算します。
サイズごとの表示
- 小:太陽系の惑星配置を図で表示します。
- 中:地球から惑星までの距離なども確認できます。
- 大:太陽からの距離や前日からの変化を含めて表示します。
設定手順
上から順に進めてください。コードの保存と設定のコピーに必要な操作欄は、それぞれの手順の中にあります。
- Scriptableを用意する
App StoreでScriptableを開き、iPhoneにインストールします。すでに入っている場合は次へ進んでください。
- コードをコピーして保存する
下のコード欄の「コピー」を押します。Scriptableへ移動し、「+」から新しいスクリプトを作ってコード全文を貼り付け、現在の惑星の位置は?などの名前で保存してください。
保存したらこのページに戻り、次の手順へ進みます。
// Variables used by Scriptable. // These must be at the very top of the file. Do not edit. // icon-color: deep-blue; icon-glyph: globe; // Version: 1.0.0 // ===================================================== // 今日の太陽系 - Scriptable Widget // // 現在の惑星配置を北の黄道極から見下ろした図で表示。 // // 軌道要素: // JPL "Keplerian Elements for Approximate Positions // of the Major Planets"(1800AD - 2050AD) // // ・APIキー不要 // ・ネット接続不要 // ・小 / 中 / 大ウィジェット対応 // // ※ 惑星の方向は軌道計算による値です。 // ※ 軌道半径は見やすさを優先して対数スケールで // デフォルメしています。 // ===================================================== // ===================================================== // 基本設定 // ===================================================== const AU_KM = 149597870.7; // ===================================================== // 惑星データ // ===================================================== // // [a, a', e, e', I, I', L, L', // 近日点経度, 同', 昇交点経度, 同'] // // ' は1世紀あたりの変化量 // ===================================================== const PLANETS = [ { name: "水星", short: "水", color: "#b8b8b8", size: 0.9, el: [ 0.38709927, 0.00000037, 0.20563593, 0.00001906, 7.00497902, -0.00594749, 252.25032350, 149472.67411175, 77.45779628, 0.16047689, 48.33076593, -0.12534081 ] }, { name: "金星", short: "金", color: "#eed9a8", size: 1.2, el: [ 0.72333566, 0.00000390, 0.00677672, -0.00004107, 3.39467605, -0.00078890, 181.97909950, 58517.81538729, 131.60246718, 0.00268329, 76.67984255, -0.27769418 ] }, { name: "地球", short: "地", color: "#4fa3ff", size: 1.3, el: [ 1.00000261, 0.00000562, 0.01671123, -0.00004392, -0.00001531, -0.01294668, 100.46457166, 35999.37244981, 102.93768193, 0.32327364, 0.0, 0.0 ] }, { name: "火星", short: "火", color: "#e8663a", size: 1.1, el: [ 1.52371034, 0.00001847, 0.09339410, 0.00007882, 1.84969142, -0.00813131, -4.55343205, 19140.30268499, -23.94362959, 0.44441088, 49.55953891, -0.29257343 ] }, { name: "木星", short: "木", color: "#dba873", size: 2.2, el: [ 5.20288700, -0.00011607, 0.04838624, -0.00013253, 1.30439695, -0.00183714, 34.39644051, 3034.74612775, 14.72847983, 0.21252668, 100.47390909, 0.20469106 ] }, { name: "土星", short: "土", color: "#ead79a", size: 2.0, el: [ 9.53667594, -0.00125060, 0.05386179, -0.00050991, 2.48599187, 0.00193609, 49.95424423, 1222.49362201, 92.59887831, -0.41897216, 113.66242448, -0.28867794 ] }, { name: "天王星", short: "天", color: "#8fe3e8", size: 1.6, el: [ 19.18916464, -0.00196176, 0.04725744, -0.00004397, 0.77263783, -0.00242939, 313.23810451, 428.48202785, 170.95427630, 0.40805281, 74.01692503, 0.04240589 ] }, { name: "海王星", short: "海", color: "#6a86ff", size: 1.6, el: [ 30.06992276, 0.00026291, 0.00859048, 0.00005105, 1.77004347, 0.00035372, -55.12002969, 218.45945325, 44.96476227, -0.32241464, 131.78422574, -0.00508664 ] } ]; // ===================================================== // 天文計算 // ===================================================== const RAD = Math.PI / 180; function julianDate(date) { return date.getTime() / 86400000 + 2440587.5; } function normDeg(x) { x = x % 360; return x > 180 ? x - 360 : x < -180 ? x + 360 : x; } function solveKepler(M, e) { let E = M + e * Math.sin(M); for (let i = 0; i < 20; i++) { const d = (E - e * Math.sin(E) - M) / (1 - e * Math.cos(E)); E -= d; if (Math.abs(d) < 1e-10) break; } return E; } // ===================================================== // 太陽中心・黄道座標 // ===================================================== function heliocentric(p, jd) { const T = (jd - 2451545.0) / 36525.0; const el = p.el; const a = el[0] + el[1] * T; const e = el[2] + el[3] * T; const I = (el[4] + el[5] * T) * RAD; const L = el[6] + el[7] * T; const varpi = el[8] + el[9] * T; const Omega = (el[10] + el[11] * T) * RAD; const omega = varpi * RAD - Omega; const M = normDeg( L - varpi ) * RAD; const E = solveKepler( M, e ); const xp = a * (Math.cos(E) - e); const yp = a * Math.sqrt( 1 - e * e ) * Math.sin(E); const cw = Math.cos(omega); const sw = Math.sin(omega); const cO = Math.cos(Omega); const sO = Math.sin(Omega); const cI = Math.cos(I); const sI = Math.sin(I); const x = (cw * cO - sw * sO * cI) * xp + (-sw * cO - cw * sO * cI) * yp; const y = (cw * sO + sw * cO * cI) * xp + (-sw * sO + cw * cO * cI) * yp; const z = (sw * sI) * xp + (cw * sI) * yp; return { x, y, z, a }; } // ===================================================== // 全惑星計算 // ===================================================== function computeAll(date) { const jd = julianDate(date); const list = PLANETS.map(p => { const h = heliocentric( p, jd ); return { ...p, ...h, lon: Math.atan2( h.y, h.x ) }; }); const earth = list.find( p => p.name === "地球" ); list.forEach(p => { p.distEarth = Math.sqrt( (p.x - earth.x) ** 2 + (p.y - earth.y) ** 2 + (p.z - earth.z) ** 2 ); }); earth.distSun = Math.sqrt( earth.x ** 2 + earth.y ** 2 + earth.z ** 2 ); return list; } // ===================================================== // 距離表示 // ===================================================== function formatKm(au) { const km = au * AU_KM; // 1億km以上 if (km >= 100000000) { const oku = Math.floor( km / 100000000 ); const man = Math.round( (km % 100000000) / 10000 ); if (man === 0) { return `${oku}億km`; } return ( `${oku}億` + `${man.toLocaleString()}万km` ); } // 1万km以上 if (km >= 10000) { return ( Math.round( km / 10000 ).toLocaleString() + "万km" ); } return ( Math.round(km) .toLocaleString() + "km" ); } // ===================================================== // 前日との差 // ===================================================== function getSunDistanceDifference(now) { const yesterday = new Date( now.getTime() - 24 * 60 * 60 * 1000 ); const todayPlanets = computeAll(now); const yesterdayPlanets = computeAll(yesterday); const earthToday = todayPlanets.find( p => p.name === "地球" ); const earthYesterday = yesterdayPlanets.find( p => p.name === "地球" ); return ( earthToday.distSun - earthYesterday.distSun ) * AU_KM; } // ===================================================== // 最も近い惑星 // ===================================================== function getNearestPlanet(planets) { const others = planets.filter( p => p.name !== "地球" ); return others.reduce( (a, b) => a.distEarth < b.distEarth ? a : b ); } // ===================================================== // 軌道半径マッピング // ===================================================== function makeRadiusMapper(S) { const rIn = S * 0.10; const rOut = S * 0.45; const l0 = Math.log(0.387); const l1 = Math.log(30.07); return a => rIn + (rOut - rIn) * (Math.log(a) - l0) / (l1 - l0); } // ===================================================== // 星空用疑似乱数 // ===================================================== function seededRandom(seed) { let s = seed; return () => { s = ( s * 1664525 + 1013904223 ) % 4294967296; return ( s / 4294967296 ); }; } // ===================================================== // 太陽系描画 // ===================================================== function drawSolarSystem( planets, S ) { const ctx = new DrawContext(); ctx.size = new Size( S, S ); ctx.opaque = false; ctx.respectScreenScale = true; const cx = S / 2; const cy = S / 2; const mapR = makeRadiusMapper(S); // ------------------------- // 星空 // ------------------------- const rnd = seededRandom( 20260920 ); for ( let i = 0; i < 45; i++ ) { const x = rnd() * S; const y = rnd() * S; const r = 0.6 + rnd() * 1.4; ctx.setFillColor( new Color( "#ffffff", 0.25 + rnd() * 0.5 ) ); ctx.fillEllipse( new Rect( x - r, y - r, r * 2, r * 2 ) ); } // ------------------------- // 軌道 // ------------------------- ctx.setLineWidth( Math.max( 1, S / 400 ) ); planets.forEach(p => { const r = mapR(p.a); ctx.setStrokeColor( new Color( "#ffffff", 0.18 ) ); ctx.strokeEllipse( new Rect( cx - r, cy - r, r * 2, r * 2 ) ); }); // ------------------------- // 春分点方向 // ------------------------- ctx.setFont( Font.systemFont( S * 0.045 ) ); ctx.setTextColor( new Color( "#ffffff", 0.45 ) ); ctx.setTextAlignedRight(); ctx.drawTextInRect( "♈︎", new Rect( S * 0.90, cy - S * 0.03, S * 0.10, S * 0.06 ) ); // ------------------------- // 太陽 // ------------------------- const sunR = S * 0.035; [3.2, 2.2, 1.5] .forEach( (k, i) => { ctx.setFillColor( new Color( "#ffb300", 0.10 + i * 0.10 ) ); const r = sunR * k; ctx.fillEllipse( new Rect( cx - r, cy - r, r * 2, r * 2 ) ); } ); ctx.setFillColor( new Color( "#ffd54a" ) ); ctx.fillEllipse( new Rect( cx - sunR, cy - sunR, sunR * 2, sunR * 2 ) ); // ------------------------- // 惑星 // ------------------------- ctx.setFont( Font.boldSystemFont( S * 0.04 ) ); ctx.setTextAlignedCenter(); planets.forEach(p => { const r = mapR(p.a); const px = cx + r * Math.cos(p.lon); const py = cy - r * Math.sin(p.lon); const pr = S * 0.014 * p.size; ctx.setFillColor( new Color( p.color ) ); ctx.fillEllipse( new Rect( px - pr, py - pr, pr * 2, pr * 2 ) ); // 地球を白枠で強調 if ( p.name === "地球" ) { ctx.setStrokeColor( new Color( "#ffffff", 0.9 ) ); ctx.setLineWidth( Math.max( 1, S / 300 ) ); ctx.strokeEllipse( new Rect( px - pr - 2, py - pr - 2, (pr + 2) * 2, (pr + 2) * 2 ) ); } // ラベル const off = pr + S * 0.03; const lx = px + off * Math.cos(p.lon); const ly = py - off * Math.sin(p.lon); ctx.setTextColor( new Color( p.color, 0.95 ) ); ctx.drawTextInRect( p.short, new Rect( lx - S * 0.04, ly - S * 0.03, S * 0.08, S * 0.06 ) ); }); return ctx.getImage(); } // ===================================================== // 惑星距離一覧 // ===================================================== function addPlanetRows( stack, planets, fontSize, showAU = false ) { planets.forEach(p => { const row = stack.addStack(); row.centerAlignContent(); const n = row.addText( p.short + " " + p.name ); n.font = Font.systemFont( fontSize ); n.textColor = new Color( p.color ); row.addSpacer(); let text = formatKm( p.distEarth ); if (showAU) { text += ` ${p.distEarth.toFixed(2)}AU`; } const d = row.addText(text); d.font = Font.regularMonospacedSystemFont( fontSize ); d.textColor = new Color( "#ffffff", 0.85 ); stack.addSpacer(2); }); } // ===================================================== // ウィジェット // ===================================================== async function createWidget() { const now = new Date(); const planets = computeAll(now); const earth = planets.find( p => p.name === "地球" ); const others = planets.filter( p => p.name !== "地球" ); const nearest = getNearestPlanet( planets ); const sunDiff = getSunDistanceDifference( now ); // ------------------------- // Widget // ------------------------- const w = new ListWidget(); const g = new LinearGradient(); g.colors = [ new Color( "#101a3d" ), new Color( "#03050f" ) ]; g.locations = [0, 1]; w.backgroundGradient = g; // ------------------------- // 日付 // ------------------------- const df = new DateFormatter(); df.dateFormat = "yyyy.MM.dd HH:mm"; const family = config.widgetFamily || "medium"; // =================================================== // SMALL // =================================================== if ( family === "small" ) { w.setPadding( 8, 8, 8, 8 ); const title = w.addText( "今日の太陽系" ); title.font = Font.boldSystemFont( 11 ); title.textColor = new Color( "#ffffff", 0.9 ); title.centerAlignText(); w.addSpacer(2); const img = w.addImage( drawSolarSystem( planets, 600 ) ); img.centerAlignImage(); img.imageSize = new Size( 132, 132 ); } // =================================================== // LARGE // =================================================== else if ( family === "large" ) { w.setPadding( 12, 12, 12, 12 ); const title = w.addText( "現在の惑星配置" ); title.font = Font.boldSystemFont( 14 ); title.textColor = new Color( "#ffffff", 0.95 ); const date = w.addText( df.string(now) ); date.font = Font.systemFont( 9 ); date.textColor = new Color( "#ffffff", 0.45 ); w.addSpacer(4); const img = w.addImage( drawSolarSystem( planets, 800 ) ); img.centerAlignImage(); img.imageSize = new Size( 210, 210 ); w.addSpacer(4); // ------------------------- // 今日の情報 // ------------------------- const info = w.addStack(); info.layoutHorizontally(); // 最も近い惑星 const nearestBox = info.addStack(); nearestBox.layoutVertically(); let t = nearestBox.addText( "地球から最も近い惑星" ); t.font = Font.systemFont( 9 ); t.textColor = new Color( "#ffffff", 0.5 ); let v = nearestBox.addText( `${nearest.name} ${formatKm( nearest.distEarth )}` ); v.font = Font.boldSystemFont( 11 ); v.textColor = new Color( nearest.color ); info.addSpacer(); // 太陽まで const sunBox = info.addStack(); sunBox.layoutVertically(); t = sunBox.addText( "☀ 太陽まで" ); t.font = Font.systemFont( 9 ); t.textColor = new Color( "#ffffff", 0.5 ); v = sunBox.addText( formatKm( earth.distSun ) ); v.font = Font.boldSystemFont( 11 ); v.textColor = new Color( "#ffd54a" ); const diffSign = sunDiff >= 0 ? "+" : "−"; const diffText = sunBox.addText( `昨日比 ${diffSign}${Math.round( Math.abs(sunDiff) ).toLocaleString()}km` ); diffText.font = Font.systemFont( 8 ); diffText.textColor = new Color( "#ffffff", 0.45 ); w.addSpacer(6); // ------------------------- // 惑星一覧 // ------------------------- const cols = w.addStack(); const left = cols.addStack(); left.layoutVertically(); cols.addSpacer(16); const right = cols.addStack(); right.layoutVertically(); addPlanetRows( left, others.slice(0, 4), 9, true ); addPlanetRows( right, others.slice(4), 9, true ); } // =================================================== // MEDIUM // =================================================== else { w.setPadding( 8, 10, 8, 12 ); const row = w.addStack(); row.centerAlignContent(); // ------------------------- // 左:惑星図 // ------------------------- const img = row.addImage( drawSolarSystem( planets, 700 ) ); img.imageSize = new Size( 140, 140 ); row.addSpacer(12); // ------------------------- // 右:情報 // ------------------------- const col = row.addStack(); col.layoutVertically(); const title = col.addText( "現在の惑星配置" ); title.font = Font.boldSystemFont( 11 ); title.textColor = new Color( "#ffffff", 0.95 ); const date = col.addText( df.string(now) ); date.font = Font.systemFont( 7 ); date.textColor = new Color( "#ffffff", 0.4 ); col.addSpacer(4); const sub = col.addText( "地球からの距離" ); sub.font = Font.systemFont( 8 ); sub.textColor = new Color( "#ffffff", 0.5 ); col.addSpacer(3); addPlanetRows( col, others, 8.5, false ); col.addSpacer(3); const near = col.addText( `最接近:${nearest.name} ${formatKm( nearest.distEarth )}` ); near.font = Font.boldSystemFont( 8 ); near.textColor = new Color( nearest.color ); } // =================================================== // 更新 // =================================================== w.refreshAfterDate = new Date( Date.now() + 60 * 60 * 1000 ); return w; } // ===================================================== // 実行 // ===================================================== const widget = await createWidget(); if ( config.runsInWidget ) { Script.setWidget( widget ); } else { await widget.presentMedium(); } Script.complete(); - ホーム画面に追加して設定する
iPhoneのホーム画面を長押しし、ウィジェット追加画面からScriptableを選びます。この記事の対応サイズの説明に合わせてサイズを選んで追加してください。
追加したウィジェットを長押しして「ウィジェットを編集」を開き、「Script」に保存したスクリプトを選びます。
「Parameter」は空欄で構いません。
編集画面を閉じて表示を確認します。ホーム画面への反映には少し時間がかかる場合があります。
惑星配置について
ウィジェットは、太陽系を北の黄道極側から見下ろしたイメージで表示しています。
惑星の方向は軌道計算による現在位置を使用しています。
ただし、水星から海王星までの実際の距離をそのまま縮小すると、内側の惑星がほとんど見えなくなってしまいます。
そのため、軌道の間隔と惑星の大きさはウィジェットで見やすいようにデフォルメしています。
実際の太陽系を完全な縮尺で再現した図ではなく、現在の惑星の並びや方向を楽しむための表示です。
地球から惑星までの距離
惑星はそれぞれ異なる速度で太陽の周りを公転しています。
そのため、
「地球から火星まで何km?」
という距離も常に同じではありません。
このウィジェットでは、現在の地球と各惑星の位置から距離を計算して表示します。
中・大サイズでは、
- 水星
- 金星
- 火星
- 木星
- 土星
- 天王星
- 海王星
までの現在距離を確認できます。
さらに、現在もっとも地球に近い惑星も表示します。
動作確認・使用結果
| 確認した端末 | iPhone 17 ProMAX |
|---|---|
| iOS | iOS27 |
| Scriptable | 1.7.19 |
| 確認したサイズ | 小・中・大 |
| バージョン | 1.0.0 |
| 動作確認日 | 2026-09-21 |
表示・使用時のポイント
現在の日付と軌道要素から惑星位置を近似計算します。配置図は見やすさを優先した図で、惑星の大きさや軌道の距離を実寸比では描いていません。
更新履歴
1.0.0
- 初回リリース
よくあるエラーと対処
- 確認すること
- 表示されない場合は、ウィジェット編集画面の「Script」に保存したスクリプトが選ばれているかも確認してください。コードを貼り直すときは全文を置き換えます。
- 図の距離と数値が合わないように見える
- 配置図は縮尺を調整して描画しています。数値と実寸比の図ではありません。
- 天文ソフトと値が違う
- 簡略化した軌道計算による誤差があります。
注意事項・制限
- 惑星の位置は、JPL(ジェット推進研究所)が公開している主要惑星の近似軌道要素をもとに計算しています。
天体観測や研究用途など、高精度な天文位置計算を目的としたウィジェットではありません。 - また、惑星の軌道間隔・惑星サイズは実際の縮尺ではなく、ウィジェット上で見やすくするために調整しています。
ScriptableやiOSの仕様により、ウィジェットの更新時刻は多少前後する場合があります。 - 軌道データ:NASA/JPL「Keplerian Elements for Approximate Positions of the Major Planets」
- 正確な観測計画用の星図ではありません。
- 地球からの距離と太陽からの距離は別の値です。表示の項目名を確認してください。
- ホーム画面の更新タイミングはiOSが管理するため、操作やデータの変更がすぐに反映されない場合があります。
データ提供・参考資料
NASA/JPL 惑星の近似位置計算:コード内の軌道要素による位置計算の参考資料です。
SHARE

