This image has been generated by the following Ruby code and optimized in GIMP.
# author: Matma Rex
# code licensed under CC-BY-SA license
require 'rubygems'
require 'RMagick'
include Magick
step=5 # degrees by which Io will move in every frame
# Io, Europa, Ganymede
distances=[46, 72, 112]
speeds=[1, 0.5, 0.25]
shifts=[-90, 90, -90]
centerx=122
centery=122
list=ImageList.new
base=Image.new 365,245
base.ticks_per_second=1000
base.delay=5*step
gc=Draw.new
# lines
gc.stroke 'lightgrey'
gc.stroke_width 1.5
distances.each{|d| gc.line centerx, centery-d, 360, centery-d}
gc.line centerx, centery, 360, centery
# orbits
gc.stroke 'grey'
gc.fill 'none'
gc.stroke_width 2
distances.each{|d| gc.circle centerx, centery, centerx, centery+d}
# Jupiter
gc.stroke 'black'
gc.fill 'black'
gc.stroke_width 2
gc.circle centerx, centery, centerx, centery+9
# labels
# gc.stroke_width 0
# gc.gravity EastGravity
# gc.font_family 'arial'
# gc.font_size 18
# gc.font_weight LighterWeight
# gc.text_align RightAlign
# gc.text_undercolor 'white'
# gc.text 360, centery-distances[0]+7, '" Io 1:1"'.upcase
# gc.text 360, centery-distances[1]+7, '" Europa 2:1"'.upcase
# gc.text 360, centery-distances[2]+7, '" Ganymede 4:1"'.upcase
# gc.font_weight BoldWeight
# gc.text 360, centery+7, '" Jupiter"'.upcase
gc.draw base
# ImageMagick sucks at text - load a predefined text img instead
base=base.composite Image.read('text.png')[0].transparent('cyan'), 0, 0, OverCompositeOp
(0..(4*360-1)).step(step) do |deg|
img=base.clone
gc=Draw.new
0.upto(2) do |i|
rad=(deg*speeds[i] + shifts[i]) * Math::PI / 180.0
x=distances[i] * -Math.cos(rad)
y=distances[i] * Math.sin(rad)
gc.circle centerx+x, centery+y, centerx+x, centery+y+4.5
end
gc.draw img
list << img
end
list.write 'magick.gif'