Repository: napari/napari

Issue:
Show logo during startup
## 🚀 Feature
Right now napari takes a long time to launch the viewer. People can get discouraged as they wait, unsure if napari is loading, or if their data is loading, or if it is just hanging. Showing the napari logo, possibly with / without some text during that time might make it feel better.


Discussion:
Just to clarify here: I think we should only do this in `__main__` or even only in the bundled app. It would be very jarring to have this happen when launching from an IPython session. The correct solution for IPython is to dramatically reduce the startup time. To reiterate what I mentioned in the meeting, startup time from the command-line is about 2s on Linux, which is reasonably fast. There's nothing fundamentally slow about our startup, and we need to check what's happening on mac to make it so slow.
We can do it in bundled app with a runtime-hook which will be executed right before execution of our main entry point @jni 
@sofroniewn pointed me to this from #744.  Just wanted to hear exactly when people feel like it's slow?  I think the majority of that time might be qt itself spinning up or imports (which is harder to do anything about).  On my system, when running from `__main__`, the majority of time is in `__init__`:
```
start init:    0.000
finish init:   1.413
start main:    1.416
start gui_qt:  1.417
app ready:     1.601
image shown:   2.281
```

So even if we wanted to do something with, say, [QSplashScreen](https://doc.qt.io/qt-5/qsplashscreen.html), that splash wouldn't show up until we instantiate the app in main, and then only very briefly... unless we tried to do something completely independent of Qt, at the very beginning of `__init__`.  I really haven't minded the startup time much, @sofroniewn, is it still slow for you, and under what specific startup procedure?
That's great profiling @tlambert03 - how did you do it? I get about `3.2` seconds between hitting enter on the command line after typing `napari` and seeing something on my screen (timed using the stop watch on my phone and me pressing buttons). That becomes a little longer if I try to load a small image at the same time too.

If we could get something up at the end right after app ready it still might feel nicer. There are also times when people are launching from scripts doing more fileIO etc inside our `gui_qt` event loop so it might be nicer there too. Putting it there would also mean people launching from jupyter or IPython wouldn't see it too, which was a concern from @jni, and makes sense to me - I think expectations are different when launching from the command line vs an interactive session.

I might give it a quick try with `QSplashScreen` and we can also decide against it. It looks like that approach will be only a couple lines, thanks for the tips!
> how did you do it?

just `import time` and printed some `time.time()` statements at various places 😅
the first statement at the top of `__init__` fired pretty much instantaneously after hitting enter.  3.2 seconds is definitely a bit frustrating, and maybe our differences are just computer differences? (but it certainly means that many users will be experiencing 3+ seconds).  

I definitely agree with @jni that we should only have splash screens with `__main__` or a standalone app... but i'd be curious to hear what you think after trying `QSplashScreen`

Resolving patch:
diff --git a/napari/__main__.py b/napari/__main__.py
--- a/napari/__main__.py
+++ b/napari/__main__.py
@@ -50,7 +50,7 @@ def main():
         'only a single image is given.',
     )
     args = parser.parse_args()
-    with gui_qt():
+    with gui_qt(startup_logo=True):
         v = Viewer()
         if len(args.images) > 0:
             images = io.magic_imread(
diff --git a/napari/_qt/event_loop.py b/napari/_qt/event_loop.py
--- a/napari/_qt/event_loop.py
+++ b/napari/_qt/event_loop.py
@@ -1,13 +1,20 @@
 import sys
 from contextlib import contextmanager
+from os.path import dirname, join
 
-from qtpy.QtWidgets import QApplication
+from qtpy.QtGui import QPixmap
+from qtpy.QtWidgets import QApplication, QSplashScreen
 
 
 @contextmanager
-def gui_qt():
+def gui_qt(*, startup_logo=False):
     """Start a Qt event loop in which to run the application.
 
+    Parameters
+    ----------
+    startup_logo : bool
+        Show a splash screen with the napari logo during startup.
+
     Notes
     -----
     This context manager is not needed if running napari within an interactive
@@ -16,5 +23,11 @@ def gui_qt():
     ``ipython --gui=qt``.
     """
     app = QApplication.instance() or QApplication(sys.argv)
+    if startup_logo:
+        logopath = join(dirname(__file__), '..', 'resources', 'logo.png')
+        splash_widget = QSplashScreen(QPixmap(logopath).scaled(400, 400))
+        splash_widget.show()
     yield
+    if startup_logo:
+        splash_widget.close()
     app.exec_()


Test patch: