Printing a gantt chart

849 views
Skip to first unread message

Rene Vergara

unread,
Feb 29, 2012, 12:14:44 AM2/29/12
to taskjugg...@googlegroups.com
Hi,

After trying printing from my browser and trying using screenshots, I
have decided to make a little script that will allow me to create a
LaTeX Gantt chart for creating a PDF. I have experience coding such
charts, I just need a little guidance extracting the info from TJ3.

I am thinking that the easiest way would be a CSV report that would
give me columns like this:

ID | Name | Duration | Start | Predecessors | isLeaf() | isMilestone()

Is a report like this possible?

-Rene

Chris Schlaeger

unread,
Feb 29, 2012, 2:33:56 PM2/29/12
to taskjugg...@googlegroups.com

Not directly. You can only use the columns listed here:
http://www.taskjuggler.org/tj3/manual/columnid.html

But you can determine isLeaf from the ID (no other task ID starts with
the ID of a leaf task) and isMilestone from having identical start and
end dates or duration 0.

Chris

Lieven Theys

unread,
Feb 29, 2012, 4:29:20 PM2/29/12
to taskjugg...@googlegroups.com
Op Wed, Feb 29, 2012 at 08:33:56PM +0100, schreef Chris Schlaeger:
Rene,

that is precisely what I do too. Let me begin by saying that this php
script has very limited use but if you want you or anyone else can use
it. No guarantees, no waranty, no nothing.

as a report I put:
taskreport "tasks"{
balance cost income
timeformat "%s"
formats csv
columns name,id,resources,start,end,complete,scenario,cost
scenarios plan,actual
}

then I run
tj3csv2gantt tasks.csv>gantt_tasks.lat
with the php script attached

then in my latex I put
\psscaleboxto(\textwidth,0){
\input{gantt_tasks.lat}
}
this uses pstricks

you can filter with flags in tasks and in the report.

parts are missing like dependency arrows which I keep planning to do.
it may produce errors and garbage but perhaps it proves useful to you.

sorry for being off topic for the list

Lieven

tj3csv2gantt

John Hendy

unread,
Feb 29, 2012, 4:54:16 PM2/29/12
to taskjugg...@googlegroups.com
This is pretty neat. Not sure how exactly you're doing this, but you
might consider ptggantt as another option:
-- Doc: http://ctan.mackichan.com/graphics/pgf/contrib/pgfgantt/pgfgantt.pdf

There's another site that seems to be down at the moment that used to
have some great examples:
-- Site: http://www.martin-kumm.de/tex_gantt_package.php
-- Cached copy:
http://webcache.googleusercontent.com/search?q=cache:http://www.martin-kumm.de/tex_gantt_package.php

Anyway, just thought I'd toss that out there. I do wish tj3 had a
better export function to something like a PDF. It's something I miss
from the UI in v2.

Thanks for contributing like this,
John

> --
> You received this message because you are subscribed to the "TaskJuggler Users" group.
> To post to this group, send email to taskjugg...@googlegroups.com
> To unsubscribe from this group, send email to
> taskjuggler-us...@googlegroups.com
> For more information about TaskJuggler visit http://www.taskjuggler.org

Rene Vergara

unread,
Feb 29, 2012, 5:36:17 PM2/29/12
to taskjugg...@googlegroups.com
Thanks for the info. I am planning to use tikz pgfgantt to generate
the printout, this would include the arrows for dependencies. I will
post the script once I have something working.

-Rene

> --
> You received this message because you are subscribed to the "TaskJuggler Users" group.
> To post to this group, send email to taskjugg...@googlegroups.com
> To unsubscribe from this group, send email to
> taskjuggler-us...@googlegroups.com
> For more information about TaskJuggler visit http://www.taskjuggler.org

> #!/usr/bin/php
>
> <?php
>
> function drawtasktext($scenario,&$atask,$listofkeys,$startofchart,$yoffset,$isfinal){
> //echo "in drawtasktext".$yoffset."\n";
> $subtasks=array_diff_key($atask,$listofkeys);
> $dagstart=$atask["Start"];
> $dagend=$atask["End"];
> $xpos=($atask["Start"]-$startofchart)/(60*60*24);
> $xpose=(($atask["End"]-$startofchart)/(60*60*24));
> if($isfinal){
> $kleur="cyan";
> }else{
> $kleur="red";
> };
> if($dagstart==$dagend){
> //echo "is milestone\n";
> //is milestone
> //$xpos=(strtotime("+ 12 hours",$atask["Start"])-$startofchart)/(60*60*24);
> $dateeve=mktime(17,0,0,date("n",$atask["Start"]),date("j",$atask["Start"]),date("Y",$atask["Start"]));
> $xpos=($dateeve-$startofchart)/(60*60*24);
> echo '\pscircle[linewidth=5pt,linecolor='.$kleur.']('.($xpos).",".$yoffset."){0.2}\n";
> if($isfinal){echo '\rput[tl]('.($xpos+0.8).",".($yoffset+0.1)."){Milestone: ".$atask["Name"]."}\n";}
> }else{
> //is tasks
> if(count($subtasks)!=0){
> //task container
> $dateeve=mktime(17,0,0,date("n",$atask["End"]),date("j",$atask["End"]),date("Y",$atask["End"]));
> $xpose=($dateeve-$startofchart)/(60*60*24);
> echo '\psline[linewidth=3pt,linecolor='.$kleur.']('.$xpos.",".($yoffset-0.3).")(".$xpose.",".($yoffset-0.3).")\n";
> if($isfinal){echo '\rput[tl]('.$xpos.",".($yoffset+0.1)."){".$atask["Name"]."}\n";}
> }else{
> //task
> echo '\psframe[linewidth=1pt,fillstyle=solid,fillcolor='.$kleur.']('.$xpos.",".($yoffset-0.3).")(".$xpose.",".($yoffset+0.3).")\n";
> if($isfinal){echo '\rput[tl]('.$xpos.",".($yoffset+0.1)."){Task: ".$atask["Name"]."}\n";}
> }
> }
> $yoffset--;
> //en dan de volgende taken
> foreach($subtasks as $key=>$subtask){
> $yoffset=drawtasktext($scenario,$subtask,$listofkeys,$startofchart,$yoffset,$isfinal);
> }
> return $yoffset;
> }
>
> setlocale(LC_NUMERIC,'en_GB');
> //$locale_info = localeconv();
> //print_r($locale_info);
> //echo locale_get_default();
> //locale_set_default("en-UK");
> $arg = $_SERVER['argv'];
> //print_r($arg);
> if(count($arg)>1){
> $handle = fopen($arg[1], "r");
> $firstrun = true;
> $thisdata=array();
> $listofkeys=array();
> $nooftasks=-1;
> while (($data = fgetcsv($handle, 10000, ";")) !== FALSE) {
> //echo "---------------------\n";
> foreach($data as $key => $val){
> if($firstrun){
> $thisdata[$val]=array();
> $listofkeys[]=$val;
> }else{
> //echo $val."\n";
> //if((!strcmp($listofkeys[$key],"Start") or !strcmp($listofkeys[$key],"End"))){
> // $datearr=preg_split("/-/",$val);
> // //print_r($datearr);
> // $val=mktime(0,0,0,$datearr[1],$datearr[0],$datearr[2]);
> //echo $val." -- ".date('Y-m-d',$val) ."\n";
> //}
> $thisdata[$listofkeys[$key]][]=$val;
> };
> };
> $nooftasks++;
> $firstrun = false;
> }
> //print_r($thisdata);
>
> $projectstart=min($thisdata["Start"]);
> //echo "projectstart:\t".date('Y-m-d:H:i:s',$projectstart) ."\n";
> $chartstart=strtotime("last Monday",$projectstart);
> //echo "chartstart:\t".date('Y-m-d:H:i:s',$chartstart) ."\n";
> $projectend=max($thisdata["End"]);
> //echo "projectend:\t".date('Y-m-d:H:i:s',$projectend) ."\n";
> $chartend=strtotime("next Sunday",$projectend);
> //echo "chartend:\t".date('Y-m-d:H:i:s',$chartend) ."\n";
> $chartinterval=($chartend-$chartstart)/(60*60*24);
> //echo "chartinterval:\t".$chartinterval."\n";
>
> //print_r($listofkeys);
> $IdKey=array_search("Id",$listofkeys);
> unset($listofkeys[$IdKey]);
> $listofkeysdiff=array_fill_keys($listofkeys,0);
> //print_r($listofkeysdiff);
>
> //print_r($listofkeys);
> //print_r($thisdata);
> //print_r($nooftasks);
> $scenarios=array();
> if(array_key_exists("Scenario",$thisdata)){
> $scenarios = array_unique($thisdata["Scenario"]);
> }
> //print_r($scenarios);
>
> $structdata=array();
> $previousId="";
> for($teller=0;$teller<$nooftasks;$teller++){
> if(array_key_exists("Scenario",$thisdata)){
> //echo "scenario included\n";
> if(!strcmp($thisdata["Id"][$teller],"")){
> $fullId=$thisdata["Scenario"][$teller].":".$previousId;
> }else{
> $fullId=$thisdata["Scenario"][$teller].":".$thisdata["Id"][$teller];
> $previousId=$thisdata["Id"][$teller];
> };
> //echo $fullId."\n";
> }
> //$here='$structdata["'.preg_replace('/[:\.]/','"]["',$thisdata[Id][$teller])."\"]";
> $here='$structdata["'.preg_replace('/[:\.]/','"]["',$fullId)."\"]";
> //echo $here."\n";
> //if(array_key_exists($val,$structdata)){
> // echo "exists:".$val."\n";
> //}else{
> //echo "new el:".$val."\n";
> $todo=$here.'=array();';
> eval($todo);
> foreach($listofkeys as $thekey){
> $todo=$here."[\"".$thekey."\"]=\$thisdata[\"".$thekey."\"][".$teller."];";
> //echo $todo."\n";
> eval($todo);
> }
> //$todo=$here."[\"volgnummer\"]=".$teller.";";
> //echo $todo."\n";
> //eval($todo);
> //}
> }
> //print_r($structdata);
>
> $uittext="";
> //$uittext=$uittext."\psset{unit=1mm}\n";
> $height=$nooftasks/count($scenarios);
> $uittext=$uittext."\begin{pspicture}(".$chartinterval.",".$height.")\n";
> echo "\begin{pspicture}(".$chartinterval.",".$height.")\n";
> //$uittext=$uittext."\psgrid\n";
> //draw grid
> $today=date('j F Y',time());
> //echo $today."\n";
> for($dag=0;$dag<$chartinterval;$dag++){
> $bottom=-1;
> $daginterval="+".$dag." day";
> //echo $daginterval."\n";
> $dedag=strtotime($daginterval,$chartstart);
> //$dedag=$chartstart+$dag*60*60*24;
> $dedagtext=date('j',$dedag);
> //echo $dedagtext."\n";
> $dagnaam=date('l',$dedag);
> $voldagnaam=date('j F Y',$dedag);
> $maandnaam=date('F Y',$dedag);
> $maanddag=date('j',$dedag);
> $weeknummer=date('W',$dedag);
> $dagwshift=$dag+.5;
> if($maanddag==1 or $dag==0){
> $top=$height+1;
> $uittext=$uittext.'\rput[tl]('.$dagwshift.",".$top."){".$maandnaam."}\n";
> echo '\rput[tl]('.$dagwshift.",".$top."){".$maandnaam."}\n";
> $uittext=$uittext."\psline[linewidth=1pt]($dag,$height)($dag,$top)\n";
> echo "\psline[linewidth=1pt]($dag,$height)($dag,$top)\n";
> }
> if(!strcmp('Monday',$dagnaam)){
> $top=$height+0.5;
> $uittext=$uittext."\psline[linewidth=1pt]($dag,$height)($dag,$top)\n";
> echo "\psline[linewidth=1pt]($dag,$height)($dag,$top)\n";
> echo '\rput[tl]('.$dagwshift.",".$top."){".$weeknummer."}\n";
> }
> if(!strcmp('Saturday',$dagnaam) or !strcmp('Sunday',$dagnaam)){
> $volgendedag=$dag+1;
> $uittext=$uittext.'\psframe[linewidth=0pt,fillstyle=solid,fillcolor=lime,linecolor=lime]('.$dag.",".$bottom.")(".$volgendedag.",".$height.")\n";
> echo '\psframe[linewidth=0pt,fillstyle=solid,fillcolor=lime,linecolor=lime]('.$dag.",".$bottom.")(".$volgendedag.",".$height.")\n";
> }
> if(!strcmp($today,$voldagnaam)){
> $volgendedag=$dag+1;
> $uittext=$uittext.'\psframe[linewidth=0pt,fillstyle=solid,fillcolor=green,linecolor=green]('.$dag.",".$bottom.")(".$volgendedag.",".$height.")\n";
> echo '\psframe[linewidth=0pt,fillstyle=solid,fillcolor=green,linecolor=green]('.$dag.",".$bottom.")(".$volgendedag.",".$height.")\n";
> }
>
> $uittext=$uittext.'\rput[tl]('.$dagwshift.",".$height."){".$dedagtext."}\n";
> echo '\rput[tl]('.$dagwshift.",".$height."){".$dedagtext."}\n";
> $uittext=$uittext."\psline[linewidth=1pt]($dag,".$bottom.")($dag,$height)\n";
> echo "\psline[linewidth=1pt]($dag,".$bottom.")($dag,$height)\n";
> }
>
> foreach(array_reverse($scenarios,true) as $sckey => $scval){
> $yoffset=$height-1-$sckey*0.2;
> //echo $yoffset."\n";
> $scenario=$structdata[$scval];
> $isfinal=($sckey==0);
> //echo $isfinal."\n";
> foreach($scenario as $key => $task){
> //echo $key."\n";
> $yoffset=drawtasktext($scval,$task,$listofkeysdiff,$chartstart,$yoffset,$isfinal);
> //$yoffset--;
> }
> }
>
> $uittext=$uittext."\end{pspicture}\n";
> echo "\end{pspicture}\n";
> fclose($handle);
> }
> ?>

Rene Vergara

unread,
Mar 4, 2012, 11:38:59 AM3/4/12
to taskjugg...@googlegroups.com
Hello,

I have completed the initial version of the converter, you can find it
at http://github.com/ravl1084/TJ2PDF

If you want to download the source code, it's available. If you just
want a runnable version, you can find a tarball in the Downloads
section.

Hope its helpful!

-Rene

John Hendy

unread,
Mar 5, 2012, 2:10:49 PM3/5/12
to taskjugg...@googlegroups.com
On Sun, Mar 4, 2012 at 10:38 AM, Rene Vergara <rene.a....@gmail.com> wrote:
Hello,

I have completed the initial version of the converter, you can find it
at http://github.com/ravl1084/TJ2PDF

If you want to download the source code, it's available. If you just
want a runnable version, you can find a tarball in the Downloads
section.

Hope its helpful!


Just tried it. Some thoughts:
-- Might have been obvious, but this requires the CTAN package pgfgantt
-- Also requires the package adjustbox

The current workflow is not ideal with copying things around, though I'm sure you knew that. It definitely gets tricky figuring out how to stat the current working directory, where the csv and whatnot are, etc. I wonder if the java script could parse the csv *and* create the tex file in one. If you're outputting Chart.txt and already have the template, gantt.tex...why not just print the .tex stuff before/after the Chart.txt output as a .tex file and be done?

My attempt produced a gantt chart spilling off of the page both to the right and onto a second page below, even with making it landscape. There might be some scaling/size checking required to do this nicely.

Thanks, though. The output looks purely awesome and I think this is a great start (don't want the above to sound harsh at all). I think this is really neat and appreciate your efforts!!


John
 
-Rene

Rene Vergara

unread,
Mar 9, 2012, 4:49:37 PM3/9/12
to taskjugg...@googlegroups.com
Hi,

The reason for creating a separate file is that the goal of the script
was to generate the LaTeX snippet for the chart, to be included in
another document (which is what I needed, heh). I did not intend for
the test case LaTeX file that is sent as part of the script to be "The
Gannt Chart", just a minimal working example that would let someone
unfamiliar with LaTeX use the snippet.

The 'adjustbox' package is included in the test case as a way of
partitioning a chart that has many tasks, more than would fit on the
page. Without it, the chart will spill out just the same, but won't
show the sections that are out of bounds.

Another option is to use the 'standalone' document class, which will
produce a PDF file of the chart with no associated paper size or
orientation that can later be included in a document as an image. This
has the drawback that the full chart will be scaled to fit where it's
inserted, potentially making it illegible.

There are limitations to the script, as this is a first approach:
- The script assumes that every month has 30 days. So you could have a
milestone in February 30th.
- The chart's resolution (chronological, not graphical) is in days. If
you are tracking your project in hours, the script will not produce
an adequate chart. LaTeX's pgfgannt does not allow for fractions as
the duration. I chose days because it produces the most accurate
approximation, using weeks really distorts the chart because you
have to use full weeks.

I recommend using it for summary charts rather than displaying the
whole project. Remember that the TJ3 report can be filtered using
flags, tasks can be rolled up, etc.

I will be making changes to this along the way, one of the things in
my list is to include the Today line. This is not hard to implement, I
just haven't figured out how to include that information in the TJ3
report.

-Rene

John Hendy

unread,
Mar 13, 2012, 8:12:40 AM3/13/12
to taskjugg...@googlegroups.com
On Fri, Mar 9, 2012 at 3:49 PM, Rene Vergara <rene.a....@gmail.com> wrote:
> Hi,
>
> The reason for creating a separate file is that the goal of the script
> was to generate the LaTeX snippet for the chart, to be included in
> another document (which is what I needed, heh). I did not intend for
> the test case LaTeX file that is sent as part of the script to be "The
> Gannt Chart", just a minimal working example that would let someone
> unfamiliar with LaTeX use the snippet.
>

Gotcha. I was primarily interested in the ganntt chart by itself, as I
usually generate a pdf and then include it vs. including a LaTeX
snippet in my document, at least if it's long.

> The 'adjustbox' package is included in the test case as a way of
> partitioning a chart that has many tasks, more than would fit on the
> page. Without it, the chart will spill out just the same, but won't
> show the sections that are out of bounds.
>
> Another option is to use the 'standalone' document class, which will
> produce a PDF file of the chart with no associated paper size or
> orientation that can later be included in a document as an image. This
> has the drawback that the full chart will be scaled to fit where it's
> inserted, potentially making it illegible.
>

I'll look into this. That might be what I want. My chart definitely
isn't *that* big. I'll see how that works.

> There are limitations to the script, as this is a first approach:
> - The script assumes that every month has 30 days. So you could have a
> milestone in February 30th.
> - The chart's resolution (chronological, not graphical) is in days. If
>  you are tracking your project in hours, the script will not produce
>  an adequate chart. LaTeX's pgfgannt does not allow for fractions as
>  the duration. I chose days because it produces the most accurate
>  approximation, using weeks really distorts the chart because you
>  have to use full weeks.
>

I'm cool with this.

> I recommend using it for summary charts rather than displaying the
> whole project. Remember that the TJ3 report can be filtered using
> flags, tasks can be rolled up, etc.
>

I haven't looked into filtering, but this all makes perfect sense --
high level summary vs. trying to show every single thing using the
pgfgantt script.

> I will be making changes to this along the way, one of the things in
> my list is to include the Today line. This is not hard to implement, I
> just haven't figured out how to include that information in the TJ3
> report.
>

Thanks again for what you've already done. It's a great addition and
getting the chart out of html is a helpful tool indeed!


John

Hendy

unread,
Sep 16, 2012, 1:32:36 PM9/16/12
to taskjugg...@googlegroups.com, rene.a....@gmail.com
Re-looking into this again, as I need a gantt chart :)

How does one set the end of the actual chart. If I keep making my paper size bigger, it looks like the chart just keeps going and will stretch with the paper. How does one get an end to the chart on the right hand side? I'm thinking this is set in the .tjp file somewhere, but I don't know what option.

My project is defined like so:
-----
project projectName "Project Name" 2011-11-30 +4m {
-----

But the whole frame is still off of the edge of the page.

Thanks for any tips. Having revisited this... it's quite neat!

John

Chris Schlaeger

unread,
Sep 20, 2012, 2:40:15 PM9/20/12
to taskjugg...@googlegroups.com
On Sun, Sep 16, 2012 at 7:32 PM, Hendy <jw.h...@gmail.com> wrote:
> Re-looking into this again, as I need a gantt chart :)
>
> How does one set the end of the actual chart. If I keep making my paper size
> bigger, it looks like the chart just keeps going and will stretch with the
> paper. How does one get an end to the chart on the right hand side? I'm
> thinking this is set in the .tjp file somewhere, but I don't know what
> option.
>
> My project is defined like so:
> -----
> project projectName "Project Name" 2011-11-30 +4m {
> -----
>
> But the whole frame is still off of the edge of the page.
>
> Thanks for any tips. Having revisited this... it's quite neat!

Not sure what exactly you are looking for. Have you tried to limit the
report period with 'end' or 'period'?

Chris

John Hendy

unread,
Sep 21, 2012, 8:54:29 AM9/21/12
to taskjugg...@googlegroups.com
This is different. The html would work for that, but this was related
to Rene's converter to PDF via the pgfgantt package. I meant that his
chart seemed to keep going and going no matter how big I set the paper
size in the LaTeX document. I've figure that out now.

I do appreciate the attempt to help, though! You're a great package
maintainer/developer/mailing list answerer!


John

> Chris
Reply all
Reply to author
Forward
0 new messages