--[[
This is the execution script for the `Lua generic terminal' driver.
This script provides an interface to the PGF/TikZ package for LaTeX.
Copyright 2008 Peter Hedwig <peter@affenbande.org>
Permission to use, copy, and distribute this software and its
documentation for any purpose with or without fee is hereby granted,
provided that the above copyright notice appear in all copies and
that both that copyright notice and this permission notice appear
in supporting documentation.
Permission to modify the software is granted, but not the right to
distribute the complete modified source code. Modifications are to
be distributed as patches to the released version. Permission to
distribute binaries produced by compiling modified sources is granted,
provided you
1. distribute the corresponding source modifications from the
released version in the form of a patch file along with the binaries,
2. add special version identification to distinguish your version
in addition to the base release version number,
3. provide your name and address as the primary contact for the
support of your modified version, and
4. retain our contact information in regard to use of the base
software.
Permission to distribute the released version of the source code along
with corresponding source modifications in the form of a patch file is
granted with same provisions 2 through 4 for binary distributions.
This software is provided "as is" without express or implied warranty
to the extent permitted by applicable law.
]]--
--[[
`term' gnuplot term_api -> local interface
`gp' local -> gnuplot interface
are both initialized by the terminal
]]--
--
-- internal variables
--
local pgf = {}
local gfx = {}
-- the terminal default size in cm
pgf.DEFAULT_CANVAS_SIZE_X = 12.5
pgf.DEFAULT_CANVAS_SIZE_Y = 8.75
-- tic default size in cm
pgf.DEFAULT_TIC_SIZE = 0.18
-- the terminal resolution in "dots" per cm.
pgf.DEFAULT_RESOLUTION = 1000
-- default font size in TeX pt
pgf.DEFAULT_FONT_SIZE = 10
-- default sizes for CM@10pt and default resolution
-- there is no need to adapt these values when changing
-- pgf.DEFAULT_FONT_SIZE or pgf.DEFAULT_RESOLUTION !
pgf.DEFAULT_FONT_H_CHAR = 184
pgf.DEFAULT_FONT_V_CHAR = 308
pgf.STYLE_FILE_BASENAME = "gnuplot-lua-tikz" -- \usepackage{gnuplot-lua-tikz}
pgf.REVISION = "105"
pgf.REVISION_DATE = "2018/03/13 18:43:00"
pgf.styles = {}
-- the styles are used in conjunction with the 'tikzarrows'
-- and the style number directly corresponds to the used
-- angle in the gnuplot style definition
pgf.styles.arrows = {
[1] = {"gp arrow 1", ">=latex"},
[2] = {"gp arrow 2", ">=angle 90"},
[3] = {"gp arrow 3", ">=angle 60"},
[4] = {"gp arrow 4", ">=angle 45"},
[5] = {"gp arrow 5", ">=o"},
[6] = {"gp arrow 6", ">=*"},
[7] = {"gp arrow 7", ">=diamond"},
[8] = {"gp arrow 8", ">=open diamond"},
[9] = {"gp arrow 9", ">={]}"},
[10] = {"gp arrow 10", ">={[}"},
[11] = {"gp arrow 11", ">=)"},
[12] = {"gp arrow 12", ">=("}
}
-- plot styles are corresponding with linetypes and must have the same number of entries
-- see option 'tikzplot' for usage
pgf.styles.plotstyles_axes = {
[1] = {"gp plot axes", ""},
[2] = {"gp plot border", ""},
}
pgf.styles.plotstyles = {
[1] = {"gp plot 0", "smooth"},
[2] = {"gp plot 1", "smooth"},
[3] = {"gp plot 2", "smooth"},
[4] = {"gp plot 3", "smooth"},
[5] = {"gp plot 4", "smooth"},
[6] = {"gp plot 5", "smooth"},
[7] = {"gp plot 6", "smooth"},
[8] = {"gp plot 7", "smooth"}
}
pgf.styles.linetypes_axes = {
[1] = {"gp lt axes", "dotted"}, -- An lt of -1 is used for the X and Y axes.
[2] = {"gp lt border", "solid"}, -- An lt of -2 is used for the border of the plot.
}
pgf.styles.linetypes = {
[1] = {"gp lt plot 0", ""}, -- first graph
[2] = {"gp lt plot 1", ""}, -- second ...
[3] = {"gp lt plot 2", ""},
[4] = {"gp lt plot 3", ""},
[5] = {"gp lt plot 4", ""},
[6] = {"gp lt plot 5", ""},
[7] = {"gp lt plot 6", ""},
[8] = {"gp lt plot 7", ""}
}
pgf.styles.dashtypes_axes = {
[1] = {"gp dt solid", "solid"},
[2] = {"gp dt axes", "dotted"}
}
pgf.styles.dashtypes = {
[0] = {"gp dt 0", "solid"},
[1] = {"gp dt 1", "solid"},
[2] = {"gp dt 2", "dash pattern=on 7.5*\\gpdashlength off 7.5*\\gpdashlength"},
[3] = {"gp dt 3", "dash pattern=on 3.75*\\gpdashlength off 5.625*\\gpdashlength"},
[4] = {"gp dt 4", "dash pattern=on 1*\\gpdashlength off 2.8125*\\gpdashlength"},
[5] = {"gp dt 5", "dash pattern=on 11.25*\\gpdashlength off 3.75*\\gpdashlength on 1*\\gpdashlength off 3.75*\\gpdashlength"},
[6] = {"gp dt 6", "dash pattern=on 5.625*\\gpdashlength off 5.625*\\gpdashlength on 1*\\gpdashlength off 5.625*\\gpdashlength"},
[7] = {"gp dt 7", "dash pattern=on 3.75*\\gpdashlength off 3.75*\\gpdashlength on 3.75*\\gpdashlength off 11.25*\\gpdashlength"},
[8] = {"gp dt 8", "dash pattern=on 1*\\gpdashlength off 3.75*\\gpdashlength on 11.25*\\gpdashlength off 3.75*\\gpdashlength on 1*\\gpdashlength off 3.75*\\gpdashlength"}
}
-- corresponds to pgf.styles.linetypes
pgf.styles.lt_colors_axes = {
[1] = {"gp lt color axes", "black!30"},
[2] = {"gp lt color border", "black"},
}
pgf.styles.lt_colors = {
[1] = {"gp lt color 0", "red"},
[2] = {"gp lt color 1", "green"},
[3] = {"gp lt color 2", "blue"},
[4] = {"gp lt color 3", "magenta"},
[5] = {"gp lt color 4", "cyan"},
[6] = {"gp lt color 5", "yellow"},
[7] = {"gp lt color 6", "orange"},
[8] = {"gp lt color 7", "purple"}
}
pgf.styles.patterns = {
[1] = {"gp pattern 0", "white"},
[2] = {"gp pattern 1", "pattern=north east lines"},
[3] = {"gp pattern 2", "pattern=north west lines"},
[4] = {"gp pattern 3", "pattern=crosshatch"},
[5] = {"gp pattern 4", "pattern=grid"},
[6] = {"gp pattern 5", "pattern=vertical lines"},
[7] = {"gp pattern 6", "pattern=horizontal lines"},
[8] = {"gp pattern 7", "pattern=dots"},
[9] = {"gp pattern 8", "pattern=crosshatch dots"},
[10] = {"gp pattern 9", "pattern=fivepointed stars"},
[11] = {"gp pattern 10", "pattern=sixpointed stars"},
[12] = {"gp pattern 11", "pattern=bricks"}
}
pgf.styles.plotmarks = {
[1] = {"gp mark 0", "mark size=.5\\pgflinewidth,mark=*"}, -- point (-1)
[2] = {"gp mark 1", "mark=+"},
[3] = {"gp mark 2", "mark=x"},
[4] = {"gp mark 3", "mark=star"},
[5] = {"gp mark 4", "mark=square"},
[6] = {"gp mark 5", "mark=square*"},
[7] = {"gp mark 6", "mark=o"},
[8] = {"gp mark 7", "mark=*"},
[9] = {"gp mark 8", "mark=triangle"},
[10] = {"gp mark 9", "mark=triangle*"},
[11] = {"gp mark 10", "mark=triangle,every mark/.append style={rotate=180}"},
[12] = {"gp mark 11", "mark=triangle*,every mark/.append style={rotate=180}"},
[13] = {"gp mark 12", "mark=diamond"},
[14] = {"gp mark 13", "mark=diamond*"},
[15] = {"gp mark 14", "mark=otimes"},
[16] = {"gp mark 15", "mark=oplus"}
}
--[[===============================================================================================
helper functions
]]--===============================================================================================
-- from the Lua wiki
explode = function(div,str)
if (div=='') then return false end
local pos,arr = 0,{}
local trim = function(s) return (string.gsub(s,"^%s*(.-)%s*$", "%1")) end
-- for each divider found
for st,sp in function() return string.find(str,div,pos,true) end do
table.insert(arr, trim(string.sub(str,pos,st-1))) -- Attach chars left of current divider
pos = sp + 1 -- Jump past current divider
end
table.insert(arr, trim(string.sub(str,pos))) -- Attach chars right of last divider
return arr
end
--[[===============================================================================================
The PGF/TikZ output routines
]]--===============================================================================================
pgf.transform_xcoord = function(coord)
return (coord+gfx.origin_xoffset)*gfx.scalex
end
pgf.transform_ycoord = function(coord)
return (coord+gfx.origin_yoffset)*gfx.scaley
end
pgf.format_coord = function(xc, yc)
return string.format("%.3f,%.3f", pgf.transform_xcoord(xc), pgf.transform_ycoord(yc))
end
pgf.write_doc_begin = function(preamble)
gp.write(gfx.format[gfx.opt.tex_format].docheader)
gp.write(preamble)
gp.write(gfx.format[gfx.opt.tex_format].begindocument)
end
pgf.write_doc_end = function()
gp.write(gfx.format[gfx.opt.tex_format].enddocument)
end
pgf.write_graph_begin = function (font, noenv)
local global_opt = "" -- unused
if gfx.opt.full_doc then
gp.write(gfx.format[gfx.opt.tex_format].beforetikzpicture)
end
if noenv then
gp.write("%% ") -- comment out
end
gp.write(string.format("%s[gnuplot%s]\n", gfx.format[gfx.opt.tex_format].begintikzpicture, global_opt))
gp.write(string.format("%%%% generated with GNUPLOT %sp%s (%s; terminal rev. %s, script rev. %s)\n",
term.gp_version, term.gp_patchlevel, _VERSION, string.sub(term.lua_term_revision,7,-2), pgf.REVISION))
if not gfx.opt.notimestamp then
gp.write(string.format("%%%% %s\n", os.date()))
end
if font ~= "" then
gp.write(string.format("\\tikzset{every node/.append style={font=%s}}\n", font))
end
if gfx.opt.fontscale ~= nil then
gp.write(string.format("\\tikzset{every node/.append style={scale=%.2f}}\n", gfx.opt.fontscale))
end
if not gfx.opt.lines_colored then
gp.write("\\gpmonochromelines\n")
end
if gfx.opt.bgcolor ~= nil then
gp.write(string.format("\\gpsetbgcolor{%.3f,%.3f,%.3f}\n", gfx.opt.bgcolor[1], gfx.opt.bgcolor[2], gfx.opt.bgcolor[3]))
end
if gfx.opt.dashlength ~= nil then
gp.write(string.format("\\def\\gpdashlength{%.2f\\pgflinewidth}\n", gfx.opt.dashlength))
end
end
pgf.write_graph_end = function(noenv)
if noenv then
gp.write("%% ") -- comment out
end
if gfx.opt.full_doc then
gp.write(gfx.format[gfx.opt.tex_format].beforeendtikzpicture)
end
gp.write(gfx.format[gfx.opt.tex_format].endtikzpicture .. "\n")
if gfx.opt.full_doc then
gp.write(gfx.format[gfx.opt.tex_format].aftertikzpicture)
end
end
pgf.draw_path = function(t)
local use_plot = false
local c_str = '--'
-- is the current linetype in the list of plots?
if #gfx.opt.plot_list > 0 then
for k, v in pairs(gfx.opt.plot_list) do
if gfx.linetype_idx_set == v then
use_plot = true
c_str = ' '
break
end
end
end
gp.write("\\draw[gp path")
if gfx.opacity < 1.0 then
gp.write(string.format(",opacity=%.3f", gfx.opacity))
end
gp.write("] ")
if use_plot then
gp.write("plot["..pgf.styles.plotstyles[((gfx.linetype_idx_set) % #pgf.styles.plotstyles)+1][1].."] coordinates {")
end
gp.write("("..pgf.format_coord(t[1][1], t[1][2])..")")
for i = 2,#t-1 do
-- pretty printing
if (i % 6) == 0 then
gp.write("%\n ")
end
gp.write(c_str.."("..pgf.format_coord(t[i][1], t[i][2])..")")
end
if (#t % 6) == 0 then
gp.write("%\n ")
end
-- check for a cyclic path
if (t[1][1] == t[#t][1]) and (t[1][2] == t[#t][2]) and (not use_plot) then
gp.write("--cycle")
else
gp.write(c_str.."("..pgf.format_coord(t[#t][1], t[#t][2])..")")
end
if use_plot then
gp.write("}")
end
gp.write(";\n")
end
pgf.draw_arrow = function(t, direction, headstyle)
gp.write("\\draw[gp path")
if direction ~= '' and direction ~= nil then
gp.write(","..direction)
end
if headstyle > 0 then
gp.write(",gp arrow "..headstyle)
end
if gfx.opacity < 1.0 then
gp.write(string.format(",opacity=%.3f", gfx.opacity))
end
gp.write("]")
gp.write("("..pgf.format_coord(t[1][1], t[1][2])..")")
for i = 2,#t do
if (i % 6) == 0 then
gp.write("%\n ")
end
gp.write("--("..pgf.format_coord(t[i][1], t[i][2])..")")
end
gp.write(";\n")
end
pgf.draw_points = function(t, pm)
gp.write("\\gppoint{"..pm.."}{")
for i,v in ipairs(t) do
gp.write("("..pgf.format_coord(v[1], v[2])..")")
end
gp.write("}\n")
end
pgf.set_linetype = function(linetype)
gp.write("\\gpsetlinetype{"..linetype.."}\n")
end
pgf.set_dashtype = function(dashtype)
gp.write("\\gpsetdashtype{"..dashtype.."}\n")
end
pgf.set_color = function(color)
gp.write("\\gpcolor{"..color.."}\n")
end
pgf.set_linewidth = function(width)
gp.write(string.format("\\gpsetlinewidth{%.2f}\n", width))
end
pgf.set_pointsize = function(size)
gp.write(string.format("\\gpsetpointsize{%.2f}\n", 4*size))
end
pgf.write_text_node = function(t, text, angle, justification, font)
local node_options = justification
if angle ~= 0 then
node_options = node_options .. ",rotate=" .. angle
end
if font ~= '' then
node_options = node_options .. ",font=" .. font
end
node_name = ''
if gfx.boxed_text then
gfx.boxed_text_count = gfx.boxed_text_count + 1
node_options = node_options .. ",inner sep=0pt"
node_name = string.format("(gp boxed node %d)", gfx.boxed_text_count)
end
if gfx.opacity < 1.0 then
node_options = node_options .. string.format(",text opacity=%.3f", gfx.opacity)
end
gp.write(string.format("\\node[%s]%s at (%s) {%s};\n",
node_options, node_name, pgf.format_coord(t[1], t[2]), text))
end
pgf.draw_fill = function(t, pattern, color, saturation, opacity)
local fill_path = ''
local fill_style = color
if saturation < 100 then
fill_style = fill_style .. ",color=.!"..saturation;
end
fill_path = fill_path .. '('..pgf.format_coord(t[1][1], t[1][2])..')'
-- draw 2nd to n-1 corners
for i = 2,#t-1 do
if (i % 5) == 0 then
-- pretty printing
fill_path = fill_path .. "%\n "
end
fill_path = fill_path .. '--('..pgf.format_coord(t[i][1], t[i][2])..')'
end
if (#t % 5) == 0 then
gp.write("%\n ")
end
-- draw last corner
-- 'cycle' is just for the case that we want to draw a
-- line around the filled area
if (t[1][1] == t[#t][1]) and (t[1][2] == t[#t][2]) then -- cyclic
fill_path = fill_path .. '--cycle'
else
fill_path = fill_path
.. '--('..pgf.format_coord(t[#t][1], t[#t][2])..')--cycle'
end
if pattern == '' then
-- solid fills
-- fill_style = 'color='..color
if opacity < 100 then
fill_style = fill_style..string.format(",opacity=%.2f", opacity/100)
else
-- fill_style = "" -- color ?
end
else
-- pattern fills
fill_style = fill_style..','..pattern..',pattern color=.'
end
local out = ''
if (pattern ~= '') and (opacity == 100) then
-- have to fill bg for opaque patterns
gp.write("\\def\\gpfillpath{"..fill_path.."}\n"
.. "\\gpfill{color=gpbgfillcolor} \\gpfillpath;\n"
.. "\\gpfill{"..fill_style.."} \\gpfillpath;\n")
else
gp.write("\\gpfill{"..fill_style.."} "..fill_path..";\n")
end
end
pgf.load_image_file = function(ll, ur, xfile)
gp.write(string.format("\\gploadimage{%.3f}{%.3f}{%.3f}{%.3f}{%s}\n",
pgf.transform_xcoord(ll[1]), pgf.transform_ycoord(ll[2]),
(pgf.transform_xcoord(ur[1]) - pgf.transform_xcoord(ll[1])),
(pgf.transform_ycoord(ur[2]) - pgf.transform_ycoord(ll[2])),
xfile))
end
pgf.draw_raw_rgb_image = function(t, m, n, ll, ur, xfile)
local gw = gp.write
local sf = string.format
local xs = sf("%.3f", pgf.transform_xcoord(ur[1]) - pgf.transform_xcoord(ll[1]))
local ys = sf("%.3f", pgf.transform_ycoord(ur[2]) - pgf.transform_ycoord(ll[2]))
gw("\\def\\gprawrgbimagedata{%\n ")
for cnt = 1,#t do
gw(sf("%02x%02x%02x", 255*t[cnt][1]+0.5, 255*t[cnt][2]+0.5, 255*t[cnt][3]+0.5))
if (cnt % 16) == 0 then
gw("%\n ")
end
end
gw("}%\n")
gw("\\gprawimage{rgb}{"..sf("%.3f", pgf.transform_xcoord(ll[1])).."}"
.."{"..sf("%.3f", pgf.transform_ycoord(ll[2])).."}"
.."{"..m.."}{"..n.."}{"..xs.."}{"..ys.."}{\\gprawrgbimagedata}{"..xfile.."}\n")
end
pgf.draw_raw_cmyk_image = function(t, m, n, ll, ur, xfile)
local gw = gp.write
local sf = string.format
local min = math.min
local max = math.max
local mf = math.floor
local UCRBG = {1,1,1,1} -- default corrections
local rgb2cmyk255 = function(r,g,b)
local c = 1-r
local m = 1-g
local y = 1-b
local k = min(c,m,y)
c = mf(255*min(1, max(0, c - UCRBG[1]*k))+0.5)
m = mf(255*min(1, max(0, m - UCRBG[2]*k))+0.5)
y = mf(255*min(1, max(0, y - UCRBG[3]*k))+0.5)
k = mf(255*min(1, max(0, UCRBG[4]*k))+0.5)
return c,m,y,k
end
local xs = sf("%.3f", pgf.transform_xcoord(ur[1]) - pgf.transform_xcoord(ll[1]))
local ys = sf("%.3f", pgf.transform_ycoord(ur[2]) - pgf.transform_ycoord(ll[2]))
gw("\\def\\gprawcmykimagedata{%\n ")
for cnt = 1,#t do
gw(sf("%02x%02x%02x%02x", rgb2cmyk255(t[cnt][1],t[cnt][2],t[cnt][3])))
if (cnt % 12) == 0 then
gw("%\n ")
end
end
gw("}%\n")
gw("\\gprawimage{cmyk}{"..sf("%.3f", pgf.transform_xcoord(ll[1])).."}"
.."{"..sf("%.3f", pgf.transform_ycoord(ll[2])).."}"
.."{"..m.."}{"..n.."}{"..xs.."}{"..ys.."}{\\gprawcmykimagedata}{"..xfile.."}\n")
end
pgf.write_clipbox_begin = function (ll, ur)
gp.write(gfx.format[gfx.opt.tex_format].beginscope.."\n")
gp.write(string.format("\\clip (%s) rectangle (%s);\n",
pgf.format_coord(ll[1],ll[2]),pgf.format_coord(ur[1],ur[2])))
end
pgf.write_clipbox_end = function()
gp.write(gfx.format[gfx.opt.tex_format].endscope.."\n")
end
pgf.write_boundingbox = function(t, num)
gp.write("%% coordinates of the plot area\n")
gp.write("\\gpdefrectangularnode{gp plot "..num.."}{"
..string.format("\\pgfpoint{%.3fcm}{%.3fcm}", pgf.transform_xcoord(t.xleft), pgf.transform_ycoord(t.ybot)).."}{"
..string.format("\\pgfpoint{%.3fcm}{%.3fcm}", pgf.transform_xcoord(t.xright), pgf.transform_ycoord(t.ytop)).."}\n")
end
pgf.write_variables = function(t)
gp.write("%% gnuplot variables\n")
for k, v in pairs(t) do
gp.write(string.format("\\gpsetvar{%s}{%s}\n",k,v))
end
end
-- write style to seperate file, or whatever...
pgf.create_style = function()
local name_common = pgf.STYLE_FILE_BASENAME.."-common.tex"
local name_latex = pgf.STYLE_FILE_BASENAME..".sty"
local name_tex = pgf.STYLE_FILE_BASENAME..".tex"
local name_context = "t-"..pgf.STYLE_FILE_BASENAME..".tex"
-- LaTeX
local f_latex = io.open(name_latex, "w+")
f_latex:write([[
%%
%% LaTeX wrapper for gnuplot-tikz style file
%%
\NeedsTeXFormat{LaTeX2e}
]])
f_latex:write("\\ProvidesPackage{"..pgf.STYLE_FILE_BASENAME.."}%\n")
f_latex:write(" ["..pgf.REVISION_DATE.." (rev. "..pgf.REVISION..") GNUPLOT Lua terminal style]\n\n")
f_latex:write([[
\RequirePackage{tikz}
\usetikzlibrary{arrows,patterns,plotmarks,backgrounds,fit}
]])
f_latex:write("\\input "..name_common.."\n")
f_latex:write([[
\endinput
]])
f_latex:close()
-- ConTeXt
local f_context = io.open(name_context, "w+")
f_context:write([[
%%
%% ConTeXt wrapper for gnuplot-tikz style file
%%
\usemodule[tikz]
\usetikzlibrary[arrows,patterns,plotmarks,backgrounds]
\edef\tikzatcode{\the\catcode`\@}
\edef\tikzbarcode{\the\catcode`\|}
\edef\tikzexclaimcode{\the\catcode`\!}
\catcode`\@=11
\catcode`\|=12
\catcode`\!=12
]])
f_context:write("\\input "..name_common.."\n")
f_context:write([[
\catcode`\@=\tikzatcode
\catcode`\|=\tikzbarcode
\catcode`\!=\tikzexclaimcode
\endinput
]])
f_context:close()
-- plain TeX
local f_tex = io.open(name_tex, "w+")
f_tex:write([[
%%
%% plain TeX wrapper for gnuplot-tikz style file
%%
\input tikz.tex
\usetikzlibrary{arrows,patterns,plotmarks,backgrounds}
\edef\tikzatcode{\the\catcode`\@}
\catcode`\@=11
]])
f_tex:write("\\input "..name_common.."\n\n")
f_tex:write([[
\catcode`\@=\tikzatcode
\endinput
]])
f_tex:close()
-- common
local f = io.open(name_common, "w+")
f:write([[
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Common style file for TeX, LaTeX and ConTeXt
%%
%% It is associated with the 'gnuplot.lua' script, and usually generated
%% automatically. So take care whenever you make any changes!
%%
% check for the correct TikZ version
\def\gpchecktikzversion#1.#2\relax{%
\ifnum#1<2%
\errmessage{PGF/TikZ version >= 2.0 is required!}%
\fi}
\expandafter\gpchecktikzversion\pgfversion\relax
% FIXME: is there a more elegant way to determine the output format?
\def\pgfsysdriver@a{pgfsys-dvi.def} % ps
\def\pgfsysdriver@b{pgfsys-dvipdfm.def} % pdf
\def\pgfsysdriver@c{pgfsys-dvipdfmx.def} % pdf
\def\pgfsysdriver@d{pgfsys-dvips.def} % ps
\def\pgfsysdriver@e{pgfsys-pdftex.def} % pdf
\def\pgfsysdriver@f{pgfsys-tex4ht.def} % html
\def\pgfsysdriver@g{pgfsys-textures.def} % ps
\def\pgfsysdriver@h{pgfsys-vtex.def} % ps
\def\pgfsysdriver@i{pgfsys-xetex.def} % pdf
\newif\ifgppdfout\gppdfoutfalse
\newif\ifgppsout\gppsoutfalse
\ifx\pgfsysdriver\pgfsysdriver@a
\gppsouttrue
\else\ifx\pgfsysdriver\pgfsysdriver@b
\gppdfouttrue
\else\ifx\pgfsysdriver\pgfsysdriver@c
\gppdfouttrue
\else\ifx\pgfsysdriver\pgfsysdriver@d
\gppsouttrue
\else\ifx\pgfsysdriver\pgfsysdriver@e
\gppdfouttrue
\else\ifx\pgfsysdriver\pgfsysdriver@f
% tex4ht
\else\ifx\pgfsysdriver\pgfsysdriver@g
\gppsouttrue
\else\ifx\pgfsysdriver\pgfsysdriver@h
\gppsouttrue
\else\ifx\pgfsysdriver\pgfsysdriver@i
\gppdfouttrue
\fi\fi\fi\fi\fi\fi\fi\fi\fi
% uncomment the following lines to make font values "appendable"
% and if you are really sure about that ;-)
% \pgfkeyslet{/tikz/font/.@cmd}{\undefined}
% \tikzset{font/.initial={}}
% \def\tikz@textfont{\pgfkeysvalueof{/tikz/font}}
%
% image related stuff
%
\def\gp@rawimage@pdf#1#2#3#4#5#6{%
\def\gp@tempa{cmyk}%
\def\gp@tempb{#1}%
\ifx\gp@tempa\gp@tempb%
\def\gp@temp{/CMYK}%
\else%
\def\gp@temp{/RGB}%
\fi%
\pgf@sys@bp{#4}\pgfsysprotocol@literalbuffered{0 0}\pgf@sys@bp{#5}%
\pgfsysprotocol@literalbuffered{0 0 cm}%
\pgfsysprotocol@literalbuffered{BI /W #2 /H #3 /CS \gp@temp}%
\pgfsysprotocol@literalbuffered{/BPC 8 /F /AHx ID}%
\pgfsysprotocol@literal{#6 > EI}%
}
\def\gp@rawimage@ps#1#2#3#4#5#6{%
\def\gp@tempa{cmyk}%
\def\gp@tempb{#1}%
\ifx\gp@tempa\gp@tempb%
\def\gp@temp{4}%
\else%
\def\gp@temp{3}%
\fi%
\pgfsysprotocol@literalbuffered{0 0 translate}%
\pgf@sys@bp{#4}\pgf@sys@bp{#5}\pgfsysprotocol@literalbuffered{scale}%
\pgfsysprotocol@literalbuffered{#2 #3 8 [#2 0 0 -#3 0 #3]}%
\pgfsysprotocol@literalbuffered{currentfile /ASCIIHexDecode filter}%
\pgfsysprotocol@literalbuffered{false \gp@temp\space colorimage}%
\pgfsysprotocol@literal{#6 >}%
}
\def\gp@rawimage@html#1#2#3#4#5#6{%
% FIXME: print a warning message here
}
\ifgppdfout
\def\gp@rawimage{\gp@rawimage@pdf}
\else
\ifgppsout
\def\gp@rawimage{\gp@rawimage@ps}
\else
\def\gp@rawimage{\gp@rawimage@html}
\fi
\fi
\def\gploadimage#1#2#3#4#5{%
\pgftext[left,bottom,x=#1cm,y=#2cm] {\pgfimage[interpolate=false,width=#3cm,height=#4cm]{#5}};%
}
\def\gp@set@size#1{%
\def\gp@image@size{#1}%
}
\def\gp@rawimage@#1#2#3#4#5#6#7#8{
\tikz@scan@one@point\gp@set@size(#6,#7)\relax%
\tikz@scan@one@point\pgftransformshift(#2,#3)\relax%
\pgftext {%
\pgfsys@beginpurepicture%
\gp@image@size% fill \pgf@x and \pgf@y
\gp@rawimage{#1}{#4}{#5}{\pgf@x}{\pgf@y}{#8}%
\pgfsys@endpurepicture%
}%
}
%% \gprawimage{color model}{xcoord}{ycoord}{# of xpixel}{# of ypixel}{xsize}{ysize}{rgb/cmyk hex data RRGGBB/CCMMYYKK ...}{file name}
%% color model is 'cmyk' or 'rgb' (default)
\def\gprawimage#1#2#3#4#5#6#7#8#9{%
\ifx	&%
\gp@rawimage@{#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}
\else
\ifgppsout
\gp@rawimage@{#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}
\else
\gploadimage{#2}{#3}{#6}{#7}{#9}
\fi
\fi
}
%
% gnuplottex comapatibility
% (see http://www.ctan.org/tex-archive/help/Catalogue/entries/gnuplottex.html)
%
\def\gnuplottexextension@lua{\string tex}
\def\gnuplottexextension@tikz{\string tex}
%
% gnuplot variables getter and setter
%
\def\gpsetvar#1#2{%
\expandafter\xdef\csname gp@var@#1\endcsname{#2}
}
\def\gpgetvar#1{%
\csname gp@var@#1\endcsname %
}
%
% some wrapper code
%
% short for a filled path
\def\gpfill#1{\path[line width=0.1\gpbaselw,draw,fill,#1]}
% short for changing the line width
\def\gpsetlinewidth#1{\pgfsetlinewidth{#1\gpbaselw}}
% short for changing the line type
\def\gpsetlinetype#1{\tikzset{gp path/.style={#1,#1 add}}}
% short for changing the dash pattern
\def\gpsetdashtype#1{\tikzset{gp path/.append style={#1}}}
% short for changing the point size
\def\gpsetpointsize#1{\tikzset{gp point/.style={mark size=#1\gpbasems}}}
% wrapper for color settings
\def\gpcolor#1{\tikzset{global #1}}
\tikzset{rgb color/.code={\pgfutil@definecolor{.}{rgb}{#1}\tikzset{color=.}}}
\tikzset{global rgb color/.code={\pgfutil@definecolor{.}{rgb}{#1}\pgfutil@color{.}}}
\tikzset{global color/.code={\pgfutil@color{#1}}}
% prevent plot mark distortions due to changes in the PGF transformation matrix
% use `\gpscalepointstrue' and `\gpscalepointsfalse' for enabling and disabling
% point scaling
%
\newif\ifgpscalepoints
\tikzset{gp shift only/.style={%
\ifgpscalepoints\else shift only\fi%
}}
\def\gppoint#1#2{%
\path[solid] plot[only marks,gp point,mark options={gp shift only},#1] coordinates {#2};%
}
%
% char size calculation, that might be used with gnuplottex
%
% Example code (needs gnuplottex.sty):
%
% % calculate the char size when the "gnuplot" style is used
% \tikzset{gnuplot/.append style={execute at begin picture=\gpcalccharsize}}
%
% \tikzset{gnuplot/.append style={font=\ttfamily\footnotesize}}
%
% \begin{tikzpicture}[gnuplot]
% \begin{gnuplot}[terminal=lua,%
% terminaloptions={tikz solid nopic charsize \the\gphcharsize,\the\gpvcharsize}]
% test
% \end{gnuplot}
% \end{tikzpicture}
%
%%%
% The `\gpcalccharsize' command fills the lengths \gpvcharsize and \gphcharsize with
% the values of the current default font used within nodes and is meant to be called
% within a tikzpicture environment.
%
\newdimen\gpvcharsize
\newdimen\gphcharsize
\def\gpcalccharsize{%
\pgfinterruptboundingbox%
\pgfsys@begininvisible%
\node at (0,0) {%
\global\gphcharsize=1.05\fontcharwd\font`0%
\global\gpvcharsize=1.05\fontcharht\font`0%
\global\advance\gpvcharsize by 1.05\fontchardp\font`g%
};%
\pgfsys@endinvisible%
\endpgfinterruptboundingbox%
}
%
% define a rectangular node in tikz e.g. for the plot area
%
% #1 node name
% #2 coordinate of "south west"
% #3 coordinate of "north east"
%
\def\gpdefrectangularnode#1#2#3{%
\expandafter\gdef\csname pgf@sh@ns@#1\endcsname{rectangle}
\expandafter\gdef\csname pgf@sh@np@#1\endcsname{%
\def\southwest{#2}%
\def\northeast{#3}%
}
\pgfgettransform\pgf@temp%
% once it is defined, no more transformations will be applied, I hope
\expandafter\xdef\csname pgf@sh@nt@#1\endcsname{\pgf@temp}%
\expandafter\xdef\csname pgf@sh@pi@#1\endcsname{\pgfpictureid}%
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% You may want to adapt the following to fit your needs (in your
%% individual style file and/or within your document).
%%
%
% style for every plot
%
\tikzset{gnuplot/.style={%
>=stealth',%
line cap=round,%
line join=round,%
}}
\tikzset{gp node left/.style={anchor=mid west,yshift=-.12ex}}
\tikzset{gp node center/.style={anchor=mid,yshift=-.12ex}}
\tikzset{gp node right/.style={anchor=mid east,yshift=-.12ex}}
% basic plot mark size (points)
\newdimen\gpbasems
\gpbasems=.4pt
% basic linewidth
\newdimen\gpbaselw
\gpbaselw=.4pt
% this is the default color for pattern backgrounds
\colorlet{gpbgfillcolor}{white}
% set background color and fill color
\def\gpsetbgcolor#1{%
\pgfutil@definecolor{gpbgfillcolor}{rgb}{#1}%
\tikzset{tight background,background rectangle/.style={fill=gpbgfillcolor},show background rectangle}%
}
% this should reverse the normal text node presets, for the
% later referencing as described below
\tikzset{gp refnode/.style={coordinate,yshift=.12ex}}
% to add an empty label with the referenceable name "my node"
% to the plot, just add the following line to your gnuplot
% file:
%
% set label "" at 1,1 font ",gp refnode,name=my node"
%
% enlargement of the bounding box in standalone mode (only used by LaTeX/ConTeXt)
\def\gpbboxborder{0mm}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% The following TikZ-styles are derived from the 'pgf.styles.*' tables
%% in the Lua script.
%% To change the number of used styles you should change them there and
%% regenerate this style file.
%%
]])
f:write("% arrow styles settings\n")
for i = 1, #pgf.styles.arrows do
f:write("\\tikzset{"..pgf.styles.arrows[i][1].."/.style={"..pgf.styles.arrows[i][2].."}}\n")
end
f:write("\n% plotmark settings\n")
for i = 1, #pgf.styles.plotmarks do
f:write("\\tikzset{"..pgf.styles.plotmarks[i][1].."/.style={"..pgf.styles.plotmarks[i][2].."}}\n")
end
f:write("\n% pattern settings\n")
for i = 1, #pgf.styles.patterns do
f:write("\\tikzset{"..pgf.styles.patterns[i][1].."/.style={"..pgf.styles.patterns[i][2].."}}\n")
end
f:write("\n% if the 'tikzplot' option is used the corresponding lines will be smoothed by default\n")
for i = 1, #pgf.styles.plotstyles_axes do
f:write("\\tikzset{"..pgf.styles.plotstyles_axes[i][1].."/.style="..pgf.styles.plotstyles_axes[i][2].."}\n")
end
for i = 1, #pgf.styles.plotstyles do
f:write("\\tikzset{"..pgf.styles.plotstyles[i][1].."/.style="..pgf.styles.plotstyles[i][2].."}\n")
end
-- line styles for borders etc ...
f:write("\n% linestyle settings\n")
for i = 1, #pgf.styles.linetypes_axes do
f:write("\\tikzset{"..pgf.styles.linetypes_axes[i][1].."/.style="..pgf.styles.linetypes_axes[i][2].."}\n")
end
f:write("\n% linestyle \"addon\" settings for overwriting a default linestyle within the\n")
f:write("% TeX document via eg. \\tikzset{gp lt plot 1 add/.style={fill=black,draw=none}} etc.\n")
for i = 1, #pgf.styles.linetypes_axes do
f:write("\\tikzset{"..pgf.styles.linetypes_axes[i][1].." add/.style={}}\n")
end
for i = 1, #pgf.styles.linetypes do
f:write("\\tikzset{"..pgf.styles.linetypes[i][1].." add/.style={}}\n")
end
--[[ The line types. These don't do anything anymore, since we have the dash types.
But they were use to hook in from TikZ and change the respective styles
from the LaTeX script. We keep those definitions for backward compatibility.
]]--
for i = 1, #pgf.styles.linetypes do
f:write("\\tikzset{"..pgf.styles.linetypes[i][1].."/.style={"..pgf.styles.linetypes[i][2].."}}\n")
end
f:write("\n% linestyle color settings\n")
for i = 1, #pgf.styles.lt_colors_axes do
f:write("\\colorlet{"..pgf.styles.lt_colors_axes[i][1].."}{"..pgf.styles.lt_colors_axes[i][2].."}\n")
end
-- dash styles for the plots
f:write("\n% dash type settings\n")
f:write("% Define this as a macro so that the dash patterns expand later with the current \\pgflinewidth.\n")
f:write("\\def\\gpdashlength{\\pgflinewidth}\n")
for i = 0, #pgf.styles.dashtypes do
f:write("\\tikzset{"..pgf.styles.dashtypes[i][1].."/.style={"..pgf.styles.dashtypes[i][2].."}}\n")
end
for i = 1, #pgf.styles.dashtypes_axes do
f:write("\\tikzset{"..pgf.styles.dashtypes_axes[i][1].."/.style={"..pgf.styles.dashtypes_axes[i][2].."}}\n")
end
f:write("\n% command for switching to colored lines\n")
f:write("\\def\\gpcoloredlines{%\n")
for i = 1, #pgf.styles.lt_colors do
f:write(" \\colorlet{"..pgf.styles.lt_colors[i][1].."}{"..pgf.styles.lt_colors[i][2].."}%\n")
end
f:write("}\n")
f:write("\n% command for switching to monochrome (black) lines\n")
f:write("\\def\\gpmonochromelines{%\n")
for i = 1, #pgf.styles.lt_colors do
f:write(" \\colorlet{"..pgf.styles.lt_colors[i][1].."}{black}%\n")
end
f:write("}\n\n")
f:write([[
%
% some initialisations
%
% by default all lines will be colored
\gpcoloredlines
\gpsetpointsize{4}
\gpsetlinetype{gp lt solid}
\gpscalepointsfalse
\endinput
]])
f:close()
end
pgf.print_help = function(fwrite)
fwrite([[
{latex | tex | context}
{color | monochrome}
{nooriginreset | originreset}
{nogparrows | gparrows}
{nogppoints | gppoints}
{picenvironment | nopicenvironment}
{noclip | clip}
{notightboundingbox | tightboundingbox}
{background "<colorpec>"}
{size <x>{unit},<y>{unit}}
{scale <x>,<y>}
{plotsize <x>{unit},<y>{unit}}
{charsize <x>{unit},<y>{unit}}
{font "<fontdesc>"}
{{fontscale | textscale} <scale>}
{dashlength | dl <DL>}
{linewidth | lw <LW>}
{nofulldoc | nostandalone | fulldoc | standalone}
{{preamble | header} "<preamble_string>"}
{tikzplot <ltn>,...}
{notikzarrows | tikzarrows}
{rgbimages | cmykimages}
{noexternalimages|externalimages}
{bitmap | nobitmap}
{providevars <var name>,...}
{createstyle}
{help}
For all options that expect lengths as their arguments they
will default to 'cm' if no unit is specified. For all lengths
the following units may be used: 'cm', 'mm', 'in' or 'inch',
'pt', 'pc', 'bp', 'dd', 'cc'. Blanks between numbers and units
are not allowed.
'monochrome' disables line coloring and switches to grayscaled
fills.
'originreset' moves the origin of the TikZ picture to the lower
left corner of the plot. It may be used to align several plots
within one tikzpicture environment. This is not tested with
multiplots and pm3d plots!
'gparrows' use gnuplot's internal arrow drawing function
instead of the ones provided by TikZ.
'gppoints' use gnuplot's internal plotmark drawing function
instead of the ones provided by TikZ.
'nopicenvironment' omits the declaration of the 'tikzpicture'
environment in order to set it manually. This permits putting
some PGF/TikZ code directly before or after the plot.
'clip' crops the plot at the defined canvas size. Default is
'noclip' by which only a minimum bounding box of the canvas size
is set. Neither a fixed bounding box nor a crop box is set if the
'plotsize' or 'tightboundingbox' option is used.
If 'tightboundingbox' is set the 'clip' option is ignored and the
final bounding box is the natural bounding box calculated by tikz.
'background' sets the background color to the value specified in
the <colorpec> argument. <colorspec> must be a valid color name or
a 3 byte RGB code as a hexadecimal number with a preceding number
sign ('#'). E.g. '#ff0000' specifies pure red. If omitted the
background is transparent.
The 'size' option expects two lenghts <x> and <y> as the canvas
size. The default size of the canvas is ]]..pgf.DEFAULT_CANVAS_SIZE_X..[[cm x ]]..pgf.DEFAULT_CANVAS_SIZE_Y..[[cm.
The 'scale' option works similar to the 'size' option but expects
scaling factors <x> and <y> instead of lengths.
The 'plotsize' option permits setting the size of the plot area
instead of the canvas size, which is the usual gnuplot behaviour.
Using this option may lead to slightly asymmetric tic lengths.
Like 'originreset' this option may not lead to convenient results
if used with multiplots or pm3d plots. An alternative approach
is to set all margins to zero and to use the 'noclip' option.
The plot area has then the dimensions of the given canvas sizes.
The 'charsize' option expects the average horizontal and vertical
size of the used font. Look at the generated style file for an
example of how to use it from within your TeX document.
'fontscale' or 'textscale' expects a scaling factor as a parameter.
All texts in the plot are scaled by this factor then.
'dashlength' or 'dl' scales the length of dashed-line segments by <DL>,
which is a floating-point number greater than zero. 'linewidth' or
'lw' scales all linewidths by <LW>.
The options 'tex', 'latex' and 'context' choose the TeX output
format. LaTeX is the default. To load the style file put the
according line at the beginning of your document:
\input ]]..pgf.STYLE_FILE_BASENAME..[[.tex % (for plain TeX)
\usepackage{]]..pgf.STYLE_FILE_BASENAME..[[} % (for LaTeX)
\usemodule[]]..pgf.STYLE_FILE_BASENAME..[[] % (for ConTeXt)
'createstyle' derives the TeX/LaTeX/ConTeXt styles from the script
and writes them to the appropriate files.
'fulldoc' or 'standalone' produces a full LaTeX document for direct
compilation.
'preamble' or 'header' may be used to put any additional LaTeX code
into the document preamble in standalone mode.
With the 'tikzplot' option the '\path plot' command will be used
instead of only '\path'. The following list of numbers of linetypes
(<ltn>,...) defines the affected plotlines. There exists a plotstyle
for every linetype. The default plotstyle is 'smooth' for every
linetype >= 1.
By using the 'tikzarrows' option the gnuplot arrow styles defined by
the user will be mapped to TikZ arrow styles. This is done by 'misusing'
the angle value of the arrow definition. E.g. an arrow style with the
angle '7' will be mapped to the TikZ style 'gp arrow 7' ignoring all the
other given values. By default the TikZ terminal uses the stealth' arrow
tips for all arrows. To obtain the default gnuplot behaviour please use
the 'gparrows' option.
With 'cmykimages' the CMYK color model will be used for inline image data
instead of the RGB model. All other colors (like line colors etc.) are
not affected by this option, since they are handled e.g. by LaTeX's
xcolor package. This option is ignored if images are externalized.
By using the 'externalimages' option all bitmap images will be written
as external PNG images and included at compile time of the document.
Generating DVI and later postscript files requires to convert the PNGs
into EPS files in a seperate step e.g. by using ImageMagick's `convert`.
Transparent bitmap images are always generated as an external PNGs.
The 'nobitmap' option let images be rendered as filled rectangles instead
of the nativ PS or PDF inline image format. This option is ignored if
images are externalized.
The 'providevars' options makes gnuplot's internal and user variables
available by using the '\gpgetvar{<var name>}' commmand within the TeX
script. Use gnuplot's 'show variables all' command to see the list
of valid variables.
The <fontdesc> string may contain any valid TeX/LaTeX/ConTeXt font commands
like e.g. '\small'. It is passed directly as a node parameter in form of
"font={<fontdesc>}". This can be 'misused' to add further code to a node,
e.g. '\small,yshift=1ex' or ',yshift=1ex' are also valid while the
latter does not change the current font settings. One exception is
the second argument of the list. If it is a number of the form
<number>{unit} it will be interpreted as a fontsize like in other
terminals and will be appended to the first argument. If the unit is
omitted the value is interpreted as 'pt'. As an example the string
'\sffamily,12,fill=red' sets the font to LaTeX's sans serif font at
a size of 12pt and red background color.
The same applies to ConTeXt, e.g. '\switchtobodyfont[iwona],10' changes the
font to Iwona at a size of 10pt.
Plain TeX users have to change the font size explicitly within the first
argument. The second should be set to the same value to get proper scaling
of text boxes.
Strings have to be put in single or double quotes. Double quoted
strings may contain special characters like newlines '\n' etc.
]])
end
--[[===============================================================================================
gfx.* helper functions
Main intention is to prevent redundancies in the drawing
operations and keep the pgf.* API as consistent as possible.
]]--===============================================================================================
-- path coordinates
gfx.path = {}
gfx.posx = nil
gfx.posy = nil
gfx.linetype_idx = nil -- current linetype intended for the plot
gfx.linetype_idx_set = nil -- current linetype set in the plot
gfx.dashtype_idx = nil -- current dashtype intended for the plot
gfx.dashtype_idx_set = nil -- current dashtype set in the plot
gfx.linewidth = nil
gfx.linewidth_set = nil
gfx.opacity = 1.0
gfx.boxed_text = false
gfx.boxed_text_count = 0 -- number of nodes inside the current box
gfx.boxed_text_xmargin = 0
gfx.boxed_text_ymargin = 0
-- internal calculated scaling factors
gfx.scalex = 1
gfx.scaley = 1
-- recalculate the origin of the plot
-- used for moving the origin to the lower left
-- corner...
gfx.origin_xoffset = 0
gfx.origin_yoffset = 0
-- color set in the document
gfx.color = ''
gfx.color_set = ''
gfx.pointsize = nil
gfx.pointsize_set = nil
gfx.text_font = ''
gfx.text_justify = "center"
gfx.text_angle = 0
-- option vars
gfx.opt = {
latex_preamble = '',
default_font = '',
default_fontsize = 10,
lines_colored = true,
-- use gnuplot arrows or points instead of TikZ?
gp_arrows = false,
gp_points = false,
-- don't put graphic commands into a tikzpicture environment
nopicenv = false,
-- produce full LaTeX document?
full_doc = false,
-- in gnuplot all sizes refer to the size of the canvas
-- and not the size of plot itself
plotsize_x = nil,
plotsize_y = nil,
set_plotsize = false,
-- recalculate the origin of the plot
-- used for moving the origin to the lower left
-- corner...
set_origin = false,
-- list of _linetypes_ of plots that should be drawn as with the \plot
-- command instead of \path
plot_list = {},
-- uses some pdf/ps specials with image function that will only work
-- with pdf/ps generation!
direct_image = true,
-- list of gnuplot variables that should be made available via
-- \gpsetvar{name}{val}
gnuplot_vars = {},
-- if true, the gnuplot arrow will be mapped to TikZ arrow styles by the
-- given angle. E.g. an arrow with the angle `7' will be mapped to `gp arrow 7'
-- style.
tikzarrows = false,
-- if true, cmyk image model will be used for bitmap images
cmykimage = false,
-- output TeX flavor, default is LaTeX
tex_format = 'latex',
-- for regression tests etc. we can turn off the timestamp
notimestamp = false,
-- background color, contains RGB triplet when set
bgcolor = nil,
-- crop to the given canvas size
clip = false,
-- if true, the natural bounding box will be used and 'clip' is ignored
tightboundingbox = false,
-- fontscale
fontscale = nil,
dashlength = nil,
linewidth = 1.0
}
-- Formats for the various TeX flavors
gfx.format = {}
gfx.format.tex = {
docheader = "\\input "..pgf.STYLE_FILE_BASENAME..".tex\n",
begindocument = "",
enddocument = "\\bye\n",
beforetikzpicture= "", -- standalone only
aftertikzpicture = "", -- standalone only
begintikzpicture = "\\tikzpicture",
endtikzpicture = "\\endtikzpicture",
beginscope = "\\scope",
endscope = "\\endscope",
beforeendtikzpicture = "", -- standalone only
fontsize = ""
}
gfx.format.latex = {
docheader = "\\documentclass["..pgf.DEFAULT_FONT_SIZE.."pt]{article}\n"
.."\\usepackage[T1]{fontenc}\n"
.."\\usepackage{textcomp}\n\n"
.."\\usepackage[utf8x]{inputenc}\n"
.."\\SetUnicodeOption{mathletters}\n\n"
.."\\usepackage{"..pgf.STYLE_FILE_BASENAME.."}\n"
.."\\pagestyle{empty}\n"
.."\\usepackage[active,tightpage]{preview}\n"
.."\\PreviewEnvironment{tikzpicture}\n"
.."\\setlength\\PreviewBorder{\\gpbboxborder}\n",
begindocument = "\\begin{document}\n",
enddocument = "\\end{document}\n",
beforetikzpicture= "", -- standalone only
aftertikzpicture = "", -- standalone only
begintikzpicture = "\\begin{tikzpicture}",
endtikzpicture = "\\end{tikzpicture}",
beginscope = "\\begin{scope}",
endscope = "\\end{scope}",
beforeendtikzpicture = "", -- standalone only
fontsize = "\\fontsize{%spt}{%spt}\\selectfont"
}
gfx.format.context = {
docheader = "\\usemodule["..pgf.STYLE_FILE_BASENAME.."]\n",
begindocument = "\\starttext\n",
enddocument = "\\stoptext\n",
beforetikzpicture= "\\startTEXpage\n", -- standalone only
aftertikzpicture = "\\stopTEXpage\n", -- standalone only
begintikzpicture = "\\starttikzpicture",
endtikzpicture = "\\stoptikzpicture",
beginscope = "\\startscope",
endscope = "\\stopscope",
beforeendtikzpicture = "\\path[use as bounding box] ([shift={(-\\gpbboxborder,-\\gpbboxborder)}]current bounding box.south west)"
.." rectangle ([shift={(\\gpbboxborder,\\gpbboxborder)}]current bounding box.north east);\n", -- standalone only
fontsize = "\\switchtobodyfont[%spt]"
}
-- within tikzpicture environment or not
gfx.in_picture = false
-- have not determined the plotbox, see the 'plotsize' option
gfx.have_plotbox = false
gfx.current_boundingbox = {
xleft = nil, xright = nil, ytop = nil, ybot = nil
}
-- plot bounding boxes counter
gfx.boundingbox_cnt = 0
gfx.TEXT_ANCHOR = {
["left"] = "gp node left",
["center"] = "gp node center",
["right"] = "gp node right"
}
gfx.HEAD_STR = {"", "->", "<-", "<->"}
-- conversion factors in `cm'
gfx.units = {
[''] = 1, -- default
['cm'] = 1,
['mm'] = 0.1,
['in'] = 2.54,
['inch']= 2.54,
['pt'] = 0.035146, -- Pica Point (72.27pt = 1in)
['pc'] = 0.42176, -- Pica (1 Pica = 1/6 inch)
['bp'] = 0.035278, -- Big Point (72bp = 1in)
['dd'] = 0.0376, -- Didot Point (1cm = 26.6dd)
['cc'] = 0.45113 -- Cicero (1cc = 12 dd)
}
gfx.parse_number_unit = function (str, from, to)
to = to or 'cm'
from = from or 'cm'
local num, unit = string.match(str, '^([%d%.]+)([a-z]*)$')
if unit and (string.len(unit) > 0) then
from = unit
else
unit = false
end
local factor_from = gfx.units[from]
local factor_to = gfx.units[to]
num = tonumber(num)
if num and factor_from then
-- to cm and then to our target unit
return num*(factor_from/factor_to), unit
else
return false, false
end
end
gfx.parse_font_string = function (str)
local size,rets,toks = nil, str, explode(',', str)
-- set_font("") must restore default font
if string.len(str) == 0 then
return gfx.opt.default_font, gfx.opt.default_fontsize
end
-- if at least two tokens
if #toks > 1 then
-- add first element to font string
rets = table.remove(toks,1)
-- no unit means 'pt'
size, _ = gfx.parse_number_unit(toks[1],'pt','pt')
if (size) then
table.remove(toks,1)
rets = rets .. string.format(gfx.format[gfx.opt.tex_format].fontsize,size,size*1.2)
end
-- add grouping braces for the font settings
if #rets > 0 then
rets = "{" .. rets .. "}"
end
-- add remaining parts
for k,v in ipairs(toks) do
rets = rets .. ',' .. v
end
else
-- assume bare font name with no size
if #rets > 0 then
rets = "{" .. rets .. "}"
end
end
return rets, size
end
gfx.write_boundingbox = function()
local t = gp.get_boundingbox()
for k, v in pairs (t) do
if v ~= gfx.current_boundingbox[k] then
gfx.boundingbox_cnt = gfx.boundingbox_cnt + 1
gfx.current_boundingbox = t
pgf.write_boundingbox(t, gfx.boundingbox_cnt)
break
end
end
end
gfx.adjust_plotbox = function()
local t = gp.get_boundingbox()
if gfx.opt.set_origin then
-- move origin to the lower left corner of the plot
gfx.origin_xoffset = - t.xleft
gfx.origin_yoffset = - t.ybot
end
if gfx.opt.set_plotsize then
if (t.xright - t.xleft) > 0 then
gfx.scalex = gfx.scalex*gfx.opt.plotsize_x * pgf.DEFAULT_RESOLUTION/(t.xright - t.xleft)
gfx.scaley = gfx.scaley*gfx.opt.plotsize_y * pgf.DEFAULT_RESOLUTION/(t.ytop - t.ybot)
else
-- could not determin a valid bounding box, so keep using the
-- plotsize as the canvas size
gp.term_out("WARNING: PGF/TikZ Terminal: `plotsize' option used, but I could not determin the plot area!\n")
end
elseif not gfx.opt.tightboundingbox then
if gfx.opt.clip then
gp.write("\\clip")
else
gp.write("\\path")
end
gp.write(" (" .. pgf.format_coord(0,0) ..") rectangle (" .. pgf.format_coord(term.xmax, term.ymax) .. ");\n")
end
end
gfx.check_variables = function()
local vl = gfx.opt.gnuplot_vars
local t = gp.get_all_variables()
local sl = {}
for i=1,#vl do
if t[vl[i]] then
sl[vl[i]] = t[vl[i]][3]
if t[vl[i]][4] then
sl[vl[i].." Im"] = t[vl[i]][4]
end
end
end
pgf.write_variables(sl)
end
-- check if the current path should be drawn
gfx.check_in_path = function()
-- also check the bounding box here
-- bounding box data is available with the first drawing command
if (not gfx.have_plotbox) and gfx.in_picture then
gfx.adjust_plotbox()
gfx.have_plotbox = true
end
-- ignore zero length paths
if #gfx.path > 1 then
-- check all line properties and draw current path
gfx.check_color()
gfx.check_linetype()
gfx.check_dashtype()
gfx.check_linewidth()
pgf.draw_path(gfx.path)
-- remember last coordinates
gfx.start_path(gfx.path[#gfx.path][1], gfx.path[#gfx.path][2])
end
end
-- did the linetype change?
gfx.check_linetype = function()
if gfx.linetype_idx ~= gfx.linetype_idx_set then
local lt
if gfx.linetype_idx == -1 or gfx.linetype_idx == -2 then
lt = pgf.styles.linetypes_axes[math.abs(gfx.linetype_idx)][1]
else
lt = pgf.styles.linetypes[(gfx.linetype_idx % #pgf.styles.linetypes)+1][1]
end
pgf.set_linetype(lt)
gfx.linetype_idx_set = gfx.linetype_idx
end
end
-- did the dashtype change?
gfx.check_dashtype = function()
if gfx.dashtype_idx ~= gfx.dashtype_idx_set then
-- if gfx.dashtype_idx is a string, it contains a custom dash pattern
if type(gfx.dashtype_idx) == type(1) then
if gfx.dashtype_idx == -1 or gfx.dashtype_idx == -2 then
pgf.set_dashtype(pgf.styles.dashtypes_axes[math.abs(gfx.dashtype_idx)][1])
elseif gfx.dashtype_idx >= 0 then
pgf.set_dashtype(pgf.styles.dashtypes[(gfx.dashtype_idx % #pgf.styles.dashtypes) + 1][1])
end
else
pgf.set_dashtype("dash pattern="..gfx.dashtype_idx)
end
gfx.dashtype_idx_set = gfx.dashtype_idx
end
end
-- did the color change?
gfx.check_color = function()
if gfx.color_set ~= gfx.color then
pgf.set_color(gfx.color)
gfx.color_set = gfx.color
end
end
-- sanity check if we already are at this position in our path
-- and save this position
gfx.check_coord = function(x, y)
if (x == gfx.posx) and (y == gfx.posy) then
return true
end
gfx.posx = x
gfx.posy = y
return false
end
-- did the linewidth change?
gfx.check_linewidth = function()
if gfx.linewidth ~= gfx.linewidth_set then
pgf.set_linewidth(gfx.linewidth)
gfx.linewidth_set = gfx.linewidth
end
end
-- did the pointsize change?
gfx.check_pointsize = function()
if gfx.pointsize ~= gfx.pointsize_set then
pgf.set_pointsize(gfx.pointsize)
gfx.pointsize_set = gfx.pointsize
end
end
gfx.start_path = function(x, y)
-- init path with first coords
gfx.path = {{x,y}}
gfx.posx = x
gfx.posy = y
end
-- ctype string LT|RGBA|GRAY
-- val table {name}|{r,g,b,alpha}
-- returns a properly formatted color parameter string, or nil if LT_NODRAW was used.
gfx.format_color = function(ctype, val)
local c
if ctype == 'LT' then
if val[1] < 0 then
if val[1] == -3 then
c = nil
elseif val[1] < -2 then -- LT_NODRAW, LT_BACKGROUND, LT_UNDEFINED
c = 'color=gpbgfillcolor'
else
c = 'color='..pgf.styles.lt_colors_axes[math.abs(val[1])][1]
end
else
c = 'color='..pgf.styles.lt_colors[(val[1] % #pgf.styles.lt_colors)+1][1]
end
-- c = pgf.styles.lt_colors[((val[1]+3) % #pgf.styles.lt_colors) + 1][1]
elseif ctype == 'RGBA' then
c = string.format("rgb color={%.3f,%.3f,%.3f}", val[1], val[2], val[3])
elseif ctype == 'GRAY' then
c = string.format("color=black!%i", 100*val[1]+0.5)
end
return c
end
gfx.set_opacity = function(ctype, val)
gfx.opacity = 1.0
if (ctype == 'RGBA') then
gfx.opacity = val[4]
end
end
gfx.set_color = function(ctype, val)
gfx.color = gfx.format_color(ctype, val)
gfx.set_opacity(ctype, val)
end
--[[===============================================================================================
The terminal layer
The term.* functions are usually called from the gnuplot Lua terminal
]]--===============================================================================================
if arg then
-- when called from the command line we have
-- to initialize the table `term' manually
-- to avoid errors
term = {}
else
--
-- gnuplot terminal default parameters and flags
--
term.xmax = pgf.DEFAULT_RESOLUTION * pgf.DEFAULT_CANVAS_SIZE_X
term.ymax = pgf.DEFAULT_RESOLUTION * pgf.DEFAULT_CANVAS_SIZE_Y
term.h_tic = pgf.DEFAULT_RESOLUTION * pgf.DEFAULT_TIC_SIZE
term.v_tic = pgf.DEFAULT_RESOLUTION * pgf.DEFAULT_TIC_SIZE
-- default size for CM@10pt
term.h_char = math.floor(pgf.DEFAULT_FONT_H_CHAR * (pgf.DEFAULT_FONT_SIZE/10) * (pgf.DEFAULT_RESOLUTION/1000) + .5)
term.v_char = math.floor(pgf.DEFAULT_FONT_V_CHAR * (pgf.DEFAULT_FONT_SIZE/10) * (pgf.DEFAULT_RESOLUTION/1000) + .5)
term.description = "Lua PGF/TikZ terminal for TeX and friends"
term_default_flags = term.TERM_BINARY + term.TERM_CAN_MULTIPLOT + term.TERM_CAN_DASH + term.TERM_ALPHA_CHANNEL
+ term.TERM_LINEWIDTH + term.TERM_IS_LATEX + term.TERM_FONTSCALE
term.flags = term_default_flags + term.TERM_CAN_CLIP
end
--
-- initial = 1 for the initial "set term" call
-- 0 for subsequent option changes -- currently unused, since the changeable options
-- are hardcoded within gnuplot :-(
--
-- t_count see e.g. int_error()
--
term.options = function(opt_str, initial, t_count)
local o_next = ""
local o_type = nil
local s_start, s_end = 1, 1
local term_opt = ""
local term_opt_font, term_opt_size, term_opt_background, term_opt_fontscale, term_opt_dashlength, term_opt_linewidth, term_opt_scale, term_opt_preamble = "", "", "", "", "", "", "", ""
local charsize_h, charsize_v, fontsize, fontscale, dashlength = nil, nil, nil, nil, nil
-- trim spaces
opt_str = opt_str:gsub("^%s*(.-)%s*$", "%1")
local opt_len = string.len(opt_str)
t_count = t_count - 1
local set_t_count = function(num)
-- gnuplot handles commas as regular tokens
t_count = t_count + 2*num - 2
end
local almost_equals = function(param, opt)
local op1, op2
local st, _ = string.find(opt, "$", 2, true)
if st then
op1 = string.sub(opt, 1, st-1)
op2 = string.sub(opt, st+1)
if (string.sub(param, 1, st-1) == op1)
and (string.find(op1..op2, param, 1, true) == 1) then
return true
end
elseif opt == param then
return true
end
return false
end
--
-- simple parser for options and strings
--
local get_next_token = function()
-- beyond the limit?
if s_start > opt_len then
o_next = ""
o_type = nil
return
end
t_count = t_count + 1
-- search the start of the next token
s_start, _ = string.find (opt_str, '[^%s]', s_start)
if not s_start then
o_next = ""
o_type = nil
return
end
-- a new string argument?
local next_char = string.sub(opt_str, s_start, s_start)
if next_char == '"' or next_char == "'" then
-- find the end of the string by searching for
-- the next not escaped quote
_ , s_end = string.find (opt_str, '[^\\]'..next_char, s_start+1)
if s_end then
o_next = string.sub(opt_str, s_start+1, s_end-1)
if next_char == '"' then
-- this is to resolve all string escapes, kind of "unescape string"
-- lua 5.2 deprecated loadstring in favor of load
o_next = assert(load("return(\""..o_next.."\")"))()
end
o_type = "string"
else
-- FIXME: error: string does not end...
-- seems that gnuplot adds missing quotes
-- so this will never happen...
end
else
-- ok, it's not a string...
-- then find the next white space or end of line
-- comma separated strings are regarded as one token
s_end, _ = string.find (opt_str, '[^,][%s]+[^,]', s_start)
if not s_end then -- reached the end of the string
s_end = opt_len + 1
else
s_end = s_end + 1
end
o_next = string.sub(opt_str, s_start, s_end-1)
if tonumber(o_next) ~= nil then
o_type = 'number'
else
o_type = "op"
end
end
s_start = s_end + 1
return
end
local get_two_sizes = function(str)
local args = explode(',', str)
set_t_count(#args)
local num1, num2, unit
if #args ~= 2 then
return false, nil
else
num1, unit = gfx.parse_number_unit(args[1])
if unit then
t_count = t_count + 1
end
num2, unit = gfx.parse_number_unit(args[2])
if unit then
t_count = t_count + 1
end
if not (num1 and num2) then
return false, nil
end
end
return num1, num2
end
local print_help = false
while true do
get_next_token()
if not o_type then break end
if almost_equals(o_next, "he$lp") then
print_help = true
elseif almost_equals(o_next, "mono$chrome") then
-- no colored lines
-- Setting `term.TERM_MONOCHROME' would internally disable colors for all drawings.
-- We do it the `soft' way by redefining all colors via a TeX command.
-- Maybe an additional terminal option is useful here...
gfx.opt.lines_colored = false
elseif almost_equals(o_next, "c$olor") or almost_equals(o_next, "c$olour") then
-- colored lines
gfx.opt.lines_colored = true
elseif almost_equals(o_next, "notime$stamp") then
-- omit output of the timestamp
gfx.opt.notimestamp = true
elseif almost_equals(o_next, "gparr$ows") then
-- use gnuplot arrows instead of TikZ
gfx.opt.gp_arrows = true
elseif almost_equals(o_next, "nogparr$ows") then
-- use gnuplot arrows instead of TikZ
gfx.opt.gp_arrows = false
elseif almost_equals(o_next, "gppoint$s") then
-- use gnuplot points instead of TikZ
gfx.opt.gp_points = true
elseif almost_equals(o_next, "nogppoint$s") then
-- use gnuplot points instead of TikZ
gfx.opt.gp_points = false
elseif almost_equals(o_next, "nopic$environment") then
-- omit the 'tikzpicture' environment
gfx.opt.nopicenv = true
elseif almost_equals(o_next, "pic$environment") then
-- omit the 'tikzpicture' environment
gfx.opt.nopicenv = false
elseif almost_equals(o_next, "origin$reset") then
-- moves the origin of the TikZ picture to the lower left corner of the plot
gfx.opt.set_origin = true
elseif almost_equals(o_next, "noorigin$reset") then
-- moves the origin of the TikZ picture to the lower left corner of the plot
gfx.opt.set_origin = false
elseif almost_equals(o_next, "plot$size") then
get_next_token()
gfx.opt.plotsize_x, gfx.opt.plotsize_y = get_two_sizes(o_next)
if not gfx.opt.plotsize_x then
gp.int_error(t_count, string.format("error: two comma seperated lengths expected, got `%s'.", o_next))
end
gfx.opt.set_plotsize = true
term_opt_size = string.format("plotsize %s,%s ", gfx.opt.plotsize_x, gfx.opt.plotsize_y)
-- we set the canvas size to the plotsize to keep the aspect ratio as good as possible
-- and rescale later once we know the actual plot size...
term.xmax = gfx.opt.plotsize_x*pgf.DEFAULT_RESOLUTION
term.ymax = gfx.opt.plotsize_y*pgf.DEFAULT_RESOLUTION
elseif almost_equals(o_next, "si$ze") then
get_next_token()
local plotsize_x, plotsize_y = get_two_sizes(o_next)
if not plotsize_x then
gp.int_error(t_count, string.format("error: two comma seperated lengths expected, got `%s'.", o_next))
end
gfx.opt.set_plotsize = false
term_opt_size = string.format("size %s,%s ", plotsize_x, plotsize_y)
term.xmax = plotsize_x*pgf.DEFAULT_RESOLUTION
term.ymax = plotsize_y*pgf.DEFAULT_RESOLUTION
elseif almost_equals(o_next, "char$size") then
get_next_token()
charsize_h, charsize_v = get_two_sizes(o_next)
if not charsize_h then
gp.int_error(t_count, string.format("error: two comma seperated lengths expected, got `%s'.", o_next))
end
elseif almost_equals(o_next, "sc$ale") then
get_next_token()
local xscale, yscale = get_two_sizes(o_next)
if not xscale then
gp.int_error(t_count, string.format("error: two comma seperated numbers expected, got `%s'.", o_next))
end
term_opt_scale = string.format("scale %s,%s ",xscale, yscale)
term.xmax = term.xmax * xscale
term.ymax = term.ymax * yscale
elseif almost_equals(o_next, "tikzpl$ot") then
get_next_token()
local args = explode(',', o_next)
set_t_count(#args)
for i = 1,#args do
args[i] = tonumber(args[i])
if args[i] == nil then
gp.int_error(t_count, string.format("error: list of comma seperated numbers expected, got `%s'.", o_next))
end
args[i] = args[i] - 1
end
gfx.opt.plot_list = args
elseif almost_equals(o_next, "provide$vars") then
get_next_token()
local args = explode(',', o_next)
set_t_count(#args)
gfx.opt.gnuplot_vars = args
elseif almost_equals(o_next, "tikzar$rows") then
-- map the arrow angles to TikZ arrow styles
gfx.opt.tikzarrows = true
elseif almost_equals(o_next, "notikzar$rows") then
-- don't map the arrow angles to TikZ arrow styles
gfx.opt.tikzarrows = false
elseif almost_equals(o_next, "nobit$map") then
-- render images as filled rectangles instead of the nativ
-- PS or PDF image format
gfx.opt.direct_image = false
elseif almost_equals(o_next, "bit$map") then
-- render images as nativ PS or PDF image
gfx.opt.direct_image = true
elseif almost_equals(o_next, "cmyk$image") then
-- use cmyk color model for images
gfx.opt.cmykimage = true
elseif almost_equals(o_next, "rgb$image") then
-- use cmyk color model for images
gfx.opt.cmykimage = false
elseif almost_equals(o_next, "full$doc") or almost_equals(o_next, "stand$alone") then
-- produce full tex document
gfx.opt.full_doc = true
elseif almost_equals(o_next, "nofull$doc") or almost_equals(o_next, "nostand$alone") then
-- produce full tex document
gfx.opt.full_doc = true
elseif almost_equals(o_next, "create$style") then
-- creates the coresponding LaTeX style from the script
pgf.create_style()
elseif almost_equals(o_next, "backg$round") then
-- set background color
get_next_token()
-- ignore rgbcolor keyword if present
if almost_equals(o_next, "rgb$color") then get_next_token() end
if o_type == 'string' then
gfx.opt.bgcolor = gp.parse_color_name(t_count, o_next)
term_opt_background = string.format("background '%s'", o_next)
else
gp.int_error(t_count, string.format("error: string expected, got `%s'.", o_next))
end
elseif almost_equals(o_next, "fo$nt") then
get_next_token()
if o_type == 'string' then
gfx.opt.default_font, fontsize = gfx.parse_font_string(o_next)
else
gp.int_error(t_count, string.format("error: string expected, got `%s'.", o_next))
end
term_opt_font = string.format("font %q ", o_next)
elseif almost_equals(o_next, "fonts$cale") or almost_equals(o_next, "texts$cale") then
get_next_token()
if o_type == 'number' then
fontscale = tonumber(o_next)
if fontscale < 0 then
fontscale = 1.0
end
else
gp.int_error(t_count, string.format("error: number expected, got `%s'.", o_next))
end
elseif almost_equals(o_next, "dashl$ength") or almost_equals(o_next, "dl") then
get_next_token()
if o_type == 'number' then
dashlength = tonumber(o_next)
if dashlength <= 0 then
dashlength = 1.0
end
else
gp.int_error(t_count, string.format("error: number expected, got `%s'.", o_next))
end
elseif almost_equals(o_next, "linew$idth") or almost_equals(o_next, "lw") then
get_next_token()
if o_type == 'number' then
gfx.opt.linewidth = tonumber(o_next)
if gfx.opt.linewidth <= 0 then
gfx.opt.linewidth = 1.0
end
term_opt_linewidth = string.format("linewidth %.1f ", gfx.opt.linewidth)
else
gp.int_error(t_count, string.format("error: number expected, got `%s'.", o_next))
end
elseif almost_equals(o_next, "externalimages") then
if term.external_images ~= nil then
term.external_images = true;
else
gp.int_warn(t_count, "Externalization of images is not supported.")
end
elseif almost_equals(o_next, "noexternalimages") then
if term.external_images ~= nil then
term.external_images = false;
else
gp.int_warn(t_count, "Externalization of images is not supported.")
end
elseif almost_equals(o_next, "pre$amble") or almost_equals(o_next, "header") then
get_next_token()
if o_type == 'string' then
term_opt_preamble = term_opt_preamble .. string.format("preamble %q ", o_next)
gfx.opt.latex_preamble = gfx.opt.latex_preamble .. o_next .. "\n"
else
gp.int_error(t_count, string.format("error: string expected, got `%s'.", o_next))
end
elseif almost_equals(o_next, "nopre$amble") or almost_equals(o_next, "noheader") then
gfx.opt.latex_preamble = ''
elseif almost_equals(o_next, "con$text") then
gfx.opt.tex_format = "context"
-- ConTeXt has a default of 12pt
fontsize = 12
elseif almost_equals(o_next, "tex") then
gfx.opt.tex_format = "tex"
elseif almost_equals(o_next, "latex") then
gfx.opt.tex_format = "latex"
elseif almost_equals(o_next, "clip") then
gfx.opt.clip = true
term.flags = term_default_flags
term.flags = term_default_flags + term.TERM_CAN_CLIP
elseif almost_equals(o_next, "noclip") then
gfx.opt.clip = false
term.flags = term_default_flags
elseif almost_equals(o_next, "tight$boundingbox") then
gfx.opt.tightboundingbox = true
elseif almost_equals(o_next, "notight$boundingbox") then
gfx.opt.tightboundingbox = false
else
gp.int_warn(t_count, string.format("unknown option `%s'.", o_next))
end
end
-- determine "internal" font size
-- FIXME: what happens on "set termoptions font ..." or subsequent terminal calls
local term_h_char, term_v_char = term.h_char, term.v_char
if fontsize ~= nil then
gfx.opt.default_fontsize = fontsize
term_h_char = pgf.DEFAULT_FONT_H_CHAR * (fontsize/10) * (pgf.DEFAULT_RESOLUTION/1000)
term_v_char = pgf.DEFAULT_FONT_V_CHAR * (fontsize/10) * (pgf.DEFAULT_RESOLUTION/1000)
-- on change apply old text scaling
if not fontscale then
fontscale = gfx.opt.fontscale;
end
end
-- a given character size overwrites font size
if charsize_h ~= nil then
term_h_char = charsize_h*pgf.DEFAULT_RESOLUTION
term_v_char = charsize_v*pgf.DEFAULT_RESOLUTION
-- on change apply old text scaling
if not fontscale then
fontscale = gfx.opt.fontscale;
end
end
if fontscale ~= nil then
term_h_char = term_h_char * fontscale
term_v_char = term_v_char * fontscale
gfx.opt.fontscale = fontscale;
term_opt_fontscale = string.format("fontscale %s", gfx.opt.fontscale)
end
term.h_char = math.floor(term_h_char + .5)
term.v_char = math.floor(term_v_char + .5)
if dashlength ~= nil then
gfx.opt.dashlength = dashlength
term_opt_dashlength = string.format("dashlength %.1f", dashlength)
end
if print_help then
pgf.print_help(gp.term_out)
end
local tf = function(b,y,n)
local addopt = ''
if b then
addopt = y
else
addopt = n
end
if (string.len(addopt) > 0) then
term_opt = term_opt .. addopt .. ' '
end
end
tf(true, gfx.opt.tex_format, nil)
tf(true, term_opt_font, nil)
tf(true, term_opt_size, nil)
tf(true, term_opt_background, nil)
tf(true, term_opt_fontscale, nil)
tf(true, term_opt_dashlength, nil)
tf(true, term_opt_linewidth, nil)
tf((#gfx.opt.latex_preamble>0), term_opt_preamble, 'nopreamble')
tf(gfx.opt.lines_colored, 'color', 'monochrome')
tf(gfx.opt.full_doc, 'standalone', 'nostandalone')
tf(gfx.opt.gp_arrows, 'gparrows', 'nogparrows')
tf(gfx.opt.tikzarrows, 'tikzarrows', 'notikzarrows')
tf(gfx.opt.gp_points, 'gppoints', 'nogppoints')
tf(gfx.opt.nopicenv, 'nopicenvironment', 'picenvironment')
tf(gfx.opt.set_origin, 'originreset', 'nooriginreset')
tf(gfx.opt.direct_image, 'bitmap', 'nobitmap')
tf(gfx.opt.cmykimage, 'cmykimage', 'rgbimage')
tf(gfx.opt.clip, 'clip', 'noclip')
tf(gfx.opt.tightboundingbox, 'tightboundingbox', 'notightboundingbox')
if term.external_images ~= nil then
tf(term.external_images, 'externalimages', 'noexternalimages')
end
gp.term_options(term_opt)
return 1
end
-- Called once, when the device is first selected.
term.init = function()
if gfx.opt.full_doc then
pgf.write_doc_begin(gfx.opt.latex_preamble)
end
return 1
end
-- Called just before a plot is going to be displayed.
term.graphics = function()
-- reset some state variables
gfx.linetype_idx_set = nil
gfx.dashtype_idx_set = nil
gfx.linewidth_set = nil
gfx.pointsize_set = nil
gfx.color_set = nil
gfx.in_picture = true
gfx.have_plotbox = false
gfx.boundingbox_cnt = 0
gfx.scalex = 1/pgf.DEFAULT_RESOLUTION
gfx.scaley = 1/pgf.DEFAULT_RESOLUTION
gfx.current_boundingbox = {
xleft = nil, xright = nil, ytop = nil, ybot = nil
}
-- put a newline between subsequent plots in fulldoc mode...
if gfx.opt.full_doc then
gp.write("\n")
end
pgf.write_graph_begin(gfx.opt.default_font, gfx.opt.nopicenv)
return 1
end
term.vector = function(x, y)
if gfx.linetype_idx ~= -3 then
if #gfx.path == 0 then
gfx.start_path(gfx.posx, gfx.posy)
elseif not gfx.check_coord(x, y) then
-- checked for zero path length and add the path coords to gfx.path
gfx.path[#gfx.path+1] = {x,y}
end
end
return 1
end
term.move = function(x, y)
if gfx.linetype_idx ~= -3 then
-- only "move" if we change our latest position
if not gfx.check_coord(x, y) then
-- finish old path and start a new one
gfx.check_in_path()
gfx.start_path(x, y)
end
end
return 1
end
term.linetype = function(ltype)
gfx.check_in_path()
gfx.set_color('LT', {ltype})
if (ltype < -4) then -- LT_NODRAW = -3, LT_BACKGROUND = -4
ltype = -3
end
if ltype == -1 then -- LT_AXIS
gfx.dashtype_idx = -2
end
if ltype == -2 then -- LT_SOLID
gfx.dashtype_idx = -1
end
gfx.linetype_idx = ltype
return 1
end
term.dashtype = function(dtype, pattern)
gfx.check_in_path()
if dtype == -3 then -- DASHTYPE_CUSTOM
gfx.dashtype_idx = ''
for i = 1,#pattern do
if (i % 2) == 1 then
gfx.dashtype_idx = gfx.dashtype_idx .. 'on '
else
gfx.dashtype_idx = gfx.dashtype_idx .. 'off '
end
gfx.dashtype_idx = gfx.dashtype_idx..string.format('%.2f*\\gpdashlength ', pattern[i])
end
else
gfx.dashtype_idx = dtype
end
return 1
end
term.point = function(x, y, num)
if gfx.opt.gp_points then
return 0
else
gfx.check_in_path()
gfx.check_color()
gfx.check_linewidth()
gfx.check_pointsize()
local pm
if num == -1 then
pm = pgf.styles.plotmarks[1][1]
else
pm = pgf.styles.plotmarks[(num % (#pgf.styles.plotmarks-1)) + 2][1]
end
pgf.draw_points({{x,y}}, pm)
return 1
end
end
--[[
this differs from the original API
one may use the additional parameters to define own styles
e.g. "misuse" angle for numbering predefined styles...
int length /* head length */
double angle /* head angle in degrees */
double backangle /* head back angle in degrees */
int filled /* arrow head filled or not */
]]
term.arrow = function(sx, sy, ex, ey, head, length, angle, backangle, filled)
if gfx.linetype_idx == -3 then -- LT_NODRAW
return 1
end
if gfx.opt.gp_arrows then
return 0
else
local headstyle = 0
if gfx.opt.tikzarrows then
headstyle = angle
end
gfx.check_in_path()
gfx.check_color()
gfx.check_linetype()
gfx.check_dashtype()
gfx.check_linewidth()
pgf.draw_arrow({{sx,sy},{ex,ey}}, gfx.HEAD_STR[head+1], headstyle)
return 1
end
end
-- Called immediately after a plot is displayed.
term.text = function()
gfx.check_in_path()
pgf.write_graph_end(gfx.opt.nopicenv)
gfx.in_picture = false
return 1
end
term.put_text = function(x, y, txt)
gfx.check_in_path()
gfx.check_color()
if (txt ~= '') or (gfx.text_font ~= '') then -- omit empty nodes
pgf.write_text_node({x, y}, txt, gfx.text_angle, gfx.TEXT_ANCHOR[gfx.text_justify], gfx.text_font)
end
return 1
end
term.justify_text = function(justify)
gfx.text_justify = justify
return 1
end
term.text_angle = function(ang)
gfx.text_angle = ang
return 1
end
term.boxed_text = function(x, y, option)
if (option == 'INIT') then
gfx.boxed_text = true
gfx.boxed_text_count = 0
elseif (option == 'MARGINS') then
gfx.boxed_text_xmargin = x / 100.0
gfx.boxed_text_ymargin = y / 100.0
elseif (option == 'BACKGROUNDFILL' or option == 'OUTLINE') then
gfx.check_color()
gfx.check_linetype()
gfx.check_dashtype()
gfx.check_linewidth()
if (gfx.boxed_text_count > 0) then
gp.write('\\node[')
if (option == 'BACKGROUNDFILL') then
gp.write('fill={}, ')
if gfx.opacity < 1.0 then
gp.write(string.format("opacity=%.2f, ", gfx.opacity))
end
else
gfx.boxed_text = false
gp.write('draw, gp path,')
end
gp.write(string.format('inner xsep=%.2f, inner ysep=%.2f,', gfx.boxed_text_xmargin, gfx.boxed_text_ymargin))
gp.write('fit=')
for i=1,gfx.boxed_text_count do
gp.write(string.format('(gp boxed node %d)', i))
end
gp.write(']{};\n')
end
elseif (option == 'FINISH') then
gfx.boxed_text = false
end
return 1
end
term.linewidth = function(width)
width = width * gfx.opt.linewidth
if gfx.linewidth ~= width then
gfx.check_in_path()
gfx.linewidth = width
end
return 1
end
term.pointsize = function(size)
if gfx.pointsize ~= size then
gfx.check_in_path()
gfx.pointsize = size
end
return 1
end
term.set_font = function(font)
local fontsize = nil
gfx.text_font, fontsize = gfx.parse_font_string(font)
if fontsize then
term.h_char = math.floor(pgf.DEFAULT_FONT_H_CHAR * (fontsize/10) * (pgf.DEFAULT_RESOLUTION/1000) + 0.5)
term.v_char = math.floor(pgf.DEFAULT_FONT_V_CHAR * (fontsize/10) * (pgf.DEFAULT_RESOLUTION/1000) + 0.5)
end
return 1
end
-- at the moment this is only used to check
-- the plot's bounding box as seldom as possible
term.layer = function(l)
if l == 'end_text' then
-- called after a plot is finished (also after each "mutiplot")
gfx.write_boundingbox()
end
return 1
end
-- we don't use this, because we are implicitly testing
-- for closed paths
term.path = function(p)
return 1
end
term.filled_polygon = function(style, fillpar, t)
local pattern = nil
local color = nil
local opacity = 100
local saturation = 100
gfx.check_in_path()
if style == 'EMPTY' then
-- FIXME: should be the "background color" and not gpbgfillcolor
pattern = ''
color = 'gpbgfillcolor'
saturation = 100
opacity = 100
elseif style == 'DEFAULT' or style == 'OPAQUE' then -- FIXME: not shure about the opaque style
pattern = ''
color = gfx.color
saturation = 100
opacity = 100 * gfx.opacity
elseif style == 'SOLID' then
pattern = ''
color = gfx.color
if fillpar < 100 then
saturation = fillpar
else
saturation = 100
end
opacity = 100
elseif style == 'PATTERN' then
pattern = pgf.styles.patterns[(fillpar % #pgf.styles.patterns) + 1][1]
color = gfx.color
saturation = 100
opacity = 100
elseif style == 'TRANSPARENT_SOLID' then
pattern = ''
color = gfx.color
saturation = 100
opacity = fillpar
elseif style == 'TRANSPARENT_PATTERN' then
pattern = pgf.styles.patterns[(fillpar % #pgf.styles.patterns) + 1][1]
color = gfx.color
saturation = 100
opacity = 0
end
pgf.draw_fill(t, pattern, color, saturation, opacity)
return 1
end
term.boxfill = function(style, fillpar, x1, y1, width, height)
local t = {{x1, y1}, {x1+width, y1}, {x1+width, y1+height}, {x1, y1+height}}
return term.filled_polygon(style, fillpar, t)
end
-- points[row][column]
-- m: #cols, n: #rows
-- corners: clip box and draw box coordinates
-- ctype: "RGBA" or "PALETTE"
term.image = function(m, n, points, corners, ctype, xfile)
gfx.check_in_path()
pgf.write_clipbox_begin({corners[3][1],corners[3][2]},{corners[4][1],corners[4][2]})
local ll = {corners[1][1],corners[2][2]}
local ur = {corners[2][1],corners[1][2]}
local xxfile
if xfile ~= nil then
-- strip file extension
xxfile = string.match(xfile, "^(.*).png$")
else
xxfile = ""
end
-- load exclusively an external file and don't generate inline images
if xfile ~= nil and term.external_images == true then
pgf.load_image_file(ll, ur, xxfile)
elseif gfx.opt.direct_image then
if gfx.opt.cmykimage then
pgf.draw_raw_cmyk_image(points, m, n, ll, ur, xxfile)
else
pgf.draw_raw_rgb_image(points, m, n, ll, ur, xxfile)
end
else
-- draw as filled squares
local w = (corners[2][1] - corners[1][1])/m
local h = (corners[1][2] - corners[2][2])/n
local yy,yyy,xx,xxx,color
for cnt = 1,#points do
xx = corners[1][1]+(cnt%m-1)*w
yy = corners[1][2]-math.floor(cnt/m)*h
yyy = yy-h
xxx = xx+w
color = gfx.format_color(ctype, points[cnt])
gfx.set_opacity(ctype, points[cnt])
if color ~= nil then
pgf.draw_fill({{xx, yy}, {xxx, yy}, {xxx, yyy}, {xx, yyy}}, '', color, 100, 100*gfx.opacity)
end
end
end
pgf.write_clipbox_end()
end
term.make_palette = function()
-- continuous number of colours
return 0
end
term.previous_palette = function()
return 1
end
term.set_color = function(ctype, lt, value, opacity, r, g, b)
gfx.check_in_path()
-- FIXME gryscale on monochrome?? ... or use xcolor?
if ctype == 'LT' then
gfx.set_color('LT', {lt})
elseif ctype == 'FRAC' then
if gfx.opt.lines_colored then
gfx.set_color('RGBA', {r, g , b, 1.0})
else
gfx.set_color('GRAY', {value})
end
elseif ctype == 'RGBA' then
gfx.set_color('RGBA', {r, g , b, opacity})
else
gp.int_error(string.format("set color: unknown type (%s), lt (%i), value (%.3f)\n", ctype, lt, value))
end
return 1
end
-- Called when gnuplot is exited.
term.reset = function(p)
gfx.check_in_path()
gfx.check_variables()
if gfx.opt.full_doc then
pgf.write_doc_end()
end
return 1
end
--[[===============================================================================================
command line code
]]--===============================================================================================
term_help = function(helptext)
local w
for w in string.gmatch(helptext, "([^\n]*)\n") do
w = string.gsub(w, "\\", "\\\\")
w = string.gsub(w, "\"", "\\\"")
io.write('"'..w.."\",\n")
end
--[[
local out = string.gsub(helptext, "\n", "\",\n\"")
local out = string.gsub(helptext, "\n", "\",\n\"")
io.write(out)]]
end
if arg then -- called from the command line!
if #arg > 0 and arg[1] == 'style' then
-- write style file
pgf.create_style()
elseif arg[1] == 'termhelp' then
io.write([["2 lua tikz",
"?set terminal lua tikz",
"?set term lua tikz",
"?term lua tikz",
" The TikZ driver is one output mode of the generic Lua terminal.",
"",
" Syntax:",
" set terminal lua tikz",
"",
]])
pgf.print_help(term_help)
io.write("\"\"\n")
else
io.write([[
This script is intended to be called from GNUPLOT.
For generating the associated TeX/LaTeX/ConTeXt style files
just call this script with the additional option 'style':
# lua gnuplot.lua style
The TikZ driver provides the following additional terminal options:
]])
pgf.print_help(io.write)
end
end