--[==[ -- -- Plots a graph based on values passed in Query String -- Doug Rice (c) copyright Jan,feb 2009 -- -- http:--127.0.0.1/pnggraph.php?xValues=1,2,3,4,5,6,7&yValues=10,20,25,12,23,24,45,90,23 -- http:--127.0.0.1/pnggraph.php?xValues=1,2,3,4,5,6,7&yValues=10,20,25,12,23,24,45,90,23&xLabel=count&yLabel=calls -- -- -- Get values from Query String or form post. -- Lists are csv -- -- -- -- ]==] -- -- lua-GD: http://lua-gd.luaforge.net/manual.html#license.luagd -- http://www.lua.org/license.html -- yvaluesA = { -10,3,-2,2,4,2,3,1,1,5 } yvalues1A = { -5,-10,3,-2,2,4,2,3,1,1,5 } yScaleStr = "yTest" xScaleStr= "xTest" -- -------------------------------------------------- -- Sec 0.0 includes -- -------------------------------------------------- require "gd" -- -- sec 2.0 - Get min and max for both x and Y so graphs fit. -- im = nil title = " Title:" key = " Key:" xScale = "xScale:" yScale = "yScale:" xLabel = "xLabel:" yLabel = "yLabel:" xmin = 0 xmax = 1 -- ymin = 0 -- ymax = 0 ymin = nil ymax = nil xmin = 0 xmax = 0 mm = 0 -- im_graph = nil xscale = nil y_graph_width = nil yscale = nil help = nil function floor ( a ) return a end function findMinMax( yTempvaluesA) if ( "table" == type( yTempvaluesA ) ) then -- global ymin, ymax, xmin, xmax, mm -- find min and max values cnt = 1 while( "number" == type( yTempvaluesA[ cnt ] ) ) do y0 = yTempvaluesA[ cnt ] -- Initilise ymin and ymax using the first value if ( "nil" == type( ymin) ) then ymin = y0 ymax = ymin end if ( ymin > y0 ) then ymin = y0 end if ( ymax < y0 ) then ymax = y0 end if ( xmax < cnt ) then xmax = cnt end cnt = cnt + 1 end end end xmin = 0 -- find min max for the six lines findMinMax( yvaluesA) print( xmin, xmax , ymin, ymax ) findMinMax( yvalues1A) findMinMax( yvalues2A) findMinMax( yvalues3A) findMinMax( yvalues4A) findMinMax( yvalues5A) findMinMax( yLogicA) -- -- sec 3.0 - Map values onto Graph Canvas. -- -- header("Content-type: im:/png") x_graph_width = 400 x_graph_width = 500 y_graph_width = 200 if ( ( xmax- xmin) > 0 ) then xscale = ( x_graph_width)/( xmax- xmin) else xscale = 1 end if ( ( ymax- ymin) > 0 ) then yscale = ( y_graph_width)/( ymax- ymin) else yscale = 1 end xLabelHeight = 30 yoo = 1 yok = xLabelHeight + yoo yog = xLabelHeight + yok yos = y_graph_width + yog yol = xLabelHeight + yos yom = xLabelHeight + yol yomm = 1 + yom xoo = 1 xos = xLabelHeight + xoo xol = xLabelHeight + xos xor = x_graph_width + xol xom = xLabelHeight + xor xomm = 1 + xom -- Label Offsets -- point size yop = 10 xop = 10 --graph xobl = xol yobl = yos xotr = xor yotr = yog -- -- sec 4.0 - Create Canvas and colours. -- im = gd.createTrueColor( xomm+1, yomm+1) -- next needed for text widths. im_text = gd.createTrueColor( xomm+1, yomm+1) im_graph = gd.createTrueColor( x_graph_width+1, y_graph_width+1) im_graph:setThickness(3) black = im:colorAllocate( 0, 0, 0) white = im:colorAllocate( 255, 255, 255) red = im:colorAllocateAlpha( 255, 0, 0, 4 ) green = im:colorAllocateAlpha( 0, 255, 0, 4 ) blue = im:colorAllocateAlpha( 0, 0, 255, 4 ) yellow = im:colorAllocateAlpha( 255, 255, 220, 4 ) purple = im:colorAllocateAlpha( 0, 255, 255, 4 ) orange = im:colorAllocateAlpha( 255, 200, 0, 4 ) cyan = im:colorAllocateAlpha( 200, 0, 200, 4 ) gray = im:colorAllocateAlpha( 127, 127, 127, 32 ) im_graph:setThickness(1) -- BackGround im:filledRectangle( xoo, yoo, xom, yom, white) -- graph im:filledRectangle( xol, yog, xor, yos, white) -- -- we have to plot the graph then add axis. -- I cannot find a clipping rectangle function -- so plot to im_graph and then copy onto main im: im -- im_graph = gd.createTrueColor( x_graph_width, y_graph_width) im_graph:filledRectangle( 0,0, x_graph_width, y_graph_width, yellow) -- we have to plot the graph then add axis. function plotBar( yvaluesA, lineColour , offset ) if ( "table" == type( yvaluesA ) ) then -- global im_graph, xscale , y_graph_width, yscale, ymin --itterate through the y values. cnt = 0 -- to have a thick line you have to use the im:setbrush() -- and im:line( im_graph, x0,y0,x1,y1, IMG_COLOR_BRUSHED ) -- Set the brush im_brush = im:createtruecolor(3,3) im_brush:filledRectangle( 0,0, 6,6, lineColour ) im_graph:setbrush( im_brush) while( isset( yvaluesA[ cnt+1] ) ) do -- if x value does not exist use cnt x0 = cnt*7 x1 = ( cnt+1) y0 = yvaluesA[ cnt] y1 = yvaluesA[ cnt+1] im_graph:line( ( x0 - xmin + offset ) * xscale/7, y_graph_width - ( y0 - ymin ) * yscale, ( x0 - xmin + offset ) * xscale/7, y_graph_width - ymin * yscale, IMG_COLOR_BRUSHED ) cnt = cnt + 1 end end end function plotLine( yvaluesA, lineColour ) if ( "table" == type( yvaluesA ) ) then --itterate through the y values. cnt = 1 -- to have a thick line you have to use the im:setbrush() -- and im:line( im_graph, x0,y0,x1,y1, IMG_COLOR_BRUSHED ) -- Set the brush im_brush = gd.createTrueColor(3,3) im_brush:filledRectangle( 0,0, 6,6, lineColour ) im_graph:setBrush( im_brush) while( "number" == type( yvaluesA[ cnt+1] ) ) do -- if x value does not exist use cnt x0 = cnt x1 = ( cnt+1) y0 = yvaluesA[ cnt] y1 = yvaluesA[ cnt+1] im_graph:line( ( x0- xmin)* xscale , y_graph_width - ( y0- ymin)* yscale, ( x1- xmin)* xscale, y_graph_width-( y1- ymin)* yscale, gd.BRUSHED ) -- print( ( x0- xmin)* xscale , y_graph_width - ( y0- ymin)* yscale, ( x1- xmin)* xscale, y_graph_width-( y1- ymin)* yscale, lineColour ) -- im_graph:line( ( x0- xmin)* xscale , y_graph_width - ( y0- ymin)* yscale, ( x1- xmin)* xscale, y_graph_width-( y1- ymin)* yscale, lineColour ) cnt = cnt + 1 end end end --[==[ function plotLogic( yvaluesA, colour1, colour0, numBits ) -- -- plots the values in yLogic as a logic analyser waveform -- keyA = explode(",", _REQUEST["key"]) if ( "table" == type( yvaluesA ) ) then -- global im_graph, xscale , y_graph_width, yscale, ymin --itterate through the y values. cnt = 0 im:setthickness( im_graph,2) while( isset( yvaluesA[ cnt+1] ) ) do -- if x value does not exist use cnt x0 = cnt x1 = ( cnt+1) y0 = yvaluesA[ cnt] y1 = yvaluesA[ cnt+1] -- im:line( im_graph, ( x0- xmin)* xscale , y_graph_width - ( y0- ymin)* yscale, ( x1- xmin)* xscale, y_graph_width-( y1- ymin)* yscale, IMG_COLOR_BRUSHED ) -- im:line( im_graph, ( x0- xmin)* xscale , y_graph_width - ( y0- ymin)* yscale, ( x1- xmin)* xscale, y_graph_width-( y1- ymin)* yscale, lineColour ) p2 = 1 for cnt2 = 0 , numBits , 1 do bit = y0 & p2 nextBit = y1 & p2 p2 = p2 + p2 if ( bit > 0 ) then logicColour = colour1 bitoffset = 0.5 else logicColour = colour0 bitoffset = 0.8 end if ( nextBit <> bit ) then im:line( im_graph, ( x1- xmin)* xscale , ( cnt2 + 0.5 )* y_graph_width/ numBits, ( x1- xmin)* xscale, ( cnt2 + 0.8 )* y_graph_width/ numBits, logicColour ) end im:line( im_graph, ( x0- xmin)* xscale , ( cnt2+ bitoffset )* y_graph_width/ numBits, ( x1- xmin)* xscale, ( cnt2 + bitoffset )* y_graph_width/ numBits, logicColour ) end cnt++ end p2 = 1 for( cnt2 = 0 cnt2 < numBits cnt2++ ) p2 = p2 + p2 im:stringFT( black, font, im_graph, y_graph_width/ numBits/3, 0, 0 , ( cnt2+0.4 )* y_graph_width/ numBits, black, './Vera.ttf', "B". cnt2 .",". keyA[ cnt2] ) end end end ]==] -- -- sec 5.0 - Draw Graph. -- -- Plot data onto graph panel if ( graphType == "bar" ) then plotBar( yvaluesA, red ,1 ) plotBar( yvalues1A, green ,2 ) plotBar( yvalues2A, blue ,3 ) plotBar( yvalues3A, purple,4 ) plotBar( yvalues4A, orange,5) plotBar( yvalues5A, cyan ,6) else plotLine( yvaluesA, red) plotLine( yvalues1A, green) plotLine( yvalues2A, blue) plotLine( yvalues3A, purple) plotLine( yvalues4A, orange) plotLine( yvalues5A, cyan) end -- im_graph:png("out_im_g.png") -- yLogicA = explode(",", _REQUEST["yLogic"]) if ( "table" == type( "yLogic" , _REQUEST ) ) then plotLogic( yLogicA, green, blue, 10 ) end -- -- plot Graticle at 10 sub divisions im_graph:setThickness( 1 ) if ( "table" == type( "yLogic" , _REQUEST ) ) then step = floor( y_graph_width/10 ) for cnt = 1 , 10 , 1 do offset = y_graph_width - cnt* step im:line( im_graph, 0, offset, x_graph_width, offset, gray ) end end step = floor( x_graph_width/10 ) for cnt = 1 , 10 , 1 do offset = cnt* step im_graph:line( offset, 0, offset , y_graph_width, gray ) end font = "./Vera.ttf" if help then yop = yop im:stringFT( black, font, yop, 10, 0, xol, yog + yop*2, " usage:Set Query string. Spaces replaced by +" ) im:stringFT( black, font, yop, 10, 0, xol, yog + yop*3, " ?title=title+text&key=Key+text" ) im:stringFT( black, font, yop, 10, 0, xol, yog + yop*4, " &yLabel=Label+text&xLabel=Label+text" ) im:stringFT( black, font, yop, 10, 0, xol, yog + yop*5, " &xScale=smallText" ) im:stringFT( black, font, yop, 10, 0, xol, yog + yop*6, " &yScale=smallText" ) im:stringFT( black, font, yop, 10, 0, xol, yog + yop*8, " &yValues=10,20,34,2,34" ) im:stringFT( black, font, yop, 10, 0, xol, yog + yop*9, " &yValues1=10,20,34,2,34" ) im:stringFT( black, font, yop, 10, 0, xol, yog + yop*10, " &yValues2=10,20,34,2,34" ) im:stringFT( black, font, yop, 10, 0, xol, yog + yop*11, " &yValues3=10,20,34,2,34" ) im:stringFT( black, font, yop, 10, 0, xol, yog + yop*12, " &yValues4=10,20,34,2,34" ) im:stringFT( black, font, yop, 10, 0, xol, yog + yop*13, " &yValues5=10,20,34,2,34" ) im:stringFT( black, font, yop, 10, 0, xol, yog + yop*15, " &yLogic=3,4,2,2,2,2" ) im:stringFT( black, font, yop, 10, 0, xol, yog + yop*17, " &graphType=bar" ) title = " Title:" key = " Key:" xScale = "xScale:" yScale = "yScale:" xLabel = "xLabel:" yLabel = "yLabel:" -- im:copy ( im_graph, xol, yog, 0, 0, x_graph_width, y_graph_width ) else -- I cannot find a cliping function so plot graph on a small panel and then copy onto main im: im:copy ( im_graph, xol, yog, 0, 0, x_graph_width, y_graph_width ) im:rectangle( xol, yog, xor, yos, black) -- graph end -- -- point,angle,x,y im:stringFT( black, font, yop*1.5, 0, xoo, ( yoo+ yok)/2 + yop/2 , title ) -- Title im:setThickness(3) -- Plot key -- yoff = ( yok+ yog )/2 yoff = yok+5 if ( "table" == type( "yLogic" , _REQUEST ) ) then im:line( xoo+ 5, yoff, xoo+20, yoff, red) im:line( xoo+25, yoff, xoo+40, yoff, green) im:line( xoo+45, yoff, xoo+60, yoff, blue) im:line( xoo+65, yoff, xoo+80, yoff, purple) im:line( xoo+85, yoff, xoo+100, yoff, orange) im:line( xoo+105, yoff, xoo+120, yoff, cyan) im:stringFT( black, font, yop, math.rad(90), 0, xoo, ( yok+ yog)/2 + yop/2 , black, font, " key: " .. _REQUEST["key"] ) -- key end im:stringFT( black, font, yop*1.25, math.rad(90), ( xoo+ xos)/2+ xop/2, yos, yLabel ) -- yLabel im:stringFT( black, font, yop*1.25, 0, xol, ( yol+ yom)/2 + yop/2, xLabel ) -- -- sec 6.0 - Annotate Scales. -- -- -- y scale, plot ymin at bottom, left justified and ymin at top, right justified -- if ( "table" == type( "yLogic" , _REQUEST ) ) then im:stringFT( black, font, yop, math.rad(90), ( xos+ xol)/2+ xop/2, yos, ymin ) -- yScale -- find bounding box to find width. -- this works but is not right. bbox = im:ttfbbox( yop, -90, font, ymax) width = bbox[3] im:stringFT( black, font, yop, math.rad(90), ( xos+ xol)/2+ xop/2, yog+ width, ymax ) -- yScale else im:stringFT( black, font, yop, math.rad(90), ( xos+ xol)/2+ xop/2, yos, ymin ) -- yScale im:stringFT( black, font, yop, math.rad(90), ( xos+ xol)/2+ xop/2, yog, ymax ) -- yScale end im:stringFT( black, font, yop , math.rad(90) , ( xos+ xol)/2+ xop/2, ( yog+ yos)/2, yScaleStr ) -- xScale -- -- x scale, plot xmin at left, left justified and ymin at right, right justified -- --gdImage:stringFT(color, fontname, ptsize, angle, x, y, string) im:stringFT( black, font, yop , 0 , xol, ( yos+ yol)/2 + yop/2, xmin ) -- xScale im:stringFT( black, font, yop , 0 , xor, ( yos+ yol)/2 + yop/2, xmax ) -- xScale llx, lly, lrx, lry, urx, ury, ulx, uly = gd.stringFT(nil, black, font, yop, 0, ( xol+ xor)/2 , ( yos+ yol)/2 + yop/2, xScaleStr ) width = ( lry-llx ) im:stringFT( black, font, yop, 0, ( xol+ xor)/2- width/2 , ( yos+ yol)/2 + yop/2, xScaleStr ) -- xScale -- find bounding box to find width. copyRightText = "pnggraph.php Copyright (c) Doug Rice 2009 " llx, lly, lrx, lry, urx, ury, ulx, uly = gd.stringFT(nil, black, font, yop*0.5, 0, xoo , yol + yop*0.5, copyRightText ) width = ( lry-llx ) im:stringFT( gray, font, yop*0.5, 0, xomm- width , yom + yop*0.5, copyRightText ) -- xScale -- -- sec 7.0 - Output graph. -- -- output stream of data im:png("out.png") --[==[ Produces graph. yoo -------------------------------|------| title panel yok -------------------------------|------| Key panel yog -------------------------------|------| yLabel | yScale | graph | | yos -------------------------------|------| | xScale | yol -------------------------------|------| | xLabel | yom -------------------------------|------| yomm--------------------------------------- | | | | | xoo xos xol xor xom xomm */ ]==]