Repository: lgienapp/aquarel

Issue:
set_tick_labels location parameter produces a value error
```py
theme = load_theme("arctic_dark").set_tick_labels(location="top")
theme.apply()
```
produces
```
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In [2], line 2
      1 theme = load_theme("arctic_dark").set_tick_labels(location="top")
----> 2 theme.apply()

File ~/Documents/aquarel/aquarel/theme.py:325, in Theme.apply(self)
    323         if mapped_key == "axes.prop_cycle":
    324             value = cycler("color", value)
--> 325         mpl.rcParams.update({sub_key: value})
    326 else:
    327     # Special treatment for color palette, as this is otherwise not JSON serializable
    328     if mapped_key == "axes.prop_cycle":

File /Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/_collections_abc.py:940, in MutableMapping.update(self, other, **kwds)
    938 if isinstance(other, Mapping):
    939     for key in other:
--> 940         self[key] = other[key]
    941 elif hasattr(other, "keys"):
    942     for key in other.keys():

File ~/Documents/aquarel/venv/lib/python3.9/site-packages/matplotlib/__init__.py:648, in RcParams.__setitem__(self, key, val)
    646         cval = self.validate[key](val)
    647     except ValueError as ve:
--> 648         raise ValueError(f"Key {key}: {ve}") from None
    649     dict.__setitem__(self, key, cval)
    650 except KeyError as err:

ValueError: Key xaxis.labellocation: 'top' is not a valid value for xaxis.labellocation; supported values are ['left', 'center', 'right']
```
If location is left
```
ValueError: Key yaxis.labellocation: 'left' is not a valid value for yaxis.labellocation; supported values are ['bottom', 'center', 'top']
```

In the docs, valid options are given as this:

```
location (Optional[str]) – location of the tick labels, can be {“left”, “right”, “bottom”, “top”, “center”}, default: center

Hints from issue comments:
@lucianosrp: I think the problem is that aquarel is attempting to set the same label position to both axes.
The XAxis has only "left","center" and "right" as valid positions, while YAxis has "bottom", "center" and "top".

When you set the location as "top" the script is: 

  1. setting the XAxis label position to "top" which raises the `ValueError`

When you set  the location as "left" the script is: 
  1. setting the XAxis label position to "left" (which is valid)
  2. attempts to set the YAxis label position to "left" which raises the `ValueError`
  
  No errors are being raise if you set the location as "center", which is the only position which is accepted by both Axes.
  
  I think aquarel should handle this scenarios better -  @lgienapp  I can have a look on a solution! @lgienapp: Sure, go ahead, a fix for this would be very welcome!

Solution patch:
diff --git a/aquarel/theme.py b/aquarel/theme.py
index 6c6d81b..a286fea 100644
--- a/aquarel/theme.py
+++ b/aquarel/theme.py
@@ -310,6 +310,13 @@ class Theme:
                         # Special treatment for color palette, as this is otherwise not JSON serializable
                         if mapped_key == "axes.prop_cycle":
                             value = cycler("color", value)
+                        if sub_key == "xaxis.labellocation":
+                            if value not in ["left", "right", "center"]:
+                                value = mpl.rcParamsDefault[sub_key]
+                        elif sub_key == "yaxis.labellocation":
+                            if value not in ["top", "bottom", "center"]:
+                                value = mpl.rcParamsDefault[sub_key]
+
                         mpl.rcParams.update({sub_key: value})
                 else:
                     # Special treatment for color palette, as this is otherwise not JSON serializable


Test patch:
diff --git a/tests/test_theme.py b/tests/test_theme.py
index 101b088..a417ccf 100644
--- a/tests/test_theme.py
+++ b/tests/test_theme.py
@@ -226,6 +226,33 @@ class TestTheme(unittest.TestCase):
         legend_test("margin", [0, 0.5, 1.5, 5])
         legend_test("spacing", [0, 0.5, 1.5, 5])
 
+    def test_set_tick_label(self):
+        def tick_label_test(parameter, option):
+            print(f"\n***** set_tick_labels.{parameter} *****")
+            print(f"> set tick_labels.{parameter} to be {option}")
+            with self.theme.set_tick_labels(**{parameter: option}):
+                for param in self.theme._rcparams_mapping["tick_labels"][parameter]:
+                    if param == "xaxis.labellocation":
+                        if option == "left":
+                            self.assertEqual(option, "left")
+                        elif option == "right":
+                            self.assertEqual(option, "right")
+                        elif option == "center":
+                            self.assertEqual(option, "center")
+                    elif param == "yaxis.labellocation":
+                        if option == "top":
+                            self.assertEqual(option, "top")
+                        elif option == "bottom":
+                            self.assertEqual(option, "bottom")
+                        elif option == "center":
+                            self.assertEqual(option, "center")
+
+        tick_label_test("location", "center")
+        tick_label_test("location", "left")
+        tick_label_test("location", "right")
+        tick_label_test("location", "bottom")
+        tick_label_test("location", "top")
+
 
 if __name__ == "__main__":
     unittest.main()