12A猫で学んだこと-Memoir-

...What are you learning now?

個人的なことしか書いていない、2019年4月の日記

人狼

上記村の3日目夜の占い先はまずかったねー 内訳はきちんと整理しないといけないねー

18A猫とかも楽しませていただけるといいなーと思うけれど、あんまり参加させていただけていないなぁ...

人狼との付き合い方はマイペース。 気負うことなくかかわっていきたいなぁ...

PyCheckIO

上の問題の回答は個人的に頑張ったという記憶...

Diary

In Japan,one specific name is given to an era, over which a certain emperor resides.
At the beginning of May 1st, the new era, 令和(Reiwa) is about to begin.
To be honest, I cannot feel importance of the change of name itself, though, I can imagine, abdication and enthronement of the Emperors have much effects, especially, on those who are related to politics.

Some companies commercially use this opportunity as some kind of festivals.

Although I'm unfamiliar with movements of society, I'd like to use this atmosphere to recall some memories in recent years.

Have a nice month each other!

折れ線グラフのAxesからデータを復元したい

状況

matplotlib, plot関数を使用して折れ線グラフを作成した。
plot関数の対象となったAxes オブジェクトから、折れ線グラフの作成に使われた データを抽出したい。

""" ## Purpose   
This is a problem related to [matplotlib](https://matplotlib.org/)
As you know, you can make a figure of line graph with such as the following functions.  

> fig, (ax) = plt.subplots(1, 1)  
> ax.plot([1, 2, 3], [4, 5, 6])

Here, I'd like the function to read the representation of the data 
from given ``Axes`` class. 


### Environment  
* matplotlib==3.0.3    
* pandas==0.24.2    

"""

import warnings
from collections import defaultdict 
import random

import matplotlib
import matplotlib.pyplot as plt 
from matplotlib.axes._axes import Axes
import pandas as pd

def read_plot(ax, *, fill=None): 
    """ Speculate the data of plotted ``Axes``. 
    Args:
        ax(Axes): The target ``Axes`` of read.
        fill(Number): The value for empty ``X``.  

    Return: 
        ``dict`` of ``list`` format of the estimated data. 
    """

    assert isinstance(ax, Axes), "Given Object must be ``Axes`` "


    """ If ``xaxis.label`` is existent, 
    then it is regarded as label. 
    Otherwiser, ``X`` is used. 
    """
    x_text = ax.xaxis.label.get_text()
    if x_text:
        xlabel = x_text
    else:
        warnings.warn("``label`` of ``X`` is not specified. ")
        xlabel =  "X"
    
    if len(ax.lines) == 0:
        raise ValueError("There is no ``Line2D`` given ``Axes``.")

    # Construct the data dependent on ``X``.  
    x_to_data = defaultdict(dict) 

    """
    ### As for the label of ``Y``.
    * Priority 1.
    If the ``label`` is set at ``line``, 
    then it is regarded as label of ``Y``. 
    """
    labeled_lines = [line for line in ax.lines if line._label]
    if labeled_lines:
        for line in labeled_lines:
            label = line._label
            for x, y in zip(*line.get_data()):
                x_to_data[x][label] = y
    else:
        if len(ax.lines) == 1:
            """
            ### As for the label of ``Y``.
            * Priority2.
            As long as the ``label`` of ``yaxis`` exists.
            it is regarded as the column of ``Y``. 
            """
            label =  ax.yaxis.label.get_text()
            if label:
                for x, y in zip(*ax.lines[0].get_data()):
                    x_to_data[x][label] = y

    if not x_to_data:
        raise ValueError("Cannot read any semantic data.")


    listmap = []
    x_values = x_to_data.keys()
    columns = {c for x in x_values for c in x_to_data[x].keys()} 

    for x in sorted(x_to_data.keys()):
        row = dict()
        row[xlabel] = x
        for c in columns:
            row[c] = x_to_data[x].get(c, fill)
        listmap.append(row)

    return listmap


if __name__ == "__main__":
    """ Example. 
    1. Plot an artificial data to ``in_ax``. 
    2. Using ``read_plot``, the target data is given from ``in_ax``. 
    3. Read data is plotted to ``out_ax``. 
    """

    fig, (in_ax, out_ax) = plt.subplots(1, 2)
    func = lambda x: 3 * x + 1 + random.random() * 10

    x_values = range(10)
    y_values = tuple(map(func, x_values))
    in_ax.plot(x_values, y_values, "-*", color="C0", label="LINE_SAMPLE1")
    y_values = tuple(map(func, x_values))
    in_ax.plot(x_values, y_values, "-*", color="C1", label="LINE_SAMPLE2")
 
    in_ax.set_title("This is ``in_ax``. ", fontsize=16)
    in_ax.set_xlabel("X_LABEL")
    in_ax.set_ylabel("Y_LABEL")

    in_ax.legend()
    in_ax.tick_params(labelsize=12)
    

    """ Read the contents of ``in_ax``, 
    and plot to ``out_ax``. 
    """
    listmap = read_plot(in_ax)

    xlabel = in_ax.get_xlabel()
    df = pd.DataFrame.from_records(listmap)
    df.plot(ax=out_ax, x=xlabel, style="-o")

    out_ax.set_title("This is read from ``in_ax``.", fontsize=16)
    out_ax.tick_params(labelsize=12)

    fig.tight_layout()
    plt.show()  # Display


""" Comment
* Return of ``read_plot`` may be preferable if the type is ``Dataframe``.   

"""

ユースケース

見当たらない。

作成動機1

JSON, YAML, CSV なんでもいいから、テキスト形式でデータをください... 再利用可能な形でデータを提供できないのは、貴方が騙りだからですよ!」
という知人の呟きを聞いたから

作成動機2

逆変換ができることって、大切だと思うんだ。

いつでも恋人同士に戻れる夫婦はいいなーって、学校の先生が言っていたし、 別れた後も友達に戻れたカップルの先輩たちはどっちもいい人だった。

安心できるから、ちょっと怖くても一歩を踏み出せるんだよね!

レポート提出期限1時間前

from datetime import datetime

class Uncertain(NotImplementedError):
    def __init__(self, message):
        self.message = message

    def __str__(self):
        return f"UncertainException:{self.message}"

class Apathy(RuntimeError):
    def __str__(self):
        return "Apathy struck the writer."

def is_submitted(year, month):
    if (year, month) == (2019, 1):
        """ In January, 2019, there is no entry now. 
        However, if this script is to be submitted,
        then I can claim that an entry is posted.
        Hence,  ``True`` is returned.
        This is nothing but a sophistory...
        """
        return True

    """ This script is intended to write some posts,   
    with no regard to the contents in January, 2019.
    Hence, other cases is not to be implemented.
    """
    raise Uncertain("The past is fixed, but the future is to be changed.")

def write_something():
    raise Apathy()

def act():
    current_time = datetime.now()
    year = int(current_time.strftime("%Y"))
    month = int(current_time.strftime("%m"))

    """ Assured that an entry is submitted.
    """
    if not is_submitted(year, month):
        write_something()

if __name__ == "__main__":
    act()

12月の日記

こんばんは。StudentSです。2018年ももう少しで終わりですね。 結局12月のブログは書けなかったですね...

さて、2018年の11月/12月は比較的るる鯖で人狼を遊ばせていただいた機会が多かった気がします。
ちょっと納得のいくゲームができなかったことが多かったですねー

  • 楽しんでゲームの時間を過ごせるようにする
  • できるだけ多くの情報を処理することが可能になる
  • パズル的に悪手と断言できる手は取らない

現在、このあたりが自分が人狼に参加させていただく時の目標なのですが、
どの点をとってもまだまだ未熟ですね...

また、同村させていただく機会がありましたら、よろしくお願いします。
来年が皆様にとって充実した年になりますようにー

PowerpointをPythonで使うための検討

サマリー

注意

技術系エントリの常ですが、問題が発生しても、こちらでは一切責任を取れません。自己責任でお願いします。

実行環境

自分の実行環境は以下となっています。

はじめに

2つの方針があります。

  • ファイル自体を生成する (python-pptx)
  • Powerpointのアプリケーション自体を操作する (COM操作)

このエントリ中では、
ファイル自体を生成することを静的なpptx操作
アプリケーション自体を操作することを動的なpptx操作
と呼びたいと思います。

静的なpptx操作 (python-pptxによる.pptxファイル出力)

pptx ファイルは.zip ファイルです。
解凍を行うと色々なフォルダやファイルが生成されます。
ファイルの形式はXMLです。
Office Open XML
というフォーマットがあります。
つまり、Powerpoint のソフトウェアをもっていなくても
フォーマットに適合したファイル群さえ作成することができれば、
Powerpointで開けるファイルを作ることができます。
Office Open XML の仕様について自分は詳しくないのですが、 かなり複雑という印象を持っています。
ありがたいことに、pythonでライブラリが作成されています。

python Object のクラスとXML の相互変換を行ってくれます。

非常に助かります。作者のscannyさんに感謝です。

動的なpptx操作 (COM操作によるPowerpointの操作)

python-pptxを使ってできることは.pptx ファイルの作成なので
Powerpointのソフトウェアを動かすことはできません。
Powerpointのソフトウェアを動かすためよく使われるのはVisual Basic for Applicationsです。
プログラムを書くことで、Powerpointの操作を行うことができます。
例えば、下記のようなサイトを参照させていただけます。

しかし、やりたいことはpythonPowerpointを使うことです。VBAの利用ではありません。

(少し古い)技術ですが、アプリケーション間の通信を行うためのCommon Object Model
というフレームワークがあります。 これを用いるとpython から Powerpointが公開しているインターフェースにアクセスすることができます。
しかし、COMを利用するための手順もかなり煩雑です。
ありがたいことに、COM を利用するためのライブラリがあります。

pip install comtypes  

にてインストールを行った後、下記のスクリプトを実行するとHello, Powerpoint.
というテキストボックスが表示されたスライドが生成されます。

import os  
from comtypes import client  
  
if __name__ == "__main__":  
    application = client.CreateObject("Powerpoint.Application")  
    application.Visible = True  
    presentation = application.Presentations.Add()  
    slides = presentation.Slides     
  
    # Reference * https://www.relief.jp/docs/powerpoint-vba-make-new-presentation.html  
    # ppLayoutBlank = 12  
    slide = slides.Add(len(slides) + 1, 12)   
  
    # Reference:  
    # * https://docs.microsoft.com/en-us/office/vba/api/powerpoint.shapes.addtextbox  
    # * https://docs.microsoft.com/en-us/office/vba/api/office.msotextorientation  
  
    shape = slide.shapes.AddTextBox(Orientation=1, Left=100, Top=100, Width=500, Height=50)  
    shape.TextFrame.TextRange.Font.Color.RGB = 0x000000  
    shape.TextFrame.TextRange.text = "Hello, Powerpoint."  
    shape.TextEffect.FontSize = 36  
  
    current_folder = os.getcwd()  
    presentation.SaveAs(os.path.join(current_folder, "sample.pptx"))  

スクリプトとして使っただけでは、あまりpythonの良さが見えてきませんね。
他のライブラリとの連携を視野に入れつつ、自分用にカスタマイズしていくことが
ポイントになる気がします。

終わりに

このエントリだけでは片手落ちの感があるので、来月もこの関連のネタでいきたいと思っています。
そういえば、来月は12月...

  • 年末で色々忙しい時...
  • 綺麗な雪が降り積もる時...
  • 大人の恋人の人たちが楽しい思い出を作る時...

自分のところにサンタクロースさんが来てくれるといいなぁ。
来月がいい1か月になりますように!

付録: 静的なpptx操作 V.S 動的なpptx操作

  • 静的なpptx操作 (python-pptxによる.pptxファイル出力)
  • 動的なpptx操作 (COM操作によるPowerpointの操作)

どちらを使ったほうがいいかはケースバイケースですが、 動的なpptx操作には以下のような特徴があります。

  • インタラクティブな操作を行いやすい
  • 信頼性に不安がある (例: プログラムの実行のユーザー操作の衝突からくるエラー)

したがって、

  • プログラムだけで処理を完結させたいとき
  • 定型的なスライドをたくさん作りたい

というときには静的なpptx操作の方が向いているでしょう。

逆に、

  • Powerpointの操作自体を楽にしたい
  • スライドのデザインを考えながら作業をしたい

というときには動的なpptx操作の方が向いているでしょう。

Halloween 前の日記

こんばんは。 StudentSです。 何とか達者でやっております。
Halloween ですねー

本日外にでると、 魔女や吸血鬼などの神秘的で攻撃的なシンボルの衣装に身を包み、歩く人たちの姿がありました。

  • Trick or Treat! - " お菓子をくれないと、悪戯しちゃうぞ!"
  • Trick or Treat! - "君は甲斐性無しなんだから、騙されても文句はないよね?"
  • Trick or Treat! - "ボクを騙してもいいし、やさしく接してくれてもどっちでもいい。(でも、貴方から何かをされたい)"

単純なフレーズを深読みすると、いろいろな妄想が広がりますねー

さて、2か月近く生産性のないブログとなっておりますが、今回も生み出せなかったですね...
読者が誰もいなくても、他人にとって何の価値もなくても、自分自身にとって価値のあるものを、少しづつでも創っていくことってすごく大事だと思うんですよね...

もうちょっと、休みの時間は続くと思いますが、また頑張れるときが来ると信じて。
No learning, No life. ちょっとずつでも、できないことをできるようにしていくことが大切だということは 忘れずに...

寒くなってきましたが、お体にお気をつけください。 お互い、来月がいい一か月になりますように!