1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Pythonで二次元データの重心とピーク位置を計算して可視化する例

Posted at

はじめに

二次元データの重心とピーク位置を計算して可視化する方法を紹介します。

本記事で扱うコードは、以下の2つの機能を持ちます。

  1. 二次元データの重心(バリセンター)と簡易ピーク(最大値)を計算
  2. 計算結果を可視化して正しい動作を検証

これらを通じて、二次元データの重心計算の方法を確認をしましょう。

この記事のコードは、google colab

で再現できます。

また、本記事の calc_center 関数は、xtend_pileup_gen_plfraction.py というコードの中で使われているものを解説したものです。

コアとなる重心計算のコード

概要

calc_center 関数は、以下を実現します:

  • 指定した初期位置を中心とした探索範囲内で簡易ピーク(最大値)を特定
  • 同じ範囲内でデータ値の重みに基づいた重心を計算
  • 探索範囲内の総カウント値を計算

コード

重心計算のコードは短いので、まずはコードをみてみましょう。


import os
import sys
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as cr

params = {'xtick.labelsize': 10, 'ytick.labelsize': 10, 'legend.fontsize': 8}
plt.rcParams['font.family'] = 'serif'
plt.rcParams.update(params)

def calc_center(data, x_center, y_center, search_radius=10):
    """
    Calculate the simple peak (just for consistency check) and barycentric peak.
    
    Parameters:
    data (2D array): The input data array.
    x_center (int): The x-coordinate of the initial guess for the peak.
    y_center (int): The y-coordinate of the initial guess for the peak.
    search_radius (int): The radius around the initial guess to search for the peak. Default is 10.
    
    Returns:
    tuple: The coordinates of the barycentric peak (barycenter_x, barycenter_y) and the total counts (total_counts).
    """
    transposed_data = data.T
    x_indices, y_indices = np.meshgrid(np.arange(-search_radius, search_radius), 
                                       np.arange(-search_radius, search_radius), 
                                       indexing='ij')
    x_indices += x_center
    y_indices += y_center
    
    values = transposed_data[x_indices, y_indices]
    total_counts = np.sum(values)
    
    if total_counts > 0:
        barycenter_x = np.sum(values * x_indices) / total_counts
        barycenter_y = np.sum(values * y_indices) / total_counts
    else:
        print("[ERROR] in calc_center: Total counts are non-positive. Something went wrong.")
        sys.exit(1)

    peak_idx = np.unravel_index(np.argmax(values), values.shape)
    peak_x, peak_y = x_indices[peak_idx], y_indices[peak_idx]
    peak_value = values[peak_idx]

    # Print simple peak and barycenter information
    color_print(f"..... in calc_center: [simple peak] x_max, y_max, z_max = {peak_x}, {peak_y}, {peak_value}", ConsoleColors.OKCYAN)
    color_print(f"..... in calc_center: [barycenter] barycenter_x = {barycenter_x:.2f}, barycenter_y = {barycenter_y:.2f}", ConsoleColors.OKCYAN)
    color_print(f"..... in calc_center: [total counts in search radius] total_counts = {total_counts}", ConsoleColors.OKCYAN)

    if peak_value < 0:
        print("[ERROR] in calc_center: Peak value not found. Something went wrong.")
        sys.exit(1)
        
    return barycenter_x, barycenter_y, total_counts

おまけで、標準出力の色をつけるコードは下記を利用しています。

class ConsoleColors:
    HEADER = '\033[95m'
    OKBLUE = '\033[94m'
    OKCYAN = '\033[96m'
    OKGREEN = '\033[92m'
    WARNING = '\033[93m'
    FAIL = '\033[91m'
    ENDC = '\033[0m'
    BOLD = '\033[1m'
    UNDERLINE = '\033[4m'

def color_print(msg, color):
    print(f"{color}{msg}{ConsoleColors.ENDC}")

重要な処理

探索範囲の設定

x_indices, y_indices = np.meshgrid(
    np.arange(-search_radius, search_radius),
    np.arange(-search_radius, search_radius),
    indexing='ij'
)
x_indices += x_center
y_indices += y_center
  • np.meshgrid を使用して探索範囲の座標を生成。
  • indexing='ij' により、行優先(数学的な行列表現)でグリッドを作成。

重心の計算

if total_counts > 0:
    barycenter_x = np.sum(values * x_indices) / total_counts
    barycenter_y = np.sum(values * y_indices) / total_counts
  • 探索範囲内のデータ値を重みとして重心を計算。

簡易ピークの特定

peak_idx = np.unravel_index(np.argmax(values), values.shape)
peak_x, peak_y = x_indices[peak_idx], y_indices[peak_idx]
  • np.argmax でフラット化した配列の最大値のインデックスを取得。
  • np.unravel_index で元の多次元インデックスに変換。

可視化用の visualize_result 関数

計算結果を可視化するための補助関数を用意します。

import matplotlib.pyplot as plt

# 二次元データの可視化
def visualize_result(data, x_center, y_center, search_radius, barycenter_x, barycenter_y, peak_x, peak_y):
    """
    Visualize the data and the results of calc_center.
    
    Parameters:
    data (2D array): The input data array.
    x_center (int): The x-coordinate of the initial guess for the peak.
    y_center (int): The y-coordinate of the initial guess for the peak.
    search_radius (int): The radius around the initial guess to search for the peak.
    barycenter_x (float): The x-coordinate of the calculated barycenter.
    barycenter_y (float): The y-coordinate of the calculated barycenter.
    peak_x (int): The x-coordinate of the simple peak.
    peak_y (int): The y-coordinate of the simple peak.
    """
    fig, ax = plt.subplots(figsize=(8, 6))
    ax.imshow(data, origin='lower', cmap='viridis', extent=(0, data.shape[1], 0, data.shape[0]))
    ax.set_title("Data Visualization with Peak and Barycenter")
    ax.set_xlabel("X")
    ax.set_ylabel("Y")

    # 探索範囲の描画
    circle = plt.Circle((x_center, y_center), search_radius, color='cyan', fill=False, linestyle='--', label="Search Radius")
    ax.add_artist(circle)

    # 簡易ピークのプロット
    ax.scatter(peak_x, peak_y, color='red', label='Simple Peak', zorder=5)

    # 重心のプロット
    ax.scatter(barycenter_x, barycenter_y, color='yellow', label='Barycenter', zorder=5)

    # 凡例の表示
    ax.legend()
    plt.colorbar(ax.imshow(data, origin='lower', cmap='viridis', extent=(0, data.shape[1], 0, data.shape[0])))
    plt.show()

可視化の特徴

  1. 入力データをカラーマップで描画
  2. 探索範囲を円で表示
  3. 簡易ピークを赤点、重心を黄色点でプロット
  4. 凡例とカラーバーを追加して視覚的にわかりやすく

動作確認と結果の可視化

コード全体の実行例

# ダミーデータの作成
data = np.random.random((100, 100))
x_center, y_center = 50, 50
search_radius = 10

# calc_center を実行
barycenter_x, barycenter_y, total_counts = calc_center(data, x_center, y_center, search_radius)

# 簡易ピークの計算
peak_idx = np.unravel_index(
    np.argmax(data[x_center-search_radius:x_center+search_radius,
                   y_center-search_radius:y_center+search_radius]),
    (2 * search_radius, 2 * search_radius)
)
peak_x = x_center - search_radius + peak_idx[0]
peak_y = y_center - search_radius + peak_idx[1]

# 可視化の実行
visualize_result(data, x_center, y_center, search_radius, barycenter_x, barycenter_y, peak_x, peak_y)

出力例

以下の図が表示されます:

  • 背景: データ値のカラーマップ。
  • 青い円: 探索範囲。
  • 赤い点: 簡易ピーク(最大値)。
  • 黄色い点: 重心。

スクリーンショット 2024-11-23 0.48.21.png

まとめ

探索範囲内での重心を計算する方法を紹介しました。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?