物理の駅 Physics station by 現役研究者

テクノロジーは共有されてこそ栄える

MacでPython 3をインストールする方法

HomeBrewをインストール

brew.sh

上記のサイトにシェルコマンドが載ってる。記事執筆時は

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

だった。HomeBrewを入れると、ついでにXcodeもインストールされる。

PATHを通せよと言われたので

Warning: /opt/homebrew/bin is not in your PATH.
  Instructions on how to configure your shell for Homebrew
  can be found in the 'Next steps' section below.

大人しく従う。

==> Next steps:
- Run these three commands in your terminal to add Homebrew to your PATH:
    echo '# Set PATH, MANPATH, etc., for Homebrew.' >> ~/.zprofile
    echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile
    eval "$(/opt/homebrew/bin/brew shellenv)"

Pythonのインストール

brew install python3

必須パッケージをインストール

pip3 install numpy scipy jupyter jupyterlab matplotlib

と、色々エラーが出たので、PATHを ~/.zprofile に追加する

echo 'export PATH="~/Library/Python/3.9/bin:$PATH"' >> ~/.zprofile
source ~/.zprofile

もう一度必須パッケージをインストール

pip3 install numpy scipy jupyter jupyterlab matplotlib

jupyterを開くと jupyter lab build せよと言われ、すると node.jsをインストールせよと言われるので、まずnodeをインストールする

brew install node

次に jupyter labをbuild

jupyter lab build

ローカル環境で使うときは

jupyter lab

SSH経由でログインするときは

ssh user@pcname -L 8889:localhost:8889

とログインした状態で

jupyter lab --no-browser --port 8889

とすると、ローカル環境から http://127.0.0.1:8889/lab?token=***************** でアクセスできる

Jupyter上のサンプルコード

import matplotlib.pyplot as plt
import numpy as np

plt.rcParams['figure.figsize'] = [5, 4]
np.random.seed(0)
plt.hist(np.random.randn(1000),range=[-5,5],bins=50)
plt.ylim(0,110)
plt.show()

日本語を使う場合は font.family で日本語を含む書体ファミリーを設定する

import matplotlib.pyplot as plt
import numpy as np

import matplotlib
matplotlib.rcParams['font.family'] = ['Hiragino sans'] #ヒラギノに設定

plt.rcParams['figure.figsize'] = [5, 4]
np.random.seed(0)
plt.hist(np.random.randn(1000),range=[-5,5],bins=50)
plt.ylim(0,110)
plt.xlabel("X軸")
plt.ylabel("Y軸")
plt.show()

Python OpenCV 大量のアイコンからモザイクアートを作ってみる

Pythonで実装してみた

元画像を読み込むところ。BGRに分割し、分割された領域ごとの平均輝度値を求める

import cv2
import glob
import numpy as np

orgfile = "original02.png"
orgimg = cv2.imread(orgfile)

P=20 #分割する縦横のピクセル数
Nx = int(orgimg.shape[1]/P)
Ny = int(orgimg.shape[0]/P)
N = Nx*Ny

assert(P*Nx==orgimg.shape[1]) #割り切れることを確認
assert(P*Ny==orgimg.shape[0]) #割り切れることを確認

print("横方向のピクセル数 width =",orgimg.shape[1])
print("横方向の分割数",Nx)
print("縦方向のピクセル数 height=",orgimg.shape[0])
print("縦方向の分割数",Ny)

orgimg_bgr = cv2.split(orgimg)
orgmean_bgr = [[],[],[]]
for ic in range(3):
    for iy in range(Ny):
        for ix in range(Nx):
            orgmean_bgr[ic].append(np.mean(orgimg_bgr[ic][iy*P:(iy+1)*P,ix*P:(ix+1)*P]))

アイコン画像を読み込むところ。各アイコンの平均輝度値を計算する

#モザイクで使うアイコン画像の読み込み

files = glob.glob("thumbnails\\*.png")
print("アイコン画像数",len(files))
meanb = []
meang = []
meanr = []
flag = []
W=150 #アイコン画像の横幅

for i,filename in enumerate(files):
    img = cv2.imread(filename)
    assert(img.shape[0]==W)
    assert(img.shape[1]==W)
    img_bgr = cv2.split(img)
    meanb.append(np.mean(img_bgr[0]))
    meang.append(np.mean(img_bgr[1]))
    meanr.append(np.mean(img_bgr[2]))
    flag.append(False)    

端から作成するとモザイクっぽくならない。画像内でランダムな場所から似た画像を調べるため、乱数を作成

seed=0
rs = np.random.RandomState(seed)
order = []
for i in range(N):
    order.append(i)
rs.shuffle(order)

元画像のBGRの輝度値とアイコン画像の輝度値の差から、最も近いアイコン画像を選ぶ

imglist = []
for i in order:
    ix=i%Nx
    iy=i//Nx
    vmin = 255*3
    jmin = -1
    orgb = orgmean_bgr[0][i]
    orgg = orgmean_bgr[1][i]
    orgr = orgmean_bgr[2][i]
    for j,(b,g,r) in enumerate(zip(meanb,meang,meanr)):
        if flag[j]:continue
        v = abs(orgb-b)+abs(orgg-g)+abs(orgr-r)
        if vmin>v:
            vmin=v
            jmin=j
    imglist.append(jmin)
    flag[jmin]=True

アイコンを張り合わせてモザイク画像を作成、出力

dst = np.zeros((Ny*W, Nx*W, 3))
print("横方向のピクセル数 width =",dst.shape[1])
print("縦方向のピクセル数 height=",dst.shape[0])
for i,j in zip(order,imglist):
    img = cv2.imread(files[j])
    ix=i%Nx
    iy=i//Nx
    dst[iy*W:(iy+1)*W, ix*W:(ix+1)*W] = img
cv2.imwrite(f"mosaic_Nx{Nx}_Ny{Ny}.png",dst)
print("出力完了")

Python tweepy Twitter APIの使い方 (メモ)

可能な限り全てのツイートを検索して取得する。ただし、サーチバン等により検索で出て来ないツイートは取得できない。

import tweepy

tweets = []
query = "物理の駅"
for page in tweepy.Cursor(api.search_tweets,q=query, tweet_mode='extended',result_type="mixed",lang='ja').pages():
    time.sleep(5)
    for tweet in page:
        tweets.append(tweet._json)

少数でいいならこういう方法もある

item_number = 10
tweets = tweepy.Cursor(api.search_tweets,q=search_word, tweet_mode='extended',result_type="mixed",lang='ja').items(item_number)

ユーザー情報を取得

user = api.get_user(screen_name='twitter')
print(user._json)

結果

{'id': 783214, 'id_str': '783214', 'name': 'Twitter', 'screen_name': 'Twitter', 'location': 'everywhere', 'profile_location': None, 'description': "What's happening?!", 'url': 'https://t.co/DAtOo6uuHk', 'entities': {'url': {'urls': [{'url': 'https://t.co/DAtOo6uuHk', 'expanded_url': 'https://about.twitter.com/', 'display_url': 'about.twitter.com', 'indices': [0, 23]}]}, 'description': {'urls': []}}, 'protected': False, 'followers_count': 65036598, 'friends_count': 5, 'listed_count': 87347, 'created_at': 'Tue Feb 20 14:35:54 +0000 2007', 'favourites_count': 6201, 'utc_offset': None, 'time_zone': None, 'geo_enabled': True, 'verified': True, 'statuses_count': 15043, 'lang': None, 'status': {'created_at': 'Thu Oct 13 21:41:45 +0000 2022', 'id': 1580675180602413057, 'id_str': '1580675180602413057', 'text': '@ElenbaasHier 🥺', 'truncated': False, 'entities': {'hashtags': [], 'symbols': [], 'user_mentions': [{'screen_name': 'ElenbaasHier', 'name': 'Katelijne', 'id': 1551146624294035456, 'id_str': '1551146624294035456', 'indices': [0, 13]}], 'urls': []}, 'source': '<a href="https://mobile.twitter.com" rel="nofollow">Twitter Web App</a>', 'in_reply_to_status_id': 1580665048271577088, 'in_reply_to_status_id_str': '1580665048271577088', 'in_reply_to_user_id': 1551146624294035456, 'in_reply_to_user_id_str': '1551146624294035456', 'in_reply_to_screen_name': 'ElenbaasHier', 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'is_quote_status': False, 'retweet_count': 16, 'favorite_count': 1781, 'favorited': False, 'retweeted': False, 'lang': 'und'}, 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': 'ACDED6', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme18/bg.gif', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme18/bg.gif', 'profile_background_tile': True, 'profile_image_url': 'http://pbs.twimg.com/profile_images/1488548719062654976/u6qfBBkF_normal.jpg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/1488548719062654976/u6qfBBkF_normal.jpg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/783214/1646075315', 'profile_link_color': '1B95E0', 'profile_sidebar_border_color': 'FFFFFF', 'profile_sidebar_fill_color': 'F6F6F6', 'profile_text_color': '333333', 'profile_use_background_image': True, 'has_extended_profile': True, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'regular', 'withheld_in_countries': []}

フォローしてるユーザーを取得

for friend in user.friends():
    print(friend.screen_name)

フォロワーを取得

count = 500
followers = []
for page in tweepy.Cursor(api.get_followers, screen_name="twitter",count=200).pages():
    followers += [user._json for user in page]
    print("取得数",len(followers))
    if len(followers)>count:break

ホームタイムラインを40個取得

count=40
tweets = []
max_id = None
while True:
    home_timeline = api.home_timeline(max_id=max_id)
    tweets += [tweet._json for tweet in home_timeline]
    print(len(tweets))
    max_id=tweets[-1]["id"]-1
    if len(tweets)>=count:break
for tweet in tweets:
    print(tweet["created_at"],tweet["user"]["name"],"@",tweet["user"]["screen_name"])

メンションを40個取得

count=40
tweets = []
max_id = None
while True:
    mentions_timeline = api.mentions_timeline(max_id=max_id)
    tweets += [tweet._json for tweet in mentions_timeline]
    print(len(tweets))
    max_id=tweets[-1]["id"]-1
    if len(tweets)>=count:break
for tweet in tweets:
    print(tweet["created_at"],"https://twitter.com/{}/status/{}".format(tweet["user"]["screen_name"],tweet["id"]))

Python tweepy twitterの標準検索APIの仕様 (日本語訳)

https://docs.tweepy.org/en/latest/api.html#tweepy.API.search_tweets

API.search_tweets(q, *, geocode, lang, locale, result_type, count, until, since_id, max_id, include_entities)

Returns a collection of relevant Tweets matching a specified query.
指定されたクエリ(q)に一致する関連ツイートのコレクションを戻します

注: クエリには色んな指定が可能

  • exclude:retweets リツイートを除く (オリジナルツイートを検索したい場合は付ける -filter:retweet と同じ)
  • until:2022-10-25_00:30:00_JST 日本時間で指定の時間までのツイート
  • since:2022-10-25_00:00:00_JST 日本時間で指定の時間よりあとのツイート
  • -ワード ワードを除く
  • -#ワード #ワードを除く

Please note that Twitter’s search service and, by extension, the Search API is not meant to be an exhaustive source of Tweets. Not all Tweets will be indexed or made available via the search interface.
Twitterの検索サービス、さらにSearch APIは、Tweetを完全な形で提供しているわけではありません。全てのTweetがインデックスに登録され、検索インターフェースから利用できるわけではありません。

Note

Twitter’s standard search API only “searches against a sampling of recent Tweets published in the past 7 days.”
Twitterの標準検索APIは「過去7日間に公開された最近のツイートのサンプルに対して検索」のみを行います。

If you’re specifying an ID range beyond the past 7 days or there are no results from the past 7 days, then no results will be returned.
過去7日間を超えるID範囲を指定している場合、または過去7日間の結果がない場合、結果は返されません。

See Twitter’s documentation on the standard search API for more information.
詳細は、標準検索APIに関するTwitterドキュメントを参照してください。

Note

In API v1.1, the response format of the Search API has been improved to return Tweet objects more similar to the objects you’ll find across the REST API and platform. However, perspectival attributes (fields that pertain to the perspective of the authenticating user) are not currently supported on this endpoint. 12

Changed in version 4.0: Renamed from API.search

Parameters q – The search query string of 500 characters maximum, including operators. Queries may additionally be limited by complexity.
演算子を含めて最大 500 文字の検索クエリ文字列。クエリは、複雑さによってさらに制限される場合があります。

geocode – Returns tweets by users located within a given radius of the given latitude/longitude. The location is preferentially taking from the Geotagging API, but will fall back to their Twitter profile. The parameter value is specified by “latitude,longitude,radius”, where radius units must be specified as either “mi” (miles) or “km” (kilometers). Note that you cannot use the near operator via the API to geocode arbitrary locations; however you can use this geocode parameter to search near geocodes directly. A maximum of 1,000 distinct “sub-regions” will be considered when using the radius modifier.
指定された緯度/経度の指定された半径内にいるユーザーによるツイートを返します。場所は Geotagging API から優先的に取得されますが、Twitter プロファイルにフォールバックされます。パラメータ値は「latitude,longitude,radius」で指定します。半径の単位は「mi」(マイル)または「km」(キロメートル)で指定する必要があります。 API 経由で near 演算子を使用して任意の場所をジオコーディングすることはできないことに注意してください。ただし、このジオコード パラメーターを使用して、近くのジオコードを直接検索できます。 radius 修飾子を使用する場合、最大 1,000 の個別の「サブ領域」が考慮されます。

lang – Restricts tweets to the given language, given by an ISO 639-1 code. Language detection is best-effort.
ツイートを ISO 639-1 コードで指定された言語に制限します。言語検出はベスト エフォートです。

locale – Specify the language of the query you are sending (only ja is currently effective). This is intended for language-specific consumers and the default should work in the majority of cases.
送信するクエリの言語を指定します (現在有効なのは ja のみです)。これは言語固有のコンシューマーを対象としており、ほとんどの場合、デフォルトで機能するはずです。

result_type –

Specifies what type of search results you would prefer to receive. The current default is “mixed.” Valid values include:
受け取りたい検索結果のタイプを指定します。現在のデフォルトは「mixed」です。有効な値は次のとおりです。

  • mixed : include both popular and real time results in the response
    一般的な結果とリアルタイムの結果の両方を応答に含めます
  • recent : return only the most recent results in the response
    レスポンスで最新の結果のみを返します
  • popular : return only the most popular results in the response
    応答で最も人気のある結果のみを返します

count – The number of results to try and retrieve per page.
ページごとに試行して取得する結果の数

注:最大100。それ以上を指定しても100個しか返ってこない

until – Returns tweets created before the given date. Date should be formatted as YYYY-MM-DD. Keep in mind that the search index has a 7-day limit. In other words, no tweets will be found for a date older than one week.
指定された日付より前に作成されたツイートを返します。日付は YYYY-MM-DD の形式にする必要があります。検索インデックスには 7 日間の制限があることに注意してください。つまり、1 週間以上前の日付のツイートは見つかりません。

since_id – Returns only statuses with an ID greater than (that is, more recent than) the specified ID. There are limits to the number of Tweets which can be accessed through the API. If the limit of Tweets has occurred since the since_id, the since_id will be forced to the oldest ID available.
指定された ID より大きい (つまり、新しい) ID を持つステータスのみを返します。 API 経由でアクセスできるツイートの数には制限があります。 since_id 以降にツイート数の制限が発生した場合、since_id は使用可能な最も古い ID に強制されます。

注: since_idよりも大きい(等しいのは含まない)(つまり新しい)Tweetを返す。

max_id – Returns only statuses with an ID less than (that is, older than) or equal to the specified ID.
指定された ID より小さい (つまり、古い) ID を持つステータスのみを返します。

注: 実際は、max_idに等しいかそれより小さい(つまり古い)Tweetを返す。

include_entities – The entities node will not be included when set to false. Defaults to true.
false に設定すると、エンティティ ノードは含まれません。デフォルトは true です。

注: entitiesとは、hashtags'、 'symbols'、'user_mentions'、'urls' の4つの情報

Returns

Return type: SearchResults

References

https://developer.twitter.com/en/docs/twitter-api/v1/tweets/search/api-reference/get-search-tweets