pikchr
Table of contents
Introduction
Pikchr (pronounced like “picture”) is a PIC-like markup language for diagrams in technical documentation. Pikchr is designed to be embedded in fenced code blocks of Markdown (or in similar mechanisms in other markup languages) to provide a convenient means of showing diagrams.
A pikchr fork with some new objects can be found at https://github.com/geraldolsribeiro/pikchr:
image
: incorporate external files into diagram.link
: create a box with hyperlink to an URL
A online editor at https://pikchr.org/home/pikchrshow.
Sample
The figure above was generated by the following code:
topmargin += 1mm
margin = 5mm
arrow right 200% "Markdown" "Source"
box rad 10px "Markdown" "Formatter" "(markdown.c)" fit
arrow right 200% "HTML+SVG" "Output"
arrow <-> down 70% from last box.s
box same "Pikchr" "Formatter" "(pikchr.c)" fit
Image
The figure above was generated by the following code:
FF: image "/icon/firefox.svg" width 1 height 1
arrow
image "/icon/chrome.svg" width 1 height 1
arrow
image "/icon/brave.svg" width 1 height 1
down
arrow down then right until even with FF then up
Link
The figure above was generated by the following code:
box width 1 height 1
link "id1" "Google" "https://google.com" width 64px height 64px
box width 1 height 1
link "id2" "Disney" "https://disney.com" width 32px height 32px
box width 1 height 1
link "id3" "Amazon" "https://amazon.com" width 1 height 1 fill blue
box width 1 height 1
link "id4" "Geraldo" "https://geraldo.dev"
Link with image
The figure above was generated by the following code:
FF: image "/icon/firefox.svg" "https://www.mozilla.org/firefox/" width 1 height 1
arrow
image "/icon/chrome.svg" "https://www.google.com/chrome/" width 1 height 1
arrow
image "/icon/brave.svg" "https://brave.com/" width 1 height 1
down
arrow down then right until even with FF then up
Ark
This is my attempt to provide a more precise arc
command.
The figure above was generated by the following code:
margin = 0.1
// Axis
line from 0,0 to 0,2 color purple
line from 0,0 to 2,0 color purple
// Approximate circle with 4 arcs
arcrad = 2
arc to 0,2 color red
arc to -2,0 color green
arc to 0,-2 color orange
arc to 2,0 color blue
// Macro ark(radius, startAngle, endAngle)
define ark {
ArkCenter: text
$arkNumberOfSegments = 5
$arkSegmentAngle = ($3-$2)/$arkNumberOfSegments
ArkP1: line invisible from ArkCenter go $1 heading $2
ArkP2: line invisible from ArkCenter go $1 heading $2+1*$arkSegmentAngle
ArkP3: line invisible from ArkCenter go $1 heading $2+2*$arkSegmentAngle
ArkP4: line invisible from ArkCenter go $1 heading $2+3*$arkSegmentAngle
ArkP5: line invisible from ArkCenter go $1 heading $2+4*$arkSegmentAngle
ArkP6:line invisible from ArkCenter go $1 heading $3
spline from ArkP1.end to ArkP2.end to ArkP3.end to ArkP4.end to ArkP5.end to ArkP6.end $4
move to ArkCenter
}
// Sample
move to 0,0
ark(0.9, 0, 90, color red)
ark(0.8, 0, 90)
ark(0.7, 0, 90, dashed color green ->)
ark(0.6,45,90, <-> thin)
ark(1.5,30,60)
ark(1.95, 0, 90, color red dotted)
ark(1.95, 90, 180, color blue dotted)
ark(1.95, 180, 270, color orange dotted)
ark(1.95, 270, 360, color green dotted)
Mable diagram
The figure above was generated by the following code:
circlerad = 0.1
linewid = 0.2
marble_color = red
define marble { circle $1 color marble_color }
define mark {
LE: last.end;
line from LE + (0,0.05) to LE - (0,0.05) then to LE
}
define stop {
LE: last.end;
line from LE - (0.05,0.05) to LE + (0.05,0.05);
line from LE - (0.05,-0.05) to LE + (0.05,-0.05);
move to LE
}
define mc { marble_color = $1 }
define mr { marble_color = red; marble $1 }
define mg { marble_color = green; marble $1 }
define my { marble_color = yellow; marble $1 }
// ------
S: dot; line; mr "1"; line width 0.6; mg "3"; line; mark; arrow
// ------
move to S - (0,0.3)
dot; line width 0.6; my "2"; line width 0.6; stop; arrow
// ------
move to S - (0,0.8)
dot; line; mr "1"; line; my "2"; line; mg "3"; line; mark; arrow
Filled Polygon
The keyword close
converts the line into a polygon.
The figure above was generated by the following code:
margin = 5mm;
text "Start here"
dot color green width 200%
# heading zero == north
line thin thin go 6cm heading 60 then down 3cm close fill DarkViolet
The figure above was generated by the following code:
A: ( 0, sqrt(3/4))
B: ( 0.5, 0)
C: ( -0.5, 0)
margin = 5mm;
line from A to B then to C then to A # fill Brow # 💩 WITHOUT CLOSE IGNORED FILL
circle rad 0.1 at A fill Aqua
circle rad 0.1 at B fill blue
circle rad 0.1 at C fill green
The then
keyword continue positioning without drawing a line.
The close
keyword changes the last line end
position.
The figure above was generated by the following code:
margin = 10mm;
dot color blue
line right 2cm then down .5cm then up 1cm right 1cm \
then up 1cm left 1cm then down .5cm then left 2cm \
close "with 'close'"
dot color red at last line.end
move to 2.5cm south of last line.start
line right 2cm then down .5cm then up 1cm right 1cm \
then up 1cm left 1cm then down .5cm then left 2cm \
then down 1cm "without 'close'"
dot color red at last line.end
Macro
https://pikchr.org/home/forumpost/83e98ec009: Once created, a macro cannot be redefined. If you attempt to redefine a macro by providing a second “define” statement with the same macro name, the macro name will be replaced by the previous macro body definition during lexical analysis, likely resulting in a syntax error.
The figure above was generated by the following code:
CP: dot invisible;
define flag {
line go 1.5 heading $flagAngle \
then go 0.5 heading $flagAngle + 110 \
then go 0.5 heading $flagAngle + 250 color $color;
move to CP;
}
margin = 10mm;
$flagAngle = 00; $color=red; flag;
$flagAngle = 30; $color=blue; flag;
$flagAngle = 60; $color=green; flag;
When parameters are present, they are substituted in the macro body in place of $1
, $2
, …, $9
in the macro body.
The figure above was generated by the following code:
define mybox {
move right 10mm;
dot color blue;
box width $1 height $2 radius 2mm color $3;
box $4 width ($1-3mm) height ($2-3mm) at last box radius 1mm;
box width ($1-6mm) height ($2-6mm) at last box;
}
margin = 10mm
mybox(3cm, 4cm, red, "text1")
mybox(2cm, 1cm, blue, "text2")
mybox(4cm,4cm, yellow, "text3")
UTF-8 characters
The figure above was generated by the following code:
margin = 1cm
P1: (0,0)
P2: (4cm,3cm)
P3: (4cm,0)
line from P1 to P2 to P3 close dashed thin thin fill purple
line invisible from P1 to P2 "☕☕" above aligned big
line invisible from P2 to P3 " ✍" ljust big
line invisible from P1 to P3 "🍕" below big
dot at P1 fill red
dot at P2 fill blue
dot at P3 fill green
box with .sw at (-1cm,-1cm) width 6cm height 5cm thin color brown radius 2mm
move to (0cm,3cm)
Caption: text "🔵🔴🟠🟡🟢🟣🟤" "🟦🟥🟧🟨🟩🟪🟫" "🛑🔶🔷🔸🔹🔺🔻"
Trigonometric functions
Zero heading == North
sin and cos assumes radian as its argument
The figure above was generated by the following code:
pi = 3.141592 # define a constant
a = sin(pi) # 0
b = cos(pi) # 1
c = abs(-pi) # 3.141592
d = int(pi) # 3
e = sqrt(25) # 5
define trigCircle {
circle radius 1 color gray
arrow from (0,-1.2) to (0,1.2) color gray
arrow from (-1.2,0) to (1.2,0) color gray
}
define angHor {
arrow from (0,0) to (sin((90-$1)*pi/180),cos((90-$1)*pi/180)) color purple
text $2 color purple
}
define angVert {
arrow from (0,0) to (sin($1*pi/180),cos($1*pi/180)) color green thin thin
text $2 above rjust color green
}
trigCircle
angHor( 30, "30⁰ = 60 from N" )
angHor( 20, "20⁰ = 70 from N" )
angHor( 10, "10⁰ = 80 from N" )
angVert( 10, "10⁰" )
angVert( 20, "20⁰" )
angVert( 30, "30⁰" )
angVert( 40, "40⁰" )
angVert( 50, "50⁰" )
arrow from (0,0) to (b,a) "Pi" above color red thick thick
The figure above was generated by the following code:
margin = 1cm
circlerad = 3mm
circle "a" color brown
circle "b" at 1st circle + (-0.4, -0.6) color green
circle "c" at 1st circle + (0.4, -0.6) color cyan
arrow from 1st circle to 2nd circle chop color purple
arrow from 1st circle to 3rd circle chop color purple
The figure above was generated by the following code:
margin = 1cm
box width 1cm height 3cm
arrow right from 0 <last box.ne, last box.se> color red "0" small small above
arrow right from 1/3 of the way between last box.ne and last box.se color orange "1/3" small small above
arrow right from 2/3 <last box.ne, last box.se> color blue "2/3" small small above
arrow right from 1 <last box.ne, last box.se> color green "1" small small above
P1: (3cm,-15mm)
P2: (4cm,1.5cm)
P3: (8cm,-15mm)
P4: (4.5cm,1.5cm)
dot at P1 "P1" below rjust
dot at P2 "P2" above rjust
dot at P3 "P3" below ljust
dot at P4 "P4" above ljust
L1: line from P1 to P2
L2: line from P3 to P4
arrow from 1/3 <P1, P2> to 1/3 <P3, P4> color blue
arrow from 2/3 <P1, P2> to 2/3 <P3, P4> color orange
The figure above was generated by the following code:
margin = 1cm
line dashed right 1 then down .5 left 1 then right 1 thin thin
spline from start of last line right 1 then down .5 left 1 then right 1 color orange
The figure above was generated by the following code:
box "1" width 4cm height 4mm
A: [
box "2" height 6mm width 2cm color green;
arrow "3" above width 1cm
box "4" width 4cm height 1cm color blue
arrow right 1cm down 1cm "5" above
] with .n at last box.s - (0,15mm)
dot at last [].w "w " rjust color red
dot at last [] "c" below color red
dot at last [].e " e" ljust color red
dot at last [].n "n" above color red
dot at last [].s "s" below color red
dot at last [].sw "sw" below color red
dot at last [].nw "nw" above color red
dot at last [].se "se" below color red
dot at last [].ne "ne" above color red
box with .sw at A.sw - (5mm,5mm) width (A.width + 10mm) height (A.height + 10mm) thin thin color orange dotted
The figure above was generated by the following code:
margin = 1cm
X: [
Y: [
down
R: box width 5mm height 5mm color red
G: box width 5mm height 5mm color green
B: box width 5mm height 5mm color blue
]
Z: [
move right 8cm up 0mm
# up last direction
A: box width 2cm height 5mm color orange "X.Z.A"
move up 1mm
B: box width 2cm height 5mm color brown "X.Z.B"
move up 1mm
C: box width 2cm height 5mm color orange "X.Z.C"
]
W: [
move right 16cm down 0mm
A: box width 2cm height 5mm color orange "X.W.A"
move down 1mm
B: box width 2cm height 5mm color brown "X.W.B"
move down 1mm
C: box width 2cm height 5mm color orange "X.W.C"
]
]
arrow from X.Y.R right "R" above
arrow from X.Y.G left "G" above
arrow from X.Y.B down " B" ljust
arrow from X.Y.B to X.Z.A chop color purple
arrow from X.Y.B to X.Z.C.w chop color purple
arrow from X.Z.C.e right 5mm then down until even with X.Z.B.e then to X.Z.B.e
line from X.Z.C to X.W.C thin thin dotted
arrow <-> from X.Z.A to X.W.A color blue chop
The figure above was generated by the following code:
define r { line 50%; arc; line; arc cw; line; arc cw; line; arc; line 50% }
color = blue
r
color = green
r
color = red
r
color = orange
r
color = purple
spline -> from (0,0) then to (4,1) then to (8,0)
spline -> from (0,0) then to (4,1.5) then to (8,0)
spline -> from (0,0) then to (4,2) then to (8,0)
Some digrams on internet
The figure above was generated by the following code:
topmargin = 1
fontscale = 3
color = 0xc65835 # Orange
define $boxlet {
oval at -0.18,0 height 0.75 width 0.33 color none fill 0xd6d6d6
box same as last at -0.12,0.28 height 0.2 width 0.2 radius 0
box at 0,0 height 1 width 1 color none fill 0x343433 radius 0.2 behind last box
}
define $wall {
box at 0,0 height 3.1 width 0.76 color none fill 0x496495
line from -0.38*$1,0.34 to $1*0.38,0.16 to $1*0.38,-0.16 to -0.38*$1,-0.34 close color none fill 0xaec0e0
}
define $wall_info {
text at last.n + (0.0, 0.5) color 0x496495 $2 bold
circle at last.n + (0.0,0.3) radius 0.25 thickness 0.05 color 0x5a79a6
line from (last.x-$1*0.11,last circle.c.y) \
right $1*0.22 then \
up $1*0.11 left $1*0.11 then \
down $1*0.11 right $1*0.11 then \
down $1*0.11 left $1*0.11 then \
up $1*0.11 right $1*0.11 \
color 0x496495 thickness 0.05
}
define $area {
box at ($1,$2) width $3 height $4 color none fill 0xf9f9f8 radius 0.2
}
# Servers
$area(0.55,0,5.2,3.1)
WS1: [ $boxlet() ] at (0, 0)
text at last.n + (0.0, 0.1) color 0x595857 "VPN Client" above
text at last.s - (0.0, 1) color 0x030303 $2 "Workstation" below
$area(0,-5.25,4.1,3.1)
$area(2.83,-5.25,0.8,3.1)
WS2: [ $boxlet() ] at (0, -5.25)
text at last.n + (0.0, 0.1) color 0x595857 "VPN Client" above
text at last.s - (0.0, 1) color 0x030303 "Workstation" below
$area(8.3,-2.3,6,5.25)
HUB: [ $boxlet() ] at (8.3, -2.4)
text at last.n + (0.0, 0.1) color 0x595857 "VPN Hub" above
text at last.s - (0.0, 1.78) color 0x030303 "Server" below
$area(16.10,HUB.c.y,4.1,3.1)
$area(13.27,HUB.c.y,0.8,3.1)
WS3: [ $boxlet() ] at (16.10, HUB.c.y)
text at last.n + (0.0, 0.1) color 0x595857 "VPN Client" above
text at last.s - (0.0, 1) color 0x030303 "EC2 VM" below
[ $wall(1) ] at (3.20,0)
$wall_info(1, "Windows Firewall")
[ $wall(1) ] at (3.2,-5.25)
$wall_info(1, "Office Firewall")
[ $wall(-1) ] at (12.9,HUB.c.y)
$wall_info(-1, "AWS" bold "Security Group" bold "")
dot at WS1.e radius 0.05
dot at WS2.e radius 0.05
dot at WS3.w radius 0.05
line from WS1.e right 4 then down until even with (0,HUB.y+0.2) right 2.3 then right until even with (HUB.w-0.03,0) thickness 0.04 radius 1
line up 0.15 left 0.15 down 0.15 right 0.15 down 0.15 left 0.15 up 0.15 right 0.15 thickness 0.04
line from WS2.e right 4 then up until even with (0,HUB.y-0.2) right 2.3 then right until even with (HUB.w-0.03,0) thickness 0.04 radius 1
line up 0.15 left 0.15 down 0.15 right 0.15 down 0.15 left 0.15 up 0.15 right 0.15 thickness 0.04
line from WS3.w to 0.03 right of HUB.e thickness 0.04
line up 0.15 right 0.15 down 0.15 left 0.15 down 0.15 right 0.15 up 0.15 left 0.15 thickness 0.04