Thanks to visit codestin.com
Credit goes to github.com

Skip to content

DOC: re-add api example #26624

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

Closed
wants to merge 1 commit into from
Closed

Conversation

jklymak
Copy link
Member

@jklymak jklymak commented Aug 29, 2023

PR summary

This re-introduces the example in api/index, and adds a pyplot counterexample.

As discussed in #26623 - this provides concrete examples of the abstract concepts being discussed and makes the API pages more self-contained.

PR checklist

@story645
Copy link
Member

I don't think self-contained should be a goal b/c that's how we end up w/ example drift and scope creep. I think as much as possible we should be cross linking to one source of truth cause that's more maintainable and makes things more discoverable.

Copy link
Member

@story645 story645 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the example as given is cluttered in a way that obfuscates the goal of trying to highlight the API differences. I also think that since this is a doc regression it should have two approvals.

ETA: I also very much appreciate that you put the example into the pyplot and axes explanations.

Comment on lines +46 to +56
x = np.arange(0, 4, 0.05)
y = np.sin(x*np.pi)
# Create a Figure and an Axes:
fig, ax = plt.subplots(figsize=(3,2), layout='constrained')
# Use the Axes to plot and label:
ax.plot(x, y)
ax.set_xlabel('t [s]')
ax.set_ylabel('S [V]')
ax.set_title('Sine wave')
# Change a property of the Figure:
fig.set_facecolor('lightsteelblue')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
x = np.arange(0, 4, 0.05)
y = np.sin(x*np.pi)
# Create a Figure and an Axes:
fig, ax = plt.subplots(figsize=(3,2), layout='constrained')
# Use the Axes to plot and label:
ax.plot(x, y)
ax.set_xlabel('t [s]')
ax.set_ylabel('S [V]')
ax.set_title('Sine wave')
# Change a property of the Figure:
fig.set_facecolor('lightsteelblue')
# Create a Figure and an Axes:
fig, ax = plt.subplots(figsize=(3,2), layout='constrained')
# add a plot to the Axes ax
ax.plot(np.sin(np.linspace(0, 2*np.pi))
# label the Axes and x and y Axis
ax.set(xlabel= 't [s]', ylabel = 'S [V]', title ='Sine wave')
# Change the face color of the Figure:
fig.set_facecolor('lightsteelblue')

I think the original is a bit too long and also I think we want to encourage set unless they need the individual properties

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ax.set is pretty obscure as a way to shorten things.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But I think we want folks to know about it. I also agree w/ Tim that this should be as short as possible, and probably in a 2 column grid rather than tabs 'cause it's that side by side that really illustrates the difference.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two column is fine, though it looks pretty cramped.

Re ax.set that seems an advanced usage to me, whereas I thought we wanted this to be straightforward? ax.,set also does not allow one to customize anything in the set methods (eg fontsize in title etc), so I'm not sure it should become canonical usage.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of scope here but I think that's a point we're trying to make in all sorts of places - that if you don't need customization we've got this nice method that will do all the things at once, but if you need customization then you've gotta use the specific methods to do so cause we try to scope our functions.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a lot of value in the 1:1 mapping between the lines so am very 👎🏻 on changing to use ax.set.

At least for me clicking between the tabs and seeing what does/does not change is way easier to see the differences than trying to scan between two columns.

@jklymak
Copy link
Member Author

jklymak commented Aug 29, 2023

I also think that since this is a doc regression it should have two approvals.

The example originally came in #19727. It was removed in #26402 without mention of the removal in the PR description, or discussion, on the strength of one review. I'm not clear how re-instating it is considered a regression.

@story645
Copy link
Member

I'm not clear how re-instating it is considered a regression

B/c it was removed and now it's going back? I think if we're thrashing back and forth then it's worth slowing down and giving space for at least one other person to sign off. In this case in particular I think it'd be good if @timhoffm at least saw this PR.

@timhoffm
Copy link
Member

timhoffm commented Aug 30, 2023

The example originally came in #19727. It was removed in #26402 without mention of the removal in the PR description, or discussion

In #26402, I motivated the change:

Reduce the interface description to very compact two-sentence descriptions and refer to the interface page for everything else.

The focus here is to point the users to relevant API resources for the respective interfaces, not to discuss these interfaces in detail. The latter is the task of https://matplotlib.org/devdocs/users/explain/figure/api_interfaces.html

This page is the entry point for the API reference, the collection of all function / class docstrings. Categorizing according to https://documentation.divio.com/ it is information-oriented, not learning-oriented or explanation-oriented.

My train of thought for deciding on the contents of the page is:

  1. In the very basic form, the Modules section would be enough.

  2. However, the user-facing interfaces are what people will need most of the time. Prominently highlighting then in the boxes directs the user to the most relevant content:

    grafik

  3. For people who already know the interfaces, this would be enough. But we know that a lot of users have no clear idea on this. To help them decide between the worlds, we sould give a very rough idea and link to the detailed description if they want to /need to learn more. - But this additional interface description should be as terse as possible because it distracts from the actual relevant links in 2. and 1.

In particular, I believe a visual plot would be harming the cause here. It draws a lot of visual attention and does not explain anything about the API or Interfaces. I would be +/-0 on adding minimal pure code-blocks to the existing interface cards

fig, ax = plt.subplots()
ax.plot(x, y)
ax.set_title('Sample plot')
plt.show()
plt.plot(x, y)
plt.title('Sample plot')
plt.show()

On a general note, the major issue with our documentation is not that it's missing content or explanations. It's structure and guidance that is lacking. IMHO we gain a lot if we focus pages on their primary purpose and strip / link other aspects.

@jklymak
Copy link
Member Author

jklymak commented Aug 30, 2023

I believe a visual plot would be harming the cause here. It draws a lot of visual attention and does not explain anything about the API or Interfaces

I strongly feel the example helps set the context for what is being discussed on this page. Our API is very bizarre in that 95% of it is on the Axes objects we create, and showing a short example of that on a top-level landing page helps orient the reader.

Categorizing according to https://documentation.divio.com/ it is information-oriented, not learning-oriented or explanation-oriented.

Divio is a nice way to think about the purposes of documentation, but I don't think it is a rational way to organize things with pristine separation of the types of information. Information doesn't mean anything without some context.

For others who do not wish to click through:

@timhoffm
Copy link
Member

Information doesn't mean anything without some context.

Fully agree and that's why I added bullet point 3. in my reasoning. The key here is some. Can we agree on the principle that some means "enough to help understanding the main information, but as little as possible to not distract from the main information"? - The judgement call, and where I think we disargee is, is what is "enough".

I strongly feel the example helps set the context for what is being discussed on this page. Our API is very bizarre in that 95% of it is on the Axes objects we create, and showing a short example of that on a top-level landing page helps orient the reader.

For the context, the priority, determined by relevance, is:

  1. Short fundamental description: we agree on this
  2. Code snippet to illustrate how the API looks: as written above, I'm +/-0 on this - I don't think it's essential, but it's compact enough to not distract.
  3. Resulting plot of the code example: The visual plot does not really help in understanding the API. I propose that
    plt.plot(x, y)
    plt.title('Sample plot')
    plt.show()
    
    is self-explanatory enough. An added problem of the visual is that you have to provide fully working code, which means you have to clutter the code with import and data generation, which clearly do not add to understanding the API.
    IMHO this is too much clutter for almost no gain.

@jklymak
Copy link
Member Author

jklymak commented Aug 30, 2023

I think it is a strange aesthetic to just show the code, but not show the code result in a plotting library. Code tends to be a lot easier to parse if you can see its result. You say it's "cluttered", and "distracts". But from what? There is no other content on this page - the rest of this page is just an index (that is repeated verbatim on the left sidebar).

@story645
Copy link
Member

You say it's "cluttered", and "distracts". But from what?

I mean that there's a lot of cognitive overload happening. Your example demonstrates data creation, figure and axes creation, plotting, labeling, and fig saving - and yes that's all very useful and things folks always want to do, but the question is are those concepts we want to be demoing here? Especially for a user who does not know the API, they may get disctracted by creation->plot->label and not focus on the difference between pyplot and axes which is what we want to be highlighting.

@timhoffm
Copy link
Member

I think it is a strange aesthetic to just show the code, but not show the code result in a plotting library.

It depends on what you want to achieve with that code. There are lots of Examples sections in our docstrings that do not generate the plot.

ax.plot(x, y)
ax.set_xlabel('t [s]')
ax.set_ylabel('S [V]')
ax.set_title('Sine wave')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ax.set_title('Sine wave')
ax.set_title('Sine wave (explicit)')

plt.plot(x, y)
plt.xlabel('t [s]')
plt.ylabel('S [V]')
plt.title('Sine wave')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
plt.title('Sine wave')
plt.title('Sine wave (implicit)')

@story645
Copy link
Member

Since #26671 is merged, should this PR be closed? Because merging this PR would undo the work in #26671 that was proposed as an alternative to this PR.

@jklymak
Copy link
Member Author

jklymak commented Sep 20, 2023

The point of this PR was to re-add the figure. #26671 did not re-add the figure, and obviously there is some disagreement about whether figures are desirable in our docs.

@story645 story645 added the status: needs comment/discussion needs consensus on next step label Sep 20, 2023
@story645
Copy link
Member

and obviously there is some disagreement about whether figures are desirable in our docs.

The disagreement is about whether a figure in this specific document clarifies or obfuscates the intended takeaway from the document, which is why #26671 added code to highlight the differences instead of a figure.

I think at this point we probably need to have a full discussion cause otherwise we'll end up w/ more add-remove cycles, so I'm gonna put up a block until that happens.

Copy link
Member

@story645 story645 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wary of an add-remove-add-remove cycle happening, so blocking until broader consensus is achieved.

@tacaswell
Copy link
Member

I think the longer example with an image is actually quite helpful here, particularly as written with the 1:1 mapping of the lines of code. By flipping back and forth between the tabs it is easy to see what the required changes are and than you get the same output either way (the only change I would suggest would be to make the titles different so it is clear that the image is changing between the tabs, currently the only way to tell is to mouse over them and see the urls are different).

We (the developers) know that the APIs are interchangeable, but that may not be clear to all of our users so showing that you can get exactly the same output using either path is a good thing. It is also good to show that the explicit API is not also necessarily more verbose.


We probably should re-write some of the examples in https://matplotlib.org/devdocs/users/explain/figure/api_interfaces.html using this 2 tab style.

@story645
Copy link
Member

By flipping back and forth between the tabs it is easy to see what the required changes are

Having to flip back and forth between tabs to see the difference itself obfuscates the difference because it requires the learner to hold the not visible code in memory while looking at the visible one - and that's a lot of cognitive overload for someone who may not know what they're supposed to be holding in their head while flipping between the tabs.

I love tabs and think they're fantastic for presenting mutually exclusive - you can either do this thing or that thing and not both - information. But I don't think the goal on this page is necessarily to get folks to pick one - my guess is they'll go w/ the one they know cause that's easiest - but to see both so they can compare. And tables are better for comparison. Here's one example of universal design folks talking about tabs for reading flow controls universaldesign.ie

@tacaswell
Copy link
Member

tabs

At least to my eye the tabs really highlight exactly what is changing between the two and widely spaced (or vertically stacked) code blocks are much much harder to compare.

@story645
Copy link
Member

and widely spaced (or vertically stacked) code blocks are much much harder to compare.

Yes, which is why in the current iteration of the page there are only 3 lines of code: it's condensed enough to fit on a phone screen: Screenshot_20230921-115113.png

@timhoffm
Copy link
Member

timhoffm commented Sep 22, 2023

My major concerns:

  • The example code is too complex. One can see 90% of the difference in a 3-4 line example as well.
    This should only be a very high-level overview. We link to the detailed interface description, which discusses all the details.
  • Back and forth switching is cumbersome, and people have to understand that they should do it to see the difference.

I still find the current side-by-side solution really concise:

image

I don't think the rendered figure is relevant, but if you consider it valuable, I suggest to make a full-width div below the two columns:

Both example codes yield the same figure:

[rendered figure]

@jklymak
Copy link
Member Author

jklymak commented Sep 22, 2023

At the end of the day, these are all taste issues. I think the final documentation say is @tacaswell, so he should just state his preference.

I will point out some usability issues with the current links - I think that Figure should be changed back to matplotlib.figure because the first links to the init docs https://matplotlib.org/stable/api/figure_api.html#matplotlib.figure.Figure which no one ever uses, and the latter links to the top of the API page, which has the TOC for Figure methods that people do use. Same for Axes/matplotlib.axes.

@story645
Copy link
Member

story645 commented Sep 24, 2023

At the end of the day, these are all taste issues

I think they're best practices issues.

  • tabs are best suited for mutually exclusive (pip or conda) or sequential (stage 1, stage 2, etc) information.
    On the other hand generally it's much easier to compare information when it is side by side- consider a paper where figure A and B need to be compared and whether you'd place them right next to each other as subbplots or place figure B six pages away from figure A.

  • too much information starts obfuscating what's trying to be communicated and leads to worse retention - what's the minimum folks need to hold in their head to see that the APIs differ. We have other pages in the docs where we show all the things, how does doing that here help to more effectively communicate the differences between the two APIs?

I think @timhoffm's suggestion of putting one figure at the buttom of the grid showing that both code blocks produce the same visual is a good compromise in terms of having a visual.

@jklymak
Copy link
Member Author

jklymak commented Sep 24, 2023

Again, whether something looks better tabbed or side-by-side is not subject to any hard and fast rules. FWIW I prefer side-by-side, but I wouldn't claim that my preference is "right" or a "best-practice". I had a slight preference for tabbed here just because it was more compact.

We have other pages in the docs where we show all the things, how does doing that here help to more effectively communicate the differences between the two APIs?

The original impetus to improving this page (#19727), and adding an example, is that this is the top-level API landing page, arrived at via "Reference". Lots of people who think they are familiar with Matplotlib probably land on "Reference", and then don't know where to go. I distinctly remember getting started with our API, and not understanding that most of it was in the Axes class. So while I knew that there was such a thing as ax.plot I did not know where to find its documentation, other than pyplot.plot, which is not quite the same thing.

In my mind, the goal of these improvements was not primarily to "communicate the difference between the two APIs". Indeed the original version of this had all the different API discussion below the TOC (https://matplotlib.org/3.5.3/api/index.html). Rather the goal was to provide a quick guide/reminder of our API using code snippets, and their results, that user may have seen elsewhere, be that in our docs, stack overflow etc. I agree that the difference between the APIs needs to be communicated, but as a small part of the larger goal of providing a guide the API reference.

@story645
Copy link
Member

story645 commented Sep 24, 2023

FWIW I prefer side-by-side

Why do you prefer it? And do you think the users reading this page may prefer it for the same reasons?

The choice of tabs or tables creates different reading/learning experiences for comparing A and B:

  • A and B next to each other
  • flipping back and forth between A and B

but I wouldn't claim that my preference is "right" or a "best-practice".

but as a small part of the larger goal of providing a guide the API reference.

How does adding data generation and a few more set methods do that? I mean this in earnest, as the current code on the page shows the three major components of making a graph that Matplotlib is in charge of:

  1. setup drawing area
  2. draw plot
  3. label things

I especially worry about including data creation b/c we already have enough trouble getting folks to realize that Matplotlib is just the graphs part, and I don't think putting Numpy on our API reference page will help.

This is also making me think that what may be a better way to improve that page would be to put modules in alphabetical order in a tab/different page and reorganize the modules list so that is instead grouped into some reasonable categories so folks who do not know what we call things could still navigate to the right modules. Something like:

@jklymak
Copy link
Member Author

jklymak commented Sep 24, 2023

The data creation is pretty trivial - I hope we can assume our readers have basic familiarity with numpy. Further, it makes it clear what kind of objects x and y are, versus completely unspecified.

As for the setters, I think labelling a plot is best practice and common enough to warrant a couple of lines here.

As for tabs versus side by side, in addition to size issues, we are trying to discourage one of the APIs - recall the original version didn't even have the pyplot API example. In fact for the purpose of indexing I'm not even sure it's needed at all since the pyplot API is easy to find

I wouldn't object to re organizing the API on the page, but that is somewhat orthogonal here

@story645
Copy link
Member

story645 commented Sep 24, 2023

The data creation is pretty trivial - I hope we can assume our readers have basic familiarity with numpy.

They may, but also may not realize that it's not built into Matplotlib. (ETA: bootcamp curricula in particular have an unfortunate tendency to lump the libraries together).

Further, it makes it clear what kind of objects x and y are, versus completely unspecified.

But isn't the point here that .plot(x,y) will work on almost any type of x,y? and also I think of this code as almost template code (basic usage pattern is what you called it in #26623) -> [create]->[visualize]->[label]
with the goal being that finding one of the creation functions or plot functions or labeling functions will find the whole batch of 'em?

, we are trying to discourage one of the APIs - recall the original version didn't even have the pyplot API example. In fact for the purpose of indexing I'm not even sure it's needed at all since the pyplot API is easy to find

this table exists to orient users to what we mean by API/OO/explicit vs pyplot/implicit API -> this is the back and forth in #26623 - so that they can find the right module. If they need usage guidance, they should be directed to the user guide where all this stuff is explained. Granted, I dunno that I'd be opposed to putting everything in tabs (so each column of the table gets integrated into a tab) but my guess is that the folks who most need the definitions would also benefit most from seeing them side by side.

As for the setters, I think labelling a plot is best practice and common enough to warrant a couple of lines here.

100% agree it's best practice, but this page isn't supposed to be a "how to use matplotlib" page.

@jklymak
Copy link
Member Author

jklymak commented Sep 24, 2023

Again, we disagree fundamentally on most of these points, none of which have an objective criteria. Someone, presumably @tacaswell, will have to decide what they want this page to look like.

@story645
Copy link
Member

Someone, presumably @tacaswell, will have to decide what they want this page to look like.

Or the API docs lead, who is @timhoffm

@jklymak
Copy link
Member Author

jklymak commented Sep 25, 2023

Sure, if that falls under that bailiwick, I'll close this.

@jklymak jklymak closed this Sep 25, 2023
@jklymak jklymak deleted the doc-re-example-api branch September 25, 2023 00:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants