def __add__()

in python-package/lets_plot/plot/core.py [0:0]


    def __add__(self, other):
        """
        Allow to add different specs to the ``PlotSpec`` object.

        Examples
        --------
        .. jupyter-execute::
            :linenos:
            :emphasize-lines: 7

            from lets_plot import *
            LetsPlot.setup_html()
            p = ggplot({'x': [0, 1, 2], 'y': [0, 1, 2]}, aes('x', 'y'))
            l = layer('point', mapping=aes(color='x'))
            s = scale_color_discrete()
            t = theme(axis_title='blank')
            p + l + s + t

        """
        """
            plot + other_plot -> fail
            plot + layer -> plot[layers] += layer
            plot + geom ->  plot[layers] += new layer(geom)
            plot + scale -> plot[scales] += scale
            plot + metainfo -> plot[metainfo_list] += metainfo
            plot + [feature]  -> plot + each feature in []
            plot + theme + theme -> merged theme
        """
        if isinstance(other, PlotSpec):
            # pass and fail
            pass

        if isinstance(other, DummySpec):
            # nothing
            return self

        elif isinstance(other, FeatureSpec):
            plot = PlotSpec.duplicate(self)
            if other.kind == 'layer':
                if other.props()['geom'] == 'livemap':
                    plot.__is_livemap = True

                from lets_plot.plot.util import is_geo_data_frame  # local import to break circular reference
                if is_geo_data_frame(other.props().get('data')) \
                        or is_geo_data_frame(other.props().get('map')):
                    if plot.__crs_initialized:
                        if plot.__crs != other.props().get('use_crs'):
                            raise ValueError(
                                'All geoms with map parameter should either use same `use_crs` or not use it at all')
                    else:
                        plot.__crs_initialized = True
                        plot.__crs = other.props().get('use_crs')

                if plot.__is_livemap and plot.__crs is not None:
                    raise ValueError("livemap doesn't support `use_crs`")

                other.before_append(plot.__is_livemap)
                plot.__layers.append(other)
                return plot

            if other.kind == 'scale':
                plot.__scales.append(other)
                return plot

            if other.kind == 'theme':
                new_theme_options = {k: v for k, v in other.props().items() if v is not None}
                if 'name' in new_theme_options:
                    # keep the previously specified flavor
                    if plot.props().get('theme', {}).get('flavor', None) is not None:
                        new_theme_options.update({'flavor': plot.props()['theme']['flavor']})

                    # pre-configured theme overrides existing theme altogether.
                    plot.props()['theme'] = new_theme_options
                else:
                    # merge themes
                    old_theme_options = plot.props().get('theme', {})
                    plot.props()['theme'] = _theme_dicts_merge(old_theme_options, new_theme_options)

                return plot

            if other.kind == 'metainfo':
                plot.__metainfo_list.append(other)
                return plot

            if isinstance(other, FeatureSpecArray):
                for spec in other.elements():
                    plot = plot.__add__(spec)
                return plot

            if other.kind == 'guides':
                existing_options = plot.props().get('guides', {})
                plot.props()['guides'] = _merge_dicts_recursively(existing_options, other.as_dict())
                return plot

            if other.kind == 'mapping':  # +aes(..)
                # existing_spec = plot.props().get('mapping', aes())
                # merged_mapping = {**existing_spec.as_dict(), **other.as_dict()}
                # plot.props()['mapping'] = aes(**merged_mapping)
                from lets_plot.plot.util import update_plot_aes_mapping  # local import to break circular reference
                update_plot_aes_mapping(plot, other)
                return plot

            # add feature to properties
            plot.props()[other.kind] = other
            return plot

        return super().__add__(other)