Repository: hyperspy/rosettasciio (language: python)

Issue:
Logo for RosettaSciIO
Was just playing with an idea for a logo for RosettaSciIO, based on some hieroglyphs (see https://de.wikipedia.org/wiki/%C3%84gyptische_Hieroglyphen). Symbols for R S TT I are used:

![image](https://user-images.githubusercontent.com/7076057/180884396-5540f454-cfaa-4d40-9629-8c90c96a055a.png)

Bright and dark versions, with either grayshades in the text or pure b/w.
Doc and import improvement
As discussed in https://github.com/hyperspy/rosettasciio/issues/38. This changes the import and docstring/documentation for the `bruker` and `blockfile` format as examples for discussion.

### Progress of the PR
- [x] Change implemented (can be split into several points),
- [x] update docstring (if appropriate),
- [x] update user guide (if appropriate),
- [ ] add an changelog entry in the `upcoming_changes` folder (see [`upcoming_changes/README.rst`](https://github.com/hyperspy/rosettasciio/blob/main/upcoming_changes/README.rst)),
- [ ] Check formatting changelog entry in the `readthedocs` doc build of this PR (link in github checks)
- [ ] add tests,
- [x] ready for review.

### Minimal example of the bug fix or the new feature
```python
from rsciio.msa import api
api.file_reader("your_msa_file.msa")
# Your new feature...
```
Note that this example can be useful to update the user guide.


Doc and import improvement #4
### Description of the change
Follow up on #47, #59, and #64 adresses #38. For readers with folder names from I...M+dens.

### Progress of the PR
- [x] Change implemented (can be split into several points),
- [x] update docstring (if appropriate),
- [x] update user guide (if appropriate),
- [ ] add an changelog entry in the `upcoming_changes` folder (see [`upcoming_changes/README.rst`](https://github.com/hyperspy/rosettasciio/blob/main/upcoming_changes/README.rst)),
- [ ] Check formatting changelog entry in the `readthedocs` doc build of this PR (link in github checks)
- [x] add tests,
- [ ] ready for review.


Consolidate docstring and documentation
The problem is also, that it is not consistent how detailed the `file_reader` and `file_writer` docstrings are. For some formats more is documented in the user guide, for others more in the docstrings.

_Originally posted by @jlaehne in https://github.com/hyperspy/rosettasciio/pull/35#discussion_r968012172_


Discussion / hints:
Wikimedia has a nice 3D model of the real rosetta stone: https://commons.wikimedia.org/wiki/File:Rosetta_Stone.stl Perhaps we could work that into a logo idea somehow? It would get across the idea of "translation"
Yes, thought about at least playing with the contour of the stone, which I find clearer than the 3D object (a bit complicated for a logo):

![rosettasciio-logo-workflow](https://user-images.githubusercontent.com/7076057/181112222-42de2ce2-16cb-40c8-b777-c5eb8a2766d4.svg)

The 3D object would be under [CC-BY-NC-SA](https://www.myminifactory.com/object-licensing), while the contour was derived from a public domain work: https://commons.wikimedia.org/wiki/File:Rosetta_Stone_BW.jpeg

Edit: Included file is now the original `.svg`.

Edit 2: And here again the `.png`, in case the svg is not properly displayed due to missing fonts (Font is `Open Sans Condensed`)

![image](https://user-images.githubusercontent.com/7076057/185058033-2734446b-f981-499a-a7ae-8111ff18cf58.png)

Thanks @jlaehne, For a square logo, personally, I find line 4, column 1 and 3 in https://github.com/hyperspy/rosettasciio/issues/5#issuecomment-1195326090 quite nice. :) 

It is possible to make one that work on both dark and light background?
Thanks for these @jlaehne! My concern is that the "hieroglyphs" don't make it obvious what this library does or is even called. I like the concept of using the stone, but maybe we make the name more explicit? 

Some quick mockups:

(I actually quite like this; The "IO" highlights that input/output is the focus)
![image](https://user-images.githubusercontent.com/1278301/184962027-0cbacda3-79c6-4f59-8e88-fb9e831f2e6c.png)

(I don't love this next one... but as more of a logo idea)
![image](https://user-images.githubusercontent.com/1278301/184962300-1e11b661-a27f-4e35-b92f-90b10c1eff71.png)

(maybe we make the acronym 'RSIO'?)
![image](https://user-images.githubusercontent.com/1278301/184962527-993d7252-3eb4-42be-8d2b-220b04f49b8b.png)

Here's an SVG with those mockups in case anyone else wants to play:

![rosettasciio_logo_mockups](https://user-images.githubusercontent.com/1278301/184962748-93fcbbdf-3213-4454-9909-98551e17efc6.svg)


@jat255 Those look pretty good.  I think the top one is the best as far as maybe something like a banner.  As far as a logo goes I think that we could probably just have the Rossetta stone with IO on it.

Maybe we think about adding some science "hieroglyphs" so that all parts of the name are part of the logo, something like a Bohr model of atom, a bandgap or a beaker etc. 
I still like the idea of some real hyroglyphs, but for clarity, which should be the main idea of a logo, the 'stone + IO' is probably the best (and also works well as a thumbnail), with 'RosettaSci' added for a banner.

Playing with some greek letters commonly used in science as a replacement to get in the language tweek, as well as with the idea of @ericpre of a background-agnostic logo:
![image](https://user-images.githubusercontent.com/7076057/185063312-3874736f-36a1-4034-ba6d-1d483587539b.png)

And the SVG (including the vector trace of the stone, which we should use for best quality): 
![rosettasciio-logo-workflow2](https://user-images.githubusercontent.com/7076057/185064005-2abd8548-d4a0-47e6-8797-dabbf5403c39.svg)


Lets narrow down the choices for the Logo, please everyone vote using thumbs up/down on the following questions:
Black/white and white/black (thumbs up)
versus background-agnostic gray scale (thumbs down)
greek letters instead of a/e (thumbs up)
versus stick with latin letters (thumbs down)
Font from png in https://github.com/hyperspy/rosettasciio/issues/5#issuecomment-1217620339 - jlaehne (thumbs up)
versus font from png in https://github.com/hyperspy/rosettasciio/issues/5#issuecomment-1217054931 - jat255 (thumbs down)
@jordiferrero, interested to do some of your magic? :) 
Thanks @ericpre for flagging this :-) I really love the suggestions already proposed. In fact, I was envisioning the exact same idea... the stone with the "IO" as writing.
I personally love simple flat design. So I took @jat255 [simple design](https://github.com/hyperspy/rosettasciio/issues/5#issuecomment-1217054931) and simply added the "Python" snake in the S of RosettaSci... as a hint of it being a Python package. Attached the .svg files in case you want to add it.

_Note: I did not know what font you used, so I vectorised the font, that's why it's not prefect..._

<img width="596" alt="logo@2x" src="https://user-images.githubusercontent.com/9082687/189213947-ab97a131-2715-49ab-9f11-b767f8ea2ba6.png">
<img width="199" alt="icon@2x" src="https://user-images.githubusercontent.com/9082687/189213950-00f65c97-c228-4e58-884c-545f561014b7.png">
SVG file:
![logo](https://user-images.githubusercontent.com/9082687/189214562-8a7a18b1-5b49-4b37-94b9-1825189c633f.svg)

> I did not know what font you used

@jordiferrero It's Lato: https://www.latofonts.com/
Thank you @jordiferrero. Time for a poll of two questions then!
normal S (thumbs up)
S with snake (thumbs down)
IO only inside the stone (thumbs up)
more letters in the stone (RSIO, RScIO) (thumbs down)
don't know if it's a problem really, but might there be people reading "IO" as "ten"?
Yes good point, it may be worth considering `I/O` or lower case `io`. Can someone have a go at making different versions, please? :)
> Yes good point, it may be worth considering `I/O` or lower case `io`. Can someone have a go at making different versions, please? :)

There should be fonts, like the one of these comments, which are Sans Serif, but still have short horizontal lines on the upper case I, which would make it clear to be IO and not 10.
Though, I do like Lento, @jordiferrero would it be possible to add the horizontal lines on the I (like in Tahoma, Verdana, Noto, Segoe UI) on your design otherwise keeping the font?
> Though, I do like Lento, @jordiferrero would it be possible to add the horizontal lines on the I (like in Tahoma, Verdana, Noto, Segoe UI) on your design otherwise keeping the font?

![image](https://user-images.githubusercontent.com/9082687/189635849-f7416279-b058-43b9-97f2-ca3c30ae8657.png)

Some iterations on your ideas
+1 for the original (f)—I just find its minimalism more appealing.

Would it be possible (and good) to keep the space between characters uniform to emphasize that it is a single word? Currently IO seems separated from the rest.
Talking about minimalism, what about remove "osetta" from the logo i.e. RSciIO with IO inside the stone?
> what about remove "osetta" from the logo

As a logo for use in presentations, documentation, etc., I'd rather have the full name in the logo. I was partial to a smaller "RS/IO" in the stone as a "square" format logo (I also think the import should be `rsio`, but that ship has probably sailed :smile: ), but I understand if that's not a shared opinion. 
> (I also think the import should be `rsio`, but that ship has probably sailed)

v0.1 has not been released yet, so I would not say that it has sailed, but we should nail it now.

The double 'i' in the import is prone to typos, so that would be an argument for the even shorter version.

I agree that it is worth considering `rsciio` versus `rsio`, as it is typo prone.

When asking around about `IO` versus `io`, people who are not familiar with what `IO` means read it as 10... so even if option f is the one I prefer, I think the best is option d.
The problem with `io` in the logo is that it changes the "official" style of the name from RosettaSciIO to RosettaSciio. Personally, I very much prefer the former.
Yes, I know, but the fact that everyone (4-5 people) that I have asked read it as 10, it did put me off from option f!
As the `io` is in the stone and is distinctive from the rest of the name, I think this is fine and a good compromise.
Based off the other discussion, I agree that lower-case is probably better for the logo. I'm partial to either *b* or *d*. One issue with *d* to me is that the two "i" characters right next to each other are slightly different size, which is a bit jarring. *b* utilizes a different font, so it's not so obvious or off-putting being a different size.
> One issue with _d_ to me is that the two "i" characters right next to each other are slightly different size, which is a bit jarring

Yes indeed, can it be fixed? :)
A remark regarding lowercase `io`: that's not an acronym but a [moth](https://en.wikipedia.org/wiki/Automeris_io). Here is its chenille, that, now that we are at it, could replace the python in the logo ;)  ![io chenille](https://upload.wikimedia.org/wikipedia/commons/8/87/Caterpillar_in_Gemini_Springs%2C_Florida_-_Flickr_-_Andrea_Westmoreland.jpg)?
> that's not an acronym but a [moth](https://en.wikipedia.org/wiki/Automeris_io)

It's also a moon! https://en.wikipedia.org/wiki/Io_(moon)
@francisco-dlp Here is the change in logo f. The spacing between the lower case i and the higher case I is x3 that of the space between the c and the i in "Sci". I have reduced it to what it was before. The reason the spacing is not x1 is that the black stone background acts as a "character" and you need a bit of extra spacing otherwise the I cannot be read.

![image](https://user-images.githubusercontent.com/9082687/190897907-548962c2-cdc6-4b7e-99a8-77565e622917.png)

@jat255 @ericpre Here are versions b-d with improved spacing and sizing.
![image](https://user-images.githubusercontent.com/9082687/190898619-bc003fd1-5b05-4d1a-908c-1dd797d6b92d.png)

I personally prefer the lower case ones (b first, then d). I also asked some colleagues and they read 10 instead of IO...


Finally, here is a mock for the shorter versions (I don't particularly like any of them more than the previous designs)...
![image](https://user-images.githubusercontent.com/9082687/190898986-32da7207-195b-4211-bd5b-974b311b1ac9.png)

I find it weird to have two different lower case `i` in version b) and still see the general problem with having lowercase in the name of these cenral letters.
To resolve the issue with the 10, I still tend towards e) - potentially with less thick 'serifs' or even slightly slanted ones:

![image](https://user-images.githubusercontent.com/7076057/190923980-c75add9e-b3a7-4c28-a224-ba44b5b27403.png)
(of course the snake needs to be added still)


I quite like @jordiferrero's new version (b). Using a different font further accentuates that "io" is an important part of the package, and using a monospaced serif font goes with the "programming" theme. 

I do not care for the serif capitalized "IO" (sorry @jlaehne!) 
This is becoming the most contentious issue in HyperSpy's history...

-1 for lowercase `io`: while it solves the confusion with 10, it makes it harder to understand what `io` means. Also, I am with @jlaehne, I find it less aesthetically pleasing. Therefore, if we must solve the confusion with 10, just like @jlaehne,  +1 for version e).

Regarding short vs long version, there are multiple options:

| | Name | Library | Logo |
| - | -------- | --------- | ------- |
| a | RosettaSciIO | rosettasciio | RosettaSciIO |
| b / b2 | RosettaSciIO | rsciio / rsio | RosettaSciIO |
| c / c2 | RosettaSciIO | rsciio / rsio | RSciIO / RSIO |
| d / d2 | RSciIO / RSIO | rsciio / rsio | RSciIO / RSIO |

+1 for a) and c)
Another for the IO in the logo is adding a dot of top of the I, like this **İ**.
I agree that variant e) is a good compromise:
- it is capitalised - in line with the name
- it can't be misread as 10

I was initially put off by using different fonts but as @jat255 mentioned [above](https://github.com/hyperspy/rosettasciio/issues/5#issuecomment-1250387628), it is actually useful to make it more distinctive.

Even if this is a bit tedious, it is worth taking the time to get it as good as we can from the start. In any case, this can be improved later, as this wouldn't be set in stone - pun intended! ;)
Ok, so I *really* don't like options `e` and `f` (sorry to be difficult). It's not that the `IO` is different, it's that it's a completely different font and the serifs on the `I` are unbalanced with the rest of the logo.

To be difficult, here's option (g), which is using a bold monospace font (Fira Code) the whole way through, so there's no confusion with `1` vs `I`, but it's a consistent font throughout (this might not work so well with the "snake", but I'm okay losing that):

![image](https://user-images.githubusercontent.com/1278301/191051138-70b4451f-db92-444d-a037-f5b3f53f2915.png)

SVG: ![184962748-93fcbbdf-3213-4454-9909-98551e17efc6](https://user-images.githubusercontent.com/1278301/191051242-606de97d-20c1-470f-a6fb-b0a29a355498.svg)

Here's an alternative with the "Consolas" font:

![image](https://user-images.githubusercontent.com/1278301/191051976-b7b1f05c-bdcf-4a0a-8f58-244767c3fc45.png)

SVG: 
![184962748-93fcbbdf-3213-4454-9909-98551e17efc6](https://user-images.githubusercontent.com/1278301/191052022-c082a249-4632-4b7f-b553-c26b6d27383e.svg)


I found it OK to modulate Lato, because in principle I did like Lato and there are other Sans Serif fonts with such an I, e.g. "Segoe UI", "Sen", "Amble", "Antic Sans":

![image](https://user-images.githubusercontent.com/7076057/191069553-dd5d9506-1724-4552-abda-b37ec0b48517.png)

But I could also live with the Code fonts you propose.
I find that Antic Sans goes well with the ancient roots of the project.
> I found it OK to modulate Lato, because in principle I did like Lato and there are other Sans Serif fonts with such an I, e.g. "Segoe UI", "Sen", "Amble", "Antic Sans":
> 
> ![image](https://user-images.githubusercontent.com/7076057/191069553-dd5d9506-1724-4552-abda-b37ec0b48517.png)
> 
> But I could also live with the Code fonts you propose.

Perfect. It seems we are now converging. I would suggest using the thicker fonts because (i) it works better for small logos + miniaturizations and (ii) it allows for the addition of the snake (which I am a big fan of). I like Amber more of these 3...

If you want thicker fonts, I even found a few more ;-) To make the choice even harder ( I did not like the squared dot on the i for Amble):

![image](https://user-images.githubusercontent.com/7076057/191259821-f6f1d451-0da8-4b6b-9deb-af43489458bf.png)


I like Noto's I, +1 for it.
I prefer the straight serifs, but happy to put it to a vote. I'm good with eitehr Radio Canada or Harmattan. Here it is with some tweaked sizing on the `IO` part (`I` is exact same height as the `R` and `S`):

![image](https://user-images.githubusercontent.com/1278301/191557340-ca3ee1e2-501c-4899-87f8-fa4a9fe0dbf8.png)

I guess @jlaehne and I must have used slightly different methods to vectorize the stone outline, but I prefer the slightly softer edges in my version:

This the SVG, which doesn't display properly for me in Chrome (probably since it's an obscure font -- possibly something to be aware of):
![184962748-93fcbbdf-3213-4454-9909-98551e17efc6](https://user-images.githubusercontent.com/1278301/191557367-d9f3f70e-adf7-489c-9f1e-cbadf2747d3a.svg)



I can live with both Noto or Radio Canada ;-)

> I guess @jlaehne and I must have used slightly different methods to vectorize the stone outline, but I prefer the slightly softer edges in my version:

As long as it is vectorized in the final version, I'm happy ;-) I used Inkscape, but even that has multiple options.

> This the SVG, which doesn't display properly for me in Chrome (probably since it's an obscure font -- possibly something to be aware of):

The final version should probably have the text converted to paths to avoid any font issues!
Before we start suffering from logo fatigue syndrome, I would suggest that we down select features with some polls.
Once we have a good idea of what features are the most popular, it will be a matter of refining the alignment, height, width, etc. 😊

I will try to select those options which seem to have been of interest - please shout if some are missing in the polls.
🚀 for Noto Sans Display Semi-bold
🎉 for Radio Canda Semi-bold
👀 for Lato

🎉 for the `I` of https://github.com/hyperspy/rosettasciio/issues/5#issuecomment-1253935214
🚀 for the `I` in the first line of https://github.com/hyperspy/rosettasciio/issues/5#issuecomment-1252296635

From the polls, we can narrow down to 2 candidates:
- Lato with different `IO` from Noto Sans Display Semi-bold
- Noto Sans Display Semi-bold

@jordiferrero: could please make these two (final?) candidates with the snake?
> From the polls, we can narrow down to 2 candidates:
> 
> * Lato with different `IO` from Noto Sans Display Semi-bold
> * Noto Sans Display Semi-bold
> 
> @jordiferrero: could please make these two (final?) candidates with the snake?

OK. Here are the final versions: let's make a final final poll. 🎉 --> Lato + Noto   OR   🚀--> Noto

Lato + Noto 🎉:
![lato_noto](https://user-images.githubusercontent.com/9082687/194722585-3276fe0f-3c69-4fbb-820e-875860acf2ca.png)

Noto 🚀:
![noto](https://user-images.githubusercontent.com/9082687/194722584-33f8c65f-ecf3-4345-8d44-871aca29cfaf.png)

It sounds like that RosettaSciIO now has a logo! :)
@jordiferrero, do you want to make a pull request with the exported file and raw file (for potential future change)? Thank you!
# [Codecov](https://codecov.io/gh/hyperspy/rosettasciio/pull/47?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperspy) Report
Base: **83.35**% // Head: **83.39**% // Increases project coverage by **`+0.04%`** :tada:
> Coverage data is based on head [(`d08ae32`)](https://codecov.io/gh/hyperspy/rosettasciio/pull/47?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperspy) compared to base [(`e641fca`)](https://codecov.io/gh/hyperspy/rosettasciio/commit/e641fcac88fd17bb9e8a8ddc7ee4a1b4f8f169f2?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperspy).
> Patch coverage: 97.29% of modified lines in pull request are covered.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main      #47      +/-   ##
==========================================
+ Coverage   83.35%   83.39%   +0.04%     
==========================================
  Files          40       43       +3     
  Lines        8337     8348      +11     
  Branches     1896     1896              
==========================================
+ Hits         6949     6962      +13     
+ Misses        913      911       -2     
  Partials      475      475              
```


| [Impacted Files](https://codecov.io/gh/hyperspy/rosettasciio/pull/47?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperspy) | Coverage Δ | |
|---|---|---|
| [rsciio/blockfile/\_api.py](https://codecov.io/gh/hyperspy/rosettasciio/pull/47/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperspy#diff-cnNjaWlvL2Jsb2NrZmlsZS9fYXBpLnB5) | `95.31% <95.65%> (ø)` | |
| [rsciio/blockfile/\_\_init\_\_.py](https://codecov.io/gh/hyperspy/rosettasciio/pull/47/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperspy#diff-cnNjaWlvL2Jsb2NrZmlsZS9fX2luaXRfXy5weQ==) | `100.00% <100.00%> (ø)` | |
| [rsciio/bruker/\_\_init\_\_.py](https://codecov.io/gh/hyperspy/rosettasciio/pull/47/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperspy#diff-cnNjaWlvL2JydWtlci9fX2luaXRfXy5weQ==) | `100.00% <100.00%> (ø)` | |
| [rsciio/bruker/\_api.py](https://codecov.io/gh/hyperspy/rosettasciio/pull/47/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperspy#diff-cnNjaWlvL2JydWtlci9fYXBpLnB5) | `88.27% <100.00%> (ø)` | |
| [rsciio/docstrings.py](https://codecov.io/gh/hyperspy/rosettasciio/pull/47/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperspy#diff-cnNjaWlvL2RvY3N0cmluZ3MucHk=) | `100.00% <100.00%> (ø)` | |
| [rsciio/image/api.py](https://codecov.io/gh/hyperspy/rosettasciio/pull/47/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperspy#diff-cnNjaWlvL2ltYWdlL2FwaS5weQ==) | `91.56% <0.00%> (+2.40%)` | :arrow_up: |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperspy). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperspy)

</details>

[:umbrella: View full report at Codecov](https://codecov.io/gh/hyperspy/rosettasciio/pull/47?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperspy).   
:loudspeaker: Do you have feedback about the report comment? [Let us know in this issue](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperspy).

Loading the API documentation in the user guide worked out for bruker, but not for blockfile.
All other format descriptions consistently have the ``.`` in the file abbreviations -- we can change it everywhere when going through the formats, but we should be consistent.
A subsection header for the API part of the format pages would be nice, e.g. *API documentation* or *API parameters* or *Provided API functions*
> Loading the API documentation in the user guide worked out for bruker, but not for blockfile.

`scikit-image` was missing from the build and as it is a requirement for the blockfile plugin, the import of this module will fail.


> All other format descriptions consistently have the `.` in the file abbreviations -- we can change it everywhere when going through the formats, but we should be consistent.

Ok, if this is done consistently in other format, I will revert this change. I am not sure if we need the `.` but we should consider it in a separate PR.

> A subsection header for the API part of the format pages would be nice, e.g. API documentation or API parameters or Provided API functions

I started to add one but I find it a bit unnecessary/redundant. 
> Ok, if this is done consistently in other format, I will revert this change. I am not sure if we need the `.` but we should consider it in a separate PR.

It was a complete mixture, but in a previous PR on the docs I did it that way. Can live with the other way at well, but should be uniform.
 
> > A subsection header for the API part of the format pages would be nice, e.g. API documentation or API parameters or Provided API functions
> 
> I started to add one but I find it a bit unnecessary/redundant.

Well, if the initial description is long, it does not hurt to have a link in the right-side menu to jump there. And for a page like the NeXus one, where there are various subsections, I would find it weird to not have one for the API part.
Before continuing this PR, it would good to agree on the main changes:

## Public API
- importing functions have changed from `from rsciio.bruker.api import file_reader` to `from rsciio.bruker import file_reader`
- the public api of a plugin is defined in `__init__` and expose only `file_reader` and `file_writer`, all other functions would be made private
- the submodules are private  
- the io plugins registry haven't changed

@francisco-dlp, you implemented the current structure of the plugins, does the simplification of this PR sounds good to you? 

## Documentation

- Pull docstring of `file_reader`/`file_write` in plugin documentation page to avoid duplication of documentation - in particular for parameters
- For plugin, the documentation should have an introduction to the format, then the API (sphinx `automodule`) and some other section where suitable.

For the procedure to continue, should we do all the readers in this PR (other people could contribute certain readers) or do separate PRs for a number of plugins at a time?
I would prefer separate PRs, otherwise the diff preview on github is difficult to use... As several plugins with simple (or related/similar) changes can be put in one single PR, there shouldn't be that many PRs, maybe about 6-7?
> Before continuing this PR, it would good to agree on the main changes:

I agree, a reply from @francisco-dlp would be good though.
> A subsection header for the API part of the format pages would be nice, e.g. _API documentation_ or _API parameters_ or _Provided API functions_

In my opinion, this PR would just need a suitable header for the pulled in API sections and then we could proceed to implement everything for the other readers as well. I would say _API functions_ is appropriate.
LGTM!
@jlaehne, should we merge this PR to update other plugins documentation in separate PRs?
Just a few points I realized while working on the first other formats that we should maybe fix before merging. In the meantime, I started working from the back of the alphabet in #59 - the PR needs to be rebased once this one is merged as I included your changes to start out with.
I will update #59 accordingly to reflect the latest changes in this PR.
# [Codecov](https://codecov.io/gh/hyperspy/rosettasciio/pull/72?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperspy) Report
Base: **84.11**% // Head: **84.27**% // Increases project coverage by **`+0.15%`** :tada:
> Coverage data is based on head [(`b86f0ab`)](https://codecov.io/gh/hyperspy/rosettasciio/pull/72?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperspy) compared to base [(`7a34b06`)](https://codecov.io/gh/hyperspy/rosettasciio/commit/7a34b06d20f0bdc2e35d526c932252af0ba5f51e?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperspy).
> Patch coverage: 96.92% of modified lines in pull request are covered.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main      #72      +/-   ##
==========================================
+ Coverage   84.11%   84.27%   +0.15%     
==========================================
  Files          56       65       +9     
  Lines        8411     8481      +70     
  Branches     1890     1894       +4     
==========================================
+ Hits         7075     7147      +72     
+ Misses        877      875       -2     
  Partials      459      459              
```


| [Impacted Files](https://codecov.io/gh/hyperspy/rosettasciio/pull/72?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperspy) | Coverage Δ | |
|---|---|---|
| [rsciio/\_\_init\_\_.py](https://codecov.io/gh/hyperspy/rosettasciio/pull/72/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperspy#diff-cnNjaWlvL19faW5pdF9fLnB5) | `100.00% <ø> (ø)` | |
| [rsciio/tiff/\_api.py](https://codecov.io/gh/hyperspy/rosettasciio/pull/72/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperspy#diff-cnNjaWlvL3RpZmYvX2FwaS5weQ==) | `88.24% <ø> (ø)` | |
| [rsciio/zspy/\_api.py](https://codecov.io/gh/hyperspy/rosettasciio/pull/72/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperspy#diff-cnNjaWlvL3pzcHkvX2FwaS5weQ==) | `92.77% <ø> (ø)` | |
| [rsciio/mrc/\_api.py](https://codecov.io/gh/hyperspy/rosettasciio/pull/72/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperspy#diff-cnNjaWlvL21yYy9fYXBpLnB5) | `21.42% <60.00%> (ø)` | |
| [rsciio/blockfile/\_api.py](https://codecov.io/gh/hyperspy/rosettasciio/pull/72/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperspy#diff-cnNjaWlvL2Jsb2NrZmlsZS9fYXBpLnB5) | `95.31% <100.00%> (ø)` | |
| [rsciio/dens/\_\_init\_\_.py](https://codecov.io/gh/hyperspy/rosettasciio/pull/72/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperspy#diff-cnNjaWlvL2RlbnMvX19pbml0X18ucHk=) | `100.00% <100.00%> (ø)` | |
| [rsciio/dens/\_api.py](https://codecov.io/gh/hyperspy/rosettasciio/pull/72/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperspy#diff-cnNjaWlvL2RlbnMvX2FwaS5weQ==) | `83.92% <100.00%> (ø)` | |
| [rsciio/docstrings.py](https://codecov.io/gh/hyperspy/rosettasciio/pull/72/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperspy#diff-cnNjaWlvL2RvY3N0cmluZ3MucHk=) | `100.00% <100.00%> (ø)` | |
| [rsciio/image/\_\_init\_\_.py](https://codecov.io/gh/hyperspy/rosettasciio/pull/72/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperspy#diff-cnNjaWlvL2ltYWdlL19faW5pdF9fLnB5) | `100.00% <100.00%> (ø)` | |
| [rsciio/image/\_api.py](https://codecov.io/gh/hyperspy/rosettasciio/pull/72/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperspy#diff-cnNjaWlvL2ltYWdlL19hcGkucHk=) | `91.86% <100.00%> (ø)` | |
| ... and [14 more](https://codecov.io/gh/hyperspy/rosettasciio/pull/72/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperspy) | |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperspy). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperspy)

</details>

[:umbrella: View full report at Codecov](https://codecov.io/gh/hyperspy/rosettasciio/pull/72?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperspy).   
:loudspeaker: Do you have feedback about the report comment? [Let us know in this issue](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperspy).

Failing test is due to old loading from the api in `hyperspy/misc/eels/eelsdb.py `. See https://github.com/hyperspy/hyperspy/pull/3074
One approach could be to:
- put the generic/introductory plugin specific documentation a `rst`/`md` file for each plugin, which could live in the `docs` folder or in the plugin folder
- add the `file_reader` and `file_write` docstrings in the plugin specific page of the docs

This could be done by one of the two:
- use a sphinx template
- include the API reference in the plugin specific documentation page.

Considering that sphinx is a bit brittle and not always clearly documented, using the sphinx template approach may be more difficult but it would have the advantage of enforcing consistence between plugins and avoid repeating code.
>     * put the generic/introductory plugin specific documentation a `rst`/`md` file for each plugin, which could live in the `docs` folder or in the plugin folder

That file exists for every plugin afaik, in `docs/supported_formats/`.
 
>     * add the `file_reader` and `file_write` docstrings in the plugin specific page of the docs

That remains to be done, though some plugins have very detailed docstrings and others none at all.
 

Fix patch:
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
index 769b2a634..ba4c1930a 100644
--- a/CONTRIBUTING.rst
+++ b/CONTRIBUTING.rst
@@ -86,8 +86,6 @@ contain the following files:
   * (optional) A function called ``file_writer`` with at least two attributes: 
     ``filename`` and ``signal`` (a python dictionary) in that order.
 
-The new plugin needs to be added to the list in ``rsciio/__init__.py``.
-
 **Tests** covering the functionality of the plugin should be added to the
 ``tests`` directory with the naming ``test_spamandeggs.py`` corresponsing to
 the plugin residing in the directory ``spamandeggs``. Data files for the tests
diff --git a/docs/conf.py b/docs/conf.py
index 9edc30af9..7f6a38f6a 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -37,6 +37,7 @@
 
 intersphinx_mapping = {
     "hyperspy": ("https://hyperspy.org/hyperspy-doc/current/", None),
+    "h5py": ("https://docs.h5py.org/en/stable/", None),
     "pyusid": ("https://pycroscopy.github.io/pyUSID/", None),
     "zarr": ("https://zarr.readthedocs.io/en/stable", None),
 }
diff --git a/docs/supported_formats/digital_micrograph.rst b/docs/supported_formats/digital_micrograph.rst
index 665e8ce69..c4c887c24 100644
--- a/docs/supported_formats/digital_micrograph.rst
+++ b/docs/supported_formats/digital_micrograph.rst
@@ -3,25 +3,18 @@
 Gatan Digital Micrograph
 ------------------------
 
-RosettaSciIO can read both ``.dm3`` and ``.dm4`` files, but the reading features are
-not complete (and probably they will remain so, unless Gatan releases the
+RosettaSciIO can read both ``.dm3`` and ``.dm4`` files, but the reading features
+are not complete (and probably they will remain so, unless Gatan releases the
 specifications of the format). That said, we understand that this is an
 important feature and if loading a particular Digital Micrograph file fails for
 you, please report it as an issue in the `issues tracker
-<https://github.com/hyperspy/rosettasciio/issues>`_ to make
-us aware of the problem.
+<https://github.com/hyperspy/rosettasciio/issues>`_ to make us aware of the
+problem.
 
 Some of the tags in the DM-files are added to the metadata of the signal
 object. This includes, microscope information and certain parameters for EELS,
 EDS and CL signals.
 
-Extra loading arguments
-^^^^^^^^^^^^^^^^^^^^^^^
-
-- ``optimize``: bool, default is True. During loading, the data is replaced by its
-  :external+hyperspy:ref:`optimized copy <signal.transpose_optimize>` to speed up operations,
-  e. g. iteration over navigation axes. The cost of this speed improvement is to
-  double the memory requirement during data loading.
 
 .. warning::
 
@@ -32,3 +25,10 @@ Extra loading arguments
     using python, e.g. `HyperSpy <https://hyperspy.org>`_, where possible.
 
     See the original `bug report here <https://github.com/hyperspy/hyperspy/issues/1624>`_.
+
+
+API functions
+^^^^^^^^^^^^^
+
+.. automodule:: rsciio.digital_micrograph
+   :members:
diff --git a/docs/supported_formats/edax.rst b/docs/supported_formats/edax.rst
index 5de13f32c..c278dae24 100644
--- a/docs/supported_formats/edax.rst
+++ b/docs/supported_formats/edax.rst
@@ -10,11 +10,12 @@ spectrum image is loaded from the corresponding ``.ipr`` and ``.spc`` files
 stored in the same directory, or from specific files indicated by the user.
 If these calibration files are not available, the data from the ``.spd``
 file will still be loaded, but with no spatial or energy calibration.
+
 When using `HyperSpy <https://hyperspy.org>`_, if elemental information has been
-defined in the spectrum image, those
-elements will automatically be added to the signal loaded by HyperSpy.
+defined in the spectrum image, those elements will automatically be added to the
+signal loaded by HyperSpy.
 
-In HyperSpy, if an ``.spd`` file is loaded, the result will be a Hyperspy
+In HyperSpy, if an ``.spd`` file is loaded, the result will be a HyperSpy
 ``EDSSEMSpectrum`` map, and the calibration will be loaded from the appropriate
 ``.spc`` and ``.ipr`` files (if available). If an ``.spc`` file is loaded, the
 result will be a single ``EDSSEMSpectrum`` with no other files needed for
@@ -22,31 +23,19 @@ calibration.
 
 .. Note ::
 
-    Currently, HyperSpy will load an ``EDSSEMSpectrum`` signal. If support for
-    TEM EDS data is needed, please open an issue in the `issues tracker
+    Currently, HyperSpy will load data as an ``EDSSEMSpectrum`` signal. If support
+    for TEM EDS data is needed, please open an issue in the `issues tracker
     <https://github.com/hyperspy/rosettasciio/issues>`_ to alert the developers
     of the need.
 
 For reference, :ref:`file specifications <edax-file_specification>` for the EDAX
 file formats have been publicly available from EDAX.
 
-Extra loading arguments for SPD files
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-- ``spc_fname``: {None, str}, name of file from which to read the spectral
-  calibration. If data was exported fully from EDAX TEAM software, an ``.spc``
-  file with the same name as the .spd should be present. If `None`, the default
-  filename will be searched for. Otherwise, the name of the ``.spc`` file to use
-  for calibration can be explicitly given as a string.
-- ``ipr_fname``: {None, str}, name of file from which to read the spatial
-  calibration. If data was exported fully from EDAX TEAM software, an ``.ipr``
-  file with the same name as the ``.spd`` (plus a "_Img" suffix) should be present.
-  If `None`, the default filename will be searched for. Otherwise, the name of the
-  ``.ipr`` file to use for spatial calibration can be explicitly given as a string.
-- ``**kwargs``: remaining arguments are passed to the Numpy ``memmap`` function.
-
-Extra loading arguments for SPD and SPC files
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-- ``load_all_spc`` : bool, switch to control if all of the ``.spc`` header is
-  read, or just the important parts for import into HyperSpy.
+
+API functions
+^^^^^^^^^^^^^
+
+.. automodule:: rsciio.edax
+   :members:
+
+
diff --git a/docs/supported_formats/emd.rst b/docs/supported_formats/emd.rst
index d2ce9a5c9..c910b3db9 100644
--- a/docs/supported_formats/emd.rst
+++ b/docs/supported_formats/emd.rst
@@ -17,31 +17,22 @@ National Center for Electron Microscopy (NCEM).
 This format is used by the `prismatic software <https://prism-em.com/docs-outputs/>`_
 to save the simulation outputs.
 
-Extra loading arguments
-+++++++++++++++++++++++
-
-- ``dataset_path`` : None, str or list of str. Path of the dataset. If None,
-  load all supported datasets, otherwise the specified dataset(s).
-- ``stack_group`` : bool, default is True. Stack datasets of groups with common
-  path. Relevant for emd file version >= 0.5 where groups can be named
-  'group0000', 'group0001', etc.
-- ``chunks`` : None, True or tuple. Determine the chunking of the dataset to save.
-  See the ``chunks`` arguments of the ``hspy`` file format for more details.
-
+Usage examples
+""""""""""""""
 
 For files containing several datasets, the `dataset_path` argument can be
 used to select a specific one:
 
 .. code-block:: python
 
-    >>> s = hs.load("adatafile.emd", dataset_path="/experimental/science_data_1/data")
-
+    >>> from rsciio.emd import file_reader
+    >>> s = file_reader("adatafile.emd", dataset_path="/experimental/science_data_1/data")
 
 Or several by using a list:
 
 .. code-block:: python
 
-    >>> s = hs.load("adatafile.emd",
+    >>> s = file_reader("adatafile.emd",
     ...             dataset_path=[
     ...                 "/experimental/science_data_1/data",
     ...                 "/experimental/science_data_2/data"])
@@ -53,13 +44,12 @@ EMD (Velox)
 ^^^^^^^^^^^
 
 This is a non-compliant variant of the standard EMD format developed by
-Thermo-Fisher (former FEI). RosettaSciIO supports importing images, EDS spectrum and EDS
+ThermoFisher (former FEI). RosettaSciIO supports importing images, EDS spectrum and EDS
 spectrum streams (spectrum images stored in a sparse format). For spectrum
-streams, there are several loading options (described below) to control the frames
-and detectors to load and if to sum them on loading.  The default is
-to import the sum over all frames and over all detectors in order to decrease
-the data size in memory.
-
+streams, there are several loading options (described in the docstring below) 
+to control the frames and detectors to load and whether to sum them on loading.
+The default is to import the sum over all frames and over all detectors in order
+to decrease the data size in memory.
 
 .. note::
 
@@ -67,12 +57,6 @@ the data size in memory.
     format that RosettaSciIO cannot read. Therefore, don't prune Velox EMD files
     if you intend to read them with RosettaSciIO.
 
-.. code-block:: python
-
-    >>> hs.load("sample.emd")
-    [<Signal2D, title: HAADF, dimensions: (|179, 161)>,
-    <EDSSEMSpectrum, title: EDS, dimensions: (179, 161|4096)>]
-
 .. note::
 
     When using `HyperSpy <https://hyperspy.org>`_, FFTs made in Velox are loaded
@@ -86,11 +70,10 @@ the data size in memory.
 
 .. note::
 
-    Currently only lazy uncompression rather than lazy loading is implemented.
+    Currently, only lazy uncompression rather than lazy loading is implemented.
     This means that it is not currently possible to read EDS SI Velox EMD files
     with size bigger than the available memory.
 
-
 .. warning::
 
    This format is still not stable and files generated with the most recent
@@ -98,49 +81,32 @@ the data size in memory.
    a file, please report it  to the RosettaSciIO developers so that they can
    add support for newer versions of the format.
 
+Usage examples
+""""""""""""""
+
+.. code-block:: python
 
-.. _Extra-loading-arguments-fei-emd:
-
-Extra loading arguments
-+++++++++++++++++++++++
-
-- ``select_type`` : one of {None, 'image', 'single_spectrum', 'spectrum_image'} (default is None).
-- ``first_frame`` : integer (default is 0).
-- ``last_frame`` : integer (default is None)
-- ``sum_frames`` : boolean (default is True)
-- ``sum_EDS_detectors`` : boolean (default is True)
-- ``rebin_energy`` : integer (default is 1)
-- ``SI_dtype`` : numpy dtype (default is None)
-- ``load_SI_image_stack`` : boolean (default is False)
-
-The ``select_type`` parameter specifies the type of data to load: if `image` is selected,
-only images (including EDS maps) are loaded, if `single_spectrum` is selected, only
-single spectra are loaded and if `spectrum_image` is selected, only the spectrum
-image will be loaded. The ``first_frame`` and ``last_frame`` parameters can be used
-to select the frame range of the EDS spectrum image to load. To load each individual
-EDS frame, use ``sum_frames=False`` and the EDS spectrum image will be loaded
-with an extra navigation dimension corresponding to the frame index
-(time axis). Use the ``sum_EDS_detectors=True`` parameter to load the signal of
-each individual EDS detector. In such a case, a corresponding number of distinct
-EDS signal is returned. The default is ``sum_EDS_detectors=True``, which loads the
-EDS signal as a sum over the signals from each EDS detectors.  The ``rebin_energy``
-and ``SI_dtype`` parameters are particularly useful in combination with
-``sum_frames=False`` to reduce the data size when one want to read the
-individual frames of the spectrum image. If ``SI_dtype=None`` (default), the dtype
-of the data in the emd file is used. The ``load_SI_image_stack`` parameter allows
-loading the stack of STEM images acquired simultaneously as the EDS spectrum image.
-This can be useful to monitor any specimen changes during the acquisition or to
-correct the spatial drift in the spectrum image by using the STEM images.
+    >>> from rsciio.emd import file_reader
+    >>> file_reader("sample.emd")
+    [<Signal2D, title: HAADF, dimensions: (|179, 161)>,
+    <EDSSEMSpectrum, title: EDS, dimensions: (179, 161|4096)>]
 
 .. code-block:: python
 
-    >>> hs.load("sample.emd", sum_EDS_detectors=False)
+    >>> file_reader("sample.emd", sum_EDS_detectors=False)
     [<Signal2D, title: HAADF, dimensions: (|179, 161)>,
     <EDSSEMSpectrum, title: EDS - SuperXG21, dimensions: (179, 161|4096)>,
     <EDSSEMSpectrum, title: EDS - SuperXG22, dimensions: (179, 161|4096)>,
     <EDSSEMSpectrum, title: EDS - SuperXG23, dimensions: (179, 161|4096)>,
     <EDSSEMSpectrum, title: EDS - SuperXG24, dimensions: (179, 161|4096)>]
 
-    >>> hs.load("sample.emd", sum_frames=False, load_SI_image_stack=True, SI_dtype=np.int8, rebin_energy=4)
+    >>> file_reader("sample.emd", sum_frames=False, load_SI_image_stack=True, SI_dtype=np.int8, rebin_energy=4)
     [<Signal2D, title: HAADF, dimensions: (50|179, 161)>,
     <EDSSEMSpectrum, title: EDS, dimensions: (50, 179, 161|1024)>]
+
+
+API functions
+^^^^^^^^^^^^^
+
+.. automodule:: rsciio.emd
+   :members:
diff --git a/docs/supported_formats/emi_ser.rst b/docs/supported_formats/emi_ser.rst
index cb00d0ea9..6997758fb 100644
--- a/docs/supported_formats/emi_ser.rst
+++ b/docs/supported_formats/emi_ser.rst
@@ -3,25 +3,25 @@
 FEI TIA (SER & EMI)
 -------------------
 
-RosettaSciIO can read ``.ser`` and ``.emi`` files but the reading features are not
-complete (and probably they will be unless FEI releases the specifications of
-the format). That said we know that this is an important feature and if loading
-a particular ser or emi file fails for you, please report it as an issue in the
+RosettaSciIO can read ``.ser`` and ``.emi`` files files created by the FEI (now
+ThermoFisher) software TEM Imaging & Analysis (TIA), but the reading features are
+not complete (and probably they will be unless FEI/ThermoFisher releases the specifications
+of the format). That said we know that this is an important feature and if loading
+a particular ``.ser`` or ``.emi`` file fails for you, please report it as an issue in the
 `issues tracker <https://github.com/hyperspy/rosettasciio/issues>`__ to make us
 aware of the problem.
 
 RosettaSciIO (unlike TIA) can read data directly from the ``.ser`` files. However,
-by doing so, the information that is stored in the emi file is lost.
-Therefore strongly recommend to load using the ``.emi`` file instead.
+by doing so, the information that is stored in the ``.emi`` file is lost.
+Therefore, it is strongly recommended to load using the ``.emi`` file instead.
 
-When reading an ``.emi`` file if there are several ``.ser`` files associated
-with it, all of them will be read and returned as a list.
+If several ``.ser`` files are associated to the ``.emi`` file being read,
+all of them will be read and returned as a list.
 
 
-Extra loading arguments
-^^^^^^^^^^^^^^^^^^^^^^^
+API functions
+^^^^^^^^^^^^^
+
+.. automodule:: rsciio.fei
+   :members:
 
-- ``only_valid_data`` : bool, in case of series or linescan data with the
-  acquisition stopped before the end: if True, load only the acquired data.
-  If False, the empty data are filled with zeros. The default is False and this
-  default value will change to True in version 2.0.
diff --git a/docs/supported_formats/empad.rst b/docs/supported_formats/empad.rst
index f403712b3..1e012db54 100644
--- a/docs/supported_formats/empad.rst
+++ b/docs/supported_formats/empad.rst
@@ -9,15 +9,23 @@ scanning transmission electron diffraction measurements, with a limited set of
 metadata. Similarly, to the :ref:`ripple format <ripple-format>`, the raw data
 and metadata are saved in two different files and for the EMPAD reader, these
 are saved in the ``.raw`` and ``.xml`` files, respectively. To read EMPAD data,
-use the ``.xml`` file:
+use the ``.xml`` file, which will automatically read the raw data from the ``.raw``
+file too. The filename of the ``.raw`` file is defined in the ``.xml`` file, which
+implies changing the file name of the ``.raw`` file will break reading the file.
 
-.. code-block:: python
+.. Note::
 
-    >>> sig = hs.load("file.xml", reader="EMPAD")
+    When using `HyperSpy <https://hyperspy.org>`_, you need to specify the correct
+    ``reader`` plugin, as different ``.xml`` formats are supported:
 
+    .. code-block:: python
 
-which will automatically read the raw data from the ``.raw`` file too. The
-filename of the ``.raw`` file is defined in the ``.xml`` file, which implies
-changing the file name of the ``.raw`` file will break reading the file.
-Specifying the reader is necessary as the :ref:`Jobin-Yvon format <jobin_yvon-format>`
-also uses the ``.xml`` file-extension.
+        >>> import hyperspy.api as hs
+        >>> sig = hs.load("file.xml", reader="EMPAD")
+
+
+API functions
+^^^^^^^^^^^^^
+
+.. automodule:: rsciio.empad
+   :members:
diff --git a/docs/supported_formats/hspy.rst b/docs/supported_formats/hspy.rst
index 338a7a695..cf6711a97 100644
--- a/docs/supported_formats/hspy.rst
+++ b/docs/supported_formats/hspy.rst
@@ -3,43 +3,44 @@
 HSpy - HyperSpy's HDF5 Specification
 ------------------------------------
 
-This is `HyperSpy's <https://hyperspy.org>`_ default format and it is the only one that guarantees that no
+This is `HyperSpy's <https://hyperspy.org>`_ default format and for data processed
+in HyperSpy, it is the only format that guarantees that no
 information will be lost in the writing process and that supports saving data
 of arbitrary dimensions. It is based on the `HDF5 open standard
 <https://www.hdfgroup.org/solutions/hdf5/>`_. The HDF5 file format is supported by `many
 applications
 <https://support.hdfgroup.org/products/hdf5_tools/SWSummarybyName.htm>`_.
-Part of the specification is documented in :external+hyperspy:ref:`metadata_structure`.
+Parts of the specifications are documented in :external+hyperspy:ref:`metadata_structure`.
 
-.. versionadded:: 1.2
+.. versionadded:: HyperSpy_v1.2
     Enable saving HSpy files with the ``.hspy`` extension. Previously only the
     ``.hdf5`` extension was recognised.
 
-.. versionchanged:: 1.3
+.. versionchanged:: HyperSpy_v1.3
     The default extension for the HyperSpy HDF5 specification is now ``.hspy``.
     The option to change the default is no longer present in ``preferences``.
 
-Only loading of HDF5 files following the HyperSpy specification are supported.
-Usually their extension is ``.hspy`` extension, but older versions of HyperSpy
-would save them with the ``.hdf5`` extension. Both extensions are recognised
-by HyperSpy since version 1.2. However, HyperSpy versions older than 1.2
-won't recognise the ``.hspy`` extension. To
-workaround the issue when using old HyperSpy installations simply change the
-extension manually to ``.hdf5`` or
-save directly the file using this extension by explicitly adding it to the
+Only loading of HDF5 files following the HyperSpy specifications is supported by
+this plugin. Usually their extension is ``.hspy`` extension, but older versions of
+HyperSpy would save them with the ``.hdf5`` extension. Both extensions are
+recognised by HyperSpy since version 1.2. However, HyperSpy versions older than 1.2
+won't recognise the ``.hspy`` extension. To work around the issue when using old
+HyperSpy installations simply change the extension manually to ``.hdf5`` or
+directly save the file using this extension by explicitly adding it to the
 filename e.g.:
 
 .. code-block:: python
 
+    >>> import hyperspy.api as hs
     >>> s = hs.signals.BaseSignal([0])
     >>> s.save('test.hdf5')
 
 
 When saving to ``.hspy``, all supported objects in the signal's
-:py:attr:`~.signal.BaseSignal.metadata` is stored. This includes lists, tuples and signals.
-Please note that in order to increase saving efficiency and speed, if possible,
-the inner-most structures are converted to numpy arrays when saved. This
-procedure homogenizes any types of the objects inside, most notably casting
+:external+hyperspy:attr:`hyperspy.signal.BaseSignal.metadata` are stored. This includes lists, tuples
+and signals. Please note that in order to increase saving efficiency and speed,
+if possible, the inner-most structures are converted to numpy arrays when saved.
+This procedure homogenizes any types of the objects inside, most notably casting
 numbers as strings if any other strings are present:
 
 .. code-block:: python
@@ -54,7 +55,7 @@ The change of type is done using numpy "safe" rules, so no information is lost,
 as numbers are represented to full machine precision.
 
 This feature is particularly useful when using
-:py:meth:`~hyperspy._signals.eds.EDSSpectrum.get_lines_intensity`:
+:external+hyperspy:meth:`hyperspy._signals.eds.EDSSpectrum.get_lines_intensity`:
 
 .. code-block:: python
 
@@ -70,7 +71,12 @@ This feature is particularly useful when using
      <BaseSignal, title: X-ray line intensity of EDS SEM Signal1D: Mn_La at 0.63 keV, dimensions: (|)>,
      <BaseSignal, title: X-ray line intensity of EDS SEM Signal1D: Zr_La at 2.04 keV, dimensions: (|)>]
 
-.. versionadded:: 1.3.1
+.. _hspy-chunks:
+
+Chunking
+^^^^^^^^
+
+.. versionadded:: HyperSpy_v1.3.1
     ``chunks`` keyword argument
 
 The HyperSpy HDF5 format supports chunking the data into smaller pieces to make it possible to load only part
@@ -89,44 +95,23 @@ Note that currently it is not possible to pass different customised chunk shapes
 arrays contained in a signal and its metadata. Therefore, the value of ``chunks`` provided on saving
 will be applied to all arrays contained in the signal.
 
-By passing ``True`` to ``chunks`` the chunk shape is guessed using ``h5py``'s ``guess_chunk`` function
-what, for large signal spaces usually leads to smaller chunks as ``guess_chunk`` does not impose the
-constrain of storing at least one signal per chunks. For example, for the signal in the example above
-passing ``chunks=True`` results in ``(7, 7, 256)`` chunks.
-
-Choosing the correct chunk-size can significantly affect the speed of reading, writing and performance of many HyperSpy algorithms.
-See the :external+hyperspy:ref:`chunking section <big_data.chunking>` for more information.
-
-Also see the :ref:`hdf5-utils` for inspecting HDF5 files.
-
-Extra saving arguments
-^^^^^^^^^^^^^^^^^^^^^^
-
-- ``compression``: One of ``None``, ``'gzip'``, ``'szip'``, ``'lzf'`` (default is ``'gzip'``).
-  ``'szip'`` may be unavailable as it depends on the HDF5 installation including it.
-
-    .. note::
-
-        RosettaSciIO uses h5py for reading and writing HDF5 files and, therefore, it
-        supports all `compression filters supported by h5py <https://docs.h5py.org/en/stable/high/dataset.html#dataset-compression>`_.
-        The default is ``'gzip'``. It is possible to enable other compression filters
-        such as ``blosc`` by installing e.g. `hdf5plugin <https://github.com/silx-kit/hdf5plugin>`_.
-        However, be aware that loading those files will require installing the package
-        providing the compression filter. If not available an error will be raised.
-
-        Compression can significantly increase the saving speed. If file size is not
-        an issue, it can be disabled by setting ``compression=None``. Notice that only
-        ``compression=None`` and ``compression='gzip'`` are available in all platforms,
-        see the `h5py documentation <https://docs.h5py.org/en/stable/faq.html#what-compression-processing-filters-are-supported>`_
-        for more details. Therefore, if you choose any other compression filter for
-        saving a file, be aware that it may not be possible to load it in some platforms.
-
-- ``chunks``: tuple of integer or None. Define the chunking used for saving
-  the dataset. If None, calculates chunks for the signal, with preferably at
-  least one chunk per signal space.
-- ``close_file``: if ``False``, doesn't close the file after writing. The file
-  should not be closed if the data need to be accessed lazily after saving.
-  Default is ``True``.
-- ``write_dataset``: if ``False``, doesn't write the dataset when writing the file.
-  This can be useful to overwrite signal attributes only (for example ``axes_manager``)
-  without having to write the whole dataset, which can take time. Default is ``True``.
+By passing ``True`` to ``chunks`` the chunk shape is guessed using the ``guess_chunk`` function of ``h5py``
+For large signal spaces, the autochunking usually leads to smaller chunks as ``guess_chunk`` does not impose the
+constrain of storing at least one signal per chunk. For example, for the signal in the example above
+passing ``chunks=True`` results in chunks of ``(7, 7, 256)``.
+
+Choosing the correct chunk-size can significantly affect the speed of reading,
+writing and performance of many HyperSpy algorithms. See the
+:external+hyperspy:ref:`HyperSpy chunking section <big_data.chunking>` for more information.
+
+.. Note::
+
+    Also see the :ref:`hdf5-utils` for inspecting HDF5 files.
+
+
+API functions
+^^^^^^^^^^^^^
+
+.. automodule:: rsciio.hspy
+   :members:
+
diff --git a/rsciio/__init__.py b/rsciio/__init__.py
index be5fc7cde..6fd34f2ad 100644
--- a/rsciio/__init__.py
+++ b/rsciio/__init__.py
@@ -31,34 +31,7 @@
         with open(_specsf, "r") as stream:
             _specs = yaml.safe_load(stream)
             # for testing purposes
-            if _specs["name"] in [
-                "Blockfile",
-                "BrukerComposite",
-                "DENS",
-                "DigitalSurfSurface",
-                "Image",
-                "Impulse",
-                "JEOL",
-                "JobinYvon",
-                "MRC",
-                "MRCZ",
-                "MSA",
-                "netCDF",
-                "NeXus",
-                "Phenom",
-                "Protochips",
-                "PantaRhei",
-                "Ripple",
-                "Semper",
-                "TIFF",
-                "TVIPS",
-                "USID",
-                "ZSPY",
-                "TriVista",
-            ]:
-                _specs["api"] = "rsciio.%s" % os.path.split(sub)[1]
-            else:
-                _specs["api"] = "rsciio.%s.api" % os.path.split(sub)[1]
+            _specs["api"] = "rsciio.%s" % os.path.split(sub)[1]
             IO_PLUGINS.append(_specs)
 
 __all__ = [
diff --git a/rsciio/digital_micrograph/__init__.py b/rsciio/digital_micrograph/__init__.py
index e69de29bb..d4de92f67 100644
--- a/rsciio/digital_micrograph/__init__.py
+++ b/rsciio/digital_micrograph/__init__.py
@@ -0,0 +1,10 @@
+from ._api import file_reader
+
+
+__all__ = [
+    "file_reader",
+]
+
+
+def __dir__():
+    return sorted(__all__)
diff --git a/rsciio/digital_micrograph/api.py b/rsciio/digital_micrograph/_api.py
similarity index 98%
rename from rsciio/digital_micrograph/api.py
rename to rsciio/digital_micrograph/_api.py
index 3d0388019..f68b4d909 100644
--- a/rsciio/digital_micrograph/api.py
+++ b/rsciio/digital_micrograph/_api.py
@@ -28,6 +28,7 @@
 import numpy as np
 from copy import deepcopy
 
+from rsciio.docstrings import FILENAME_DOC, LAZY_DOC, RETURNS_DOC
 import rsciio.utils.utils_readfile as iou
 from rsciio.exceptions import DM3TagIDError, DM3DataTypeError, DM3TagTypeError
 from box import Box
@@ -440,11 +441,11 @@ def get_image_dictionaries(self):
 
 
 class ImageObject(object):
-    def __init__(self, imdict, file, order="C", record_by=None):
+    def __init__(self, imdict, file, order="C"):
         self.imdict = Box(imdict, box_dots=True)
         self.file = file
         self._order = order if order else "C"
-        self._record_by = record_by
+        self._record_by = None
 
     @property
     def shape(self):
@@ -1237,34 +1238,34 @@ def get_mapping(self):
         return mapping
 
 
-def file_reader(filename, record_by=None, order=None, lazy=False, optimize=True):
+def file_reader(filename, lazy=False, order=None, optimize=True, **kwargs):
     """Reads a DM3/4 file and loads the data into the appropriate class.
-    data_id can be specified to load a given image within a DM3/4 file that
-    contains more than one dataset.
+    If more than one dataset is contained in the ``.dm3/4`` file, a list of
+    signals is returned.
 
     Parameters
     ----------
-    record_by: Str
-        One of: SI, Signal2D
-    order : Str
+    %s
+    %s
+    order : str
         One of 'C' or 'F'
-    lazy : bool, default False
-        Load the signal lazily.
-    optimize : bool
-        If ``True``, the location of the data in memory is optimised for the
-        fastest iteration over the navigation axes. This operation can
-        cause a peak of memory usage and requires considerable processing
-        times for large datasets and/or low specification hardware.
-        See the :ref:`signal.transpose` section of the HyperSpy user guide
-        for more information. When operating on lazy signals, if ``True``,
+    optimize : bool, Default=True
+        If ``True``, the data is replaced by its
+        :external+hyperspy:ref:`optimized copy <signal.transpose_optimize>` during
+        loading to speed up operations, e.g. iteration over navigation axes.
+        The cost of this speed improvement is to double the memory requirement
+        during data loading, which for large data sets can lead to a slow down on
+        machines with limited memory. When operating on lazy signals, if ``True``,
         the chunks are optimised for the new axes configuration.
+
+    %s
     """
 
     with open(filename, "rb") as f:
         dm = DigitalMicrographReader(f)
         dm.parse_file()
         images = [
-            ImageObject(imdict, f, order=order, record_by=record_by)
+            ImageObject(imdict, f, order=order)
             for imdict in dm.get_image_dictionaries()
         ]
         imd = []
@@ -1307,3 +1308,6 @@ def file_reader(filename, record_by=None, order=None, lazy=False, optimize=True)
             )
 
     return imd
+
+
+file_reader.__doc__ %= (FILENAME_DOC, LAZY_DOC, RETURNS_DOC)
diff --git a/rsciio/edax/__init__.py b/rsciio/edax/__init__.py
index e69de29bb..d4de92f67 100644
--- a/rsciio/edax/__init__.py
+++ b/rsciio/edax/__init__.py
@@ -0,0 +1,10 @@
+from ._api import file_reader
+
+
+__all__ = [
+    "file_reader",
+]
+
+
+def __dir__():
+    return sorted(__all__)
diff --git a/rsciio/edax/api.py b/rsciio/edax/_api.py
similarity index 92%
rename from rsciio/edax/api.py
rename to rsciio/edax/_api.py
index aa4e943a2..430814f6f 100644
--- a/rsciio/edax/api.py
+++ b/rsciio/edax/_api.py
@@ -24,6 +24,12 @@
 import logging
 import numpy as np
 
+from rsciio.docstrings import (
+    FILENAME_DOC,
+    LAZY_DOC,
+    ENDIANESS_DOC,
+    RETURNS_DOC,
+)
 from rsciio.utils.tools import sarray2dict
 from rsciio.utils.elements import atomic_number2name
 
@@ -39,8 +45,7 @@ def get_spd_dtype_list(endianess="<"):
     """
     Get the data type list for an SPD map.
     Further information about the file format is available `here
-    <https://github.com/hyperspy/hyperspy/
-    files/29505/SpcMap-spd.file.format.pdf>`__.
+    <https://github.com/hyperspy/rosettasciio/raw/57b114cc02a0cbe022f1c50c1d59779a44952685/docs/file_specification/edax/SpcMap-spd.file.format.pdf>`__.
 
     Table of header tags:
      - tag: 16 byte char array;    *File ID tag ("MAPSPECTRA_DATA")*
@@ -57,7 +62,8 @@ def get_spd_dtype_list(endianess="<"):
 
     Parameters
     ----------
-    endianess : byte-order used to read the data
+    endianess : char
+        Byte-order used to read the data.
 
     Returns
     -------
@@ -93,9 +99,9 @@ def __get_spc_header(f, endianess, load_all_spc):
         already opened with ``open()``)
     endianess : char
         Byte-order of data to read
-    load_all_spc : bool
-        Switch to control if all of the .spc header is read, or just the parts
-        relevant to HyperSpy
+    load_all_spc : bool, Default=False
+        Switch to control whether the complete .spc header is read, or just the
+        important parts for import into HyperSpy.
 
     Returns
     -------
@@ -123,7 +129,7 @@ def get_spc_dtype_list(load_all=False, endianess="<", version=0.61):
     """
     Get the data type list for an SPC spectrum.
     Further information about the file format is available `here
-    <https://github.com/hyperspy/hyperspy/files/29506/SPECTRUM-V70.pdf>`__.
+    <https://github.com/hyperspy/rosettasciio/raw/57b114cc02a0cbe022f1c50c1d59779a44952685/docs/file_specification/edax/SPECTRUM-V70.pdf>`__.
 
     Parameters
     ----------
@@ -524,7 +530,7 @@ def get_ipr_dtype_list(endianess="<", version=333):
     """
     Get the data type list for an IPR image description file.
     Further information about the file format is available `here
-    <https://github.com/hyperspy/hyperspy/files/29507/ImageIPR.pdf>`__.
+    <https://github.com/hyperspy/rosettasciio/raw/57b114cc02a0cbe022f1c50c1d59779a44952685/docs/file_specification/edax/ImageIPR.pdf>`__.
 
     Table of header tags:
 
@@ -682,27 +688,22 @@ def _add_spc_metadata(metadata, spc_header):
     return metadata
 
 
-def spc_reader(filename, endianess="<", load_all_spc=False, **kwargs):
+def spc_reader(filename, lazy=False, endianess="<", load_all_spc=False, **kwargs):
     """
     Read data from an SPC spectrum specified by filename.
 
     Parameters
     ----------
-    filename : str
-        Name of SPC file to read
-    endianess : char
-        Byte-order of data to read
-    load_all_spc : bool
-        Switch to control if all of the .spc header is read, or just the
-        important parts for import into HyperSpy
+    %s
+    %s
+    %s
+    load_all_spc : bool, Default=False
+        Switch to control whether the complete .spc header is read, or just the
+        important parts for import into HyperSpy.
     **kwargs
         Remaining arguments are passed to the Numpy ``memmap`` function
 
-    Returns
-    -------
-    list
-        list with dictionary of signal information to be passed back to
-        hyperspy.io.load_with_reader
+    %s
     """
     with open(filename, "rb") as f:
         _logger.debug(" Reading {}".format(filename))
@@ -715,7 +716,6 @@ def spc_reader(filename, endianess="<", load_all_spc=False, **kwargs):
         data_offset = original_metadata["spc_header"]["dataStart"]
 
         mode = kwargs.pop("mode", "c")
-        lazy = kwargs.pop("lazy", False)
         if lazy:
             mode = "r"
 
@@ -759,8 +759,12 @@ def spc_reader(filename, endianess="<", load_all_spc=False, **kwargs):
     ]
 
 
+spc_reader.__doc__ %= (FILENAME_DOC, LAZY_DOC, ENDIANESS_DOC, RETURNS_DOC)
+
+
 def spd_reader(
     filename,
+    lazy=False,
     endianess="<",
     spc_fname=None,
     ipr_fname=None,
@@ -772,10 +776,9 @@ def spd_reader(
 
     Parameters
     ----------
-    filename : str
-        Name of SPD file to read
-    endianess : char
-        Byte-order of data to read
+    %s
+    %s
+    %s
     spc_fname : None or str
         Name of file from which to read the spectral calibration. If data
         was exported fully from EDAX TEAM software, an .spc file with the
@@ -790,17 +793,13 @@ def spd_reader(
         If `None`, the default filename will be searched for.
         Otherwise, the name of the .ipr file to use for spatial calibration
         can be explicitly given as a string.
-    load_all_spc : bool
-        Switch to control if all of the .spc header is read, or just the
-        important parts for import into HyperSpy
+    load_all_spc : bool, Default=False
+        Switch to control whether the complete .spc header is read, or just the
+        important parts for import into HyperSpy.
     **kwargs
-        Remaining arguments are passed to the Numpy ``memmap`` function
+        Remaining arguments are passed to the Numpy ``memmap`` function.
 
-    Returns
-    -------
-    list
-        list with dictionary of signal information to be passed back to
-        hyperspy.io.load_with_reader
+    %s
     """
     with open(filename, "rb") as f:
         spd_header = np.fromfile(f, dtype=get_spd_dtype_list(endianess), count=1)
@@ -815,7 +814,6 @@ def spd_reader(
         data_type = {"1": "u1", "2": "u2", "4": "u4"}[
             str(original_metadata["spd_header"]["countBytes"])
         ]
-        lazy = kwargs.pop("lazy", False)
         mode = kwargs.pop("mode", "c")
         if lazy:
             mode = "r"
@@ -952,29 +950,54 @@ def spd_reader(
     ]
 
 
-def file_reader(filename, record_by="spectrum", endianess="<", **kwargs):
+spd_reader.__doc__ %= (FILENAME_DOC, LAZY_DOC, ENDIANESS_DOC, RETURNS_DOC)
+
+
+def file_reader(filename, lazy=False, endianess="<", **kwargs):
     """
+    Reads ``.spc`` (spectrum) or ``.spd`` (spectrum image) files from EDAX
+    Genesis or TEAMS software.
 
     Parameters
     ----------
-    filename : str
-        Name of file to read
-    record_by : str
-        EDAX EDS data is always recorded by 'spectrum', so this parameter
-        is not used
-    endianess : char
-        Byte-order of data to read
+    %s
+    %s
+    %s
+    load_all_spc : bool, Default=False
+        Switch to control whether the complete .spc header is read, or just the
+        important parts for import into HyperSpy.
+    spc_fname : None or str
+        For spd files only.
+        Name of file from which to read the spectral calibration. If data
+        was exported fully from EDAX TEAM software, an .spc file with the
+        same name as the .spd should be present.
+        If `None`, the default filename will be searched for.
+        Otherwise, the name of the .spc file to use for calibration can
+        be explicitly given as a string.
+    ipr_fname : None or str
+        For spd files only.
+        Name of file from which to read the spatial calibration. If data
+        was exported fully from EDAX TEAM software, an .ipr file with the
+        same name as the .spd (plus a "_Img" suffix) should be present.
+        If `None`, the default filename will be searched for.
+        Otherwise, the name of the .ipr file to use for spatial calibration
+        can be explicitly given as a string.
     **kwargs
-        Additional keyword arguments supplied to the readers
+        Remaining arguments are passed to the Numpy ``memmap`` function.
 
-    Returns
-    -------
+    %s
 
+    Notes
+    -----
+    The file specification is available at :ref:`edax-file_specification`.
     """
     ext = os.path.splitext(filename)[1][1:]
     if ext in spd_extensions:
-        return spd_reader(filename, endianess, **kwargs)
+        return spd_reader(filename, lazy, endianess, **kwargs)
     elif ext in spc_extensions:
-        return spc_reader(filename, endianess, **kwargs)
+        return spc_reader(filename, lazy, endianess, **kwargs)
     else:
         raise IOError("Did not understand input file format.")
+
+
+file_reader.__doc__ %= (FILENAME_DOC, LAZY_DOC, ENDIANESS_DOC, RETURNS_DOC)
diff --git a/rsciio/emd/__init__.py b/rsciio/emd/__init__.py
index e69de29bb..5699aa972 100644
--- a/rsciio/emd/__init__.py
+++ b/rsciio/emd/__init__.py
@@ -0,0 +1,14 @@
+from ._api import (
+    file_reader,
+    file_writer,
+)
+
+
+__all__ = [
+    "file_reader",
+    "file_writer",
+]
+
+
+def __dir__():
+    return sorted(__all__)
diff --git a/rsciio/emd/api.py b/rsciio/emd/_api.py
similarity index 94%
rename from rsciio/emd/api.py
rename to rsciio/emd/_api.py
index dda8d5b45..ed4feb293 100644
--- a/rsciio/emd/api.py
+++ b/rsciio/emd/_api.py
@@ -37,6 +37,12 @@
 import dask.array as da
 from dateutil import tz
 
+from rsciio.docstrings import (
+    FILENAME_DOC,
+    LAZY_DOC,
+    RETURNS_DOC,
+    SIGNAL_DOC,
+)
 from rsciio.utils.tools import _UREG, DTBox
 from rsciio.utils.elements import atomic_number2name
 import rsciio.utils.fei_stream_readers as stream_readers
@@ -1532,19 +1538,59 @@ def _is_EMD_velox(file):
 
 def file_reader(filename, lazy=False, **kwds):
     """
-    Read EMD file, which can be a NCEM or a Velox variant of the EMD format.
-    Also reads Direct Electron's DE5 format, which is read as if it is the
-    NCEM format.
+    Read EMD file, which can be an NCEM or a Velox variant of the EMD format.
+    Also reads Direct Electron's DE5 format, which is read according to the
+    NCEM specifications.
 
     Parameters
     ----------
-    filename : str
-        Filename of the file to write.
-    lazy : bool
-        Open the data lazily. Default is False.
+    %s
+    %s
     **kwds : dict
-        Keyword argument pass to the EMD NCEM or EMD Velox reader. See user
-        guide or the docstring of the `load` function for more information.
+        Keyword arguments passed to the EMD NCEM or EMD Velox reader as specified
+        in the following.
+    dataset_path : None, str or list of str, default=None
+        NCEM only: Path of the dataset. If None, load all supported datasets,
+        otherwise the specified dataset(s).
+    stack_group : None, bool, default=None
+        NCEM only: Stack datasets of groups with common path. Relevant for emd file
+        version >= 0.5, where groups can be named ``group0000``, ``group0001``, etc.
+    select_type : {None, 'image', 'single_spectrum', 'spectrum_image'}
+        Velox only: specifies the type of data to load: if ``'image'`` is selected,
+        only images (including EDS maps) are loaded, if ``'single_spectrum'`` is
+        selected, only single spectra are loaded and if ``'spectrum_image'`` is
+        selected, only the spectrum image will be loaded.
+    first_frame : int, default=0
+        Velox only: Select the start for the frame range of the EDS spectrum image
+        to load.
+    last_frame : int or None, default=None
+        Velox only: Select the end for the frame range of the EDS spectrum image
+        to load.
+    sum_frames : bool, default=True
+        Velox only: Load each individual EDS frame. The EDS spectrum image will
+        be loaded with an extra navigation dimension corresponding to the frame
+        index (time axis).
+    sum_EDS_detectors : bool, default=True
+        Velox only: Load the EDS signal as a sum over the signals from all EDS
+        detectors (default) or, alternatively, load the signal of each individual
+        EDS detector. In the latter case, a corresponding number of distinct
+        EDS signals is returned.
+    rebin_energy : int, default=1
+        Velox only: Rebin the energy axis by given factor. Useful in combination
+        with ``sum_frames=False`` to reduce the data size when reading the
+        individual frames of the spectrum image.
+    SI_dtype : numpy dtype or None, default=None
+        Velox only: Change the datatype of a spectrum image. Useful in combination
+        with ``sum_frames=False`` to reduce the data size when reading the individual
+        frames of the spectrum image. If not specified, the dtype of the data in
+        the emd file is used.
+    load_SI_image_stack : bool, default=False
+        Velox only: Allows loading the stack of STEM images acquired
+        simultaneously with the EDS spectrum image. This option can be useful to
+        monitor any specimen changes during the acquisition or to correct the
+        spatial drift in the spectrum image by using the STEM images.
+
+    %s
     """
     file = h5py.File(filename, "r")
     dictionaries = []
@@ -1574,18 +1620,26 @@ def file_reader(filename, lazy=False, **kwds):
     return dictionaries
 
 
+file_reader.__doc__ %= (FILENAME_DOC, LAZY_DOC, RETURNS_DOC)
+
+
 def file_writer(filename, signal, **kwds):
     """
-    Write signal to EMD NCEM file.
+    Write signal to EMD file. Only the specifications by the National Center
+    for Electron Microscopy (NCEM) are supported.
 
     Parameters
     ----------
-    file : str of h5py file handle
-        If str, filename of the file to write, otherwise a h5py file handle
-    signal : instance of hyperspy signal
-        The signal to save.
+    %s
+    %s
+    chunks : None, True or tuple, Default=None
+        Determine the chunking of the dataset to save. See the :ref:`chunks
+        argument of the hspy-format <hspy-chunks>` for more details.
     **kwargs : dict
-        Dictionary containing metadata which will be written as attribute
+        Dictionary containing metadata, which will be written as attribute
         of the root group.
     """
     EMD_NCEM().write_file(filename, signal, **kwds)
+
+
+file_writer.__doc__ %= (FILENAME_DOC.replace("read", "write to"), SIGNAL_DOC)
diff --git a/rsciio/empad/__init__.py b/rsciio/empad/__init__.py
index e69de29bb..d4de92f67 100644
--- a/rsciio/empad/__init__.py
+++ b/rsciio/empad/__init__.py
@@ -0,0 +1,10 @@
+from ._api import file_reader
+
+
+__all__ = [
+    "file_reader",
+]
+
+
+def __dir__():
+    return sorted(__all__)
diff --git a/rsciio/empad/api.py b/rsciio/empad/_api.py
similarity index 95%
rename from rsciio/empad/api.py
rename to rsciio/empad/_api.py
index f9d306e03..705c57093 100644
--- a/rsciio/empad/api.py
+++ b/rsciio/empad/_api.py
@@ -22,6 +22,7 @@
 import numpy as np
 import logging
 
+from rsciio.docstrings import FILENAME_DOC, LAZY_DOC, RETURNS_DOC
 from rsciio.utils.tools import _UREG
 from rsciio.utils.tools import convert_xml_to_dict
 
@@ -95,7 +96,16 @@ def _convert_scale_units(value, units, factor=1):
 
 
 def file_reader(filename, lazy=False, **kwds):
+    """
+    Reads file format used by the Electron Microscope Pixel Array Detector (EMPAD).
 
+    Parameters
+    ----------
+    %s
+    %s
+
+    %s
+    """
     om, info = _parse_xml(filename)
     dname, fname = os.path.split(filename)
 
@@ -185,3 +195,6 @@ def file_reader(filename, lazy=False, **kwds):
     return [
         dictionary,
     ]
+
+
+file_reader.__doc__ %= (FILENAME_DOC, LAZY_DOC, RETURNS_DOC)
diff --git a/rsciio/fei/__init__.py b/rsciio/fei/__init__.py
index e69de29bb..d4de92f67 100644
--- a/rsciio/fei/__init__.py
+++ b/rsciio/fei/__init__.py
@@ -0,0 +1,10 @@
+from ._api import file_reader
+
+
+__all__ = [
+    "file_reader",
+]
+
+
+def __dir__():
+    return sorted(__all__)
diff --git a/rsciio/fei/api.py b/rsciio/fei/_api.py
similarity index 97%
rename from rsciio/fei/api.py
rename to rsciio/fei/_api.py
index 8dc661441..ad5a3210e 100644
--- a/rsciio/fei/api.py
+++ b/rsciio/fei/_api.py
@@ -27,6 +27,7 @@
 
 import numpy as np
 
+from rsciio.docstrings import FILENAME_DOC, LAZY_DOC, RETURNS_DOC
 from rsciio.utils.tools import sarray2dict
 from rsciio.utils.tools import DTBox
 
@@ -283,6 +284,21 @@ def emi_reader(filename, dump_xml=False, **kwds):
 
 
 def file_reader(filename, *args, **kwds):
+    """
+    Read sets of ``.ser`` and ``.emi`` files from the FEI/ThermoFisher software TIA
+    (TEM Imaging & Analysis).
+
+    Parameters
+    ----------
+    %s
+    %s
+    only_valid_data: bool, Default=True
+        For cases, where acquisition of series or linescan data stopped before
+        the end. If `True`, load only the acquired data. If `False`, the empty
+        data are filled with zeros.
+
+    %s
+    """
     ext = os.path.splitext(filename)[1][1:]
     ser_extensions = ("ser", "SER")
     emi_extensions = ("emi", "EMI")
@@ -294,6 +310,9 @@ def file_reader(filename, *args, **kwds):
         return emi_reader(filename, *args, **kwds)
 
 
+file_reader.__doc__ %= (FILENAME_DOC, LAZY_DOC, RETURNS_DOC)
+
+
 def load_ser_file(filename):
     _logger.info("Opening the file: %s", filename)
     with open(filename, "rb") as f:
@@ -482,7 +501,7 @@ def convert_xml_to_dict(xml_object):
     return op
 
 
-def ser_reader(filename, objects=None, lazy=False, only_valid_data=False):
+def ser_reader(filename, objects=None, lazy=False, only_valid_data=True):
     """Reads the information from the file and returns it in the HyperSpy
     required format.
 
@@ -676,7 +695,7 @@ def load_only_data(
     num_axes,
     data=None,
     header=None,
-    only_valid_data=False,
+    only_valid_data=True,
 ):
     if data is None:
         header, data = load_ser_file(filename)
diff --git a/rsciio/hspy/__init__.py b/rsciio/hspy/__init__.py
index e69de29bb..5699aa972 100644
--- a/rsciio/hspy/__init__.py
+++ b/rsciio/hspy/__init__.py
@@ -0,0 +1,14 @@
+from ._api import (
+    file_reader,
+    file_writer,
+)
+
+
+__all__ = [
+    "file_reader",
+    "file_writer",
+]
+
+
+def __dir__():
+    return sorted(__all__)
diff --git a/rsciio/hspy/api.py b/rsciio/hspy/_api.py
similarity index 77%
rename from rsciio/hspy/api.py
rename to rsciio/hspy/_api.py
index 196f2c87f..c50eb9e3b 100644
--- a/rsciio/hspy/api.py
+++ b/rsciio/hspy/_api.py
@@ -23,6 +23,12 @@
 import dask.array as da
 import h5py
 
+from rsciio.docstrings import (
+    FILENAME_DOC,
+    LAZY_DOC,
+    RETURNS_DOC,
+    SIGNAL_DOC,
+)
 from rsciio._hierarchical import HierarchicalWriter, HierarchicalReader, version
 from rsciio.utils.tools import get_file_handle
 
@@ -136,14 +142,17 @@ def _get_object_dset(group, data, key, chunks, **kwds):
 
 
 def file_reader(filename, lazy=False, **kwds):
-    """Read data from hdf5 files saved with the hyperspy hdf5 format specification
+    """Read data from hdf5-files saved with the HyperSpy hdf5-format
+    specification (``.hspy``).
 
     Parameters
     ----------
-    filename: str
-    lazy: bool
-        Load image lazily using dask
-    **kwds, optional
+    %s
+    %s
+    **kwds
+
+
+    %s
     """
     try:
         # in case blosc compression is used
@@ -161,27 +170,49 @@ def file_reader(filename, lazy=False, **kwds):
     return exp_dict_list
 
 
+file_reader.__doc__ %= (FILENAME_DOC, LAZY_DOC, RETURNS_DOC)
+
+
 def file_writer(filename, signal, close_file=True, **kwds):
-    """Writes data to hyperspy's hdf5 format
+    """Writes data to HyperSpy's hdf5-format (``.hspy``).
 
     Parameters
     ----------
-    filename : str
-        The name of the file used to save the signal.
-    signal : a BaseSignal instance
-        The signal to save.
-    chunks : tuple of integer or None, default: None
-        Define the chunking used for saving the dataset. If None, calculates
+    %s
+    %s
+    compression : None, 'gzip', 'szip', 'lzf', Default='gzip'.
+        Compression can significantly increase the saving speed. If file size is not
+        an issue, it can be disabled by setting ``compression=None``.
+        RosettaSciIO uses h5py for reading and writing HDF5 files and, therefore,
+        it supports all `compression filters supported by h5py
+        <https://docs.h5py.org/en/stable/high/dataset.html#dataset-compression>`_.
+        The default is ``'gzip'``. Also see notes below.
+    chunks : tuple of integer or None, Default=None
+        Define the chunking used for saving the dataset. If ``None``, calculates
         chunks for the signal, with preferably at least one chunk per signal
         space.
-    close_file : bool, default: True
-        Close the file after writing.
-    write_dataset : bool, default: True
-        If True, write the data, otherwise, don't write it. Useful to
-        save attributes without having to write the whole dataset.
+    close_file : bool, Default=True
+        Close the file after writing.  The file should not be closed if the data
+        needs to be accessed lazily after saving.
+    write_dataset : bool, Default=True
+        If True, write the dataset, otherwise, don't write it. Useful to
+        overwrite attributes (for example ``axes_manager``) only without having
+        to write the whole dataset.
     **kwds
         The keyword argument are passed to the
-        :py:meth:`h5py.Group.require_dataset` function.
+        :external+h5py:meth:`h5py.Group.require_dataset` function.
+
+    Notes
+    -----
+    It is possible to enable other compression filters such as ``blosc`` by
+    installing e.g. `hdf5plugin <https://github.com/silx-kit/hdf5plugin>`_.
+    Similarly, the availability of ``'szip'`` depends on the HDF5 installation.
+    If not available an error will be raised. Be aware that loading those
+    files will require installing the package providing the compression filter
+    and it may thus not be possible to load it on some platforms.
+    Only ``compression=None`` and ``compression='gzip'`` are available on all
+    platforms. For more details, see the `h5py documentation
+    <https://docs.h5py.org/en/stable/faq.html#what-compression-processing-filters-are-supported>`_.
     """
     if "compression" not in kwds:
         kwds["compression"] = "gzip"
@@ -248,4 +279,7 @@ def file_writer(filename, signal, close_file=True, **kwds):
         f.close()
 
 
+file_writer.__doc__ %= (FILENAME_DOC.replace("read", "write to"), SIGNAL_DOC)
+
+
 overwrite_dataset = HyperspyWriter.overwrite_dataset
diff --git a/rsciio/nexus/_api.py b/rsciio/nexus/_api.py
index 73af2e8d7..b2e448527 100644
--- a/rsciio/nexus/_api.py
+++ b/rsciio/nexus/_api.py
@@ -31,7 +31,7 @@
     SIGNAL_DOC,
 )
 from rsciio._hierarchical import get_signal_chunks
-from rsciio.hspy.api import overwrite_dataset
+from rsciio.hspy._api import overwrite_dataset
 from rsciio.utils.tools import DTBox
 
 
diff --git a/rsciio/nexus/specifications.yaml b/rsciio/nexus/specifications.yaml
index e5c56d869..a00642783 100644
--- a/rsciio/nexus/specifications.yaml
+++ b/rsciio/nexus/specifications.yaml
@@ -7,5 +7,3 @@ default_extension: 0
 writes: True
 non_uniform_axis: False
 
-
-
diff --git a/upcoming_changes/76.doc.rst b/upcoming_changes/76.doc.rst
new file mode 100644
index 000000000..5a3c2b21a
--- /dev/null
+++ b/upcoming_changes/76.doc.rst
@@ -0,0 +1,1 @@
+Consolidate docstrings and documentation for all plugins (see also `#47 <https://github.com/hyperspy/rosettasciio/issues/47`_, `#59 <https://github.com/hyperspy/rosettasciio/issues/59`_, `#64 <https://github.com/hyperspy/rosettasciio/issues/64`_, `#72 <https://github.com/hyperspy/rosettasciio/issues/72`_)


Test patch:
diff --git a/rsciio/tests/test_dm3.py b/rsciio/tests/test_dm3.py
index 7fc0c3b5e..7cd44fa51 100644
--- a/rsciio/tests/test_dm3.py
+++ b/rsciio/tests/test_dm3.py
@@ -23,7 +23,7 @@
 import numpy as np
 import pytest
 
-from rsciio.digital_micrograph.api import DigitalMicrographReader, ImageObject
+from rsciio.digital_micrograph._api import DigitalMicrographReader, ImageObject
 from rsciio.tests.generate_dm_testing_files import dm3_data_types, dm4_data_types
 
 hs = pytest.importorskip("hyperspy.api", reason="hyperspy not installed")
@@ -530,7 +530,7 @@ def test_multi_signal():
                 "0": {
                     "operation": "load",
                     "hyperspy_version": hs.__version__,
-                    "io_plugin": "rsciio.digital_micrograph.api",
+                    "io_plugin": "rsciio.digital_micrograph",
                 }
             },
         },
@@ -577,7 +577,7 @@ def test_multi_signal():
                 "0": {
                     "operation": "load",
                     "hyperspy_version": hs.__version__,
-                    "io_plugin": "rsciio.digital_micrograph.api",
+                    "io_plugin": "rsciio.digital_micrograph",
                 }
             },
         },
diff --git a/rsciio/tests/test_emd.py b/rsciio/tests/test_emd.py
index 7619a418c..bcccc6d3e 100644
--- a/rsciio/tests/test_emd.py
+++ b/rsciio/tests/test_emd.py
@@ -350,7 +350,7 @@ def test_fei_emd_image(self, lazy):
                     "0": {
                         "operation": "load",
                         "hyperspy_version": hs.__version__,
-                        "io_plugin": "rsciio.emd.api",
+                        "io_plugin": "rsciio.emd",
                     }
                 },
             },
diff --git a/rsciio/tests/test_empad.py b/rsciio/tests/test_empad.py
index 0b459aaab..af2e3daf0 100644
--- a/rsciio/tests/test_empad.py
+++ b/rsciio/tests/test_empad.py
@@ -26,7 +26,7 @@
 
 import traits.api as t
 
-from rsciio.empad.api import _parse_xml
+from rsciio.empad._api import _parse_xml
 
 
 DATA_DIR = os.path.join(os.path.dirname(__file__), "empad_data")
diff --git a/rsciio/tests/test_fei.py b/rsciio/tests/test_fei.py
index 27014f806..1a306289e 100644
--- a/rsciio/tests/test_fei.py
+++ b/rsciio/tests/test_fei.py
@@ -25,7 +25,7 @@
 
 import traits.api as t
 
-from rsciio.fei.api import load_ser_file
+from rsciio.fei._api import load_ser_file
 
 
 MY_PATH = os.path.dirname(__file__)
@@ -414,7 +414,7 @@ def test_load_units_scale(self):
         )
 
     def test_guess_units_from_mode(self):
-        from rsciio.fei.api import (
+        from rsciio.fei._api import (
             _guess_units_from_mode,
             convert_xml_to_dict,
             get_xml_info_from_emi,
diff --git a/rsciio/tests/test_hdf5.py b/rsciio/tests/test_hspy.py
similarity index 99%
rename from rsciio/tests/test_hdf5.py
rename to rsciio/tests/test_hspy.py
index b26d5a1bf..5e171cb14 100644
--- a/rsciio/tests/test_hdf5.py
+++ b/rsciio/tests/test_hspy.py
@@ -382,7 +382,7 @@ def test_metadata_update_to_v3_1(self):
                     "0": {
                         "operation": "load",
                         "hyperspy_version": hs.__version__,
-                        "io_plugin": "rsciio.hspy.api",
+                        "io_plugin": "rsciio.hspy",
                     }
                 },
             },
diff --git a/rsciio/tests/test_import.py b/rsciio/tests/test_import.py
index 7992959a6..19d8db5cb 100644
--- a/rsciio/tests/test_import.py
+++ b/rsciio/tests/test_import.py
@@ -115,6 +115,30 @@ def test_dir_plugins():
 
     assert dir(dens) == ["file_reader"]
 
+    from rsciio import digital_micrograph
+
+    assert dir(digital_micrograph) == ["file_reader"]
+
+    from rsciio import edax
+
+    assert dir(edax) == ["file_reader"]
+
+    from rsciio import emd
+
+    assert dir(emd) == ["file_reader", "file_writer"]
+
+    from rsciio import empad
+
+    assert dir(empad) == ["file_reader"]
+
+    from rsciio import fei
+
+    assert dir(fei) == ["file_reader"]
+
+    from rsciio import hspy
+
+    assert dir(hspy) == ["file_reader", "file_writer"]
+
     from rsciio import image
 
     assert dir(image) == ["file_reader", "file_writer"]
diff --git a/rsciio/tests/test_io.py b/rsciio/tests/test_io.py
index 187bcbd28..f2409e474 100644
--- a/rsciio/tests/test_io.py
+++ b/rsciio/tests/test_io.py
@@ -264,7 +264,7 @@ def test_file_reader_options():
         # Test object reader
         from rsciio import hspy
 
-        t = hs.load(Path(dirpath, "temp.hspy"), reader=hspy.api)
+        t = hs.load(Path(dirpath, "temp.hspy"), reader=hspy)
         assert len(t) == 1
         np.testing.assert_allclose(t.data, np.arange(10))
 
@@ -318,12 +318,12 @@ def test_load_save_filereader_metadata():
                 "hyperspy_version": hs.__version__,
             },
             "1": {
-                "io_plugin": "rsciio.hspy.api",
+                "io_plugin": "rsciio.hspy",
                 "operation": "save",
                 "hyperspy_version": hs.__version__,
             },
             "2": {
-                "io_plugin": "rsciio.hspy.api",
+                "io_plugin": "rsciio.hspy",
                 "operation": "load",
                 "hyperspy_version": hs.__version__,
             },