CPUとメモリ消費量の3次元グラフをぐりぐり動かす

matplotlibの3次元グラフ描いてみたい!そしてグラフをアニメする機能があるらしいのでぐりぐり動かしたい!

1. WindowsでCPUとメモリの消費量を取得する。

ぐりぐりリアルタイムで動かすデータと言えばCPUとメモリ消費量が気軽でいいかな。Windowsではちょうどいいコマンドが用意されていないので探したらPythonのモジュールでちょうどいいのがあった。


psutil -


A cross-platform process and system utilities module for Python - Google Project Hosting

プロセスとシステムの使用量(CPU, disk, memory, network)を取得できる。
しかもLinux, Windows, OSX,FreeBSDに対応!32bitでも64bitでも!頼もしい!

(1) システムのCPU使用量(%)
import psutil
psutil.cpu_percent(interval=0.1, percpu=False)
  • intervalはCPU割り当て時間の計測期間
    • CPU割り当て時間 / 経過時間 * 100
    • interval=0.0 の場合は前回にこのメソッドが呼び出され時から計測
  • percpuは複数CPUある場合の挙動
    • Falseの場合は結果は1個にまとめられる。(上限は100%)
    • Trueの場合は結果はCPUの個数分、リストで出力される。
(2) システムの物理メモリ使用量(%)
import psutil
psutil.used_phymem()
(3) プロセスのCPU使用量・メモリ使用量
import psutil
# プロセスIDからProcessオブジェクトを生成
p = psutil.Process(pid)

# CPU使用量(%)
# interval引数の使い方は(1)と同様
# CPUが複数個の場合はCPU個数*100が上限となる
p.get_cpu_percent(interval=0.0)
# メモリ使用量(%) 
p.get_memory_percent()

2.3次元グラフを動かす

(1) 3次元のグラフ描画
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt

# Axes3DSubplotを取得
fig = plt.figure()
ax = fig.gca(projection='3d')

# 直線をプロット
x = [i for i in range(10)]
y = [i for i in range(10)]
z = [i for i in range(10)]
line, = ax.plot(x, y, zs=np.array(z), zdir='z')
plt.show()
(2) グラフを動かす

matplotlib.animationのFuncAnimation関数を使用する。

import matplotlib.animation as animation
line_ani = animation.FuncAnimation(fig, update_line, frames=360,
                                        fargs=(line, ax),
                                        interval=100, blit=False)
plt.show()
引数
fig Figureオブジェクト
func グラフを更新する関数。この関数の1個目の引数は現在のフレーム数が渡される。
frames 描画するフレーム数
fargs funcに渡す引数
interval グラフを更新する間隔
blit 描画するグラフを最適化するかどうか(?)
グラフを更新する関数の例
def update_line(num, line, ax):
    # ラインの更新
  # x軸、y軸、z軸それぞれに値リストをセットする。(伸びてく直線)
    line.set_xdata([i for i in range(num)])
    line.set_ydata([i for i in range(num)])
    line.set_3d_properties([i for i in range(num)])
    # グラフ全体を回転
    ax.view_init(30, 1 * num)

3.作ったスクリプト

psutil と matplotlib を使用してシステム・プロセスの3次元グラフ(x軸:メモリ使用量、y軸:時間、z軸:CPU使用量)をリアルタイムで描画するスクリプト。
This is a script which draws the amount of CPU used and memory usage of a process to a 3D graph. — Gist
(GitHubのGistを使ってみた。初回保存時、ログオンし忘れててAnonymousになってしまった……。)

<実行例>

f:id:meganehouser:20120206232535p:image
FuncAnimationの結果を動画で保存できるっぽいんだけどうまくいかない…。

全「???48」を生成してみる

課題1

  • 大文字のアルファベット3文字 + '48' の全パターンのリストを作る

解答 その1

単純にループの入れ子で
# まず大文字のアルファベットのリストを作る
al = [chr(a) for a in range(65, 91)]

# 全パターンのジェネレータ
def akb():
    for a1 in al:
        for a2 in al:
            for a3 in al:
                yield a1 + a2 + a3 + '48'
# リストで取得
allptns = [p for p in akb()]

allptns.index('AKB48') #=> 本家は261番目に出てきた

解答 その2

リスト内包表記の入れ子
# al は大文字アルファベットのリスト
# 全パターンのリスト
allPtns = [a1 + a2 + a3 + '48' for a1 in al for a2 in al for a3 in al]

解答その3

アルファベットの桁数を指定できるようにしてみる

# al は大文字アルファベットのリスト

# 2個のリストを組み合わせる関数
getprd = lambda list1, list2 : [a1 + a2 for a1 in list1 for a2 in list2]

# 全パターンのリストを生成する関数
def akb(num):
    temp = ['']
    def _akb(tl, n):
        if n == 0:
            return getprd(tl, ['48'])
        else:
            return _akb(getprd(tl, al), n - 1)
    return _akb(temp, num)
allPtns = akb(3)

なんかいまいちだなー。もっとかっこよい解答求む。

課題2

課題1に制限を加える

アルファベット3文字は別々のアルファベットを使う(AAAとかAABはダメ)

解答

課題1の解答3のリストを組み合わせる関数(getprd)を以下に修正すれば対応できる。

# 2個のリストを組み合わせる関数(重複省く)
getprd = lambda list1, list2 : [a1 + a2 for a1 in list1for a2 in list2 if a2 not in a1]

課題2の場合は本家は216番目に出てきた。

やってみた感想

ループとか関数とか考えながら書けるので、初めてのプログラミング言語に取り組むときはHello Worldよりこの課題やると楽しそう。

別解

ちなみに標準モジュールのitertoolsを使えば以下のように書ける。
至れり尽くせり!

import itertools
# al は大文字アルファベットのリスト

# 課題1
allptns1 = [''.join(a) + '48' for a in itertools.product(al, al, al)]
# 課題2
allptns2 = [''.join(a) + '48' for a in itertools.permutations(al, 3)]

EXIFタグで写真の情報を見てみる

自分がデジカメで撮った写真のEXIFタグ情報を見てみようかと思い立った。大量に集めれば何か撮影の傾向が見えるかも?
とりあえずPythonEXIF情報を取得してみよう。

1.EXIF情報を取得するモジュール

EXIF.py プロジェクト日本語トップページ - SourceForge.JP
2008年8月のリリース以後、更新されていないので2010年に策定されたExif2.3に対応したデジカメだとうまく情報がとれないかもしれない。

Exif規格に7年ぶりの新バージョンExif 2.3 - PhotoXP


自分のデジカメは2011年1月発売のOLYMPUS PEN Lite E-PL2。まあ試してみてダメだったら考えよう。

2.EXIFを読み込み!

EXIFモジュールのprocess_file関数使用する。

> from EXIF import process_file
> fp = r'd:\sample.jpg' # EXIFタグを読みたい画像ファイルパス
> f = open(fp, 'rb')
> exifDic = process_file(f)

process_fileは以下の名前付き引数が指定できる。

名前 既定値 説明
stop_tag 'UNDEF' 出現した場合に読み込みを切り上げるタグ名を指定する
details True メーカーが独自に使っているMakerNoteタグを読み込むかどうか。
strict False タグ読み込み時にエラーが発生した場合に実行を停止するかどうか。
debug False タグ読み込み時にデバッグレベルの情報を出力するかどうか

戻り値はタグ名がkeyでEXIF.IFD_Tagのインスタンスをvalueとする辞書型となる。

> ifdTag = exifDic['Image Model'] #IFD_Tagのインスタンス
> dir(ifdTag)
['__doc__',
 '__init__',
 '__module__',
 '__repr__',
 '__str__',
 'field_length',
 'field_offset',
 'field_type',
 'printable',
 'tag',
 'values']

E-PL2のタグはdetailsにFalseを指定すると読み込むことができた。

3.サンプル画像を読み込む!

以下の関数で、フォルダ内のjpgファイルのEXIFタグ情報を一度に読めるようにする。

ExifReader.py

#cording:utf-8
import EXIF
import os
import glob

# 読み込みたくないタグは以下に指定する
excludetags = ['JPEGThumbnail','TIFFThumbnail']

def getTagValueDict(filePath):
    f = open(filePath, 'rb')
    exifTags = EXIF.process_file(f, details=False, strict=False)
    f.close()
    exifKeys = [key for key in exifTags.keys() if key not in excludetags]

    exifDict = {}
    for exifKey in exifKeys:
        exifDict[exifKey] = exifTags[exifKey].printable
    return exifDict

def getTagValueDicts(root, pattern='*.jpg'):
    files = glob.glob(os.path.join(root, pattern))
    exifDicts = {}
    for file in files:
        tags = getTagValueDict(file)
        exifDicts[os.path.basename(file)] = tags
    return exifDicts

EXIF.py プロジェクト日本語トップページ - SourceForge.JPではサンプル画像もダウンロードできるので読み込ませてみる。
デジカメで撮った画像である以下を対象とする。

Canon_40D.jpg
Canon_DIGITAL_IXUS_400.jpg
Fujifilm_FinePix6900ZOOM.jpg
Fujifilm_FinePix_E500.jpg
Kodak_CX7530.jpg
Konica_Minolta_DiMAGE_Z3.jpg
Nikon_COOLPIX_P1.jpg
Nikon_D70.jpg
Olympus_C8080WZ.jpg
Panasonic_DMC-FZ30.jpg
PC040163.JPG
Pentax_K10D.jpg
Ricoh_Caplio_RR330.jpg
Samsung_Digimax_i50_MP3.jpg
Sony_HDR-HC3.jpg
WWL_(Polaroid)_ION230.jpg

さらにE-PL2で撮った画像を一枚対象に含める。

全機種で使われているタグを調べてみる

> from ExifReader import getTagValueDicts,getTagValueDict
> rootPath = r'D:\Exif_test_images' # サンプル画像のフォルダ
> exifTagsDict = getTagValueDicts(rootPath)
> tagSets = [tagnames for dic in exifTagsDict.values() for tagnames in dic.keys()]
> distinctTags = reduce(lambda x,y: x.intersection(y) ,tagSets)
> distinctTags
set(['EXIF Flash', 'Image ExifOffset', 'Image Model', 'EXIF ColorSpace', 'EXIF DateTimeOriginal', 'Image XResolution', 'Image Make', 'Image DateTime', 'Image YResolution', 'EXIF FNumber', 'EXIF ExifImageLength', 'Image ResolutionUnit', 'EXIF ExifImageWidth'])

サンプル画像のExifバージョンを調べる

> versions = [str(v) for tags in exifTagsDict.values() for t,v in tags.iteritems() if t=="EXIF ExifVersion"]
> set(['0220', '0221', '0210'])

ちなみにE-PL2で撮った画像の結果は以下

> d = getTagValueDict(epl2FilePath)
> tagNames = sorted(d.keys())
>  for t in tagNames:
    v = d[t]
    print t,':'v

EXIF ColorSpace : sRGB
EXIF ComponentsConfiguration : YCbCr
EXIF Contrast : Normal
EXIF CustomRendered : Normal
EXIF DateTimeDigitized : 2011:12:04 12:18:44
EXIF DateTimeOriginal : 2011:12:04 12:18:44
EXIF DigitalZoomRatio : 1
EXIF ExifImageLength : 4032
EXIF ExifImageWidth : 3024
EXIF ExifVersion : 0221
EXIF ExposureBiasValue : 0
EXIF ExposureMode : Auto Exposure
EXIF ExposureProgram : Program Normal
EXIF ExposureTime : 1/500
EXIF FNumber : 71/10
EXIF FileSource : Digital Camera
EXIF Flash : Auto Off
EXIF FlashPixVersion : 0100
EXIF FocalLength : 17
EXIF GainControl : None
EXIF ISOSpeedRatings : 200
EXIF InteroperabilityOffset : 17202
EXIF LightSource : Unknown
EXIF MaxApertureValue : 761/256
EXIF MeteringMode : Pattern
EXIF Padding : []
EXIF Saturation : Normal
EXIF SceneCaptureType : Standard
EXIF Sharpness : Normal
EXIF Tag 0xEA1D : 1872
EXIF WhiteBalance : Auto
Image Artist : 
Image Copyright : 
Image DateTime : 2011:12:31 21:47:17
Image ExifOffset : 2538
Image ImageDescription : OLYMPUS DIGITAL CAMERA         
Image Make : OLYMPUS IMAGING CORP.  
Image Model : E-PL2           
Image Orientation : Horizontal (normal)
Image Padding : []
Image PrintIM : [80, 114, 105, 110, 116, 73, 77, 0, 48, 51, 48, 48, 0, 0, 37, 0, 1, 0, 20, 0, ... ]
Image ResolutionUnit : Pixels/Inch
Image Software : Microsoft Windows Photo Viewer 6.1.7600.16385
Image XResolution : 314
Image YCbCrPositioning : Co-sited
Image YResolution : 314
Thumbnail Compression : JPEG (old-style)
Thumbnail JPEGInterchangeFormat : 17864
Thumbnail JPEGInterchangeFormatLength : 5873
Thumbnail ResolutionUnit : Pixels/Inch
Thumbnail XResolution : 72
Thumbnail YResolution : 72