How to generate a table in Haddock documentation - haskell

I am writing some documentation with Haddock, and I need to put a multi-column table with some values in it. How can I do it with Haddock? I cannot find info about it. Embedding some html as alternative looks no possible too.

Haddock bundled with GHC 8.4 or newer (Haddock version >= 2.18.2) supports tables. As per the pull request where this was added, the syntax is based on RST Grid tables.
Sample use:
module Sample where
-- | A table:
--
-- +------------------------+------------+----------+----------+
-- | Header row, column 1 | Header 2 | Header 3 | Header 4 |
-- | (header rows optional) | | | |
-- +========================+============+==========+==========+
-- | body row 1, column 1 | column 2 | column 3 | column 4 |
-- +------------------------+------------+----------+----------+
-- | body row 2 | Cells may span columns. |
-- +------------------------+------------+---------------------+
-- | body row 3 | Cells may | \[ |
-- +------------------------+ span rows. | f(n) = \sum_{i=1} |
-- | body row 4 | | \] |
-- +------------------------+------------+---------------------+
sample :: ()
sample = ()
Turns into

Haddock "markup" doesn't currently support tables, see also Haddock User Guide - Chapter 3. Documentation and Markup. There is an open issue to add support for simple tables.

Related

MS Excel: How to list all column if the rows contain a given date?

My data looks like below. I have Groups that I share topics each day. We do this randomly based on need.
| | Topic 1 | Topic 2 | Topic 3 | Topic 4 | Topic 5 | Topic 6 | Topic 7 | Topic 8 | Topic 9 |
|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|
| Group 1 | | 19-apr | 30-apr | | | | | | |
| Group 2 | 18-apr | 25-apr | | | | | | | |
| Group 3 | | | | | 19-apr | 30-apr | | | |
| Group 4 | 18-apr | 25-apr | | | | | | | |
| Group 5 | | | | | | | 19-apr | 30-apr | |
| Group 6 | | | 25-apr | | | | | | |
| Group 7 | 18-apr | 25-apr | | | | | | | |
For our metrics & analysis, we need a list of groups per date on a different sheet. We like to know which all groups were engaged a given day. Like below
Can somebody please help me how I can get this done with only using formulas and without macros?
I believe this can somehow be handled on Index Matching or look-ups.
You could definitely do this with macros. You can do something similar without macros; it may not be precisely what you were looking for because it will leave blank space where groups were not addressed.
Method 1
Here is the formula I used and a picture of the sheet it is in:
=IF(IFERROR(MATCH(L$4,$B6:$H6,0),FALSE),INDEX($B$5:$B$13,MATCH($K5,$B$5:$B$13,0),1),"")
The idea is that if you have absolute references alongside your list of groups per date, then you can use index and match to fill in that group's name, but only if Match finds that precise date code in that group's row from the previous table. If you place an equivalent formula in the first cell, you can drag it out to the rest of the array.
The formula I used is not the only way to do this, but if you know Index and Match, then it should make sense to you.
Method 2
A more convoluted method would be to use image references. With these, it is possible to make the report precisely what you asked for on a separate sheet.
Suppose you took Method 1 and separated each column out into a different table. Nearly the same formula inside the cells below the date heading, except that you enclose the heading reference in int() as shown below. Create one table for each of N dates, where N is the number of days you want to monitor at once. Then when you want the summary to show you different dates, you go to each table and change the heading, and filter out blanks.
formula:
=IF(IFERROR(MATCH(INT($L$2),$B4:$H4,1),FALSE),INDEX($B$4:$B$11,MATCH($K3,$B$4:$B$11,1),0),"")
The below image shows what I mean by one table for each date:
Then you insert an image. Doesn't matter what image; could be a screenshot of anything. Click on that image, then click into the formula bar. Then highlight the table column you want it to represent. Below is a screenshot of how to to that:
Now place that picture on its own sheet in the workbook. Place each date table on its own sheet in the workbook. The reason you do this is: if you filter a table, everything else overlapping the filtered rows outside the table will also be hidden. You move tables to separate sheets to prevent them from hiding each other.
Finally, arrange your pictures into the order you like, filter the blanks out of the tables, and your images will be exactly what you were looking for:
Again, this is a little convoluted because if you want the report to show you new date summaries, you would have to change the headings on every table. Then you would have to go to each table and refresh it's filter. This is where macros usually come in.
Assume range A1:J8 housed your Source table, and L1:P8 housed the Date/Group Output
1] In L2, copied across :
=IFERROR(1/(1/AGGREGATE(15,6,$B$2:$J$8/($B$2:$J$8>K$2),1)),"")
2] In L3, copied across to P3 and all copied down :
=IF(L$2="","",IFERROR(INDEX($A:$A,AGGREGATE(15,6,ROW($A$2:$A$8)/($B$2:$J$8=L$2),ROW(A1))),""))
You can use the following formula to get a list of dates from a table:
=IFERROR(AGGREGATE(15,6,($B$2:$J$8/($B$2:$J$8*(COUNTIF($A$15:A15,$B$2:$J$8)=0)))*$B$2:$J$8,1),"")
To get a list of groups by date, use the following:
=IFERROR(INDEX($A$1:$A$8,AGGREGATE(15,6,(1/(B$15=$B$1:$J$8))*ROW($B$1:$J$8),ROW(A1))),"")

Excel function, exclude dates in chart data source

I am forming a chart from sheet A. Sheet B contains all my data.
I want to exclude a specified date(s).
Sample data:
+---+----------+--------------+--------------+-------------+-------------+-------------+
| | A | B | C | D | E | F |
+---+----------+--------------+--------------+-------------+-------------+-------------+
| 1 | Date | 29/03/2017 | 30/03/2017 | 31/03/2017 | 03/04/2017 | 04/04/2017 |
| 2 | Number 1 | -594590.4649 | -636666.4504 | 795637.1614 | 842563.4322 | 496463.9301 |
| 3 | Number 2 | 2189587.44 | 1301681.418 | 2080839.353 | 1945335.214 | 2421728.123 |
+---+----------+--------------+--------------+-------------+-------------+-------------+
The final output would be me excluding 30/03/2017 , and keeping the rest in my data selected for my chart.
the issue is that I want to maybe exclude a date in the middle of my selected range. But since this may be a hassle to input a long formula each time into my data selected. I would like to see if there is any formula/function to eliminate a specified date/column. Perhaps manually enter the column you want to exclude in a formula.
My current range is something like =Graph!$AB$5:$KA$7 But is there a function to exclude one of these columns?
I can manually select which dates with Ctrl but seems tedious.

Create a dynamic table in Tableau

What I am trying to do is simply replicate an excel sheet on Tableau. However, my worksheet shall contain many columns having been calculated using other columns. Calculating a field is not much in Tableau I understand but I want to see the changes happening in the calculated field as one enters the data in the parent field on the dashboard directly. For example I put up the following data on Tableau:
x y(=x*5) z(=x+10)
1 5 11
2 10 12
3 15 13
4 20 14
5 25 15
I would like to see the values of y and z change automatically as the values of x are fed in directly on the dashboard.
I am not able to figure out how to accomplish this on tableau. Would be highly obliged on any help extended. Thanks in Advance.
I know its late but if you still need this to answer then here is my speculations. I am assuming this is how you want your table to be:
| Column X | Column Y| Column Z | A | B | C | ... |
-------------------------------------------------------
| 2 | 10(2*5) | 12(2+10) | 2 | 4 | 1 | ... |
| 4 | 20(4*5) | 14(4+10) | 3 | 1 | 3 | ... |
| 8 | 40(8*5) | 18(8+10) | 6 | 0 | 9 | ... |
| . | . | . | . | . | . | ... |
| . | . | . | . | . | . | ... |
-------------------------------------------------------
You can create calculated fields for ColumnY and ColumnZ . In calculated columns you can you use lookup to find value in a particular column (here ColumnX) and perform calculations on it.
Here is how you create your calculated column:
ColumnY
LOOKUP(SUM(ColumnX),0) * 5
and
ColumnZ
LOOKUP(SUM(ColumnX),0) + 10
Have a look at this LOOKUP function Lookup Table calculation function
Regards
You are essentially talking about parameters. A complete detailed article can be found here
Parameters are dynamic values that can replace constant values in
calculations and can serve as filters. For example, you might have a
calculated field that returns True if Sales are greater than $500,000,
and otherwise returns False. Using a parameter, you can replace the
constant value of $500,000 in the calculated field with a parameter
than you can change dynamically using the Parameter control.
In your case, you can simply create a parameter X, that will be entered by user on the fly, and then in turn use x in the calculations of y and z, thus accomplishing your requirements.
If input is of concern to you than Tableau also enables you to create user based input into your parameters. You can create columns that run off these input, such as Column 1 = X (Parameter 1) * Y (Parameter 2)
To set this up create the parameters, name them, and define their input ranges. For example say Parameter 1 can take integers from 1-1000. Then do the same for Parameter 2.
Next create a calculated field where field = X*Y
Do this for as many variables (parameters) and as many equations (columns) as you want! there you go, the dynamic table.

Excel Formula Optimisation

I am no excel expert and after some research have come up with this formula to look at two sets of the same data from different times. It then displays new entries that are in the latest list of data but not in the old list.
This is my formula:
{=IF(ROWS(L$4:L8)<=(SUMPRODUCT(--ISNA(MATCH($E$1:$E$2500,List1!$E$1:$E$2500,0)))),
INDEX(E$1:E$2500,
SMALL(IF(ISNA(MATCH($E$1:$E$2500&$F$1:$F$2500,List1!$E$1:$E$2500&List1!$F$1:$F$2500,0)),
ROW($F$1:$F$2500)-ROW($F$1)+1),ROWS(L$4:L8))),"")}
Are there any optimisation techniques I could employ to speed up the calculation?
As requested
Some example data(link to a spreadsheet):
https://docs.google.com/file/d/0B186C84TADzrMlpmelJoRHN2TVU/edit?usp=sharing
On this scaled down version its more efficent but on my actual sheet with a lot more data it is slowed.
Well, I was playing around a bit and I think that this works the same, and without the first IF statement:
=IFERROR(INDEX(A$1:A$2500,SMALL(IF(ISNA(MATCH($A$1:$A$2500&$B$1:$B$2500,List1!$A$1:$A$2500&List1!$B$1:$B$2500,0)),ROW($B$1:$B$2500)-ROW($B$1)+1),ROWS(F$2:F2))),"")
That part in your sample data:
ROWS(F$2:F2)<=(SUMPRODUCT(--ISNA(MATCH($A$1:$A$2500,List1!$A$1:$A$2500,0))))
As I understood it, it only sees to it that the row number in which the formula is entered is lower than the number of 'new' items, but it doesn't serve any purpose because when you drag the formula more than required, you still get errors instead of the expected blank. So I thought it could be removed altogether (after trying to substitute it with COUNTA() instead) and use an IFERROR() on the part directly fetching the details.
EDIT: Scratched that out. See barry houdini's comment for the importance of those parts.
Next, you had this:
ROW($B$1:$B$2500)-ROW($B$1)+1
-ROW($B$1)+1 always returns 0, so I didn't find any use to it and removed it altogether.
It's still quite long and takes some time I guess, but I believe it should be faster than previously by a notch :)
A relatively fast solution is to add a multi-cell array formula in a column alongside List 2
{=MATCH($A$1:$A$16,List1!$A$1:$A$11,0)}
and filter the resultant output for #N/A.
(Or see Compare.Lists vs VLOOKUP for my commercial solution)
Array formula is slow. When you have thousands of array formula, it will make the speed very slow. Thus the key will be to avoid any array formula.
The following will be my way to achieve it, using only simple formula. It should be fast enough if you only have 2500 rows.
Column F and H are "Keys", created by concatenating your 2 columns (E and F in your original formula)
Assuming the first line of data is on row 3.
Data:
| A | B | | D | E | F | | H |
| index | final value | | ID | exist in Old? | Key (New) | | Key (Old) |
--------------------------------------------------------------------------------
| 1 | XXX-33 | | 0 | 3 | OOD-06 | | OOC-01 |
| 2 | ZZZ-66 | | 0 | 1 | OOC-01 | | OOC-02 |
| 3 | ZZZ-77 | | 1 | N/A | XXX-33 | | OOD-06 |
| 4 | | | 1 | 4 | OOE-01 | | OOE-01 |
| 5 | | | 1 | 2 | OOC-02 | | OOF-03 |
| 6 | | | 2 | N/A | ZZZ-66 | | |
| 7 | | | 3 | N/A | ZZZ-77 | | |
Column E "exist in Old?": test if the new key (Column F) exists in the old list (Column H)
=MATCH(F3, $H$3:$H$2500, 0)
Column D "ID": to increment by one whenever a new item is found
=IF(ISNA(E3), 1, 0)+IF(ISNUMBER(D2), D2, 0)
the 2nd part of ISNUMBER is just for the first row, where just using D2 can cause an error
Column A "index": just a plain series starting from 1 (until the length of new list Column F)
Column B "final value": to find the new key by matching column A to Column D.
=IF(A3>MAX($D$3:$D$2500), "", INDEX($F$3:$F$2500, MATCH(A3, $D$3:$D$2500, 0))
This column B will be the list you want.
If it is still too slow, there exists some dirty tricks to speed up the calculation, e.g. by utilizing a sorted list with MATCH( , , 1) instead of MATCH( , , 0).

return values from multiple matching rows

First off, I'd like to do this without VB if possible, so I don't have to go through the hassle of teaching recipients how to enable macros.
Now, I believe what I'd like to do is simple, but the answer may be complex formula-wise. I'm trying to list out in new columns the values from a specified column in rows which have matching values from two other columns. Sounds tricky I'm sure, but an example should help immensely...
Say I have the following data:
------------------
| sts | pos | bye |
------------------
| 0 | QB | 8 |
| 2 | WR | 3 |
| 2 | QB | 10 |
| 0 | QB | 4 |
| 2 | QB | 7 |
| 0 | WR | 11 |
| 2 | WR | 9 |
| 2 | QB | 5 |
------------------
That's my source. I want to list out the bye value from all rows that have sts = 2, for each respective pos. In other words, from the source data above I'd want to see the following result set:
--------------------------
| pos | byes |
--------------------------
| QB | 10 | 7 | 5 | |
| WR | 3 | 9 | | |
--------------------------
...because those are the bye values in the rows with sts = 2 and pos equal to the corresponding pos in the result table.
Again, I'd like to avoid macros if possible, and just use a formula in the bye cells of the results table.
Hopefully that makes enough sense for you to take a stab at it. Thanks!
FOLLOW-UP:
#Richard-Morgan I attempted to use your formula but can't get it to work. Here is a screenshot of my actual spreadsheet so we can use real cell references:
So sts is B2:B303, pos is D2:D303, and bye is E2:E303. So then I'd like to list out the byes in columns U thru Y. It looks like your answer, if I'm smart enough to implement it, will get me what I need, so any assistance you can provide to get me to the finish line is greatly appreciated!
Something along the lines of the following could be used:
{=INDEX(tbl, SMALL(IF(COUNTIF(G$3, $A$2:$A$9)
*COUNTIF(G$4, $B$2:$B$9), ROW(tbl)-MIN(ROW(tbl))+1), ROW($C1)), COLUMN($C1))}
where the A column is sts, B column is pos, and C column is bye. The variable tbl is the range of data (not the headers). G$3 would be the sts filter and G$4 is the pos filter.
Copy the array formula DOWN to find all the matching byes; #NUM! will appear after finding no more matches. If this bothers your users, you can add an ISERROR or a tricky conditional format that makes the text white on white.
You can then copy over the formula to the next column and enter new filter values.
G H
sts Search 2 2
pos Search QB WR
10 3
7 9
5 #NUM!
#NUM!#NUM!
If your users are comfortable with pivot tables, using them would be much easier, I would think.
EDIT
Making the formula "transpose" is a bit tricky and I am not having any breakthrough on how to fix that. However, if you want to manually edit the column formulas, here is what you want.
(I made the assumption that S is the sts filter. Maybe you're just doing a count there, but I didn't see where you enter the filter for sts. If S isn't the sts filter, update the formulas to point to where sts is 2 or whatever.)
U2:
{=INDEX(tbl, SMALL(IF(COUNTIF($S2, $B$2:$B$303)*COUNTIF($R2, $D$2:$D$303),
ROW(tbl)-MIN(ROW(tbl))+1), ROW($D$1)), COLUMN($D$1))}
V2:
{=INDEX(tbl, SMALL(IF(COUNTIF($S2, $B$2:$B$303)*COUNTIF($R2, $D$2:$D$303),
ROW(tbl)-MIN(ROW(tbl))+1), ROW($D$2)), COLUMN($D$2))}
etc.
This allows the cells to be copied down.
I am sure there is a way to INDIRECT the ROW/COLUMN, but I ran out of time to look at this at the moment.
EDIT 2
If you put a simple number increment somewhere, let's say U1 has 1, V1 has 2, W1 has 3, etc., you could use the following:
{=INDEX(tbl, SMALL(IF(COUNTIF($S2, $B$2:$B$9)*COUNTIF($R2, $D$2:$D$9),
ROW(tbl)-MIN(ROW(tbl))+1), U$1), COLUMN($D$1))}
This will copy down and across.
This sounds like a job for pivot tables and go to special. You need to add an ID # column though. Here is one way you could do it:
Then once the blanks are selected using go to special you just need to delete them and shift cells left.
Good Luck.
OK I figured out a way to get my desired results. It isn't the cleanest or best way, but it achieves my goal of listing the results horizontally, and avoids macros or pivot tables.
I use a hidden worksheet to list out all the pos and sts values, concatenated as a single value. So...
sts | pos | bye
----------------------
2 | QB | 8
2 | RB | 5
2 | QB | 11
0 | WR | 7
. . .
...becomes....
D | E
-----------
5 | 2QB | 8
6 | 2RB | 5
7 | 2QB | 11
8 | 0WR | 7
. . .
Then, I have a "shadow" results area that mimics the results area on my front-page worksheet. It looks like so:
G | H | I | J | K
-----------------------------
5 | QB | | | | |
6 | RB | | | | |
7 | WR | | | | | . . .
In H5:H7, I have the following formula:
=IFERROR((ADDRESS(MATCH("2"&$G5,$D$5:$D$305,0)+4,COLUMN($E5),4)),"")
This returns the first cell reference it finds in the concatenated column that starts with 2 and ends with the value in column G (e.g. the formulas in row 5 are looking for "2QB").
Then, in I5:n7 I have the following modified formula:
=IFERROR(ADDRESS(MATCH("2"&$G5,INDIRECT(ADDRESS(ROW(INDIRECT(H5))+1,4)&":$d$"&MAX(305,ROW(INDIRECT(H5))+1)),0)+ROW(INDIRECT(H5)),COLUMN($E5),4),"")
The reason I modify the subsequent columns is to change the range in which the formula is looking for its value to start at the next row after the previously found value. For example, with the data above, the formula in H5 would look for "2QB" in D5:D*n*, and return the first row it finds and attach it to column E, which would be E5.
The formula in I5 would then look for "2QB" starting in D*6* instead of D5, a row after the row referenced in H5's result.
Hopefully that made sense.
So what I end up with in my hidden worksheet is this:
G | H | I | J | K
-----------------------------
5 | QB | E5 | E7 | | |
6 | RB | E6 | | | |
7 | WR | | | | | . . .
Then, on my front page worksheet, I simply get the values (the bye) referenced by the cells in H5:*n*7 using:
=IFERROR(INDIRECT(lookups!H5),"")
...which gives me my final result:
G | H | I | J | K
-----------------------------
5 | QB | 8 | 11 | | |
6 | RB | 5 | | | |
7 | WR | | | | | . . .
Like I said, it's totally convoluted, but it works, and I can always refine it later if I figure out how. :) Thanks to you who took a swing at this seemingly complex problem for me! I'm sure your answers work beautifully as well.

Resources