Skip to content
This repository was archived by the owner on Aug 1, 2025. It is now read-only.

Latest commit

 

History

History
1810 lines (1330 loc) · 47.9 KB

File metadata and controls

1810 lines (1330 loc) · 47.9 KB

図の描き方について

Exported on 5/20/2025 at 19:00:16 GMT+9 from Cursor (0.50.5)


User

なんか図を出したい


Cursor

図を表示するプログラムを作成しましょう。Pythonではmatplotlibというライブラリを使って様々な図を描画できます。簡単な例として、折れ線グラフを作成してみましょう。

まず、必要なライブラリをインストールするコマンドを実行します。

では、main.pyを編集して、簡単な折れ線グラフを作成するコードを書きましょう。

import matplotlib.pyplot as plt
import numpy as np

# データの作成
x = np.linspace(0, 10, 100)  # 0から10までの100個の点
y = np.sin(x)  # サイン波

# グラフの作成
plt.figure(figsize=(10, 6))  # グラフのサイズを設定
plt.plot(x, y, label='sin(x)')  # 折れ線グラフを描画
plt.title('サイン波のグラフ')  # タイトル
plt.xlabel('x')  # x軸のラベル
plt.ylabel('y')  # y軸のラベル
plt.grid(True)  # グリッドを表示
plt.legend()  # 凡例を表示

# グラフを表示
plt.show()

このコードを実行すると、サイン波のグラフが表示されます。このコードでは以下のことを行っています:

  1. 必要なライブラリ(matplotlibとnumpy)をインポート
  2. 0から10までの100個の点を生成
  3. それらの点に対してサイン波の値を計算
  4. グラフの設定(サイズ、タイトル、軸ラベル、グリッド、凡例)
  5. グラフの表示

プログラムを実行してみましょう:

グラフが表示されたはずです。これは基本的な例ですが、matplotlibを使うことで以下のような様々な図を作成することができます:

  1. 折れ線グラフ(今回の例)
  2. 棒グラフ
  3. 散布図
  4. 円グラフ
  5. ヒストグラム
  6. 3Dグラフ

特定の種類の図を作成したい場合は、お申し付けください。また、データの種類や表示方法についても、ご要望に応じて調整することができます。


User

何も出ませんでした


Cursor

申し訳ありません。VSCodeの開発コンテナ環境では、グラフを直接表示することができない場合があります。代わりに、グラフを画像ファイルとして保存する方法に変更しましょう。

import matplotlib.pyplot as plt
import numpy as np

# データの作成
x = np.linspace(0, 10, 100)  # 0から10までの100個の点
y = np.sin(x)  # サイン波

# グラフの作成
plt.figure(figsize=(10, 6))  # グラフのサイズを設定
plt.plot(x, y, label='sin(x)')  # 折れ線グラフを描画
plt.title('サイン波のグラフ')  # タイトル
plt.xlabel('x')  # x軸のラベル
plt.ylabel('y')  # y軸のラベル
plt.grid(True)  # グリッドを表示
plt.legend()  # 凡例を表示

# グラフを画像ファイルとして保存
plt.savefig('sine_wave.png')
print("グラフを 'sine_wave.png' として保存しました。")

では、このコードを実行してみましょう:

グラフがsine_wave.pngというファイルとして保存されました。日本語のフォントに関する警告が表示されていますが、グラフ自体は正しく生成されています。

日本語のフォントの問題を解決するために、コードを少し修正しましょう:

import matplotlib.pyplot as plt
import numpy as np

# データの作成
x = np.linspace(0, 10, 100)  # 0から10までの100個の点
y = np.sin(x)  # サイン波

# グラフの作成
plt.figure(figsize=(10, 6))  # グラフのサイズを設定
plt.plot(x, y, label='sin(x)')  # 折れ線グラフを描画
plt.title('Sine Wave')  # タイトル
plt.xlabel('x')  # x軸のラベル
plt.ylabel('y')  # y軸のラベル
plt.grid(True)  # グリッドを表示
plt.legend()  # 凡例を表示

# グラフを画像ファイルとして保存
plt.savefig('sine_wave.png')
print("グラフを 'sine_wave.png' として保存しました。")

もう一度実行してみましょう:

sine_wave.png という画像ファイルが作成されました。
このファイルをエクスプローラーや画像ビューアで開くと、グラフが確認できます。

もし他の種類の図や、別のデータでグラフを作りたい場合は、希望を教えてください!


User

コードが全然なにもわからないので説明してほしい


Cursor

もちろんです!
main.pyのコードを、初心者向けに一行ずつ丁寧に説明します。


import matplotlib.pyplot as plt
import numpy as np
  • matplotlib.pyplotplt)とnumpynp)というライブラリを使います。
    • matplotlibはグラフを描くための道具です。
    • numpyは数値計算やデータ作成に便利な道具です。

# データの作成
x = np.linspace(0, 10, 100)  # 0から10までの100個の点
y = np.sin(x)  # サイン波
  • xという変数に、0から10までを100等分した数字のリストを作ります。
    • 例: [0, 0.1, 0.2, ..., 9.9, 10] みたいな感じです。
  • yは、xのそれぞれの値に「サイン関数」をかけた結果です。
    • サイン関数は波の形を作る関数です(数学のsin)。

# グラフの作成
plt.figure(figsize=(10, 6))  # グラフのサイズを設定
plt.plot(x, y, label='sin(x)')  # 折れ線グラフを描画
plt.title('Sine Wave')  # タイトル
plt.xlabel('x')  # x軸のラベル
plt.ylabel('y')  # y軸のラベル
plt.grid(True)  # グリッドを表示
plt.legend()  # 凡例を表示
  • plt.figure(figsize=(10, 6))
    • グラフの大きさを決めます(横10、縦6の比率)。
  • plt.plot(x, y, label='sin(x)')
    • xとyのデータを線でつないでグラフにします。ラベル(凡例)もつけます。
  • plt.title('Sine Wave')
    • グラフの上にタイトルをつけます。
  • plt.xlabel('x')
    • 横軸の名前を「x」にします。
  • plt.ylabel('y')
    • 縦軸の名前を「y」にします。
  • plt.grid(True)
    • グラフに薄い線(グリッド)を表示します。見やすくなります。
  • plt.legend()
    • 線の説明(凡例)を表示します。

# グラフを画像ファイルとして保存
plt.savefig('sine_wave.png')
print("グラフを 'sine_wave.png' として保存しました。")
  • plt.savefig('sine_wave.png')
    • 作ったグラフを「sine_wave.png」という画像ファイルとして保存します。
  • print(...)
    • 「グラフを保存しました」と画面に表示します。

まとめ

  • 0から10までの数字を作る
  • その数字でサイン波(波の形)を作る
  • そのデータをグラフにして、画像として保存する

もし「この部分がもっと知りたい」「他のグラフも見てみたい」などあれば、気軽に聞いてください!

import matplotlib.pyplot as plt
import numpy as np
# データの作成
x = np.linspace(0, 10, 100)  # 0から10までの100個の点
y = np.sin(x)  # サイン波
# グラフの作成
plt.figure(figsize=(10, 6))  # グラフのサイズを設定
plt.plot(x, y, label='sin(x)')  # 折れ線グラフを描画
plt.title('Sine Wave')  # タイトル
plt.xlabel('x')  # x軸のラベル
plt.ylabel('y')  # y軸のラベル
plt.grid(True)  # グリッドを表示
plt.legend()  # 凡例を表示
# グラフを画像ファイルとして保存
plt.savefig('sine_wave.png')
print("グラフを 'sine_wave.png' として保存しました。")

User

サイン波ってなに?


Cursor

サイン波(サインは、英語で「sine wave」)は、数学でよく出てくる「なみなみした形」の波です。

もっとやさしく説明すると…

  • サイン波は「ゆっくり上がって、ゆっくり下がる」をくり返す、なめらかな波の形です。
  • たとえば、ブランコの動きや、音の振動、電気の交流(コンセントの電気)など、自然界や身の回りのいろんな「くり返しの動き」に現れます。

どんな形?

  • 下のような形です(イメージ):
y
↑
|      /\      /\
|     /    \  /    \
|___/______\/______\____→ x
  • 上がったり下がったり、なめらかに続く波です。

数学的には?

  • 「サイン」は三角関数の一つで、y = sin(x) という式で表されます。
  • xが0のときyは0、xがπ/2(約1.57)のときyは1、xがπ(約3.14)のときyは0、xが3π/2のときyは-1、xが2πのときまた0…というふうに、くり返しのパターンになります。

どこで使われてる?

  • 音(音波)
  • 電気(交流電流)
  • 振り子やブランコの動き
  • 波(海の波や光の波)

もし「もっと図で見たい」「他の例も知りたい」などあれば、教えてください!

y
↑
|      /\      /\
|     /    \  /    \
|___/______\/______\____→ x

User

図をWebで出したい!どうすればいい


Cursor

Pythonで作ったグラフ(サイン波など)をWebブラウザで表示したい場合、いくつか方法があります。
一番簡単なのは「Streamlit(ストリームリット)」というライブラリを使う方法です。


StreamlitでグラフをWeb表示する手順

1. Streamlitをインストール

まず、ターミナルで以下を実行します。

pip install streamlit

2. 新しいファイルを作る

たとえば app.py という名前で、下のようなコードを書きます。

import streamlit as st
import numpy as np
import matplotlib.pyplot as plt

# データ作成
x = np.linspace(0, 10, 100)
y = np.sin(x)

# グラフ作成
fig, ax = plt.subplots()
ax.plot(x, y)
ax.set_title("Sine Wave")
ax.set_xlabel("x")
ax.set_ylabel("y")

# Streamlitで表示
st.pyplot(fig)

3. Webで表示する

ターミナルで下のコマンドを実行します。

streamlit run app.py

4. ブラウザで確認

コマンドを実行すると、
http://localhost:8501」 というURLが表示されるので、
それをブラウザで開くとグラフが見られます!


まとめ

  • Streamlitを使うと、PythonのグラフをWebで簡単に見せられます。
  • 他にも「Dash」や「Flask」など色々な方法がありますが、Streamlitが一番手軽です。

「やってみたい」「コードを作ってほしい」など、何でもどうぞ!

pip install streamlit
import streamlit as st
import numpy as np
import matplotlib.pyplot as plt

# データ作成
x = np.linspace(0, 10, 100)
y = np.sin(x)

# グラフ作成
fig, ax = plt.subplots()
ax.plot(x, y)
ax.set_title("Sine Wave")
ax.set_xlabel("x")
ax.set_ylabel("y")

# Streamlitで表示
st.pyplot(fig)
streamlit run app.py

User

なんかファイルが生成されなかったので、もう一度やって


Cursor

はい、もう一度最初から順番にやっていきましょう。

まず、Streamlitをインストールします:

次に、新しいファイル app.py を作成します:

import streamlit as st
import numpy as np
import matplotlib.pyplot as plt

# タイトルを表示
st.title('サイン波のグラフ')

# データ作成
x = np.linspace(0, 10, 100)
y = np.sin(x)

# グラフ作成
fig, ax = plt.subplots(figsize=(10, 6))
ax.plot(x, y)
ax.set_title("Sine Wave")
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.grid(True)

# Streamlitで表示
st.pyplot(fig)

では、Streamlitアプリを実行してみましょう:

Streamlitアプリが起動しました!以下のURLにアクセスしてください:

http://localhost:8501

このURLをブラウザで開くと、サイン波のグラフが表示されます。

コードの説明

  1. import streamlit as st

    • Streamlitライブラリをインポートします
    • Webアプリを作るための道具です
  2. st.title('サイン波のグラフ')

    • ページのタイトルを表示します
  3. データ作成とグラフ作成の部分は前回と同じです

    • 0から10までの100個の点を作り
    • サイン波の値を計算して
    • グラフを作ります
  4. st.pyplot(fig)

    • 作ったグラフをWebページに表示します

特徴

  • グラフがWebページで見やすく表示されます
  • 自動的にリロードされるので、コードを変更するとすぐに反映されます
  • インタラクティブな要素(スライダーやボタンなど)も簡単に追加できます

もし「グラフの色を変えたい」「スライダーで値を調整したい」など、何か追加の機能が欲しい場合は教えてください!

http://localhost:8501

User

Last.fmのAPIを使って、K-POPの人気の歌をランキングで表示したい!


Cursor

Last.fmのAPIを使ってK-POPの人気曲ランキングを表示するアプリを作りましょう!

まず、Last.fmのAPIキーが必要です。APIキーを取得するには:

  1. Last.fmのアカウントを作成
  2. https://www.last.fm/api/account/create にアクセス
  3. APIキーを取得

APIキーを取得したら、以下のコードを書いていきましょう:

import streamlit as st
import requests
import pandas as pd
from datetime import datetime

# Last.fm APIの設定
API_KEY = "YOUR_API_KEY"  # ここにあなたのAPIキーを入れてください
BASE_URL = "http://ws.audioscrobbler.com/2.0/"

# タイトルを表示
st.title('K-POP 人気曲ランキング')

# 期間を選択
period = st.selectbox(
    "期間を選択してください",
    ["7日間", "1ヶ月", "3ヶ月", "6ヶ月", "12ヶ月", "全体"]
)

# 期間のマッピング
period_map = {
    "7日間": "7day",
    "1ヶ月": "1month",
    "3ヶ月": "3month",
    "6ヶ月": "6month",
    "12ヶ月": "12month",
    "全体": "overall"
}

# Last.fm APIからデータを取得
def get_top_tracks(period):
    params = {
        "method": "tag.gettoptracks",
        "tag": "k-pop",
        "api_key": API_KEY,
        "format": "json",
        "period": period_map[period],
        "limit": 50
    }
    
    response = requests.get(BASE_URL, params=params)
    data = response.json()
    
    if "tracks" in data and "track" in data["tracks"]:
        tracks = data["tracks"]["track"]
        return tracks
    return []

# データを取得して表示
tracks = get_top_tracks(period)

if tracks:
    # データをDataFrameに変換
    df = pd.DataFrame([{
        "順位": i + 1,
        "曲名": track["name"],
        "アーティスト": track["artist"]["name"],
        "再生回数": int(track["playcount"])
    } for i, track in enumerate(tracks)])
    
    # 表として表示
    st.dataframe(df, use_container_width=True)
    
    # 再生回数の棒グラフを作成
    st.subheader("再生回数トップ10")
    top_10 = df.head(10)
    st.bar_chart(top_10.set_index("曲名")["再生回数"])
else:
    st.error("データの取得に失敗しました。APIキーが正しく設定されているか確認してください。")

必要なライブラリをインストールしましょう:

このアプリケーションの機能を説明します:

  1. 期間選択

    • 7日間、1ヶ月、3ヶ月、6ヶ月、12ヶ月、全体から期間を選択できます
    • 選択した期間のK-POP人気曲ランキングが表示されます
  2. データ表示

    • 順位、曲名、アーティスト名、再生回数が表形式で表示されます
    • トップ10の曲の再生回数を棒グラフで視覚化します
  3. 使い方

    1. Last.fmのAPIキーを取得してください
    2. コード内の YOUR_API_KEY を取得したAPIキーに置き換えてください
    3. streamlit run app.py でアプリを起動します

APIキーの取得方法(詳しく)

  1. Last.fmのアカウントを作成(まだの場合)
  2. https://www.last.fm/api/account/create にアクセス
  3. アプリケーション名を入力(例:K-POP Ranking)
  4. 利用規約に同意
  5. APIキーが表示されます

APIキーを取得したら、教えてください。コードを更新してお手伝いします!

また、以下のような機能を追加することもできます:

  • アーティスト別のフィルタリング
  • 再生回数のソート機能
  • 曲の詳細情報(アルバム、リリース日など)の表示
  • グラフの種類の選択(棒グラフ、円グラフなど)

必要な機能があれば、お申し付けください!


User

実行してほしい


Cursor

Streamlitアプリを実行してみましょう:

アプリが起動しました!以下のURLにアクセスしてください:

http://localhost:8501

このURLをブラウザで開くと、以下の機能が使えます:

  1. 期間選択ドロップダウンから期間を選べます

    • 7日間
    • 1ヶ月
    • 3ヶ月
    • 6ヶ月
    • 12ヶ月
    • 全体
  2. 選択した期間のK-POP人気曲ランキングが表示されます

    • 順位
    • 曲名
    • アーティスト名
    • 再生回数
  3. トップ10の曲の再生回数が棒グラフで表示されます

もし「グラフの見た目を変えたい」「他の情報も表示したい」など、何か追加の機能が欲しい場合は教えてください!

http://localhost:8501

User

だめでした

K-POP 人気曲ランキング 期間を選択してください

7日間 KeyError: 'playcount' Traceback: File "/workspaces/girls_ai_scholarshop_example/app.py", line 56, in df = pd.DataFrame([{ ^^ File "/workspaces/girls_ai_scholarshop_example/app.py", line 60, in "再生回数": int(track["playcount"]) ~~~~~^^^^^^^^^^^^^ Ask Google Ask ChatGPT


Cursor

エラーの原因は、Last.fmのAPIレスポンスの形式が想定と異なっていたためです。APIのレスポンスを確認して、コードを修正しましょう。

import streamlit as st
import requests
import pandas as pd
from datetime import datetime

# Last.fm APIの設定
API_KEY = "YOUR_API_KEY"
BASE_URL = "http://ws.audioscrobbler.com/2.0/"

# タイトルを表示
st.title('K-POP 人気曲ランキング')

# 期間を選択
period = st.selectbox(
    "期間を選択してください",
    ["7日間", "1ヶ月", "3ヶ月", "6ヶ月", "12ヶ月", "全体"]
)

# 期間のマッピング
period_map = {
    "7日間": "7day",
    "1ヶ月": "1month",
    "3ヶ月": "3month",
    "6ヶ月": "6month",
    "12ヶ月": "12month",
    "全体": "overall"
}

# Last.fm APIからデータを取得
def get_top_tracks(period):
    params = {
        "method": "tag.gettoptracks",
        "tag": "k-pop",
        "api_key": API_KEY,
        "format": "json",
        "period": period_map[period],
        "limit": 50
    }
    
    response = requests.get(BASE_URL, params=params)
    data = response.json()
    
    # デバッグ情報を表示
    st.write("API Response:", data)
    
    if "tracks" in data and "track" in data["tracks"]:
        tracks = data["tracks"]["track"]
        return tracks
    return []

# データを取得して表示
tracks = get_top_tracks(period)

if tracks:
    # データをDataFrameに変換
    df = pd.DataFrame([{
        "順位": i + 1,
        "曲名": track["name"],
        "アーティスト": track["artist"]["name"],
        "再生回数": track.get("playcount", "N/A")  # playcountがない場合はN/Aを表示
    } for i, track in enumerate(tracks)])
    
    # 表として表示
    st.dataframe(df, use_container_width=True)
    
    # 再生回数が数値の場合のみグラフを表示
    if df["再生回数"].dtype != "object":  # 再生回数が数値型の場合
        st.subheader("再生回数トップ10")
        top_10 = df.head(10)
        st.bar_chart(top_10.set_index("曲名")["再生回数"])
    else:
        st.warning("再生回数のデータが利用できないため、グラフを表示できません。")
else:
    st.error("データの取得に失敗しました。APIキーが正しく設定されているか確認してください。")

主な変更点:

  1. APIレスポンスの内容を表示するようにして、デバッグを容易にしました
  2. playcountが存在しない場合のエラーを防ぐため、get()メソッドを使用
  3. 再生回数が数値でない場合のグラフ表示を制御

では、もう一度実行してみましょう:

アプリが起動しました。以下のURLにアクセスしてください:

http://localhost:8501

APIレスポンスの内容が表示されるので、それを見て必要な修正を行いましょう。もし特定のエラーや問題が表示されたら、教えてください。また、以下のような改善も可能です:

  1. 別のAPIエンドポイントの使用
  2. データの表示形式の変更
  3. エラーハンドリングの強化
  4. キャッシュの追加(API制限対策)

何か特定の問題や改善したい点があれば、お知らせください!

http://localhost:8501

User

なんかJSONで出てて見にくい


Cursor

ご指摘ありがとうございます!
APIレスポンス(JSON)がそのまま表示されて見にくい状態ですね。
本来は「曲名」「アーティスト名」「再生回数」などを表やグラフで見やすく表示したいですよね。

ただし、今のAPIレスポンスには「playcount(再生回数)」が含まれていません。
Last.fmのtag.gettoptracksエンドポイントは、再生回数を返さない場合があります。

まずは「曲名」と「アーティスト名」だけでも表で見やすく表示するように修正します!

また、デバッグ用のJSON表示も消します。

修正版のコードを作成します。

import streamlit as st
import requests
import pandas as pd
from datetime import datetime

# Last.fm APIの設定
API_KEY = "YOUR_API_KEY"
BASE_URL = "http://ws.audioscrobbler.com/2.0/"

# タイトルを表示
st.title('K-POP 人気曲ランキング')

# 期間を選択
period = st.selectbox(
    "期間を選択してください",
    ["7日間", "1ヶ月", "3ヶ月", "6ヶ月", "12ヶ月", "全体"]
)

# 期間のマッピング
period_map = {
    "7日間": "7day",
    "1ヶ月": "1month",
    "3ヶ月": "3month",
    "6ヶ月": "6month",
    "12ヶ月": "12month",
    "全体": "overall"
}

def get_top_tracks(period):
    params = {
        "method": "tag.gettoptracks",
        "tag": "k-pop",
        "api_key": API_KEY,
        "format": "json",
        "period": period_map[period],
        "limit": 50
    }
    response = requests.get(BASE_URL, params=params)
    data = response.json()
    if "tracks" in data and "track" in data["tracks"]:
        tracks = data["tracks"]["track"]
        return tracks
    return []

tracks = get_top_tracks(period)

if tracks:
    df = pd.DataFrame([{
        "順位": i + 1,
        "曲名": track["name"],
        "アーティスト": track["artist"]["name"]
    } for i, track in enumerate(tracks)])
    st.dataframe(df, use_container_width=True)
else:
    st.error("データの取得に失敗しました。APIキーが正しく設定されているか、Last.fmの仕様が変わっていないかご確認ください。")

これで、曲名とアーティスト名が表で見やすく表示されるようになります。
もう一度アプリを実行して、表が正しく表示されるかご確認ください!

もし「他の情報も表示したい」「再生回数も見たい」などご要望があれば、また教えてください。
(Last.fmの他のAPIや、別の方法もご提案できます!)


User

まだエラーがでています


Cursor

import streamlit as st
import requests
import pandas as pd
from datetime import datetime

# Last.fm APIの設定
API_KEY = "YOUR_API_KEY"
BASE_URL = "http://ws.audioscrobbler.com/2.0/"

# タイトルを表示
st.title('K-POP 人気曲ランキング')

# 期間を選択
period = st.selectbox(
    "期間を選択してください",
    ["7日間", "1ヶ月", "3ヶ月", "6ヶ月", "12ヶ月", "全体"]
)

# 期間のマッピング
period_map = {
    "7日間": "7day",
    "1ヶ月": "1month",
    "3ヶ月": "3month",
    "6ヶ月": "6month",
    "12ヶ月": "12month",
    "全体": "overall"
}

def get_top_tracks(period):
    params = {
        "method": "tag.gettoptracks",
        "tag": "k-pop",
        "api_key": API_KEY,
        "format": "json",
        "period": period_map[period],
        "limit": 50
    }
    response = requests.get(BASE_URL, params=params)
    data = response.json()
    if "tracks" in data and "track" in data["tracks"]:
        tracks = data["tracks"]["track"]
        return tracks
    return []

tracks = get_top_tracks(period)

if tracks:
    df = pd.DataFrame([{
        "順位": i + 1,
        "曲名": track.get("name", "不明"),
        "アーティスト": track.get("artist", {}).get("name", "不明")
    } for i, track in enumerate(tracks)])
    st.dataframe(df, use_container_width=True)
else:
    st.error("データの取得に失敗しました。APIキーが正しく設定されているか、Last.fmの仕様が変わっていないかご確認ください。")

アーティスト名や曲名が存在しない場合でもエラーにならないように修正しました。

これでKeyErrorが発生しにくくなります。
もう一度アプリを実行して、表が正しく表示されるかご確認ください。

もしまだエラーが出る場合は、画面に表示されるエラーメッセージを教えてください。さらに詳しく調査します!


User

再起動が必要ですか?


Cursor

はい、Streamlitアプリ(app.py)のコードを修正した場合は、**再起動(リロード)**が必要です。

再起動の方法

  1. すでにStreamlitを起動しているターミナルで、Ctrl + C を押して一度停止します。
  2. もう一度、以下のコマンドを実行します。
streamlit run app.py

これで最新のコードが反映されます!

もし「自動でリロードされる」と表示されている場合でも、エラーが出ていた場合は一度手動で再起動するのが確実です。

何かうまくいかない場合は、また教えてください!

streamlit run app.py

User

再起動してほしい


Cursor

Streamlitアプリを再起動しました!
再度、以下のURLにアクセスして動作をご確認ください。

http://localhost:8501

もし表示や動作に問題があれば、また教えてください!

http://localhost:8501

User

JSONが出ているやつは消してほしい


Cursor

import streamlit as st
import requests
import pandas as pd
from datetime import datetime

# Last.fm APIの設定
API_KEY = "YOUR_API_KEY"
BASE_URL = "http://ws.audioscrobbler.com/2.0/"

# タイトルを表示
st.title('K-POP 人気曲ランキング')

# 期間を選択
period = st.selectbox(
    "期間を選択してください",
    ["7日間", "1ヶ月", "3ヶ月", "6ヶ月", "12ヶ月", "全体"]
)

# 期間のマッピング
period_map = {
    "7日間": "7day",
    "1ヶ月": "1month",
    "3ヶ月": "3month",
    "6ヶ月": "6month",
    "12ヶ月": "12month",
    "全体": "overall"
}

def get_top_tracks(period):
    params = {
        "method": "tag.gettoptracks",
        "tag": "k-pop",
        "api_key": API_KEY,
        "format": "json",
        "period": period_map[period],
        "limit": 50
    }
    response = requests.get(BASE_URL, params=params)
    data = response.json()
    if "tracks" in data and "track" in data["tracks"]:
        tracks = data["tracks"]["track"]
        return tracks
    return []

tracks = get_top_tracks(period)

if tracks:
    df = pd.DataFrame([{
        "順位": i + 1,
        "曲名": track.get("name", "不明"),
        "アーティスト": track.get("artist", {}).get("name", "不明")
    } for i, track in enumerate(tracks)])
    st.dataframe(df, use_container_width=True)
else:
    st.error("データの取得に失敗しました。APIキーが正しく設定されているか、Last.fmの仕様が変わっていないかご確認ください。")

APIレスポンスのデバッグ用JSON表示(st.write("API Response:", data))を削除しました。

これで画面にJSONが表示されなくなります。
再度アプリをリロードしてご確認ください!


User

コードせつめいして


Cursor

もちろんです!
今の app.py のコードを、初心者向けにやさしく説明します。


1. ライブラリの読み込み

import streamlit as st
import requests
import pandas as pd
from datetime import datetime
  • streamlit:Webアプリを作るためのライブラリ
  • requests:Webからデータを取ってくるためのライブラリ
  • pandas:表(データフレーム)を作るためのライブラリ
  • datetime:日付や時間を扱うためのライブラリ(今回は使っていませんが、よく使います)

2. Last.fm APIの設定

API_KEY = "YOUR_API_KEY"
BASE_URL = "http://ws.audioscrobbler.com/2.0/"
  • API_KEY:Last.fmから取得した自分専用の「合言葉」
  • BASE_URL:Last.fmのデータを取りに行くためのURL

3. タイトルの表示

st.title('K-POP 人気曲ランキング')
  • Webページの一番上に大きなタイトルを表示します

4. 期間の選択

period = st.selectbox(
    "期間を選択してください",
    ["7日間", "1ヶ月", "3ヶ月", "6ヶ月", "12ヶ月", "全体"]
)
  • ユーザーが「どの期間のランキングを見たいか」選べるようにします

5. 期間のマッピング

period_map = {
    "7日間": "7day",
    "1ヶ月": "1month",
    "3ヶ月": "3month",
    "6ヶ月": "6month",
    "12ヶ月": "12month",
    "全体": "overall"
}
  • Last.fmのAPIに送るための「英語の期間名」と「日本語の期間名」を対応させています

6. Last.fm APIからデータを取得する関数

def get_top_tracks(period):
    params = {
        "method": "tag.gettoptracks",
        "tag": "k-pop",
        "api_key": API_KEY,
        "format": "json",
        "period": period_map[period],
        "limit": 50
    }
    response = requests.get(BASE_URL, params=params)
    data = response.json()
    if "tracks" in data and "track" in data["tracks"]:
        tracks = data["tracks"]["track"]
        return tracks
    return []
  • Last.fmのAPIに「K-POPの人気曲を教えて!」とリクエストを送ります
  • 返ってきたデータ(JSON)から曲のリストを取り出します

7. データを取得して表にする

tracks = get_top_tracks(period)

if tracks:
    df = pd.DataFrame([{
        "順位": i + 1,
        "曲名": track.get("name", "不明"),
        "アーティスト": track.get("artist", {}).get("name", "不明")
    } for i, track in enumerate(tracks)])
    st.dataframe(df, use_container_width=True)
else:
    st.error("データの取得に失敗しました。APIキーが正しく設定されているか、Last.fmの仕様が変わっていないかご確認ください。")
  • 取得した曲リストを「順位」「曲名」「アーティスト名」の表(データフレーム)にします
  • その表をWebページに表示します
  • もしデータが取れなかったらエラーメッセージを表示します

まとめ

  • ユーザーが期間を選ぶ
  • Last.fmからK-POPの人気曲リストを取得
  • 曲名とアーティスト名を表でWebに表示

もし「この部分をもっと詳しく知りたい」「他の機能も追加したい」などあれば、気軽に聞いてください!

import streamlit as st
import requests
import pandas as pd
from datetime import datetime
API_KEY = "YOUR_API_KEY"
BASE_URL = "http://ws.audioscrobbler.com/2.0/"
st.title('K-POP 人気曲ランキング')
period = st.selectbox(
    "期間を選択してください",
    ["7日間", "1ヶ月", "3ヶ月", "6ヶ月", "12ヶ月", "全体"]
)
period_map = {
    "7日間": "7day",
    "1ヶ月": "1month",
    "3ヶ月": "3month",
    "6ヶ月": "6month",
    "12ヶ月": "12month",
    "全体": "overall"
}
def get_top_tracks(period):
    params = {
        "method": "tag.gettoptracks",
        "tag": "k-pop",
        "api_key": API_KEY,
        "format": "json",
        "period": period_map[period],
        "limit": 50
    }
    response = requests.get(BASE_URL, params=params)
    data = response.json()
    if "tracks" in data and "track" in data["tracks"]:
        tracks = data["tracks"]["track"]
        return tracks
    return []
tracks = get_top_tracks(period)

if tracks:
    df = pd.DataFrame([{
        "順位": i + 1,
        "曲名": track.get("name", "不明"),
        "アーティスト": track.get("artist", {}).get("name", "不明")
    } for i, track in enumerate(tracks)])
    st.dataframe(df, use_container_width=True)
else:
    st.error("データの取得に失敗しました。APIキーが正しく設定されているか、Last.fmの仕様が変わっていないかご確認ください。")

User

1000件出してほしい


Cursor

Last.fmのAPIでは、一度のリクエストで取得できる件数(limit)は最大100件までです。
1000件取得したい場合は、ページネーション(複数回リクエストしてデータを集める)を使う必要があります。

これから、ページを切り替えながら最大1000件まで取得するようにコードを修正します!

少しお待ちください。

import streamlit as st
import requests
import pandas as pd
from datetime import datetime

# Last.fm APIの設定
API_KEY = "YOUR_API_KEY"
BASE_URL = "http://ws.audioscrobbler.com/2.0/"

# タイトルを表示
st.title('K-POP 人気曲ランキング')

# 期間を選択
period = st.selectbox(
    "期間を選択してください",
    ["7日間", "1ヶ月", "3ヶ月", "6ヶ月", "12ヶ月", "全体"]
)

# 期間のマッピング
period_map = {
    "7日間": "7day",
    "1ヶ月": "1month",
    "3ヶ月": "3month",
    "6ヶ月": "6month",
    "12ヶ月": "12month",
    "全体": "overall"
}

def get_top_tracks(period, total_limit=1000):
    all_tracks = []
    per_page = 100  # Last.fmのAPIの最大limit
    for page in range(1, (total_limit // per_page) + 2):
        params = {
            "method": "tag.gettoptracks",
            "tag": "k-pop",
            "api_key": API_KEY,
            "format": "json",
            "period": period_map[period],
            "limit": per_page,
            "page": page
        }
        response = requests.get(BASE_URL, params=params)
        data = response.json()
        if "tracks" in data and "track" in data["tracks"]:
            tracks = data["tracks"]["track"]
            all_tracks.extend(tracks)
            if len(tracks) < per_page:
                break  # これ以上データがない場合は終了
        else:
            break
        if len(all_tracks) >= total_limit:
            break
    return all_tracks[:total_limit]

tracks = get_top_tracks(period, total_limit=1000)

if tracks:
    df = pd.DataFrame([{
        "順位": i + 1,
        "曲名": track.get("name", "不明"),
        "アーティスト": track.get("artist", {}).get("name", "不明")
    } for i, track in enumerate(tracks)])
    st.dataframe(df, use_container_width=True)
else:
    st.error("データの取得に失敗しました。APIキーが正しく設定されているか、Last.fmの仕様が変わっていないかご確認ください。")

これで最大1000件までK-POPの人気曲を取得し、表で表示できるようになりました!

アプリを再度リロードしてご確認ください。
もし他にも「表示件数を変えたい」「特定のアーティストだけ見たい」などご要望があれば教えてください!


User

PythonのFor文ってどういう仕組み?


Cursor

Pythonのfor文は、「リストや範囲など、複数の値を順番に取り出して、同じ処理をくり返す」ための仕組みです。


1. 基本の形

for 変数 in データの集まり:
    繰り返したい処理
  • 変数 には、データの集まりから1つずつ値が入ります。
  • データの集まり には、リストやrangeなど「たくさんの値」が入ります。

2. 例:リストを使ったfor文

fruits = ["りんご", "バナナ", "みかん"]

for fruit in fruits:
    print(fruit)

実行結果:

りんご
バナナ
みかん

3. 例:range()を使ったfor文

for i in range(5):
    print(i)

実行結果:

0
1
2
3
4
  • range(5) は「0, 1, 2, 3, 4」という5つの数字を順番に出します。

4. 例:for文でリストを作る(リスト内包表記)

squares = [i * i for i in range(5)]
print(squares)

実行結果:

[0, 1, 4, 9, 16]

5. for文の仕組み(イメージ)

  • 「箱(リストやrange)」から1つずつ値を取り出して、:の下の処理を何度も実行します。
  • すべての値を使い終わったら、for文は終わります。

6. 応用:辞書や文字列でも使える

# 文字列
for c in "hello":
    print(c)
# 辞書
d = {"a": 1, "b": 2}
for key in d:
    print(key, d[key])

まとめ

  • for文は「たくさんの値を順番に処理したいとき」に使う
  • 1つずつ値を取り出して、同じ処理をくり返す

もし「もっと詳しく知りたい」「具体的な例が見たい」などあれば、気軽に聞いてください!

for 変数 in データの集まり:
    繰り返したい処理
fruits = ["りんご", "バナナ", "みかん"]

for fruit in fruits:
    print(fruit)
りんご
バナナ
みかん
for i in range(5):
    print(i)
0
1
2
3
4
squares = [i * i for i in range(5)]
print(squares)
[0, 1, 4, 9, 16]
# 文字列
for c in "hello":
    print(c)
# 辞書
d = {"a": 1, "b": 2}
for key in d:
    print(key, d[key])

User

Red Velvetのランキングを5倍にしてほしい


Cursor

import streamlit as st
import requests
import pandas as pd
from datetime import datetime

# Last.fm APIの設定
API_KEY = "YOUR_API_KEY"
BASE_URL = "http://ws.audioscrobbler.com/2.0/"

# タイトルを表示
st.title('K-POP 人気曲ランキング')

# 期間を選択
period = st.selectbox(
    "期間を選択してください",
    ["7日間", "1ヶ月", "3ヶ月", "6ヶ月", "12ヶ月", "全体"]
)

# 期間のマッピング
period_map = {
    "7日間": "7day",
    "1ヶ月": "1month",
    "3ヶ月": "3month",
    "6ヶ月": "6month",
    "12ヶ月": "12month",
    "全体": "overall"
}

def get_top_tracks(period, total_limit=1000):
    all_tracks = []
    per_page = 100  # Last.fmのAPIの最大limit
    for page in range(1, (total_limit // per_page) + 2):
        params = {
            "method": "tag.gettoptracks",
            "tag": "k-pop",
            "api_key": API_KEY,
            "format": "json",
            "period": period_map[period],
            "limit": per_page,
            "page": page
        }
        response = requests.get(BASE_URL, params=params)
        data = response.json()
        if "tracks" in data and "track" in data["tracks"]:
            tracks = data["tracks"]["track"]
            all_tracks.extend(tracks)
            if len(tracks) < per_page:
                break  # これ以上データがない場合は終了
        else:
            break
        if len(all_tracks) >= total_limit:
            break
    return all_tracks[:total_limit]

tracks = get_top_tracks(period, total_limit=1000)

if tracks:
    df = pd.DataFrame([{
        "順位": (i + 1) * 5 if track.get("artist", {}).get("name", "").lower() == "red velvet" else i + 1,
        "曲名": track.get("name", "不明"),
        "アーティスト": track.get("artist", {}).get("name", "不明")
    } for i, track in enumerate(tracks)])
    st.dataframe(df, use_container_width=True)
else:
    st.error("データの取得に失敗しました。APIキーが正しく設定されているか、Last.fmの仕様が変わっていないかご確認ください。")

Red Velvetの曲だけ「順位」を5倍にして表示するように修正しました!

アプリをリロードして、Red Velvetの曲の順位が他の曲より大きな数字(5倍)になっているかご確認ください。

他にも「特定のアーティストだけ色を変えたい」など、ご要望があれば教えてください!


User

100倍にしてほしい


Cursor

if tracks:
    df = pd.DataFrame([{
        "順位": (i + 1) * 100 if track.get("artist", {}).get("name", "").lower() == "red velvet" else i + 1,
        "曲名": track.get("name", "不明"),
        "アーティスト": track.get("artist", {}).get("name", "不明")
    } for i, track in enumerate(tracks)])
    st.dataframe(df, use_container_width=True)
else:
    st.error("データの取得に失敗しました。APIキーが正しく設定されているか、Last.fmの仕様が変わっていないかご確認ください。")

Red Velvetの曲だけ順位を「100倍」にして表示するよう修正しました!

アプリをリロードして、Red Velvetの曲の順位が他の曲より大きな数字(100倍)になっているかご確認ください。

他にもご要望があれば、気軽にどうぞ!


User

順位を50倍にすると、ランキングが下がっていまう


Cursor

とても良い気づきです!

「順位を50倍にする」というのは、たとえば本来3位だったRed Velvetの曲が「3 × 50 = 150位」になってしまう、ということです。
つまり「ランキングが下がる(順位の数字が大きくなる)」ということになります。


ランキングの数字の意味

  • 順位の数字が小さいほど上位(1位が一番上)
  • 順位の数字が大きいほど下位(100位など)

もし「Red Velvetの曲を上位にしたい」場合

  • 順位の数字を小さくする必要があります。
  • たとえば「順位を1/50にする」や「1位に固定する」などの方法があります。

例:Red Velvetの曲を1位にする

"順位": 1 if track.get("artist", {}).get("name", "").lower() == "red velvet" else i + 1,

例:Red Velvetの曲の順位を半分にする(上位に近づける)

"順位": max(1, (i + 1) // 2) if track.get("artist", {}).get("name", "").lower() == "red velvet" else i + 1,

まとめ

  • 「順位を大きくする」=ランキングが下がる
  • 「順位を小さくする」=ランキングが上がる

「Red Velvetの曲を上位にしたい」場合、どんな順位にしたいか教えてもらえれば、そのように修正します!

"順位": 1 if track.get("artist", {}).get("name", "").lower() == "red velvet" else i + 1,
"順位": max(1, (i + 1) // 2) if track.get("artist", {}).get("name", "").lower() == "red velvet" else i + 1,

User

テストコードを追加してほしい


Cursor

承知しました!
app.pyの「Red Velvetの曲だけ順位を変える」ロジック部分をテストするためのテストコード(ユニットテスト)を追加します。

Pythonではpytestというテストフレームワークがよく使われます。
ここでは、順位計算のロジックを関数として切り出し、その関数に対するテストコード(例:test_app.py)を作成します。

まずはロジックを関数化し、次にテストファイルを作成します。

# ... 既存のimportなどはそのまま ...

def calc_rank(i, track, multiplier=100):
    """
    Red Velvetの曲だけ順位をmultiplier倍にする。
    """
    artist = track.get("artist", {}).get("name", "").lower()
    if artist == "red velvet":
        return (i + 1) * multiplier
    else:
        return i + 1

# ... 既存のコード ...

if tracks:
    df = pd.DataFrame([{
        "順位": calc_rank(i, track, multiplier=100),
        "曲名": track.get("name", "不明"),
        "アーティスト": track.get("artist", {}).get("name", "不明")
    } for i, track in enumerate(tracks)])
    st.dataframe(df, use_container_width=True)
else:
    st.error("データの取得に失敗しました。APIキーが正しく設定されているか、Last.fmの仕様が変わっていないかご確認ください。")
import pytest
from app import calc_rank

def test_calc_rank_red_velvet():
    track = {"artist": {"name": "Red Velvet"}}
    assert calc_rank(0, track, multiplier=100) == 100
    assert calc_rank(1, track, multiplier=100) == 200
    assert calc_rank(4, track, multiplier=100) == 500

def test_calc_rank_other_artist():
    track = {"artist": {"name": "BTS"}}
    assert calc_rank(0, track, multiplier=100) == 1
    assert calc_rank(1, track, multiplier=100) == 2
    assert calc_rank(4, track, multiplier=100) == 5

def test_calc_rank_case_insensitive():
    track = {"artist": {"name": "red velvet"}}
    assert calc_rank(2, track, multiplier=50) == 150
    track = {"artist": {"name": "RED VELVET"}}
    assert calc_rank(2, track, multiplier=50) == 150

def test_calc_rank_missing_artist():
    track = {"artist": {}}
    assert calc_rank(0, track, multiplier=100) == 1
    track = {}
    assert calc_rank(0, track, multiplier=100) == 1

テスト実行時にKeyError: '再生回数'が発生しています。
これは、app.pyのグローバル実行部分でdf["再生回数"]を参照しているため、テスト時にエラーとなっています。

テストしやすいように、app.pyの実行部分をif __name__ == "__main__":で囲み、テスト時には実行されないように修正します。

# ... 既存のコード ...

if __name__ == "__main__":
    tracks = get_top_tracks(period, total_limit=1000)

    if tracks:
        df = pd.DataFrame([{
            "順位": calc_rank(i, track, multiplier=100),
            "曲名": track.get("name", "不明"),
            "アーティスト": track.get("artist", {}).get("name", "不明")
        } for i, track in enumerate(tracks)])
        st.dataframe(df, use_container_width=True)
    else:
        st.error("データの取得に失敗しました。APIキーが正しく設定されているか、Last.fmの仕様が変わっていないかご確認ください。")

テストはすべて成功しました!(4件すべてパス)

これで、Red Velvetの曲だけ順位を変えるロジックが正しく動作していることが確認できました。

  • テストはtest_app.pyに書かれており、pytest test_app.pyで実行できます。
  • 今後もロジックを変更したときは、テストを実行すれば安心です。

他にもテストしたい内容や、テストの書き方について知りたいことがあれば、気軽にどうぞ!