LoginSignup
33
38

Plotlyで作るグラフをDjangoで使う

Last updated at Posted at 2020-01-16

本記事について

Plotlyでガントチャートを作成する方法と、それをDjangoのテンプレートに配置して表示する方法を書きます。

先に結論

  1. plotly.figure_factory.create_gantt()を読み込む
  2. fig = ff.create_gantt(df)でガントチャートのオブジェクトを作成する
  3. plotly.offline.offline.plot()を読み込む
  4. gantt = plot(fig, output_type='div', include_plotlyjs=False)でグラフとグラフを描画するスクリプトを含むhtmlコードの文字列を取得する
  5. autoescapeendautoescapeでエスケープ機能をoffにした上で、4.で取得した文字列をテンプレートにわたす

Plotlyとは

オンラインデータの分析や視覚化のツールを開発している会社で、JavaScriptやPython、Rで使えるグラフ作成ライブラリを提供しています。
Python用のライブラリを使えば、例えば以下のリンク先のようなグラフを描画することができます。
Plotly Python Open Source Graphing Library

ガントチャートの作成方法

以下のリンク先に例が記載されています。
Gantt Charts in Python

simpleなsample
import plotly.figure_factory as ff

# 日時のフォーマットは `2000-01-01 00:00:00`
df = [dict(Task="Job A", Start='2009-01-01', Finish='2009-02-28'),
      dict(Task="Job B", Start='2009-03-05', Finish='2009-04-15'),
      dict(Task="Job C", Start='2009-02-20', Finish='2009-05-30')]

fig = ff.create_gantt(df)
fig.show()

newplot (1).png

データフレームもしくはリスト型のデータを使います。

キーがTast,Start,Finishの辞書型が、ガントチャートのバー1本分に相当し、それをリスト(変数figとする)に格納します
ff.create_gantt()の第一引数に変数figセットすることで、ガントチャートのオブジェクトが作成されます。
.show()はブラウザを起動して、引数に入れたオブジェクトのガントチャートを描画します。

又、create_gantt()には様々な引数があり、グラフをカスタマイズすることが可能です。
(カラーバーを表示したり、色を変えたり、太さを変えたりなどなど)

create_gantt(df, colors=None, index_col=None, show_colorbar=False, reverse_colors=False, title='Gantt Chart', bar_width=0.2, showgrid_x=False, showgrid_y=False, height=600, width=None, tasks=None, task_names=None, data=None, group_tasks=False, show_hover_fill=True)

help(ff.create_gantt)で説明が見られます。

作成したグラフをHTMLとして取得する

上記の.show()の代わりにplotly.offline.offline.plot()を使うことで、HTML形式のファイルを作成したり、divで囲まれたHTMLのコードを出力してくれます。Djangoのテンプレートに配置したい場合は、こちらの関数を使います。

sample2
from plotly.offline import plot

df = [dict(Task="Job A", Start='2009-01-01', Finish='2009-02-28'),
      dict(Task="Job B", Start='2009-03-05', Finish='2009-04-15'),
      dict(Task="Job C", Start='2009-02-20', Finish='2009-05-30')]

fig = ff.create_gantt(df)
plot_fig = plot(fig, output_type='div', include_plotlyjs=False)
print(plot_fig)


スクリーンショット 2020-01-16 23.28.10.png

plot()の引数
Chart StudiotというGUIでグラフをカスタマイズできるサービスへのリンクを表示するか否か・アニメーションを自動再生するかなど、色々ある

plot(figure_or_data, show_link=False, link_text='Export to plot.ly', validate=True, output_type='file', include_plotlyjs=True, filename='temp-plot.html', auto_open=True, image=None, image_filename='plot_image', image_width=800, image_height=600, config=None, include_mathjax=False, auto_play=True, animation_opts=None)

Djangoでplotlyを使う際は、主にinclude_plotlyjsoutput_typeを設定します

output_type

グラフと、グラフを生成するスクリプトを含むHTMLを、どのように出力するかの設定。

output_type='div'
グラフとグラフを生成するスクリプトを含むHTMLのコード(divに囲まれている)が、文字列で出力される

output_type=file
グラフとグラフを生成するスクリプトを含むHTMLファイルが生成される

include_plotlyjs

plotly.jsライブラリのソースコードをどのように読み込むか設定できます。

include_plotlyjs=False
plotly.js CDNを参照するコードは含まれない
output_type = 'div'で出力したコードが、plotly.jsを読み込んでいるHTMLドキュメント内に配置されれば利用可能

include_plotlyjs=con
plotly.js CDNを参照するスクリプトタグが出力に含まれまれる。

include_plotlyjs=True
plotly.jsのソースコートが丸々含まれる。3MB程度になる。

Djangoで使うとき

Djangoはbase.htmlなどの基盤となるテンプレートにcssjavascriptの読み込みを記述し、他のテンプレートにおいて{% extends 'app/base.html' %}としてbase.htmlを引き継ぎます。そのため、基盤となるテンプレートにplotly.jsを読み込む旨記述し、include_plotlyjs=Falseとするのがよいかなと思います。

base.html
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>

又、output_type='div'で取得したHTMLコードの文字列をテンプレートに渡せば、そのテンプレート内でグラフを描画できます。
ただし、テンプレートタグの{% autoescape off %}{% endautoescape %}を使い、エスケープ機能をoffにしないと正しく描画されません。

グラフを描画するhtml
{% extends 'blog/base.html' %}
{% block content %}

{% autoescape off %}
{{ plot_gantt }}  <!-- HTMLコードの文字列が格納されたコンテキスト -->
{% endautoescape %}

まとめ

  1. plotly.figure_factory.create_gantt()を読み込む
  2. fig = ff.create_gantt(df)でガントチャートのオブジェクトを作成する
  3. plotly.offline.offline.plot()を読み込む
  4. gantt = plot(fig, output_type='div', include_plotlyjs=False)でグラフとグラフを描画するスクリプトを含むhtmlコードの文字列を取得する
  5. autoescapeendautoescapeでエスケープ機能をoffにした上で、4.で取得した文字列をテンプレートにわたす

プロジェクトを立ち上げそれに向けてタスクを作成するというアプリケーションを作っており、そこで使ってみた。
すでに完了したタスクのスケジュールを取得し、ガントチャートを作成、テンプレートに配置してみる

models.py
# Projectsと、その小モデルTasks
class Projects(models.Model):
    # 略

class Tasks(models.Model):
    STATUS_LIST = ((0, '待機'), (1, '取組中'), (2, '完了'))

    project = models.ForeignKey(Projects, on_delete=models.CASCADE, related_name='project_task')
    taskName = models.CharField(max_length=100, verbose_name='タスク')
    status = models.IntegerField(choices=STATUS_LIST, verbose_name='状況')
    createdDate = models.DateTimeField(default=now, null=True, blank=True, verbose_name='開始日')
    deadline = DateTimeField(blank=True,null=True, verbose_name='締め切り')
    finishedDate = DateTimeField(blank=True,null=True, verbose_name='達成した日')
views.py
def projects_detail_view(request, p_pk):
    project = Projects.objects.get(pk=p_pk)
    # 完了済のタスクを取得し、開始日の昇順でタスク一覧を取得
    tasks = project.project_task.filter(status=2).order_by('createdDate')
    df = []
    for task in tasks:
        df.append(
            dict(Task=task.taskName,
                 # create_ganttのStartとFinishで使うため、フォーマットを整形
                 Start="{0:%Y-%m-%d %H:%M:%S}".format(task.createdDate),
                 Finish="{0:%Y-%m-%d %H:%M:%S}".format(task.finishedDate),))
    fig = ff.create_gantt(df, title='これまでの軌跡', bar_width=0.5, showgrid_x=True, showgrid_y=False,)
    plot_html = plot(fig, output_type='div', include_plotlyjs=False)

    context = {
        'plot_html': plot_html,
    }
    return render(request, 'detail.html', context)
detail.html
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
{% autoescape off %}
{{ plot_html }}
{% endautoescape %}

結果
スクリーンショット 2020-01-17 1.00.02.png

タスク名が長いため、グラフを圧迫している。

33
38
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
33
38