Постоянные посетители знают, что на странице О сайте можно посмотреть график запросов страниц сайта за последние несколько месяцев. Для его получения я каждый месяц в ручную выполнял запрос в базу данных сайта, полученное значение переносил в Excel, потом диаграмму с графиком сохранял в формате png, и закачивал на сайт. Получился прям целый ритуал, который мне порядком надоел, и я решил его автоматизировать, а раз уж взялся за изучение Python, то и реализовать решил на нём. Вот что у меня получилось.
#-*- coding: utf-8 -*-
import MySQLdb
import aggdraw
from PIL import Image, ImageDraw, ImageFont
mon = (u"Янв", u"Фев", u"Мар", u"Апр",
u"Май", u"Июн", u"Июл", u"Авг",
u"Сен", u"Окт", u"Ноя", u"Дек")
graphcolors = ("red", "green", "blue")
y_steps = (200, 500, 1000, 2000, 5000, 10000)
xcw = 50 # ширина ячейки
# Соединение с БД
db = MySQLdb.connect(host='host', user='user', passwd='pass', db='database')
query = 'SELECT `Counter` FROM `stat`'
cursor= db.cursor()
cursor.execute(query)
result = cursor.fetchall()
maxval = 0
minval = 1000000
for record in result:
if record[2] > maxval:
maxval = record[2]
if record[2] < minval:
minval = record[2]
# временно отключаем ограничение шкалы графика по минимальному значению
minval = 0
delta = (maxval - minval) / 10
# округляем до большего кратного
for i in y_steps:
if delta < i:
delta = i
break
# диапазон для вывода графика
min_gr = 0
for i in range(100):
if i*delta < minval:
min_gr = i*delta
if i*delta > maxval:
max_gr = i*delta
break
lcount = i
# получение масштаба по Y
m_y = 430.0 / (max_gr - min_gr)
# рисование
#image = Image.new("RGBA", (660,480), (255,255,255,255))
image = Image.new("RGB", (660,480), "white")
draw = aggdraw.Draw(image)
draw.setantialias(False)
apen = aggdraw.Pen("#999", 1)
apen1 = aggdraw.Pen("#ddd", 1)
draw.line((50,20,50,450), apen)
draw.line((50,450,650,450), apen)
arial = aggdraw.Font('#333', "C:\WINDOWS\Fonts\arial.ttf", 12)
# Черточки и подписи на оси X
for i in range(13):
draw.line(((50+xcw*i),446,(50+xcw*i),454), apen)
if i > 0:
draw.line(((50+xcw*i),450,(50+xcw*i),20), apen1)
if i < 12:
draw.text((65+xcw*i, 455), mon[i], arial) # подписи
#draw.line(((50+50*12),446,(50+50*12),454), apen)
# Рисование чёрточек на Y
for i in range(lcount+1):
draw.line((48,(450-delta*m_y*i),52,(450-delta*m_y*i)), apen)
if i > 0:
draw.line((50,(450-delta*m_y*i),650,(450-delta*m_y*i)), apen1)
st = str(min_gr+i*delta)
a = draw.textsize(st, arial)
draw.text(((45 - a[0]), (443-delta*m_y*i)), st, arial)
# Рисование графика
draw.setantialias(True)
grColor = -1
x = y = 1
pyear = -1 # предыдущий год
px = py = -1 # предыдущие координаты
for record in result:
# настройка цветов
if int(record[0])<> pyear:
pyear = record[0]
grColor += 1
px = py = -1
abrush = aggdraw.Brush(graphcolors[grColor])
apen = aggdraw.Pen(graphcolors[grColor], 2)
x = 25 + xcw * int(record[1])
y = 450 - (int(record[2]) - min_gr) * m_y
draw.rectangle((x-2, y-2, x+2, y+2), apen, abrush)
# соединяем с предыдущей точкой
if px <> -1 and py <> -1:
draw.line((px, py, x, y), apen)
px = x
py = y
# print record[0], "-->", record[1], "-->", record[2]
print minval, maxval, delta, min_gr, max_gr, lcount, m_y
draw.flush()
image.save("test.png", "PNG")
raw_input("Done")
Здесь приведён не окончательный вариант скрипта. Я его ещё дописываю, так как есть некоторые недостатки:
- Графику не хватает легенды;
- Скрипт не умеет загружать файл на сервер. Возможно загрузку на FTP делать не буду, а просто размещу скрипт на web-сервере.
- Получаемая картинка большая по объему (около 30кб), так как указана палитра в 256 бит. Но само изображение можно без видимой потери качества конвертировать до глубины цвета 4 бита, тогда изображение становится около 5кб, что приятно.
Из-за использования сторонних библиотек для работы с графикой и соединения с MySQL, пришлось отказаться от использования последней версии Python и ограничится версией 2.5.4. Несмотря ни на что, данный скрипт упростил мне работу. Новый вариант графика можно просмотреть на странице о сайте, а старый "ручной" вариант здесь.