Repository: plotly/plotly.py

Issue:
Presentation template should not change colors
## Issue

If you combine the 'presentation' template with another template using the plus-sign (+) composition syntax, the presentation template will change the colors of points, lines, and other traces that are defined in the other template.

```
plotly==4.1.1
```

## Expected behavior

The 'presentation' template should only change the size of text, points, and lines. It should not change the colors.

## Reprex

```
import plotly.express as px

iris = px.data.iris()

# Colors correctly follow the 'plotly_dark' theme
dark_plt = px.scatter(iris, x='sepal_length', y='sepal_width', color='species', template='plotly_dark')
dark_plt.show()

# 'presentation' template changes colors from 'plotly_dark' theme when it shouldn't
dark_pres_plt = px.scatter(iris, x='sepal_length', y='sepal_width', color='species', template='plotly_dark+presentation')
dark_pres_plt.show()
```



Discussion:

Resolving patch:
diff --git a/packages/python/plotly/plotly/basedatatypes.py b/packages/python/plotly/plotly/basedatatypes.py
--- a/packages/python/plotly/plotly/basedatatypes.py
+++ b/packages/python/plotly/plotly/basedatatypes.py
@@ -492,7 +492,10 @@ def update(self, dict1=None, **kwargs):
                             else:
                                 # Accept v
                                 self[k] = v
-                        elif isinstance(update_target, BasePlotlyType) or (
+                        elif (
+                            isinstance(update_target, BasePlotlyType)
+                            and isinstance(v, (dict, BasePlotlyType))
+                        ) or (
                             isinstance(update_target, tuple)
                             and isinstance(update_target[0], BasePlotlyType)
                         ):
diff --git a/packages/python/plotly/plotly/io/_templates.py b/packages/python/plotly/plotly/io/_templates.py
--- a/packages/python/plotly/plotly/io/_templates.py
+++ b/packages/python/plotly/plotly/io/_templates.py
@@ -8,6 +8,8 @@
 import json
 from functools import reduce
 
+from six import string_types
+
 try:
     from math import gcd
 except ImportError:
@@ -61,24 +63,34 @@ def __iter__(self):
         return iter(self._templates)
 
     def __getitem__(self, item):
-        template = self._templates[item]
-        if template is Lazy:
-            from plotly.graph_objs.layout import Template
-
-            if item == "none":
-                # "none" is a special built-in named template that applied no defaults
-                template = Template()
-                self._templates[item] = template
-            else:
-                # Load template from package data
-                path = os.path.join("package_data", "templates", item + ".json")
-                template_str = pkgutil.get_data("plotly", path).decode("utf-8")
-                template_dict = json.loads(template_str)
-                template = Template(template_dict)
-
-                self._templates[item] = template
-
-        return template
+        if isinstance(item, string_types):
+            template_names = item.split("+")
+        else:
+            template_names = [item]
+
+        templates = []
+        for template_name in template_names:
+            template = self._templates[template_name]
+            if template is Lazy:
+                from plotly.graph_objs.layout import Template
+
+                if template_name == "none":
+                    # "none" is a special built-in named template that applied no defaults
+                    template = Template()
+                    self._templates[template_name] = template
+                else:
+                    # Load template from package data
+                    path = os.path.join(
+                        "package_data", "templates", template_name + ".json"
+                    )
+                    template_str = pkgutil.get_data("plotly", path).decode("utf-8")
+                    template_dict = json.loads(template_str)
+                    template = Template(template_dict)
+
+                    self._templates[template_name] = template
+            templates.append(self._templates[template_name])
+
+        return self.merge_templates(*templates)
 
     def __setitem__(self, key, value):
         self._templates[key] = self._validate(value)


Test patch:
diff --git a/packages/python/plotly/plotly/tests/test_core/test_graph_objs/test_template.py b/packages/python/plotly/plotly/tests/test_core/test_graph_objs/test_template.py
--- a/packages/python/plotly/plotly/tests/test_core/test_graph_objs/test_template.py
+++ b/packages/python/plotly/plotly/tests/test_core/test_graph_objs/test_template.py
@@ -508,6 +508,18 @@ def test_merge_by_flaglist_string(self):
         self.assertEqual(self.template1, self.template1_orig)
         self.assertEqual(self.template2, self.template2_orig)
 
+    def test_flaglist_string_getitem(self):
+        result = pio.templates["template1+template2"]
+        expected = self.expected1_2
+        self.assertEqual(result, expected)
+
+    def test_update_template_with_flaglist(self):
+        fig = go.Figure()
+        fig.update(layout_template="template1+template2")
+        result = fig.layout.template
+        expected = self.expected1_2
+        self.assertEqual(result, expected)
+
     def test_set_default_template(self):
         orig_default = pio.templates.default
         pio.templates.default = "plotly"