PERF: load plotting entrypoint only when necessary
State: closed

- [x] closes #41492
- [x] tests added / passed (I only ran plotting/test_backend.py, which seemed appropriate)
- [x] Ensure all linting tests pass, see [here](https://pandas.pydata.org/pandas-docs/dev/development/contributing.html#code-standards) for how to run them
- [x] whatsnew entry

Labels:
name: Visualization
description: plotting
name: Performance
description: Memory or execution speed performance

Comments:
> is there some way to actually test this?

A first thing I see in `test_backend` is that `test_setting_backend_without_plot_raises` does not test `_get_plot_backend` directly but via `set_option`, and does not test with an entry point without a `.plot` method, only for unregistered modules, because it wasn't checked in the code either.

A second is to test whether `_get_plot_backend("matplotlib")` returns `pandas.plotting._matplotlib`.
how do we know that this is better perf wise? we don't have any registered backends in pandas tests (I think). I am very leary of changing this as last time this broke things for a while as its pretty fragile. If we have some testsing & perf benchmarks would feel better here.
I've added a benchmark that runs `_get_plot_backend` with many (1000) dummy backends added in the setup. That's the way I found to have some loading time, another would be to add a dummy but slow to load backend, which I don't know how to make.

Here's the output from `asv continuous -f 1.1 master entry-pt-lazy-load -b plotting.BackendLoading`:
```
       before           after         ratio
     [b2a36bdf]       [76a912ec]
     <master>         <entry-pt-lazy-load>
-      2.20±0.6μs        159±0.5ns     0.07  plotting.BackendLoading.time_get_plot_backend`
```
I'm surprised by how low the measured times are, when I run the same thing outside of `asv` I get times of the order of ~100ms. I'm very new to benchmarking so let me know if you can explain this, especially if it's because I did something wrong.

Edit: had already tried setting `repeat` and `number` to 1 and saw no change, but I wasn't aware of `warmup_time`! Here are the new results in 6105c6f, which make much more sense:
```
       before           after         ratio
     [b2a36bdf]       [47130fad]
     <master>         <entry-pt-lazy-load>
-       232±0.2ms       4.00±0.3ms     0.02  plotting.BackendLoading.time_get_plot_backend
```
@TLouf 1000 is not realistic, let's see 10
It's not realistic in terms of number of backends, but these are also extremely fast to load, as opposed to some real plotting backends. As I mentioned in the issue, `hvPlot` takes 2s to load on my machine, and in the current implementation, if it is present in the environment, it will be loaded, even if the user plots with `matplotlib`. So the performance improvement highly depends on what backends have been installed.

Anyway, here's the result  with 10:
```
       before           after         ratio
     [b2a36bdf]       [47130fad]
     <master>         <entry-pt-lazy-load>
-       10.9±0.1ms       3.29±0.5ms     0.30  plotting.BackendLoading.time_get_plot_backend
```

Done. I had to add a boolean `found_backend` in `_load_backend` to make mypy happy, because initialising `module` to None was incompatible with the return type, which is necessarily a module, as the function raises when no backend is found.
thanks @TLouf