PyScrapers: Difference between revisions

From XPUB & Lens-Based wiki
No edit summary
 
No edit summary
 
Line 5: Line 5:
Nested while loops create a two-dimensional iterator that draws the grid cell by cell.
Nested while loops create a two-dimensional iterator that draws the grid cell by cell.


<pre>#!python numbers=off
<source lang="python">
#!python numbers=off
import math, random     ## standard Python modules
import math, random     ## standard Python modules
import Image, [[ImageDraw]]     ## PIL modules
import Image, [[ImageDraw]]     ## PIL modules
Line 33: Line 34:


im.save("pyscrapers01.png", "png")
im.save("pyscrapers01.png", "png")
</pre>
</source>


attachment:pyscrapers01.png
attachment:pyscrapers01.png
Line 39: Line 40:
Now, you can use one of the loop variables, say the columns, or c, to determine a color to use in filling each cell. Here, we use some basic maths to translate the column index to an RGB value. Notice the use of 1.0 to force Python to use precise (floating point) math, and then the int() function to finally turn the result back into a whole number (as needed for the color specification for the PIL).
Now, you can use one of the loop variables, say the columns, or c, to determine a color to use in filling each cell. Here, we use some basic maths to translate the column index to an RGB value. Notice the use of 1.0 to force Python to use precise (floating point) math, and then the int() function to finally turn the result back into a whole number (as needed for the color specification for the PIL).


<pre>#!python numbers=off
<source lang="python">#!python numbers=off
colorcomp = int((1.0*c/cols) * 255)
colorcomp = int((1.0*c/cols) * 255)
</pre>
</source>


The PIL accepts color defined as text string in the form "rgb(red, green, blue)" where red, green, and blue are (whole) numbers from 0 to 255, each specifying the amount of each color. To translate the colorcomp variable to a PIL-format string, you could use. Notice again how you need to use str() to convert the integer to a string type:
The PIL accepts color defined as text string in the form "rgb(red, green, blue)" where red, green, and blue are (whole) numbers from 0 to 255, each specifying the amount of each color. To translate the colorcomp variable to a PIL-format string, you could use. Notice again how you need to use str() to convert the integer to a string type:


<pre>#!python numbers=off
<source lang="python">#!python numbers=off
color="rgb("+str(colorcomp)+",0,0)"
color="rgb("+str(colorcomp)+",0,0)"
</pre>
</source>


Here's the full code, and resulting image, using this colorcomp variable as the red component of the cell color:
Here's the full code, and resulting image, using this colorcomp variable as the red component of the cell color:
<pre>#!python numbers=off
<source lang="python">#!python numbers=off
import math, random
import math, random
import Image, [[ImageDraw]]
import Image, [[ImageDraw]]
Line 80: Line 81:


im.save("pyscrapers02.png", "png")
im.save("pyscrapers02.png", "png")
</pre>
</source>


attachment:pyscrapers02.png
attachment:pyscrapers02.png
Line 86: Line 87:
You could use the same technique to translate the row to the level of blue in the fill color:
You could use the same technique to translate the row to the level of blue in the fill color:


<pre>#!python numbers=off
<source lang="python">#!python numbers=off
import math, random
import math, random
import Image, [[ImageDraw]]
import Image, [[ImageDraw]]
Line 117: Line 118:


im.save("pyscrapers03.png", "png")
im.save("pyscrapers03.png", "png")
</pre>
</source>


attachment:pyscrapers03.png
attachment:pyscrapers03.png
Line 125: Line 126:
You could apply the same idea above, now mapping column to saturation, and row to lightness. The hue in this case is a constant, set in this case to 0:
You could apply the same idea above, now mapping column to saturation, and row to lightness. The hue in this case is a constant, set in this case to 0:


<pre>#!python numbers=off
<source lang="python">#!python numbers=off
import math, random
import math, random
import Image, [[ImageDraw]]
import Image, [[ImageDraw]]
Line 157: Line 158:


im.save("pyscrapers04.png", "png")
im.save("pyscrapers04.png", "png")
</pre>
</source>


attachment:pyscrapers04.png
attachment:pyscrapers04.png

Latest revision as of 13:49, 9 December 2008

Build a city in Python using just while loops and the PIL? Yes, and along the way some basic principles of programming visualisations and simple 3D with isometric projection.

You start by establishing a grid (based in this case on a single variable, gridsize, which determines the width in height, in pixels, of each cell of the grid).

Nested while loops create a two-dimensional iterator that draws the grid cell by cell.

#!python numbers=off
import math, random	     ## standard Python modules
import Image, [[ImageDraw]]	     ## PIL modules

width = 480
height = 360
im = Image.new("RGB", (width, height))
draw = [[ImageDraw]].Draw(im)

gridsize = 24
cols = width / gridsize
rows = height / gridsize
print "drawing with", cols, "columns, and", rows, "rows"

r = 0
while r &lt; rows:
	c = 0
	while c &lt; cols:
		left = c*gridsize
		top = r*gridsize
		right = left + gridsize
		bottom = top + gridsize
		draw.rectangle((left, top, right, bottom))
		c += 1
	
	r += 1

im.save("pyscrapers01.png", "png")

attachment:pyscrapers01.png

Now, you can use one of the loop variables, say the columns, or c, to determine a color to use in filling each cell. Here, we use some basic maths to translate the column index to an RGB value. Notice the use of 1.0 to force Python to use precise (floating point) math, and then the int() function to finally turn the result back into a whole number (as needed for the color specification for the PIL).

#!python numbers=off
colorcomp = int((1.0*c/cols) * 255)

The PIL accepts color defined as text string in the form "rgb(red, green, blue)" where red, green, and blue are (whole) numbers from 0 to 255, each specifying the amount of each color. To translate the colorcomp variable to a PIL-format string, you could use. Notice again how you need to use str() to convert the integer to a string type:

#!python numbers=off
color="rgb("+str(colorcomp)+",0,0)"

Here's the full code, and resulting image, using this colorcomp variable as the red component of the cell color:

#!python numbers=off
import math, random
import Image, [[ImageDraw]]

width = 480
height = 360
im = Image.new("RGB", (width, height))
draw = [[ImageDraw]].Draw(im)

gridsize = 24
cols = width / gridsize
rows = height / gridsize
print "drawing with", cols, "columns, and", rows, "rows"

r = 0
while r &lt; rows:
	c = 0
	while c &lt; cols:
		colorcomp = int((1.0*c/cols)*255)
		color = "rgb("+str(colorcomp)+",0,0)"
		left = c*gridsize
		top = r*gridsize
		right = left + gridsize
		bottom = top + gridsize
		draw.rectangle((left, top, right, bottom), fill=color)
		c += 1
	
	r += 1

im.save("pyscrapers02.png", "png")

attachment:pyscrapers02.png

You could use the same technique to translate the row to the level of blue in the fill color:

#!python numbers=off
import math, random
import Image, [[ImageDraw]]

width = 480
height = 360
im = Image.new("RGB", (width, height))
draw = [[ImageDraw]].Draw(im)

gridsize = 24
cols = width / gridsize
rows = height / gridsize
print "drawing with", cols, "columns, and", rows, "rows"

r = 0
while r &lt; rows:
	c = 0
	while c &lt; cols:
		redcomp = int((1.0*c/cols)*255)
		bluecomp = int((1.0*r/rows)*255)
		color = "rgb("+str(redcomp)+",0,"+str(bluecomp)+")"
		left = c*gridsize
		top = r*gridsize
		right = left + gridsize
		bottom = top + gridsize
		draw.rectangle((left, top, right, bottom), fill=color)
		c += 1
	
	r += 1

im.save("pyscrapers03.png", "png")

attachment:pyscrapers03.png

The PIL also allows color to specified as HSL (hue-saturation-lightness) triplets. The format is "hsl(hue,sat%,lightness%)", where the hue is a (whole) number from 0 to 360 (degrees on a color wheel, where 0 is red), and saturation and lightness are percentages (whole numbers from 0 to 100). Read more color models supported by the PIL: http://www.pythonware.com/library/pil/handbook/imagecolor.htm

You could apply the same idea above, now mapping column to saturation, and row to lightness. The hue in this case is a constant, set in this case to 0:

#!python numbers=off
import math, random
import Image, [[ImageDraw]]

width = 480
height = 360
im = Image.new("RGB", (width, height))
draw = [[ImageDraw]].Draw(im)

gridsize = 24
cols = width / gridsize
rows = height / gridsize
print "drawing with", cols, "columns, and", rows, "rows"

r = 0
while r &lt; rows:
	c = 0
	while c &lt; cols:
		hue = 0
		satcomp = int((1.0*c/cols)*100)
		lcomp = int((1.0*r/rows)*100)
		color = "hsl("+str(hue)+","+str(satcomp)+"%,"+str(lcomp)+"%)"
		left = c*gridsize
		top = r*gridsize
		right = left + gridsize
		bottom = top + gridsize
		draw.rectangle((left, top, right, bottom), fill=color)
		c += 1
	
	r += 1

im.save("pyscrapers04.png", "png")

attachment:pyscrapers04.png

HSL is often a very useful color model for creating visualisations, as it allows you to use variations of brightness / saturation while preserving a particular color (hue). For drawing PyScrapers, HSL will be useful to simulate some basic lighting / shadow effects.

On to PyScrapers2...