Repository: vega/altair

Issue:
Equal default chart dimensions
Currently the default theme in Altair specifies an aspect ratio of 4/3, with a width of 400 and a height of 300 (for continuous data):

![image](https://user-images.githubusercontent.com/4560057/160310026-189ab3c6-226b-4659-9fe0-e2a7b9d595a0.png)

The default in VegaLite is to make both dimensions of equal length, which I think makes sense since it spreads the data over the same amount of pixels on both the X and Y axis. This could have benefits in terms of making it easier to fairly compare the distribution of the data between the two plotted variables instead of it appearing more spread out over the X axis due to the increase chart width. The default in Vega-Lite is to use 200 px for the width and height which I think is a bit small, but setting both to 300 px looks good:

![image](https://user-images.githubusercontent.com/4560057/160310042-ca229ef9-2d9c-451e-9af2-a66c899bd941.png)

What do you all think about changing the default width in Altair to 300 px, so that both the X and Y axes occupy the same amount of pixels by default? Are there benefits of having an unequal aspect ratio like the current default that I am missing (maybe that it is more similar to the screen aspect ratio)? I don't think this is a major concern, but thought I would bring it up and see if others also regard it as a small improvement or just a matter of personal aesthetics/taste.


Discussion:
I like the default of vega-lite
I see your point about the distortion along the x axis for scatter plots. However, for some charts such as histograms and timeseries charts I prefer a wider chart which better uses the usual screen ratio.

I don't have a strong opinion on this as I usually use a custom theme anyway to increase the size of the chart to something like 400x700 and font sizes to 14-16. To me, this is visually more appealing and easier to read especially on bigger screens. It's also feedback I got when showing the Altair library as an alternative to e.g. Plotly

```python
def altair_theme(font_size: int = 16):
    return {
        "config": {
            "axis": {
                "labelFontSize": font_size,
                "titleFontSize": font_size,
            },
            "header": {"labelFontSize": font_size, "titleFontSize": font_size},
            "legend": {
                "labelFontSize": font_size,
                "titleFontSize": font_size,
            },
            "title": {"fontSize": font_size},
            "view": {"width": 700, "height": 400},
        }
    }
```

Is there any interest in including such a slight modification of the default theme in Altair, maybe "default_large"? For charts which are used for reports, web apps, etc. I'd specify the exact configuration anyway but for data exploration it's great if such a theme can be quickly activated at the start of a notebook with `alt.themes.enable('default_large')` instead of having to import it from a custom module or always defining this function.
I agree that histograms and timeseries can benefit from a wider aspect ratio. However, I think that at least timeseries often need to be changed even from the current aspect ratio. For histograms, I don't think they look terrible with[ the default square dimensions](https://vega.github.io/vega-lite/examples/#histograms-density-plots-and-dot-plots), although I would probably have them at around half the height personally. Importantly, I don't think that either of these scenarios can lead to misintrerpreting the data and it is often easy to see that you want to make the chart wider in these cases, whereas having non-equal axis can distort the data a little and make it more difficult to realize that you should change it so it feels like the safer default for me which is also the most appropriate in many cases.

I agree with you that the font size is small by default and would be in favor of having it slightly bigger in the default theme. I am think 1-2 pts bigger, so around 13-14 if the default is 12 (which I think it is). Rather than adding a different theme for this, I think we should add a way to easily scale all fonts and all chart elements [as I suggested here for vega](https://github.com/vega/vega/issues/2946). I would be happy if we added this to altair in the meantime and I am thinking it would be similar to how in Seaborn's [set_theme](http://seaborn.pydata.org/generated/seaborn.set_theme.html#seaborn.set_theme) function, you can change the scaling of all plot elements (so text, axes, markers, etc) via the `plotting_context` param, and control the size of just the text with the `font_scale` param.

One part that is tricky in Altair, is that all the default font sizes are only available in the Vega source files, so we would need to manually right those down to be able to scale them properly. We also need a mechanism that appends to the current theme rather than overwrites it (e.g. if someone enable the dark theme and then wanted to scale the font size). I started working on these a while back but haven't had time to revisit. This is what I had then in case someone is interested of continuing this before I get back to it (which likely will not be soon):

```diff
commit f775500aa35b3b6d6d2aa87032099de250224910
Author: Joel Ostblom <joel.ostblom@gmail.com>
Date:   Sun Mar 27 21:53:01 2022 -0700

    Add draft of theme modification function

diff --git a/altair/utils/theme.py b/altair/utils/theme.py
index 10dc6fa8..35294f96 100644
--- a/altair/utils/theme.py
+++ b/altair/utils/theme.py
@@ -1,10 +1,39 @@
 """Utilities for registering and working with themes"""
 
-from .plugin_registry import PluginRegistry
+from .plugin_registry import PluginRegistry, PluginEnabler
 from typing import Callable
 
 ThemeType = Callable[..., dict]
 
 
 class ThemeRegistry(PluginRegistry[ThemeType]):
-    pass
+
+    # The name could be update / edit / modify
+    # TODO how to make a useful docstring listing all params?
+    # docs mention that **config can be passed
+    # does this need to accept the **options kwds?? then we can't use **kwds which is convenient here, maybe optins_dict?
+    # also add scaling of all graphical elements?
+    # Could fonts be partial points? Otherwise always round down?
+    # if this is added in VL in the future, we can likely keep this interface the same, forward compatible
+    def modify(self, font_scale=None, **config):
+        if font_scale is not None:
+            config = self._scale_font()
+
+        # Register the modified theme under a new name
+        if self.active.split("_")[-1] == "modified":
+            updated_theme_name = self.active
+        else:
+            updated_theme_name = "{}_modified".format(self.active)
+        self.register(updated_theme_name, lambda: {"config": config})
+
+        # Enable the newly registered theme
+        return PluginEnabler(self, updated_theme_name)
+
+    def _scale_font(self, config):
+        # scale font and append to dict
+        # I think all font options are defined here https://github.com/vega/vega/blob/main/packages/vega-parser/src/config.js#L82-L129=
+        return config
```
I really like the idea of scaling the chart elements and fonts as in Seaborn! I'll take the scaling of the fonts first as that seems easier and still very useful. Thanks for the code snippet.
I made some minor progress but don't think I get around to a decent solution before the release of version 5. If someone else wants to pick this up, of course feel free! But this functionality could also easily be added in a minor release.

@mattijn @joelostblom However, the switch to the vega-lite default chart sizes should probably happen in a major release as it is quite a noticeable change impacting many users and not opt-in. What do you think? Height would need to be changed in https://github.com/altair-viz/altair/blob/master/altair/vegalite/v5/theme.py, https://github.com/altair-viz/altair/blob/master/altair/vegalite/v5/tests/test_theme.py, and https://github.com/altair-viz/altair/blob/master/altair/vegalite/v5/tests/test_api.py. Optionally, also in v3 and v4 folders.

Resolving patch:
diff --git a/altair/vegalite/v5/theme.py b/altair/vegalite/v5/theme.py
--- a/altair/vegalite/v5/theme.py
+++ b/altair/vegalite/v5/theme.py
@@ -22,7 +22,7 @@ def __init__(self, theme):
     def __call__(self):
         return {
             "usermeta": {"embedOptions": {"theme": self.theme}},
-            "config": {"view": {"continuousWidth": 400, "continuousHeight": 300}},
+            "config": {"view": {"continuousWidth": 300, "continuousHeight": 300}},
         }
 
     def __repr__(self):
@@ -37,14 +37,14 @@ def __repr__(self):
 
 themes.register(
     "default",
-    lambda: {"config": {"view": {"continuousWidth": 400, "continuousHeight": 300}}},
+    lambda: {"config": {"view": {"continuousWidth": 300, "continuousHeight": 300}}},
 )
 themes.register(
     "opaque",
     lambda: {
         "config": {
             "background": "white",
-            "view": {"continuousWidth": 400, "continuousHeight": 300},
+            "view": {"continuousWidth": 300, "continuousHeight": 300},
         }
     },
 )


Test patch:
diff --git a/tests/vegalite/v5/tests/test_api.py b/tests/vegalite/v5/tests/test_api.py
--- a/tests/vegalite/v5/tests/test_api.py
+++ b/tests/vegalite/v5/tests/test_api.py
@@ -704,13 +704,13 @@ def test_themes():
 
     with alt.themes.enable("default"):
         assert chart.to_dict()["config"] == {
-            "view": {"continuousWidth": 400, "continuousHeight": 300}
+            "view": {"continuousWidth": 300, "continuousHeight": 300}
         }
 
     with alt.themes.enable("opaque"):
         assert chart.to_dict()["config"] == {
             "background": "white",
-            "view": {"continuousWidth": 400, "continuousHeight": 300},
+            "view": {"continuousWidth": 300, "continuousHeight": 300},
         }
 
     with alt.themes.enable("none"):
diff --git a/tests/vegalite/v5/tests/test_theme.py b/tests/vegalite/v5/tests/test_theme.py
--- a/tests/vegalite/v5/tests/test_theme.py
+++ b/tests/vegalite/v5/tests/test_theme.py
@@ -15,5 +15,5 @@ def test_vega_themes(chart):
             dct = chart.to_dict()
         assert dct["usermeta"] == {"embedOptions": {"theme": theme}}
         assert dct["config"] == {
-            "view": {"continuousWidth": 400, "continuousHeight": 300}
+            "view": {"continuousWidth": 300, "continuousHeight": 300}
         }