Skip to main content
`Ctrl`+`K`

# How to contribute to the NumPy documentation

This guide will help you decide what to contribute and how to submit it to the official NumPy documentation.

## Documentation team meetings

The NumPy community has set a firm goal of improving its documentation. We hold regular documentation meetings on Zoom (dates are announced on the numpy-discussion mailing list), and everyone is welcome. Reach out if you have questions or need someone to guide you through your first steps – we’re happy to help. Minutes are taken on hackmd.io and stored in the NumPy Archive repository.

## What’s needed

The NumPy Documentation has the details covered. API reference documentation is generated directly from docstrings in the code when the documentation is built. Although we have mostly complete reference documentation for each function and class exposed to users, there is a lack of usage examples for some of them.

What we lack are docs with broader scope – tutorials, how-tos, and explanations. Reporting defects is another way to contribute. We discuss both.

## Contributing fixes

We’re eager to hear about and fix doc defects. But to attack the biggest problems we end up having to defer or overlook some bug reports. Here are the best defects to go after.

Top priority goes to technical inaccuracies – a docstring missing a parameter, a faulty description of a function/parameter/method, and so on. Other “structural” defects like broken links also get priority. All these fixes are easy to confirm and put in place. You can submit a pull request (PR) with the fix, if you know how to do that; otherwise please open an issue.

Typos and misspellings fall on a lower rung; we welcome hearing about them but may not be able to fix them promptly. These too can be handled as pull requests or issues.

Obvious wording mistakes (like leaving out a “not”) fall into the typo category, but other rewordings – even for grammar – require a judgment call, which raises the bar. Test the waters by first presenting the fix as an issue.

Some functions/objects like numpy.ndarray.transpose, numpy.array etc. defined in C-extension modules have their docstrings defined separately in _add_newdocs.py

## Contributing new pages

Your frustrations using our documents are our best guide to what needs fixing.

If you write a missing doc you join the front line of open source, but it’s a meaningful contribution just to let us know what’s missing. If you want to compose a doc, run your thoughts by the mailing list for further ideas and feedback. If you want to alert us to a gap, open an issue. See this issue for an example.

If you’re looking for subjects, our formal roadmap for documentation is a NumPy Enhancement Proposal (NEP), NEP 44 — Restructuring the NumPy documentation. It identifies areas where our docs need help and lists several additions we’d like to see, including Jupyter notebooks.

### Documentation framework

There are formulas for writing useful documents, and four formulas cover nearly everything. There are four formulas because there are four categories of document – `tutorial`, `how-to guide`, `explanation`, and `reference`. The insight that docs divide up this way belongs to Daniele Procida and his Diátaxis Framework. When you begin a document or propose one, have in mind which of these types it will be.

### NumPy tutorials

In addition to the documentation that is part of the NumPy source tree, you can submit content in Jupyter Notebook format to the NumPy Tutorials page. This set of tutorials and educational materials is meant to provide high-quality resources by the NumPy project, both for self-learning and for teaching classes with. These resources are developed in a separate GitHub repository, numpy-tutorials, where you can check out existing notebooks, open issues to suggest new topics or submit your own tutorials as pull requests.

### More on contributing

Don’t worry if English is not your first language, or if you can only come up with a rough draft. Open source is a community effort. Do your best – we’ll help fix issues.

Images and real-life data make text more engaging and powerful, but be sure what you use is appropriately licensed and available. Here again, even a rough idea for artwork can be polished by others.

For now, the only data formats accepted by NumPy are those also used by other Python scientific libraries like pandas, SciPy, or Matplotlib. We’re developing a package to accept more formats; contact us for details.

NumPy documentation is kept in the source code tree. To get your document into the docbase you must download the tree, build it, and submit a pull request. If GitHub and pull requests are new to you, check our Contributor Guide.

Our markup language is reStructuredText (rST), which is more elaborate than Markdown. Sphinx, the tool many Python projects use to build and link project documentation, converts the rST into HTML and other formats. For more on rST, see the Quick reStructuredText Guide or the reStructuredText Primer

## Contributing indirectly

If you run across outside material that would be a useful addition to the NumPy docs, let us know by opening an issue.

You don’t have to contribute here to contribute to NumPy. You’ve contributed if you write a tutorial on your blog, create a YouTube video, or answer questions on Stack Overflow and other sites.

## Documentation style

### User documentation

- In general, we follow the Google developer documentation style guide for the User Guide.

- NumPy style governs cases where:

  - Google has no guidance, or

  - We prefer not to use the Google style

  Our current rules:

  - We pluralize index as indices rather than indexes, following the precedent of `numpy.indices`.

  - For consistency we also pluralize matrix as matrices.

- Grammatical issues inadequately addressed by the NumPy or Google rules are decided by the section on “Grammar and Usage” in the most recent edition of the Chicago Manual of Style.

- We welcome being alerted to cases we should add to the NumPy style rules.

### Docstrings

When using Sphinx in combination with the NumPy conventions, you should use the `numpydoc` extension so that your docstrings will be handled correctly. For example, Sphinx will extract the `Parameters` section from your docstring and convert it into a field list. Using `numpydoc` will also avoid the reStructuredText errors produced by plain Sphinx when it encounters NumPy docstring conventions like section headers (e.g. `-------------`) that sphinx does not expect to find in docstrings.

It is available from:

- numpydoc on PyPI

- numpydoc on GitHub

Note that for documentation within NumPy, it is not necessary to do `import numpy as np` at the beginning of an example.

Please use the `numpydoc` formatting standard as shown in their example.

### Documenting C/C++ code

NumPy uses Doxygen to parse specially-formatted C/C++ comment blocks. This generates XML files, which are converted by Breathe into RST, which is used by Sphinx.

It takes three steps to complete the documentation process:

#### 1. Writing the comment blocks

Although there is still no commenting style set to follow, the Javadoc is more preferable than the others due to the similarities with the current existing non-indexed comment blocks.

Note

Please see “Documenting the code”.

This is what Javadoc style looks like:

    /**
     * This a simple brief.
     *
     * And the details goes here.
     * Multi lines are welcome.
     *
     * @param  num  leave a comment for parameter num.
     * @param  str  leave a comment for the second parameter.
     * @return      leave a comment for the returned value.
     */
    int doxy_javadoc_example(int num, const char *str);

And here is how it is rendered:

int doxy_javadoc_example(int num, const char *str)

  This a simple brief.

  And the details goes here. Multi lines are welcome.

  Parameters:

    - num – leave a comment for parameter num.

    - str – leave a comment for the second parameter.

  Returns:

    leave a comment for the returned value.

For line comment, you can use a triple forward slash. For example:

    /**
     *  Template to represent limbo numbers.
     *
     *  Specializations for integer types that are part of nowhere.
     *  It doesn't support with any real types.
     *
     *  @param Tp Type of the integer. Required to be an integer type.
     *  @param N  Number of elements.
    */
    template<typename Tp, std::size_t N>
    class DoxyLimbo {
     public:
        /// Default constructor. Initialize nothing.
        DoxyLimbo();
        /// Set Default behavior for copy the limbo.
        DoxyLimbo(const DoxyLimbo<Tp, N> &l);
        /// Returns the raw data for the limbo.
        const Tp *data();
     protected:
        Tp p_data[N]; ///< Example for inline comment.
    };

And here is how it is rendered:

template<typename Tp, std::size_t N>
class DoxyLimbo

  Template to represent limbo numbers.

  Specializations for integer types that are part of nowhere. It doesn’t support with any real types.

  Param Tp:

    Type of the integer. Required to be an integer type.

  Param N:

    Number of elements.

  Public Functions

  DoxyLimbo()

    Default constructor. Initialize nothing.

  DoxyLimbo(const DoxyLimbo<Tp, N> &l)

    Set Default behavior for copy the limbo.

  const Tp *data()

    Returns the raw data for the limbo.

  Protected Attributes

  Tp p_data[N]

    Example for inline comment.

##### Common Doxygen Tags:

Note

For more tags/commands, please take a look at https://www.doxygen.nl/manual/commands.html

`@brief`

Starts a paragraph that serves as a brief description. By default the first sentence of the documentation block is automatically treated as a brief description, since option JAVADOC_AUTOBRIEF is enabled within doxygen configurations.

`@details`

Just like `@brief` starts a brief description, `@details` starts the detailed description. You can also start a new paragraph (blank line) then the `@details` command is not needed.

`@param`

Starts a parameter description for a function parameter with name <parameter-name>, followed by a description of the parameter. The existence of the parameter is checked and a warning is given if the documentation of this (or any other) parameter is missing or not present in the function declaration or definition.

`@return`

Starts a return value description for a function. Multiple adjacent `@return` commands will be joined into a single paragraph. The `@return` description ends when a blank line or some other sectioning command is encountered.

`@code/@endcode`

Starts/Ends a block of code. A code block is treated differently from ordinary text. It is interpreted as source code.

`@rst/@endrst`

Starts/Ends a block of reST markup.

##### Example

Take a look at the following example:

    /**
     * A comment block contains reST markup.
     * @rst
     * .. note::
     *
     *   Thanks to Breathe_, we were able to bring it to Doxygen_
     *
     * Some code example::
     *
     *   int example(int x) {
     *       return x * 2;
     *   }
     * @endrst
     */
    void doxy_reST_example(void);

And here is how it is rendered:

void doxy_reST_example(void)

  A comment block contains reST markup.

  Some code example:

      int example(int x) {
          return x * 2;
      }

  Note

  Thanks to Breathe, we were able to bring it to Doxygen

#### 2. Feeding Doxygen

Not all headers files are collected automatically. You have to add the desired C/C++ header paths within the sub-config files of Doxygen.

Sub-config files have the unique name `.doxyfile`, which you can usually find near directories that contain documented headers. You need to create a new config file if there’s not one located in a path close(2-depth) to the headers you want to add.

Sub-config files can accept any of Doxygen configuration options, but do not override or re-initialize any configuration option, rather only use the concatenation operator “+=”. For example:

    # to specify certain headers
    INPUT += @CUR_DIR/header1.h \
             @CUR_DIR/header2.h
    # to add all headers in certain path
    INPUT += @CUR_DIR/to/headers
    # to define certain macros
    PREDEFINED += C_MACRO(X)=X
    # to enable certain branches
    PREDEFINED += NPY_HAVE_FEATURE \
                  NPY_HAVE_FEATURE2

Note

@CUR_DIR is a template constant returns the current dir path of the sub-config file.

#### 3. Inclusion directives

Breathe provides a wide range of custom directives to allow converting the documents generated by Doxygen into reST files.

Note

For more information, please check out “Directives & Config Variables”

##### Common directives:

`doxygenfunction`

This directive generates the appropriate output for a single function. The function name is required to be unique in the project.

    .. doxygenfunction:: <function name>
        :outline:
        :no-link:

Checkout the example to see it in action.

`doxygenclass`

This directive generates the appropriate output for a single class. It takes the standard project, path, outline and no-link options and additionally the members, protected-members, private-members, undoc-members, membergroups and members-only options:

    .. doxygenclass:: <class name>
       :members: [...]
       :protected-members:
       :private-members:
       :undoc-members:
       :membergroups: ...
       :members-only:
       :outline:
       :no-link:

Checkout the doxygenclass documentation for more details and to see it in action.

`doxygennamespace`

This directive generates the appropriate output for the contents of a namespace. It takes the standard project, path, outline and no-link options and additionally the content-only, members, protected-members, private-members and undoc-members options. To reference a nested namespace, the full namespaced path must be provided, e.g. foo::bar for the bar namespace inside the foo namespace.

    .. doxygennamespace:: <namespace>
       :content-only:
       :outline:
       :members:
       :protected-members:
       :private-members:
       :undoc-members:
       :no-link:

Checkout the doxygennamespace documentation for more details and to see it in action.

`doxygengroup`

This directive generates the appropriate output for the contents of a doxygen group. A doxygen group can be declared with specific doxygen markup in the source comments as covered in the doxygen grouping documentation.

It takes the standard project, path, outline and no-link options and additionally the content-only, members, protected-members, private-members and undoc-members options.

    .. doxygengroup:: <group name>
       :content-only:
       :outline:
       :members:
       :protected-members:
       :private-members:
       :undoc-members:
       :no-link:
       :inner:

Checkout the doxygengroup documentation for more details and to see it in action.

### Legacy directive

If a function, module or API is in legacy mode, meaning that it is kept around for backwards compatibility reasons, but is not recommended to use in new code, you can use the `.. legacy::` directive.

By default, if used with no arguments, the legacy directive will generate the following output:

Legacy

This submodule is considered legacy and will no longer receive updates. This could also mean it will be removed in future NumPy versions.

We strongly recommend that you also add a custom message, such as a new API to replace the old one:

    .. legacy::

       For more details, see :ref:`distutils-status-migration`.

This message will be appended to the default message and will create the following output:

Legacy

This submodule is considered legacy and will no longer receive updates. This could also mean it will be removed in future NumPy versions. For more details, see Status of numpy.distutils and migration advice.

Finally, if you want to mention a function, method (or any custom object) instead of a submodule, you can use an optional argument:

    .. legacy:: function

This will create the following output:

Legacy

This function is considered legacy and will no longer receive updates. This could also mean it will be removed in future NumPy versions.

## Documentation reading

- The leading organization of technical writers, Write the Docs, holds conferences, hosts learning resources, and runs a Slack channel.

- “Every engineer is also a writer,” says Google’s collection of technical writing resources, which includes free online courses for developers in planning and writing documents.

- Software Carpentry’s mission is teaching software to researchers. In addition to hosting the curriculum, the website explains how to present ideas effectively.