你好,很抱歉这个问题不完整,只有通灵者才能回答:-)
我的问题是,我想要一个漂亮的甘特图或时间表,但不包括周末。我的问题是,如果我将项目部分的日期设置为例如 3 天,并将下一个部分也设置为 3 天,那么第二个部分会更长,因为它包括周末。最容易看到的是 AP1100 和 AP1200,它们的长度应该相等。我真的很感激帮助,谢谢。
\documentclass[a4paper]{article}
\usepackage{fullpage}
\usepackage{lscape}
\usepackage{pgfgantt}
\begin{document}
\begin{landscape}
\noindent\resizebox*{\linewidth}{!}{ % Rescale the chart to linewidth
\begin{ganttchart}[hgrid,time slot format = isodate]{2014-05-12}{2014-09-14}
\gantttitlecalendar{year, month=shortname, week}\\
\ganttgroup[progress=00] {AP 1000: test eee}{2014-05-12}{2014-05-23}\\ %
\ganttbar[progress=00] {AP 1100: test eee}{2014-05-12}{2014-05-14}\\
\ganttlinkedbar[progress=00] {AP 1200: test eee}{2014-05-15}{2014-05-19}\\
\ganttlinkedbar[progress=00] {AP 1300: test eee}{2014-05-20}{2014-05-23}\\
\ganttgroup{AP 2000: test eee}{2014-05-26}{2014-06-11}\\
\ganttbar {AP 2100: test eee}{2014-05-26}{2014-05-28}\\
\ganttbar {AP 2200: test eee}{2014-05-29}{2014-05-30}\\
\ganttbar {AP 2300: test eee}{2014-06-02}{2014-06-06}\\
\ganttbar {AP 2400: test eee}{2014-06-09}{2014-06-11}\\
\ganttgroup{AP 3000: test eee}{2014-06-12}{2014-08-13}\\
\ganttbar {AP 3100: test eee}{2014-06-12}{2014-07-17}\\
\ganttbar {AP 3200: test eee}{2014-07-18}{2014-07-21}\\
\ganttbar {AP 3300: test eee}{2014-07-22}{2014-08-05}\\
\ganttbar {AP 3300: test eee}{2014-08-06}{2014-08-13}\\
\ganttgroup{AP 4000: test eee}{2014-08-14}{2014-08-29}\\
\ganttbar {AP 4100: test eee}{2014-08-14}{2014-08-20}\\
\ganttbar {AP 4200: test eee}{2014-08-21}{2014-08-27}\\
\ganttbar {AP 4300: test eee}{2014-08-28}{2014-08-29}\\
\ganttgroup{AP 5000: test eee}{2014-09-01}{2014-09-12}\\
\ganttbar {AP 5100: test eee}{2014-09-01}{2014-09-05}\\
\ganttbar {AP 5200: test eee}{2014-09-08}{2014-09-10}\\
\ganttbar {AP 5300: test eee}{2014-09-11}{2014-09-12}\\
\ganttmilestone{Status}{2014-05-12}\\
\end{ganttchart}
}
\end{landscape}
\end{document}
答案1
更新:Marijn 在这里指出了如何更新它以与 gant 5.0 兼容。
pgfgantt
主要技巧是重新定义索引到图表中的方式。该包采用通过以下方式指定的格式获取日期time slot format = someformat
,并将其转换为“儒略日数”,即“自公元前 4713 年 1 月 1 日星期一中午世界标准时间 (UT) 的初始纪元以来,在预测儒略历中经过的 (整数) 天数。”
然后pgfgantt
取给定日期的儒略日数并将其转换为“时间段”,如果compress calendar
没有该选项,则仅为(日期 - 开始日期 + 1),其中开始日期是日历的第一天:
\newcommand\gtt@juliantotimeslot[2]{%
\begingroup%
\@tempcnta=#1\relax%
\ifgtt@compresscalendar % test for `compress calendar` option
% do something here we don't care about
\else % set \@tempcnta = current date - start date + 1
\advance\@tempcnta by-\gtt@startjulian\relax%
\advance\@tempcnta by1\relax%
\fi%
#2=\@tempcnta\relax % output the result into #2
\gtt@smugglecount#2%
\endgroup%
}
因此,我们需要更改此索引命令,将儒略历数字转换为图表开始日期和当前日期之间的工作日数。
我们需要做的另一个更改是修复\gantttitlecalendar
命令。此命令遍历开始日期和结束日期之间的日期,并创建一个宽度为 (结束日期) - (开始日期) + 1 的标题。我们需要修复此问题,以便标题仅计算工作日。此命令的主要工作在以下命令中完成:
\newcommand\@@@gantttitlecalendar[3]{%
\pgfcalendarjuliantodate{#1}{\@tempa}{\@tempb}{\@tempc}%
\edef\gtt@calendar@startdate{\@tempa-\@tempb-\@tempc}%
\pgfcalendarjuliantodate{#2}{\@tempa}{\@tempb}{\@tempc}%
\edef\gtt@calendar@enddate{\@tempa-\@tempb-\@tempc}%
\gtt@calendar@eolfalse%
\pgfqkeys{/pgfgantt/calendar}{#3}%
\endgroup%
}
参数year
、month
、week
、day
和weekday
to\ganttitlecalendar
被定义为 中的键/pgfgantt/calendar
。我们将定义这些参数的新变体,其中/pgfgantt/calendar week days only
不计算工作日。这是一个很小的变化,例如days
代码如下所示:
day/.code={%
\ifgtt@calendar@eol\ganttnewline\fi%
\begingroup%
\pgfcalendar{}{\gtt@calendar@startdate}{\gtt@calendar@enddate}{%
%%% This is the command that draws the day:
\gantttitle{\pgfcalendarcurrentday}{1}
}%
\endgroup%
\gtt@calendar@eoltrue%
}
并且我们只需要在星期几为工作日时绘制日期。因此我们添加代码
\ifnum\pgfcalendarcurrentweekday<5\relax % 0 -- 4 are Monday -- Friday
\gantttitle{\pgfcalendarcurrentday}{1}
\fi
其它键的改变也十分类似。
最后一个问题是,当您给出周末的代码日期时会发生什么。我将其设置为将开始日期四舍五入为星期一,将结束日期四舍五入为星期五。为了做到这一点,我必须制作 : 和 的两个变体,\gtt@juliantotimeslot
并将\gtt@juliantotimeslot@roundup
它们修补到使用 的\gtt@juliantotimeslot@rounddown
包中的其余命令中。\gtt@juliantotimeslot
完整代码如下:
\documentclass[a4paper]{article}
\usepackage{fullpage}
\usepackage{lscape}
\usepackage{etoolbox}
\usepackage{pgfgantt}
\parindent=0pt
\parskip=60pt
\makeatletter
% some extra count registers
\newcount\gtt@tempweekdaya
\newcount\gtt@tempweekdayb
\newcount\gtt@tempcounta
\newcount\gtt@tempcountb
% Define the "weekdays only" key
\ganttset{weekdays only/.code={% install the modified commands
\let\gtt@juliantotimeslot@roundup\gtt@juliantotimeslot@roundup@weekdaysonly
\let\gtt@juliantotimeslot@rounddown\gtt@juliantotimeslot@rounddown@weekdaysonly
\let\@@@gantttitlecalendar\@@@gantttitlecalendar@weekdaysonly
}}
\def\gtt@patchcmd#1{\expandafter\patchcmd\csname\string#1\endcsname}
% Add check whether start date is on the weekend, if so round it up to Monday:
\gtt@patchcmd\ganttchart{\gtt@tsstojulian{#2}{\gtt@startjulian}}{%
\gtt@tsstojulian{#2}{\gtt@startjulian}%
\ifx\@@@gantttitlecalendar\@@@gantttitlecalendar@weekdaysonly % If weekdays only key is present
\pgfcalendarjuliantoweekday{\gtt@startjulian}{\gtt@tempweekdaya}
\ifnum\gtt@tempweekdaya>4\relax % and start date is a weekend
\advance\gtt@startjulian7\relax
\advance\gtt@startjulian-\gtt@tempweekdaya\relax % round to the nearest Monday
\@gtt@PackageWarning{Given start date was on the weekend, rounding to the next Monday}
\fi
\fi
}{}{\error}
% Fix \gtt@juliantotimeslot calls to either refer to \gtt@juliantotimeslot@rounddown or \gtt@juliantotimeslot@roundup
\gtt@patchcmd\ganttchart{\gtt@juliantotimeslot{\gtt@endjulian}}{\gtt@juliantotimeslot@rounddown{\gtt@endjulian}}{}{\error}
\gtt@patchcmd\ganttchart{\gtt@juliantotimeslot{\gtt@today@slot}}{\gtt@juliantotimeslot@rounddown{\gtt@today@slot}}{}{\error}
\gtt@patchcmd\gtt@chartelement{\gtt@juliantotimeslot{\gtt@left@slot}}{\gtt@juliantotimeslot@roundup{\gtt@left@slot}}{}{\error}
\gtt@patchcmd\gtt@chartelement{\gtt@juliantotimeslot{\gtt@right@slot}}{\gtt@juliantotimeslot@rounddown{\gtt@right@slot}}{}{\error}
% Both rounddown and roundup by default are just synonyms for \gtt@juliantotimeslot
\let\gtt@juliantotimeslot@rounddown\gtt@juliantotimeslot
\let\gtt@juliantotimeslot@roundup\gtt@juliantotimeslot
% \gtt@juliantotimeslot computes the number of days between the start date and the Julian day #1 and stores the result in #2.
% Our modified versions compute the number of weekdays between the start date and the Julian day #1 and stores the result in #2.
% \gtt@juliantotimeslot@roundup rounds weekend days to the next Monday
% \gtt@juliantotimeslot@rounddown rounds weekend days to the previous Monday
\newcommand\gtt@juliantotimeslot@roundup@weekdaysonly[2]{
\begingroup
\@tempcnta=#1\relax%
\pgfcalendarjuliantoweekday{\@tempcnta}{\gtt@tempweekdaya}
\ifnum\gtt@tempweekdaya>4\relax % if start date is a weekend
\advance\@tempcnta7\relax
\advance\@tempcnta-\gtt@tempweekdaya\relax % round to the nearest Monday
\@gtt@PackageWarning{Given start date was on the weekend, rounding to the next Monday}
\fi
\gtt@tempcounta=\@tempcnta\relax
\gtt@juliantotimeslot@rounddown@weekdaysonly{\gtt@tempcounta}{\gtt@tempcountb}
#2=\gtt@tempcountb\relax
\gtt@smugglecount#2%
\endgroup%
}
\newcommand\gtt@juliantotimeslot@rounddown@weekdaysonly[2]{%
\begingroup%
\@tempcnta=#1\relax%
\ifgtt@compresscalendar%
\pgfcalendarjuliantodate{\@tempcnta}{\@tempa}{\@tempb}{\@tempc}%
\@tempcnta=\@tempa\relax%
\advance\@tempcnta by-\gtt@startyear\relax%
\multiply\@tempcnta by12\relax%
\advance\@tempcnta by\@tempb\relax%
\advance\@tempcnta by-\gtt@startmonth\relax%
\advance\@tempcnta by1\relax%
\else%
\pgfcalendarjuliantoweekday{\gtt@startjulian}{\gtt@tempweekdaya} % Put the day of the week of the start and end days into counters
\pgfcalendarjuliantoweekday{\@tempcnta}{\gtt@tempweekdayb}
\ifnum\gtt@tempweekdayb>4\relax
\@gtt@PackageWarning{Weekend date rounded down to the preceding Friday}
\fi
\advance\@tempcnta by-\gtt@startjulian\relax % Now \@tempcnta has the number of days in the period minus one
\divide\@tempcnta7\relax % Now it has how many whole weeks occur
\multiply\@tempcnta5\relax % Now it has the number of weekdays that occur in whole weeks minus one
\advance\@tempcnta1\relax % Now the number of weekdays that occur in whole weeks
%
% Okay now let's correct for the last partial week. First we need to calculate how many days we have left over.
\@tempcntb=#1\relax%
\advance\@tempcntb by-\gtt@startjulian\relax% Number of days
\divide\@tempcntb7\relax
\multiply\@tempcntb-7\relax % negative number of days that occur in whole weaks
\advance\@tempcntb#1\relax
\advance\@tempcntb by-\gtt@startjulian\relax% Number of left over days
\advance\@tempcnta\@tempcntb % \@tempcnta has (weekdays occurring in whole weeks) + (all left over days).
%
% We still need to subtract off the left over days that land on weekends.
\ifnum\gtt@tempweekdayb<\gtt@tempweekdaya\relax
\advance\gtt@tempweekdayb7\relax % make sure the end day is greater than or equal to start day
\fi
%
% Is Saturday in left over days?
\@tempcntb=5\relax % Saturday is day 5
\ifnum\@tempcntb<\gtt@tempweekdaya\relax
\advance\@tempcntb7\relax % make sure Saturday is greater than or equal to start day
\fi
\ifnum\@tempcntb>\gtt@tempweekdayb\relax\else % If Saturday is one of left over days
\advance\@tempcnta-1\relax % subtract it
\fi
% Is Sunday in left over days?
\@tempcntb=6 % Sunday is day 6
\ifnum\@tempcntb<\gtt@tempweekdaya\relax
\advance\@tempcntb7\relax
\fi
\ifnum\@tempcntb>\gtt@tempweekdayb\relax\else
\advance\@tempcnta-1\relax
\fi
\fi%
#2=\@tempcnta\relax%
\gtt@smugglecount#2%
\endgroup%
}
% Now it's time to fix \ganttitlecalendar
% Our modified version of \ganttitlecalendar passes control to "/pgfgantt/calendar weekdays only" instead of "/pgfgantt/calendar"
\newcommand\@@@gantttitlecalendar@weekdaysonly[3]{%
\pgfcalendarjuliantodate{#1}{\@tempa}{\@tempb}{\@tempc}%
\edef\gtt@calendar@startdate{\@tempa-\@tempb-\@tempc}%
\pgfcalendarjuliantodate{#2}{\@tempa}{\@tempb}{\@tempc}%
\edef\gtt@calendar@enddate{\@tempa-\@tempb-\@tempc}%
\gtt@calendar@eolfalse%
\pgfqkeys{/pgfgantt/calendar weekdays only}{#3}% Only difference is here
\endgroup%
}
% Here is the modified calendar printing code. It's mostly the same as the original code, with a bunch of extra tests for weekdays and
% some minor differences in the edge cases
\pgfqkeys{/pgfgantt/calendar weekdays only}{
year/.code={%
\ifgtt@calendar@eol\ganttnewline\fi%
\begingroup%
\gtt@calendar@slots=0\relax%
\ifgtt@compresscalendar%
\pgfcalendar{}{\gtt@calendar@startdate}{\gtt@calendar@enddate}{%
\ifdate{equals=12-31}{%
\advance\gtt@calendar@slots by1\relax %added this line
\gantttitle{\pgfcalendarcurrentyear}{\the\gtt@calendar@slots}%
\gtt@calendar@slots=1\relax%
}{%
\ifdate{end of month=1}{%
\advance\gtt@calendar@slots by1\relax%
}{}%
}%
\ifdate{equals=\pgfcalendarendiso}{%
\ifdate{end of month=1}{%
% Used to be a decrement here
}{}%
\ifdate{equals=12-31}{}{%
\gantttitle{\pgfcalendarcurrentyear}{\the\gtt@calendar@slots}%
}%
}{}%
}%
\else%
\pgfcalendar{}{\gtt@calendar@startdate}{\gtt@calendar@enddate}{%
\ifdate{equals=12-31}{%
\ifnum\pgfcalendarcurrentweekday<5\relax % Only increment if it's a weekday
\advance\gtt@calendar@slots by1\relax%
\fi
\gantttitle{\pgfcalendarcurrentyear}{\the\gtt@calendar@slots}%
\gtt@calendar@slots=0\relax% used to be 1
}{%
\ifnum\pgfcalendarcurrentweekday<5\relax % Only increment if it's a weekday
\advance\gtt@calendar@slots by1\relax%
\fi
}%
\ifdate{equals=\pgfcalendarendiso}{%
\ifnum\gtt@calendar@slots=1\relax\else%
% Used to be a decrement here
\gantttitle{\pgfcalendarcurrentyear}{\the\gtt@calendar@slots}%
\fi%
}{}%
}%
\fi%
\endgroup%
\gtt@calendar@eoltrue%
},%
month/.code={%
\ifgtt@calendar@eol\ganttnewline\fi%
\begingroup%
\gtt@calendar@slots=0\relax
\pgfcalendar{}{\gtt@calendar@startdate}{\gtt@calendar@enddate}{%
\ifdate{end of month=1}{%
\ifnum\pgfcalendarcurrentweekday<5\relax % Only increment if it's a weekday
\advance\gtt@calendar@slots by1\relax%
\fi
\gantttitle{%
\csname pgfcalendarmonth#1\endcsname{\pgfcalendarcurrentmonth}%
}{%
\ifgtt@compresscalendar1\else\the\gtt@calendar@slots\fi%
}%
\gtt@calendar@slots=0\relax% used to be 1
}{%
\ifnum\pgfcalendarcurrentweekday<5\relax % Only increment if it's a weekday
\advance\gtt@calendar@slots by1\relax%
\fi
}%
\ifdate{equals=\pgfcalendarendiso}{%
\ifnum\gtt@calendar@slots=0\relax\else % used to test for 1
% Used to be a decrement here
\gantttitle{%
\csname pgfcalendarmonth#1\endcsname{\pgfcalendarcurrentmonth}%
}{%
\ifgtt@compresscalendar1\else\the\gtt@calendar@slots\fi%
}%
\fi%
}{}%
}%
\endgroup%
\gtt@calendar@eoltrue%
},%
week/.code={%
\ifgtt@calendar@eol\ganttnewline\fi%
\begingroup%
\gtt@calendar@slots=0\relax%
\gtt@calendar@weeknumber=#1\relax%
\pgfcalendar{}{\gtt@calendar@startdate}{\gtt@calendar@enddate}{%
\ifdate{Sunday}{%
\gtt@calendar@startofweek=\pgfcalendarcurrentjulian\relax%
\advance\gtt@calendar@startofweek by1\relax%
\advance\gtt@calendar@startofweek by-\gtt@calendar@slots\relax%
\pgfcalendarjuliantodate{\gtt@calendar@startofweek}%
{\startyear}{\startmonth}{\startday}%
\def\currentweek{\the\gtt@calendar@weeknumber}%
\gantttitle{%
\ganttvalueof{calendar week text}%
}{%
\the\gtt@calendar@slots%
}%
\gtt@calendar@slots=0\relax% Used to be 1
\advance\gtt@calendar@weeknumber by1\relax%
}{%
\ifnum\pgfcalendarcurrentweekday<5\relax % Only increment if it's a weekday
\advance\gtt@calendar@slots by1
\fi
}%
\ifdate{equals=\pgfcalendarendiso}{%
\ifnum\gtt@calendar@slots=0\relax\else% used to test for 1
% Deleted decrement line used to be here
\gtt@calendar@startofweek=\pgfcalendarcurrentjulian\relax%
\advance\gtt@calendar@startofweek by1\relax%
\advance\gtt@calendar@startofweek by-\gtt@calendar@slots\relax%
\pgfcalendarjuliantodate{\gtt@calendar@startofweek}%
{\startyear}{\startmonth}{\startday}%
\def\currentweek{\the\gtt@calendar@weeknumber}%
\gantttitle{%
\ganttvalueof{calendar week text}%
}{%
\the\gtt@calendar@slots%
}%
\fi%
}{}%
}%
\endgroup%
\gtt@calendar@eoltrue%
},%
week/.default=1,
weekday/.code={%
\ifgtt@calendar@eol\ganttnewline\fi%
\begingroup%
\pgfcalendar{}{\gtt@calendar@startdate}{\gtt@calendar@enddate}{%
\ifnum\pgfcalendarcurrentweekday<5\relax % only increment if it's a weekday
\gantttitle{%
\csname pgfcalendarweekday#1\endcsname{\pgfcalendarcurrentweekday}%
}{1}%
\fi
}%
\endgroup%
\gtt@calendar@eoltrue%
},
day/.code={%
\ifgtt@calendar@eol\ganttnewline\fi%
\begingroup%
\pgfcalendar{}{\gtt@calendar@startdate}{\gtt@calendar@enddate}{%
\ifnum\pgfcalendarcurrentweekday<5\relax % only increment if it's a weekday
\gantttitle{\pgfcalendarcurrentday}{1}
\fi
}%
\endgroup%
\gtt@calendar@eoltrue%
}%
}
\makeatother
\begin{document}
\def\pgfcalendarweekdayletter#1{\ifcase#1M\or Tu\or W\or Th\or F\or Sa\or Su\fi}
\begin{ganttchart}[
time slot format=little-endian,
progress=today,
today=4.5.13,
calendar week text = {W~\currentweek},
]{1.5.13}{14.5.13}
\gantttitlecalendar{week,day,weekday=letter}\\
\ganttgroup{Group 1}{1.5.13}{14.5.13} \\
\ganttbar{Subtask 1}{1.5.13}{3.5.13} \\
\ganttbar{Subtask 2}{3.5.13}{8.5.13} \\
\ganttbar{Subtask 3}{9.5.13}{14.5.13}
\end{ganttchart}
\begin{ganttchart}[
time slot format=little-endian,
progress=today,
today=4.5.13,
calendar week text = {W~\currentweek},
weekdays only
]{1.5.13}{14.5.13}
\gantttitlecalendar{week,day,weekday=letter}\\
\ganttgroup{Group 1}{1.5.13}{14.5.13} \\
\ganttbar{Subtask 1}{1.5.13}{3.5.13} \\
\ganttbar{Subtask 2}{3.5.13}{8.5.13} \\
\ganttbar{Subtask 3}{9.5.13}{14.5.13}
\end{ganttchart}
\newpage
\begin{ganttchart}[
time slot format=little-endian,
progress=today,
today=3.12.16,
calendar week text = {W~\currentweek},
]{26.11.16}{11.12.16}
\gantttitlecalendar{week,day,weekday=letter}\\
\ganttgroup{Group 1}{26.11.16}{11.12.16} \\
\ganttbar{Subtask 1}{26.11.16}{3.12.16} \\
\ganttbar{Subtask 2}{3.12.16}{11.12.16} \\
\end{ganttchart}
\begin{ganttchart}[
time slot format=little-endian,
progress=today,
today=3.12.16,
calendar week text = {W~\currentweek},
weekdays only
]{26.11.16}{11.12.16}
\gantttitlecalendar{week,day,weekday=letter}\\
\ganttgroup{Group 1}{26.11.16}{11.12.16} \\
\ganttbar{Subtask 1}{26.11.16}{3.12.16} \\
\ganttbar{Subtask 2}{3.12.16}{11.12.16} \\
\end{ganttchart}
\end{document}
这是输出(相同的输入,首先没有密钥,然后有密钥weekdays only
):