fluxとmagnitudeを二次軸で重ねる：星の表情に触れる可視化

## はじめに

星の明るさを伝えるために、
私たちは二つのものさしを愛用してきました。

flux と magnitude。
線形と対数。

頭では理解している。
……けれど、直感的に引き出せるかと問われれば、答えに詰まるかもしれません。

この二つの世界を自在に行き来できることは、
星のかすかな表情を、見逃さずに捉える力になるでしょう。

<br>

この記事では、
fluxとmagnitude、
この二つの関係を同じグラフに重ねて、可視化していきます。


---

本記事の実装コードは[こちら（Google Colab）](https://colab.research.google.com/drive/1mAJKQqUPKVtyuRxvXmZEeqUq7Jg3AO8Q?usp=sharing)からもご覧いただけます。


## fluxとmagnitudeの変換式

星の明るさを測るとき、  
光の強さ（flux）と等級（magnitude）は、次の式で結ばれています。

```math
m = -2.5 \log_{10}(F) + \text{zero_point}
```

逆に、

```math
F = 10^{-0.4(m - \text{zero_point})}
```

と変換することもできます。

---

また、本記事では誤差の扱いを中心にしていませんが、
実際の測光データ解析では、誤差の変換が必要になる場面も多くあります。

そのため、コードには汎用性を考慮して、誤差も扱える形にしてあります。

ここで、誤差伝搬による変換後の誤差について、簡単に触れておきます。


- magnitudeに誤差 $\sigma_m$ があるとき、fluxの誤差 $\sigma_F$：

```math
\sigma_F = \left| \frac{dF}{dm} \right| \sigma_m = 0.4 \ln(10) \times F \times \sigma_m
```

- fluxに誤差 $\sigma_F$ があるとき、magnitudeの誤差 $\sigma_m$：

```math
\sigma_m = \left| \frac{dm}{dF} \right| \sigma_F = \frac{2.5}{\ln(10)} \times \frac{\sigma_F}{F}
```

## Pythonで変換関数を作る

実際に、Pythonでこの変換をコードにしてみます。
ここでは、誤差の扱いがテーマではないため、単純に2軸表示に特化した方法を紹介します。

### 共通コード（関数定義とダミーデータ）

```python:fluxとmagnitude
import numpy as np
import matplotlib.pyplot as plt

# 変換関数
def create_mag_flux_funcs(zero_point=0.0):
    def mag_to_flux(mag, mag_err=None):
        flux = 10**(-0.4 * (mag - zero_point))
        if mag_err is not None:
            flux_err = 0.4 * np.log(10) * flux * mag_err
            return flux, flux_err
        return flux

    def flux_to_mag(flux, flux_err=None):
        flux_safe = np.clip(flux, 1e-12, np.inf)  # 0以下にならないように小さな値にクリップ
        mag = -2.5 * np.log10(flux_safe) + zero_point
        if flux_err is not None:
            mag_err = (2.5 / np.log(10)) * (flux_err / flux)
            return mag, mag_err
        return mag

    return mag_to_flux, flux_to_mag

# ダミーデータ
np.random.seed(0)
time = np.linspace(0, 5, 100)
true_mag = 13 + 0.5 * np.sin(2 * np.pi * time / 5)
mag_noise = true_mag + np.random.normal(0, 0.05, size=time.shape)

mag_to_flux, flux_to_mag = create_mag_flux_funcs(zero_point=13.0)
flux = mag_to_flux(mag_noise)
```

これで、`mag_to_flux`、`flux_to_mag`の両方を簡単に呼び出せます。

:::note warn
なお、`flux_to_mag()`内では、  
fluxがゼロまたは負になると、$\log_{10}$(flux) の計算で発散が生じます。  

通常のデータ変換では問題になりにくいですが、  
`secondary_axis`は軸目盛りのために幅広い値域で関数を呼び出すため、  
不適切な値が入る可能性があります。

このエラーを防ぐため、fluxの下限値を十分小さな正の値（ここでは $10^{-12}$）にクリップしています。
:::

---

### プロット例1：magnitudeを主軸にして可視化

共通コードで作成したデータを使って、
magnitudeを左軸に、fluxを右軸に表示します。


```python:magnitudeとflux
fig, ax = plt.subplots(figsize=(10, 5))

ax.plot(time, mag_noise, label='Magnitude', color='blue')
ax.set_ylabel('Magnitude', color='blue')
ax.invert_yaxis()

secax = ax.secondary_yaxis('right', functions=(mag_to_flux, flux_to_mag))
secax.set_ylabel('Flux (arb. units)', color='red')

ax.set_xlabel('Time')
ax.grid(True)
plt.title('Light Curve: Magnitude (left) and Flux (right)')
plt.tight_layout()
plt.show()
```
**出力結果**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1599258/1b4f845e-eaa8-435c-b361-d8bc9970ef7f.png)

Magnitudeが13を基準にした時のFluxを右軸に表示しています。

---

### プロット例2：fluxを主軸にして可視化

同様に、fluxを左軸に、magnitudeを右軸に表示します。

```python:flux and mag
fig, ax = plt.subplots(figsize=(10, 5))

ax.plot(time, flux, label='Flux', color='red')
ax.set_ylabel('Flux (arb. units)', color='red')

secax = ax.secondary_yaxis('right', functions=(flux_to_mag, mag_to_flux))
secax.set_ylabel('Magnitude', color='blue')
secax.invert_yaxis()

ax.set_xlabel('Time')
ax.grid(True)
plt.title('Light Curve: Flux (left) and Magnitude (right)')
plt.tight_layout()
plt.show()
```
**出力結果**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1599258/0d38779d-fe69-41c1-a321-65d9f9d0a2ac.png)


# おわりに

私たちが観測する光は、
空の明るさも、大気の揺らぎも、観測装置の震えさえも——
あらゆるものを飲み込んで届きます。

それらすべてが、光という共通のラベルに溶け込み、
数式を介してfluxやmagnitudeへと言語化されます。

けれど。
私たちは、その数式の向こうにある「星の表情」を、
本当に感じ取れているでしょうか。

光をどう受け取り、どう読み取るか。
無数の選択の中から、確かなものを掬い取ること。

それが、星に「意味」を与えるのだと、
以前書いた [この記事](https://qiita.com/yusuke_s_yusuke/items/e83070179956009e69da) が教えてくれました。

<br>

数式でつながっている。
でも、心でつながるには、もう一歩の想像力がいる。

<br>

可視化を通じて、
遠い灯火の知らなかった顔に気づけたとき——
それは、筆を上げるときかもしれません。