Skip to content

Commit

Permalink
Topic tree drawing with GraphViz.
Browse files Browse the repository at this point in the history
  • Loading branch information
jamiemccarthy committed Jul 1, 2004
1 parent 765abe9 commit 17e56f4
Show file tree
Hide file tree
Showing 11 changed files with 229 additions and 16 deletions.
3 changes: 1 addition & 2 deletions Bundle/Slash.pm
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ mod_perl must be installed by hand, because of the special configuration
required for it.
Optional but recommended modules include: Cache::Memcached Silly::Werder
GD GD::Text Apache::SSI Apache::RegistryFilter
GD GD::Text Apache::SSI Apache::RegistryFilter GraphViz
=cut
14 changes: 8 additions & 6 deletions Slash/DB/MySQL/MySQL.pm
Original file line number Diff line number Diff line change
Expand Up @@ -1142,15 +1142,17 @@ sub undoModeration {
# If no tid is given, returns the whole tree. Otherwise,
# returns the data for the topic with that numeric id.
sub getTopicTree {
my($self, $tid) = @_;
my($self, $tid_wanted, $options) = @_;
my $constants = getCurrentStatic();

my $table_cache = "_topictree_cache";
my $table_cache_time = "_topictree_cache_time";
_genericCacheRefresh($self, 'topictree', $constants->{block_expire});
_genericCacheRefresh($self, 'topictree',
$options->{no_cache} ? -1 : $constants->{block_expire}
);
if ($self->{$table_cache_time}) {
if ($tid) {
return $self->{$table_cache}{$tid} || undef;
if ($tid_wanted) {
return $self->{$table_cache}{$tid_wanted} || undef;
} else {
return $self->{$table_cache};
}
Expand Down Expand Up @@ -1201,8 +1203,8 @@ sub getTopicTree {

$self->{$table_cache} = $tree_ref;
$self->{$table_cache_time} = time;
if ($tid) {
return $tree_ref->{$tid} || undef;
if ($tid_wanted) {
return $tree_ref->{$tid_wanted} || undef;
} else {
return $tree_ref;
}
Expand Down
2 changes: 2 additions & 0 deletions plugins/Admin/PLUGIN
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pg_dump=dump
htdoc=admin.pl
task=refresh_uncommon.pl
task=topic_popup_static.pl
task=topic_tree_draw.pl
image=images/L.png
image=images/closed_node.png
image=images/minus.png
Expand Down Expand Up @@ -38,6 +39,7 @@ template=templates/slashd_box;misc;default
template=templates/slashd_status;admin;default
template=templates/templateEdit;admin;default
template=templates/titles;admin;default
template=templates/topicTree;admin;default
template=templates/topic_popup_css;admin;default
template=templates/topic_popup_js;admin;default
template=templates/topic_popup_tree;admin;default
Expand Down
22 changes: 22 additions & 0 deletions plugins/Admin/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
For using admin.pl's option to visually see your topic tree, you need
the perl module GraphViz, which requires some libraries to be installed.
Note that the GraphViz libraries are apparently not under a license that
is strictly open-source; IBM has some mild but nonetheless restrictive
terms about how you have to let them know if you change its code.
So if non-Free software gives you the willies, simply don't install this
module, set the topic_tree_draw constant to 0, and all will be well
except that you won't get the pretty picture.

If you leave that constant 1, you'll want to install the GraphViz perl
module and whatever it requires. You can read its own advice on doing
that if you like. On Debian unstable as of July 2004, we simply had to
do:

apt-get install graphviz

and for the free monospaced font we use by default for labels, we did:

apt-get install ttf-freefont

(You can use your own font, of course.)

18 changes: 13 additions & 5 deletions plugins/Admin/admin.pl
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ sub main {
},
colors => { # colored,colorpreview,colorsave,colorrevert,
# colororig,colorsavedef,

function => \&colorEdit,
seclev => 10000,
adminmenu => 'config',
Expand Down Expand Up @@ -112,23 +111,25 @@ sub main {
adminmenu => 'info',
tab_selected => 'site',
},

topictree => {
function => \&topicTree,
seclev => 100,
adminmenu => 'info',
tab_selected => 'topictree',
},
templates => {
function => \&templateEdit,
seclev => 500,
adminmenu => 'config',
tab_selected => 'templates',
},

topics => { # topiced,topicnew,topicsave,topicdelete

function => \&topicEdit,
seclev => 10000,
adminmenu => 'config',
tab_selected => 'topics',
},
vars => { # varsave, varedit

function => \&varEdit,
seclev => 10000,
adminmenu => 'config',
Expand Down Expand Up @@ -333,6 +334,13 @@ sub siteInfo {

}

##################################################################
sub topicTree {
my($form, $slashdb, $user, $constants) = @_;

slashDisplay('topicTree');
}

##################################################################
sub pageEdit {
my($seclev, $page) = @_;
Expand Down
12 changes: 9 additions & 3 deletions plugins/Admin/dump
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ INSERT INTO menus (menu, label, sel_label, value, seclev, menuorder) VALUES ('co
INSERT INTO menus (menu, label, sel_label, value, seclev, menuorder) VALUES ('config','Info','Info','[% gSkin.rootdir %]/admin.pl?op=recent',500,10);

INSERT INTO menus (menu, label, sel_label, value, seclev, menuorder) VALUES ('info','Site','Site','[% gSkin.rootdir %]/admin.pl?op=siteinfo',100,9);
INSERT INTO menus (menu, label, sel_label, value, seclev, menuorder) VALUES ('info','Tree','Tree','[% gSkin.rootdir %]/admin.pl?op=topictree',100,9);
INSERT INTO menus (menu, label, sel_label, value, seclev, menuorder) VALUES ('info','Slashd','Slashd','[% gSkin.rootdir %]/admin.pl?op=slashd',500,9);
INSERT INTO menus (menu, label, sel_label, value, seclev, menuorder) VALUES ('info','Recent','Recent','[% gSkin.rootdir %]/admin.pl?op=recent',500,10);
INSERT INTO menus (menu, label, sel_label, value, seclev, menuorder) VALUES ('info','Normal','Normal','[% gSkin.rootdir %]/admin.pl',500,12);
Expand All @@ -34,9 +35,14 @@ INSERT INTO vars (name, value, description) VALUES ('similarstorydays', '30', 'N
INSERT INTO vars (name, value, description) VALUES ('similarstorymaxwords', '30', 'Maximum number of top-weighted scores to search for in previous stories');
INSERT INTO vars (name, value, description) VALUES ('similarstoryminweight', '4', 'Minimum weight necessary for a story to be displayed as similar');
INSERT INTO vars (name, value, description) VALUES ('similarstorynumshow', '5', 'Maximum number of similar stories to show in admin preview');
INSERT INTO vars (name, value, description) VALUES ('uncommon_weight_bodytext','0.5','The min M1 karma');
INSERT INTO vars (name, value, description) VALUES ('uncommon_weight_introtext','1','The min M1 karma');
INSERT INTO vars (name, value, description) VALUES ('uncommon_weight_title','8','The min M1 karma');
INSERT INTO vars (name, value, description) VALUES ('topic_tree_draw', '1', 'Draw the images/topic_tree.png?');
INSERT INTO vars (name, value, description) VALUES ('topic_tree_draw_fontname', 'freefont/FreeMono', 'Name of font used for labels in the topic tree');
INSERT INTO vars (name, value, description) VALUES ('topic_tree_draw_fontsize', '10', 'Size of font used for labels in the topic tree');
INSERT INTO vars (name, value, description) VALUES ('topic_tree_lastchange', '1', 'Unix timestamp of last change to the topic tree');
INSERT INTO vars (name, value, description) VALUES ('topic_tree_lastdraw', '1', 'Unix timestamp of last time topic_tree_draw.pl redrew images/topic_tree.png');
INSERT INTO vars (name, value, description) VALUES ('uncommon_weight_bodytext','0.5','Relative weight for uncommon words found in bodytext of stories');
INSERT INTO vars (name, value, description) VALUES ('uncommon_weight_introtext','1','Relative weight for uncommon words found in introtext of stories');
INSERT INTO vars (name, value, description) VALUES ('uncommon_weight_title','8','Relative weight for uncommon words found in titles of stories');
INSERT INTO vars (name, value, description) VALUES ('uncommonstorywords', '', 'A generated list of uncommon words found in recent stories');
INSERT INTO vars (name, value, description) VALUES ('uncommonstorywords_maxlen', '65000', 'Maximum length of the uncommon words list');
INSERT INTO vars (name, value, description) VALUES ('uncommonstoryword_minlen', '3', 'Minimum length of the words in the uncommon words list');
Expand Down
21 changes: 21 additions & 0 deletions plugins/Admin/templates/topicTree;admin;default
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
__section__
default
__description__
Just displays the topic tree PNG, assuming it's there.
__title__
admin interface topicTree template
__page__
admin
__lang__
en_US
__name__
topicTree
__template__
[% PROCESS titlebar title=constants.sitename _ " Topic Tree Graphic" width='100%' %]
<table width="100%" cellspacing="0" cellpadding="0" border="0"><tr><td>
<img src="[% constants.imagedir %]/topic_tree.png">
</td></tr></table>
__seclev__
100
__version__
$Id$
118 changes: 118 additions & 0 deletions plugins/Admin/topic_tree_draw.pl
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
#!/usr/bin/perl -w

# $Id$

use strict;

use Slash::Constants ':slashd';

use vars qw( %task $me );

$task{$me}{timespec} = '0-59/5 * * * *';
$task{$me}{timespec_panic_1} = ''; # if panic, we can wait
$task{$me}{on_startup} = 1;
$task{$me}{fork} = SLASHD_NOWAIT;
$task{$me}{code} = sub {
my($virtual_user, $constants, $slashdb, $user) = @_;

if (!$constants->{topic_tree_draw}) {
return "topic_tree_draw not set";
}

my $lc = $slashdb->getVar('topic_tree_lastchange', 'value', 1) || 0;
my $ld = $slashdb->getVar('topic_tree_lastdraw', 'value', 1) || 0;
if ($lc < $ld) {
return "no change";
}

my $ok;
eval {
$ok = require GraphViz;
};
if ($@ || $! || !$ok) {
my $msg = "GraphViz not available, exiting";
# Don't throw a serious error here. If the admin doesn't
# want to install GraphViz that's fine, it's not required.
# slashdErrnote($msg);
return $msg;
}

my $fontname = $constants->{topic_tree_draw_fontname} || 'freefont/FreeMono';
my $fontsize = $constants->{topic_tree_draw_fontsize} || 10;
my $g = GraphViz->new(
epsilon => 0.001, # try real hard to reduce clutter
rankdir => 1, # horizontal layout
node => { fontname => $fontname, fontsize => $fontsize },
edge => { fontname => $fontname, fontsize => $fontsize,
dir => "back" },
);
return "could not initialize GraphViz object, aborting" unless $g;

# Set up random colors for arrows.
srand(1);
my @hsv = ( );
for my $h (0..16) {
for my $s (7..8) {
for my $v (4..8) {
push @hsv, sprintf("%0.4f,%0.4f,%0.4f", $h/16, $s/8, $v/8)
}
}
}
@hsv = sort { int(rand(3))-1 } @hsv;

my $new_lastdraw = time;
my $tree = $slashdb->getTopicTree('', { no_cache => 1 });
my $mpt = $constants->{mainpage_nexus_tid} || 1;

# Tell GraphViz what it needs to know.
for my $tid (keys %$tree) {
my $topic = $tree->{$tid};
my $color;
if ($tid == $mpt) {
$color = "cyan";
} else {
$color = $topic->{nexus} ? "yellow" : "white";
}
my $shape = $topic->{nexus} ? "box" : "ellipse";
$g->add_node($tid,
label => "$topic->{textname}\n$tid",
fillcolor => $color,
style => "filled",
shape => $shape,
);
for my $ctid ( @{$topic->{children}} ) {
$g->add_edge($tid, $ctid,
style => $topic->{child}{$ctid} >= 3 ? "dashed" : "solid",
color => $hsv[ ($tid+$ctid) % @hsv ],
);
}
}

# Get the PNG from GraphViz.
my $png_data = $g->as_png;

# Write it to disk.
my $filename = "$constants->{basedir}/images/topic_tree.png";
if (open(my $fh, ">$filename")) {
print $fh $png_data;
close $fh;
} else {
my $msg = "could not write to '$filename', $!";
# slashdErrnote($msg);
return $msg;
}

# Update the lastdraw var. If it hasn't been created, create it.
# (It really should have been created, but if it wasn't, and we
# didn't, then we'd redraw the PNG every time this task was
# called, which would be quite a waste.)
if ($ld == 0) {
$slashdb->createVar("topic_tree_lastdraw", $new_lastdraw, 'Unix timestamp of last time topic_tree_draw.pl redrew images/topic_tree.png');
} else {
$slashdb->setVar("topic_tree_lastdraw", $new_lastdraw);
}

return "drew new tree";
};

1;
5 changes: 5 additions & 0 deletions sbin/slashd
Original file line number Diff line number Diff line change
Expand Up @@ -953,4 +953,9 @@ sub PRINTF {
main::slashdLog(sprintf($format, @args));
}

sub FILENO {
my($fh) = @_;
return fileno($fh);
}

1;
29 changes: 29 additions & 0 deletions sql/mysql/upgrades
Original file line number Diff line number Diff line change
Expand Up @@ -2337,3 +2337,32 @@ INSERT INTO vars (name, value, description) VALUES ('ignore_uid_date_index', '1'
# SLASHCLUSTER LAST UPDATED HERE

# End of T_2_3_0_156, Start of T_2_3_0_157 - 2004/06/01

######################################################################

# End of T_2_3_0_157, Start of T_2_5_0_1 - 2004/07/01

# You want to run utils/convertDBto200406 here, then follow its
# instructions, read its output. Shut your site down and execute
# the commands it gives. Then if all looks well, do a 'make install'
# and run utils/convertDBto200406_suggest and execute whatever of
# _its_ commands you see fit to. Finally, run
# utils/convertDBto200406_render. Of course, you need more detailed
# instructions than this because without them you don't know what
# the heck you're reading or what you "see fit to," but we're working
# on those instructions, they aren't written yet. This is the fun
# part about cutting-edge code, isn't it!

# You probably want to install the CPAN module GraphViz here, along
# with whatever it needs; see plugins/Admin/README for details.
# If you don't, set topic_tree_draw to 0 instead of 1.

# Changes for plugins/Admin (which you are almost certainly using)
INSERT INTO vars (name, value, description) VALUES ('topic_tree_draw', '1', 'Draw the images/topic_tree.png?');
INSERT INTO vars (name, value, description) VALUES ('topic_tree_draw_fontname', 'freefont/FreeMono', 'Name of font used for labels in the topic tree');
INSERT INTO vars (name, value, description) VALUES ('topic_tree_draw_fontsize', '10', 'Size of font used for labels in the topic tree');
INSERT INTO vars (name, value, description) VALUES ('topic_tree_lastchange', '1', 'Unix timestamp of last change to the topic tree');
INSERT INTO vars (name, value, description) VALUES ('topic_tree_lastdraw', '1', 'Unix timestamp of last time topic_tree_draw.pl redrew images/topic_tree.png');
INSERT INTO menus (menu, label, sel_label, value, seclev, menuorder) VALUES ('info','Tree','Tree','[% gSkin.rootdir %]/
admin.pl?op=topictree',100,9);

1 change: 1 addition & 0 deletions themes/slashcode/templates/info;menu;default
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ __template__
{ link = "$gSkin.rootdir/admin.pl", label = "Stories", sel_label = "stories" },
{ link = "$gSkin.rootdir/stats.pl", label = "Stats", sel_label = "stats" },
{ link = "$gSkin.rootdir/admin.pl?op=siteinfo", label = "Site", sel_label = "site" },
{ link = "$gSkin.rootdir/admin.pl?op=topictree", label = "Tree", sel_label = "tree" },
{ link = "$gSkin.rootdir/admin.pl?op=recent_subs", label = "Subs", sel_label = "subs" },
{ link = "$gSkin.rootdir/admin.pl?op=slashd", label = "Slashd", sel_label = "slashd" },
{ link = "$gSkin.rootdir/admin.pl?op=recent_webheads", label = "Webheads", sel_label = "webheads" },
Expand Down

0 comments on commit 17e56f4

Please sign in to comment.