Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reorganize attribute documentation #323

Open
Ininterrompue opened this issue Nov 22, 2022 · 14 comments
Open

Reorganize attribute documentation #323

Ininterrompue opened this issue Nov 22, 2022 · 14 comments

Comments

@Ininterrompue
Copy link
Contributor

Ininterrompue commented Nov 22, 2022

The current documentation for attributes could use some refreshing.

  1. Most attributes cannot be searched directly in the search bar (known problem). Ideally the way that attributes are documented should be done in a way where they can be searched. Maybe we should replace the table with something closer to the API page?
  2. Attributes are not organized well. Organizing them into series, plot, subplot, and axis is something I have found very confusing.
    • In particular, typing something like plotattr(:Subplot) in the REPL outputs a large list of attributes. This hinders discoverability and accessibility. In my experience, I have always had to look through all four tabs in the docs to look for an attribute.
    • What would be better for plotattr(:Subplot) is to reorganize the categories into things like Annotation, Background, Foreground, Colorbar, Legend, Title, as well as a few others. A lot of the attribute names in this list heavily suggest this anyway. This way, when one needs to find attributes related to the legend, there is a clearly labeled tab in the docs for that, or typing e.g. plotattr(:Legend) would yield all of its relevant attributes (cf. this issue)
  3. The types required for the attributes are not always intuitive. For example, colorbar_ticks could use some explaining on the different possible argument types, as Union{Symbol, Tuple{AbstractVector{Real}, AbstractVector{AbstractString}}, AbstractVector{Real}} is not obvious how to interpret. Also, a lot of attributes have no description.

A documentation style like that on the API page would be able to solve these problems simply by allowing more room for the description, explanation of types, and examples. Categorizing them into titles like Colorbar, Legend, etc. would keep these pages manageable in length.

@mkborregaard
Copy link
Member

These are good suggestions IMHO. See also JuliaPlots/Plots.jl#676 bit unsure whether this JuliaPlots/Plots.jl#2337 should still be open

@t-bltg
Copy link
Member

t-bltg commented Nov 22, 2022

Point 1. has finally been fixed yesterday (#318 - #320). When searching for e.g. show_empty_bins, a search results pointing to https://docs.juliaplots.org/stable/generated/attributes_series/ is proposed.
You can search for attributes but also aliases now.

Not sure about 2. (I am not sure that the proposed approach would enhance clarity).

Point 3. is a julia language pre-requisite and has nothing to do with Plots, although since beginners are likely to use Plots rapidly, we could maybe add a link to https://docs.julialang.org/en/v1/manual/types/#Type-Unions and a note in the attributes page. Maybe somewhere around here: https://github.com/JuliaPlots/PlotDocs.jl/blob/master/src/PlotDocs.jl#L267-L270.

@Ininterrompue
Copy link
Contributor Author

Ininterrompue commented Dec 11, 2022

Point 1. has finally been fixed yesterday (#318 - #320). When searching for e.g. show_empty_bins, a search results pointing to https://docs.juliaplots.org/stable/generated/attributes_series/ is proposed. You can search for attributes but also aliases now.

If I search show_empty_bins, the relevant hits with the list of attributes are the last two. I'm not sure about the details of the search mechanism with Documenter.jl. This may be an issue with that package.

If I search markersize, the first result should point straight to the page that has the information about this attribute. But this page is far down the list, and it's not obvious which one. (It's the one called "Series Attributes") Also, if I search for its alias ms, it's basically at the bottom of the results.

Maybe the attribute pages need to be prioritized more in the search results.

Not sure about 2. (I am not sure that the proposed approach would enhance clarity).

I think it would enhance clarity greatly. I'm not the only one that has been frustrated with finding attribute documentation. See here, here, here. Also, anecdotes from my friends. I'm motivated to fix this partly because this was by far the most frustrating thing about learning Julia for me.

I remember trying to figure out how to manipulate the legend and could not figure out which one of Series, Plot, Subplot, and Axis had the entries for legend attributes, even after many iterations. But if they were all listed under a section called "Legend Attributes," it would be obvious. Legend attributes was particularly confusing since one can have a plot of lines and points all on the same canvas, with one legend, and yet the attributes are listed under Subplot, not Plot.

Point 3. is a julia language pre-requisite and has nothing to do with Plots, although since beginners are likely to use Plots rapidly, we could maybe add a link to https://docs.julialang.org/en/v1/manual/types/#Type-Unions and a note in the attributes page. Maybe somewhere around here: https://github.com/JuliaPlots/PlotDocs.jl/blob/master/src/PlotDocs.jl#L267-L270.

The type system is indeed something baked into the language itself. However, it is a good idea to explain the types and give examples of the possible values that it can take. This is especially important since beginners and many end-users do not regularly use or encounter abstract types, yet these are the very people that probably want to understand what the attributes mean.

To give another example, bins has the type

Union{Integer, Symbol, Tuple{Integer, Integer}, AbstractVector}

but a lot of people don't know that StepRange <: AbstractVector, or may be confused by Int vs. Integer.

Instead, here is how I would write the following doc entry:


bins :: Union{Integer, Symbol, Tuple{Integer, Integer}, AbstractVector}

Defines the number of bins. Aliases :bin, :nb, :nbin, :nbins.

Can take in one of the following types:

  • Integer – defines the approximate number of bins to aim for. Not guaranteed to give the exact value.
    • bins=10 gives a 1D histogram with about 10 bins.
    • bins=10 gives a 2D histogram with about 10 bins for each dimension.
  • Tuple{Integer, Integer} – for two-dimensional histograms, defines the approximate number of bins per dimension. Not guaranteed to give the exact values.
    • bins=(10, 20) gives a 2D histogram with about 10 bins for the x dimension and about 20 bins for the y dimension.
  • Symbol – defines the auto-binning algorithm to use.
  • AbstractVector – defines a vector of values for bin edges.
    • bins=range(-10, 10, length=21) gives a histogram with bins starting from -10, ending at 10, and containing 21 break values, giving 20 bins.

Relevant attribute for the following series types:


This is the type of entry I'd like to see for every single attribute that exists.

@t-bltg
Copy link
Member

t-bltg commented Dec 11, 2022

If I search show_empty_bins, the relevant hits with the list of attributes are the last two. I'm not sure about the details of the search mechanism with Documenter.jl. This may be an issue with that package.

Yeah well I didn't say it was perfect. The current solution is monkey patching the domify method from Documenter in order to tweak the search index when using raw html tables:

PlotDocs.jl/docs/make.jl

Lines 14 to 48 in 4809512

# monkey patch `Documenter` - note that this could break on minor `Documenter` releases
@eval Documenter.Writers.HTMLWriter domify(ctx, navnode) = begin
# github.com/JuliaDocs/Documenter.jl/blob/327d155f992ec7c63e35fa2cb08f7f7c2d33409a/src/Writers/HTMLWriter.jl#L1448-L1455
page = getpage(ctx, navnode)
map(page.elements) do elem
rec = SearchRecord(ctx, navnode, elem)
############################################################
# begin addition
info = "[src=$(rec.src) fragment=$(rec.fragment) title=$(rec.title) page_title=$(rec.page_title)]"
if (m = match(r"generated/attributes_(\w+)", lowercase(rec.src))) nothing
# fix attributes search terms: `Series`, `Plot`, `Subplot` and `Axis` (github.com/JuliaPlots/Plots.jl/issues/2337)
@info "$info: fix attribute search"
for (attr, alias) $(ATTRIBUTE_SEARCH)[first(m.captures)]
push!(
ctx.search_index,
SearchRecord(rec.src, rec.page, rec.fragment, rec.category, rec.title, rec.page_title, attr * ' ' * alias)
)
end
else
add_to_index = if (m = match(r"gallery/(\w+)/", lowercase(rec.src))) nothing
first(m.captures) == "gr" # only add `GR` gallery pages to `search_index` (github.com/JuliaPlots/Plots.jl/issues/4157)
else
true
end
if add_to_index
push!(ctx.search_index, rec)
else
@info "$info: skip adding to `search_index`"
end
end
# end addition
############################################################
domify(ctx, navnode, page.mapping[elem])
end
end

I agree that it would be better to weight the search result in order to make the result appear at the top of the results. As you can see in search.js, there is a boost field, that we could use to tweak the search order. I gave it a try but couldn't find a solution while implementing #318 (which in the end is just a hack).

But if they were all listed under a section called "Legend Attributes," it would be obvious.

That could work, but that would need some effort to integrate smoothly in Plots and PlotDocs. It's "only" a matter of putting in development time, and producing something not being too convoluted and difficult to maintain because of its complexity.

Instead, here is how I would write the following doc entry:

That looks nice indeed. Currently you can see that the description types are defined here. If you can make it work without increasing the complexity too much I'd be happy to integrate this, but be aware that implementing a clean and generic solution for the arguments and their description might be non-trivial.

@Ininterrompue
Copy link
Contributor Author

Ininterrompue commented Dec 11, 2022

With the entry I wrote, I think it's a bit too complex to be included as part of a dictionary. The majority of attributes won't be as complex as bins, but there are still quite a few that need more than a few lines to completely document.

My idea is the tables should be replaced with pages that resemble the API page. The disadvantages with the tables right now is that the attributes cannot directly be searched, and the amount of information for a given attribute is softly constrained by a box. (Not an actual constraint...but the dictionary+table format strongly suggests terse descriptions) Additionally, there seems to be a lot of inherent complications that are coming from the fact that it's the Plots.jl repository generating the attribute tables.

With the API pages, all the information I wrote can be put into an entry for bins and formatted just like above, and it will also be easier to search for the particular attribute in the search bar (but enhancing the search itself should be a separate issue).

One issue is how to include this information in the REPL. Right now, typing plotattr("bins") gives the information, but it is different than typing ?bins since bins has to be a method, and ?plotattr("bins") won't work. Is there a way to make this work if the attributes were documented on an API page? I understand that this is not how keywords are normally documented...

I'm willing to put in the work to recategorize all of the attributes and create separate API pages for each of them. Just want to figure out the best way to approach this.

@Ininterrompue
Copy link
Contributor Author

Ininterrompue commented Dec 11, 2022

One way to recategorize them is the following:

  • Series attributes stay the same. On the API page, every entry contains a "Relevant attribute for the following series types:" list that denotes all of the series types which the attribute can modify.
  • Plot attributes is renamed to Global attributes. This is probably a less ambiguous word to refer to those attributes which impact the entire plot.
  • Subplot attributes are split up into the following categories:
    • Annotation attributes: annotationcolor annotationfontfamily annotationfontsize annotationhalign annotationrotation annotations annotationvalign
    • Colorbar attributes: clims colorbar colorbar_continuous_values colorbar_discrete_values colorbar_fontfamily colorbar_formatter colorbar_scale colorbar_tickfontcolor colorbar_tickfontfamily colorbar_tickfonthalign colorbar_tickfontrotation colorbar_tickfontsize colorbar_tickfontvalign colorbar_ticks colorbar_title colorbar_title_location colorbar_titlefontcolor colorbar_titlefontfamily colorbar_titlefonthalign colorbar_titlefontrotation colorbar_titlefontsize colorbar_titlefontvalign
    • Legend attributes: legend_background_color legend_column legend_font legend_font_color legend_font_family legend_font_halign legend_font_pointsize legend_font_rotation legend_font_valign legend_foreground_color legend_position legend_title legend_title_font legend_title_font_family legend_title_font_halign
      legend_title_font_pointsize legend_title_font_rotation legend_title_font_valign
    • Margin attributes: bottom_margin left_margin margin right_margin top_margin
    • Title attributes: title titlefontcolor titlefontfamily titlefonthalign titlefontrotation titlefontsize titlefontvalign titlelocation
    • 3D-specific attributes: camera projection projection_type
    • Other subplot attributes: aspect_ratio background_color_inside background_color_subplot color_palette extra_kwargs fontfamily_subplot foreground_color_subplot foreground_color_title framestyle subplot_index
  • Axis attributes stay the same.

We might also want to consider making the attribute names consistent with regards to spacing, snake-case, etc. Right now, all the annotation attributes are concatenated words, the colorbar attributes are all over the place, the legend attributes are all snakecase, and the title attributes are concatenated. Also, clims (colorbar limits) has an official name that is different from the other colorbar attributes.

@BeastyBlacksmith
Copy link
Member

BeastyBlacksmith commented Dec 13, 2022

What we shouldn't change is that there is a single source of truth.
On the other hand I don't see a reason why you couldn't generate the markdown in #323 (comment) from the current stucture when you change the descripion string in Plots.jl.
I would probably like to have a frontpage that only lists the attributes as links, such that you get the detailed information if you click on it.

@Ininterrompue
Copy link
Contributor Author

Ininterrompue commented Dec 13, 2022

On the other hand I don't see a reason why you couldn't generate the markdown in #323 (comment) from the current stucture when you change the descripion string in Plots.jl.

I'm not sure I follow. It is technically possible to fit all of the information in the table, but it wouldn't look good as the last column would take up too much space. There's a bunch of nested bullet points, and for some attributes, the list of relevant series types which the attribute applies to can be huge. The information really needs the entire space on the page to be readable, not just a single column. A tabular format encourages terse docstrings, so it would be nice to have more information to enhance accessibility. Plus, right now the backticks don't render in the table, and there is the occasional \n in the descriptions.

Essentially, my position is this: I know what format I want to present the information to be as complete and concise as possible, and am thinking the present table is not adequate enough to realize that, but function docstrings do. Thus the question becomes how to replicate the function docstring format as closely as possible within the limits of Documenter.jl. If the attribute names themselves show up on the results page when searching in the docs, that would help greatly with discoverability.

@BeastyBlacksmith
Copy link
Member

I'm not saying we should keep that table. We can generate from the dictionary in Plots.jl/src/attr_descr.jl any markdown.

@Ininterrompue
Copy link
Contributor Author

Does the information have to be written as part of a dictionary, or can I write the markdown directly? Using ## and ### headers would be good enough for organization.

@BeastyBlacksmith
Copy link
Member

BeastyBlacksmith commented Dec 13, 2022

In principle its fine to use markdown stings there, however we should take care not to break usage of that information in plotattr and docstrings.
Thats either keeping the dictionary structure or also changing how these functions use that information.

@Ininterrompue
Copy link
Contributor Author

One way is to keep the dictionary as-is, but create new pages with pure Markdown, replacing the generated/attribute_series.md, etc. That way plotattr functionality won't be broken. There'll be a disconnect between documentation on the site and documentation as seen in the REPL via plotattr, but I think this'll be a good start. What do you think?

@BeastyBlacksmith
Copy link
Member

Sounds reasonable to me

@Ininterrompue
Copy link
Contributor Author

Example for series attributes. While creating this page, it was found that match_dimensions was not being generated in the table.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants