gv(3tcl)
π gv(3tcl) π
okay bestie, sit down, we're learning gv(3tcl) today and honestly? it's giving main character energy. this is the manual page for the Tcl graph extension, and by the end of it you're gonna be manipulating graphs like it's nothing. no cap. π¦
β¨ NAME β¨
gv_tcl β graph manipulation in tcl. that's it, that's the whole name, short and iconic π
πΈ SYNOPSIS πΈ
#!/usr/bin/tclsh
package require gv
look at her. two lines. effortless. π
π USAGE π
Requires tcl8.3 or later. yes, or later. don't be out here running ancient tcl and then acting surprised, i'm literally begging π
π INTRODUCTION π
gv_tcl is a dynamically loaded extension for tcl that provides access to the graph facilities of graphviz. so like, tcl gets to hang out with graphviz and honestly the friendship is thriving π
π«Ά COMMANDS π«Ά
this is the part where it gets long, bestie. hydrate. we're going through all of it. every single one. periodt.
π§ New graphs
π± New empty graph
<graph_handle> gv::graph <name>
<graph_handle> gv::digraph <name>
<graph_handle> gv::strictgraph <name>
<graph_handle> gv::strictdigraph <name>
four flavours of blank canvas. pick your vibe: plain, directed, strict, or strict-and-directed. lowkey a personality quiz π
π New graph from a dot-syntax string or file
<graph_handle> gv::readstring <string>
<graph_handle> gv::read <string> filename
<graph_handle> gv::read <channel>
got a graph already sitting in a dot string, a filename, or an open channel? gv::read said "say no more". gv::readstring takes the raw string. easy. β¨
πͺ Add new subgraph to existing graph
<graph_handle> gv::graph <graph_handle> <name>
yes it's the same gv::graph command, but now it's nesting. graphs within graphs. it's giving inception, it's giving matryoshka, we love a recursive moment π
π New nodes
β Add new node to existing graph
<node_handle> gv::node <graph_handle> <name>
you hand it a graph, you hand it a name, it hands you back a node handle. a little transaction. a little exchange of goods. so cute π₯°
π₯ New edges
π Add new edge between existing nodes
<edge_handle> gv::edge <tail_node_handle> <head_node_handle>
both ends already exist? perfect, we just connect them. slay.
π Add a new edge between an existing tail node, and a named head node which will be induced in the graph if it doesn't already exist
<edge_handle> gv::edge <tail_node_handle> <head_name>
you've got the tail already, you just name the head, and if that head isn't in the graph yet β boom, it gets induced. it manifests. it shows up uninvited and honestly we respect it π
π Add a new edge between an existing head node, and a named tail node which will be induced in the graph if it doesn't already exist
<edge_handle> gv::edge <tail_name> <head_node_handle>
same energy, other direction. the tail is the named one this time, and it also gets induced if it doesn't already exist. symmetry. we love to see it πΈ
π Add a new edge between named tail and head nodes which will be induced in the graph if they don't already exist
<edge_handle> gv::edge <graph_handle> <tail_name> <head_name>
neither end exists yet? doesn't matter, bestie. give it the graph and two names and both nodes get induced. iconic. no notes. π
π Setting attribute values
βοΈ Set value of named attribute of graph/node/edge - creating attribute if necessary
<string> gv::setv <graph_handle> <attr_name> <attr_value>
<string> gv::setv <node_handle> <attr_name> <attr_value>
<string> gv::setv <edge_handle> <attr_name> <attr_value>
name the attribute, give it a value, and if that attribute didn't exist? gv::setv creates it for you. it's the friend who shows up with snacks you didn't even ask for π
βοΈ Set value of existing attribute of graph/node/edge (using attribute handle)
<string> gv::setv <graph_handle> <attr_handle> <attr_value>
<string> gv::setv <node_handle> <attr_handle> <attr_value>
<string> gv::setv <edge_handle> <attr_handle> <attr_value>
same command, but now you're passing an attribute handle instead of a name, and the attribute has to already exist. glow-up edition π
π Getting attribute values
π Get value of named attribute of graph/node/edge
<string> gv::getv <graph_handle> <attr_name>
<string> gv::getv <node_handle> <attr_name>
<string> gv::getv <edge_handle> <attr_name>
you ask by name, you get a <string> back. simple. clean. β¨
π Get value of attribute of graph/node/edge (using attribute handle)
<string> gv::getv <graph_handle> <attr_handle>
<string> gv::getv <node_handle> <attr_handle>
<string> gv::getv <edge_handle> <attr_handle>
and here you ask with an attribute handle instead. two ways in, same <string> coming out the other side π
π·οΈ Obtain names from handles
<string> gv::nameof <graph_handle>
<string> gv::nameof <node_handle>
<string> gv::nameof <attr_handle>
you've got a handle but you forgot what it's called? relatable. gv::nameof reminds you. bestie behavior fr fr π«Ά
π Find handles from names
<graph_handle> gv::findsubg <graph_handle> <name>
<node_handle> gv::findnode <graph_handle> <name>
<edge_handle> gv::findedge <tail_node_handle> <head_node_handle>
<attr_handle> gv::findattr <graph_handle> <name>
<attr_handle> gv::findattr <node_handle> <name>
<attr_handle> gv::findattr <edge_handle> <name>
the reverse move: you've got names, you want handles. gv::findsubg, gv::findnode, gv::findedge (that one wants the tail and head node handles, not names, btw π), and gv::findattr which works on a graph, a node, or an edge. finders keepers π
π§ Misc graph navigators returning handles
<node_handle> gv::headof <edge_handle>
<node_handle> gv::tailof <edge_handle>
<graph_handle> gv::graphof <graph_handle>
<graph_handle> gv::graphof <edge_handle>
<graph_handle> gv::graphof <node_handle>
<graph_handle> gv::rootof <graph_handle>
little handle hopscotch π« gv::headof and gv::tailof give you the nodes on either end of an edge, gv::graphof climbs up from a graph, an edge, or a node, and gv::rootof takes you all the way to the root. it's giving ancestry.com π§¬
π― Obtain handles of proto node/edge for setting default attribute values
<node_handle> gv::protonode <graph_handle>
<edge_handle> gv::protoedge <graph_handle>
the proto node and proto edge! set your defaults on these and every future node/edge inherits the vibe. it's the blueprint. it's the template. it's the mood board β¨
π Iterators
β Iteration termination tests
<boolean_string> gv::ok <graph_handle>
<boolean_string> gv::ok <node_handle>
<boolean_string> gv::ok <edge_handle>
<boolean_string> gv::ok <attr_handle>
the vibe check of the iterator world π«‘ you get a <boolean_string> back, and it tells you whether to keep going or wrap it up.
π³ Iterate over subgraphs of a graph
<graph_handle> gv::firstsubg <graph_handle>
<graph_handle> gv::nextsubg <graph_handle> <subgraph_handle>
first one, then keep asking for the next one. classic. no notes.
π Iterate over supergraphs of a graph (obscure and rarely useful)
<graph_handle> gv::firstsupg <graph_handle>
<graph_handle> gv::nextsupg <graph_handle> <subgraph_handle>
okay the page itself calls this "obscure and rarely useful" so i'm just passing that along π it exists! it's there! it's yours if you want it!
π Iterate over edges of a graph
<edge_handle> gv::firstedge <graph_handle>
<edge_handle> gv::nextedge <graph_handle> <edge_handle>
every edge, one at a time. π¦
π Iterate over outedges of a graph
<edge_handle> gv::firstout <graph_handle>
<edge_handle> gv::nextout <graph_handle> <edge_handle>
the outgoing ones specifically. out with it. π
π Iterate over edges of a node
<edge_handle> gv::firstedge <node_handle>
<edge_handle> gv::nextedge <node_handle> <edge_handle>
same commands, but the starting point is a node now. yes, gv::firstedge and gv::nextedge again β they're flexible like that π
π Iterate over out-edges of a node
<edge_handle> gv::firstout <node_handle>
<edge_handle> gv::nextout <node_handle> <edge_handle>
out-edges, but from a node. and yep, gv::firstout and gv::nextout do double duty π
π― Iterate over head nodes reachable from out-edges of a node
<node_handle> gv::firsthead <node_handle>
<node_handle> gv::nexthead <node_handle> <head_node_handle>
you're not iterating edges, you're iterating the head nodes those out-edges point at. follow the arrows, bestie β‘οΈ
π Iterate over in-edges of a graph
<edge_handle> gv::firstin <graph_handle>
<edge_handle> gv::nextin <node_handle> <edge_handle>
in-edges, graph edition. exactly as written, character for character π
π Iterate over in-edges of a node
<edge_handle> gv::firstin <node_handle>
<edge_handle> gv::nextin <graph_handle> <edge_handle>
and the node version. also exactly as written π«Ά
π― Iterate over tail nodes reachable from in-edges of a node
<node_handle> gv::firsttail <node_handle>
<node_handle> gv::nexttail <node_handle> <tail_node_handle>
the mirror image of the head thing: now you're collecting the tail nodes those in-edges come from. πΈ
π Iterate over nodes of a graph
<node_handle> gv::firstnode <graph_handle>
<node_handle> gv::nextnode <graph_handle> <node_handle>
every node in the graph. go forth. β
π Iterate over nodes of an edge
<node_handle> gv::firstnode <edge_handle>
<node_handle> gv::nextnode <edge_handle> <node_handle>
an edge has two nodes and you can walk them. tiny graph, big energy π₯
π·οΈ Iterate over attributes of a graph
<attr_handle> gv::firstattr <graph_handle>
<attr_handle> gv::nextattr <graph_handle> <attr_handle>
all the graph's attributes, handed to you one by one as <attr_handle>s π
π·οΈ Iterate over attributes of an edge
<attr_handle> gv::firstattr <edge_handle>
<attr_handle> gv::nextattr <edge_handle> <attr_handle>
same deal, edge edition. π¦
π·οΈ Iterate over attributes of a node
<attr_handle> gv::firstattr <node_handle>
<attr_handle> gv::nextattr <node_handle> <attr_handle>
and node edition. gv::firstattr / gv::nextattr really said "i contain multitudes" π
ποΈ Remove graph objects
<boolean_string> gv::rm <graph_handle>
<boolean_string> gv::rm <node_handle>
<boolean_string> gv::rm <edge_handle>
yeet. you get a <boolean_string> back so you know how it went. this is the unalive button and it works on graphs, nodes, and edges π
π¨ Layout
π§ Annotate a graph with layout attributes and values using a specific layout engine
<boolean_string> gv::layout <graph_handle> <string> engine
you pick the engine (as a <string>) and it goes and annotates your graph with layout attributes and values. you get a <boolean_string> back. this is where the graph gets its lil outfit on β¨
πΌοΈ Render
π¨ Render a layout into attributes of the graph
<boolean_string> gv::render <graph_handle>
no format, no file β just render the layout straight into the graph's own attributes. keep it in-house π
π¨οΈ Render a layout to stdout
<boolean_string> gv::render <graph_handle> <string> format
give it a format and it prints to stdout like it owns the place. π«Ά
π Render to an open file
<boolean_string> gv::render <graph_handle> <string> format
<channel> fout
format plus an already-open <channel> called fout. it writes right into the file you've got open. teamwork! π€
π Render a layout to an unopened file by name
<boolean_string> gv::render <graph_handle> <string> format
<string> filename
no open channel needed β just hand over a filename and it handles the rest. the self-sufficient icon it is π
π Render to a string result
<string> gv::renderresult <graph_handle> ing <string> format
gv::renderresult <graph_handle> <string> format <string> outdata
yes, that first line has an ing in it. that's literally what the page says, so that's what you get β i do not make the rules π and the second form takes outdata and gives nothing back, no <string> return on that one, exactly as written π
π‘ Render to an open channel
<boolean_string> gv::renderchannel <graph_handle> <string> format
<string> channelname
same idea, but you name the channel as a <string> instead of passing the channel itself. naming rights π
𧨠Render a layout to a malloc'ed string, to be free'd by the caller
(deprecated - too easy to leak memory)
(still needed for "eval [gv::renderdata $G tk]" )
<string> gv::renderdata <graph_handle> <string> format
okay listen. this one hands you a malloc'ed string and you have to free it. the page says it's deprecated because it is β it's too easy to leak memory. π that is not a drill, bestie, that's a genuine memory leak waiting to happen.
but also: it's still needed for "eval [gv::renderdata $G tk]" so it's not going anywhere. complicated queen. we respect her even if we don't fully trust her π
πΎ Writing graph back to file
<boolean_string> gv::write <graph_handle> <string> filename
<boolean_string> gv::write <graph_handle> <channel>
save your work! by filename, or straight into an open <channel>. <boolean_string> back either way. πΎβ¨
π Graph transformation tools
<boolean_string> gv::tred <graph_handle>
gv::tred β a graph transformation tool. that's the one the page gives us, and it returns a <boolean_string> like all the other doers π
π« KEYWORDS π«
graph, dot, neato, fdp, circo, twopi, tcl.
(the search terms that got you here. hi. welcome. glad you came. π«Ά)
and that's the whole page, bestie!! you made it all the way to the bottom, which honestly deserves a round of applause πππ
this was gv(3tcl), dated 21 March 2026 β so if you're reading this and the date on your screen says something else, no you're not, mind your business π
now go manipulate some graphs. you're literally so good at this. i'm obsessed. bye!! πππ¦
π¦ where this page comes from
- fedora 44: graphviz-tcl 14.1.4-2.fc44 Β· epl-1.0 AND cpl-1.0 AND bsd-3-clause AND mit AND gpl-3.0-or-later WITH bison-exception-2.2 AND apache-1.1 AND lgpl-2.0-or-later WITH libtool-exception AND smlnj AND hpnd-uc
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms