[Image-SIG] Palette fill on lines?

Deirdre Saoirse Moen deirdre@deirdre.net
Mon, 13 May 2002 21:30:53 -0700


BTW, got all the code working. For the picture it generates, see the page:
http://fuzzyorange.com/stats-month.php

It pulls from the same data shown tabularly on the page (stored in a 
mysql database).

As this may be of interest to others, code is below. Feel free to use 
in any manner except ridicule. :)

import Image
import ImageDraw
import ImageFont
import MySQLdb

class loggraph:
  def __init__(self):
   self.db = None
   self.cursor = None
   self.im = None
   self.lg = None
   self.curfont = None

   self.imright = 0
   self.imtop = 0

   self.left = 0
   self.right = 0
   self.top = 0
   self.bottom = 0

   self.chartmax = 0

   self.months = []
   self.hits = []
   self.indexhits = []
   self.xpoints = []

def dbinit(lg):
  # change if you need different parameters obviously

  host = 'localhost'
  db  = 'destash_log'

  user = 'foo'
  passwd = 'bar'
  lg.db = MySQLdb.connect(db=db, host=host, user=user, passwd=passwd)
  lg.cursor = lg.db.cursor()

def drawBackground(lg):
  lg.imright = 500
  lg.imbottom = 305

  lg.left = 50
  lg.right =  lg.imright - 10
  lg.top = 10
  lg.bottom =  lg.imbottom - 35

  lg.im = Image.new("P", (lg.imright, lg.imbottom), 0)

  lg.im.putpalette([
     255, 255, 255,      # white background
     127, 127, 127,      # grey lines
       0,   0,   0,      # black axes
     255,   0,   0,      # index 3 is red
     255, 255,   0,      # index 4 is yellow
     255, 153,   0,      # index 5 is orange
       0,   0, 255,      # index 6 is blue
     ])

  lg.d = ImageDraw.ImageDraw(lg.im)
  lg.curfont = ImageFont.load('/usr/share/fonts/courB08.pil')

  lg.d.setfill(1)

  # draw outside box

  lg.d.setink(2)
  lg.d.setfill(0)
  lg.d.rectangle((0, 0,  lg.imright-1,  lg.imbottom-1))

  # draw inner box
  lg.d.rectangle((lg.left,  lg.top,  lg.right,  lg.bottom))

  # make lines
  lg.d.setink(4)
  lg.d.setfill(1)
  ys = (lg.chartmax / 500) - 1
  for i in xrange(500, lg.chartmax, 500):
   y = int((((lg.bottom - lg.top) / ys) * (i/500)) + lg.top)
   lg.d.line((lg.left, y) + (lg.right, y), fill=128)

  #d.line((0, 0) + im.size, fill=128)

def getChartMax(lg):
  # we can't do complex statements in mysql, so we'll have to
  # walk through the results. That's OK, we need to keep the
  # results for later anyway

  stmt = "select logdate, sum(hits) from logmonth where url = '/' or url = "
  stmt = stmt + "'index-ebay.php' or url = '' or url = 'index.php' "
  stmt = stmt + "group by logdate order by logdate"

  lg.cursor.execute(stmt)

  try:
   resultSet = lg.cursor.fetchall()

   for i in xrange(0, len(resultSet)):
    lg.months.append(resultSet[i][0])
    lg.indexhits.append(int(resultSet[i][1]))
  except:
   pass

  stmt = "select logdate, sum(hits) from logmonth "
  stmt = stmt + "group by logdate order by logdate"

  lg.cursor.execute(stmt)

  try:
   resultSet = lg.cursor.fetchall()

   for i in xrange(0, len(resultSet)):
    lg.hits.append(int(resultSet[i][1]))
    if (resultSet[i][1] > lg.chartmax):
     lg.chartmax = int(resultSet[i][1])
  except:
   pass

  lg.chartmax = float((((lg.chartmax / 500 ) + 1 ) * 500))

def calcXPoints(lg):
  # assume we want to space evenly across n spaces

  interval = (lg.right - lg.left) / len(lg.hits)

  for i in xrange(0, len(lg.hits)):
   lg.xpoints.append((interval * i) + (interval / 2) + lg.left)

def convertToY(lg, val):
  y  = (1 -(val / lg.chartmax)) * (lg.bottom - lg.top)
  y += lg.top

  return y

def drawLabels(lg):
  lg.d.setfill(0)
  lg.d.setink(6)
  for i in xrange(0, len(lg.hits)):
   lg.d.line((lg.xpoints[i], lg.bottom-2)+ (lg.xpoints[i], lg.bottom+2))

   texts = lg.d.textsize(lg.months[i], font=lg.curfont)
   lg.d.text((lg.xpoints[i] - (texts[0]/2), lg.bottom + 8), 
lg.months[i], font=lg.curfont)

  sections = ((lg.bottom - lg.top) / 20) -1
  sectsize = int (lg.chartmax / (sections + 1))
  for i in xrange(0, sections + 2):
   val = lg.chartmax - (i * sectsize)
   val = '%d' % (val,)
   texts = lg.d.textsize(val, font=lg.curfont)
   lg.d.text((lg.left - texts[0] - 4, lg.top + (i * 20) - 5), val, 
font=lg.curfont)

def drawHits(lg):
  for i in xrange(0, len(lg.hits) - 1):
    # we have the x for each value, so draw lines
   lg.d.setfill(0)
   lg.d.setink(6)
   lg.d.line((lg.xpoints[i], convertToY(lg, lg.hits[i]))
        + (lg.xpoints[i+1], convertToY(lg, lg.hits[i+1])))

   lg.d.setfill(0)
   lg.d.setink(3)
   lg.d.line((lg.xpoints[i], convertToY(lg, lg.indexhits[i]))
        + (lg.xpoints[i+1], convertToY(lg, lg.indexhits[i+1])))


def drawGraph(lg):
  getChartMax(lg)
  drawBackground(lg)
  calcXPoints(lg)
  drawLabels(lg)
  drawHits(lg)


def saveImage(lg):
  lg.im.save("stats.gif")

if __name__ == '__main__':
  lg = loggraph()
  db = dbinit(lg)
  drawGraph(lg)
  saveImage(lg)

-- 
_Deirdre    Stash-o-Matic: http://fuzzyorange.com    http://deirdre.net
"I'm writing a book. I've got the page numbers done."   - Steven Wright