code: def getLayout(
      kind=None,
      theme=None,
      title="",
      xTitle="",
      yTitle="",
      zTitle="",
      barmode="",
      bargap=None,
      bargroupgap=None,
      margin=None,
      dimensions=None,
      width=None,
      height=None,
      annotations=None,
      is3d=False,
      **kwargs,
  ):
      """
      Generates a plotly Layout
  
      Parameters:
      -----------
              theme : string
                      Layout Theme
                              solar
                              pearl
                              white
              title : string
                      Chart Title
              xTitle : string
                      X Axis Title
              yTitle : string
                      Y Axis Title
              zTitle : string
                      Z Axis Title
                      Applicable only for 3d charts
              barmode : string
                      Mode when displaying bars
                              group
                              stack
                              overlay
              bargap : float
                      Sets the gap between bars
                              [0,1)
                      Applicabe for bar and histogram plots
              bargroupgap : float
                      Set the gap between groups
                              [0,1)
                      Applicabe for bar and histogram plots
              gridcolor : string
                              grid color
              zerolinecolor : string
                              zero line color
              margin : dict or tuple
                              Dictionary (l,r,b,t) or
                              Tuple containing the left,
                              right, bottom and top margins
              dimensions : tuple
                      Dimensions of figure
              annotations : dict or list
                      Dictionary of annotations
                              {x_point : text}
                      or
                      List of Plotly Annotations
              is3d : bool
                      Indicates if the layout is for a 3D chart
  
              Other Kwargs
              ============
  
              Shapes
                      hline : int, list or dict
                              Draws a horizontal line at the
                              indicated y position(s)
                              Extra parameters can be passed in
                              the form of a dictionary (see shapes)
                      vline : int, list or dict
                              Draws a vertical line at the
                              indicated x position(s)
                              Extra parameters can be passed in
                              the form of a dictionary (see shapes)
                      hspan : (y0,y1)
                              Draws a horizontal rectangle at the
                              indicated (y0,y1) positions.
                              Extra parameters can be passed in
                              the form of a dictionary (see shapes)
                      vspan : (x0,x1)
                              Draws a vertical rectangle at the
                              indicated (x0,x1) positions.
                              Extra parameters can be passed in
                              the form of a dictionary (see shapes)
                      shapes : dict or list(dict)
                              List of dictionaries with the
                              specifications of a given shape.
                              See help(cufflinks.tools.get_shape)
                              for more information
  
              Axis Ranges
                      xrange : [lower_bound,upper_bound]
                              Sets the range for the x axis
                      yrange : [lower_bound,upper_bound]
                              Sets the range for the y axis
                      zrange : [lower_bound,upper_bound]
                              Sets the range for the z axis
  
              Explicit Layout Updates
                      layout_update : dict
                              The layout will be modified with all
                              the explicit values stated in the
                              dictionary
  
              Range Selector
                      rangeselector : dict
                              Defines a rangeselector object
                              see help(cf.tools.get_range_selector) for more information
                              Example:
                                      {'steps':['1y','2 months','5 weeks','ytd','2mtd'],
                                       'axis':'xaxis', 'bgcolor' : ('blue',.3),
                                       'x': 0.2 , 'y' : 0.9}
  
              Range Slider
                      rangeslider : bool or dict
                              Defines if a rangeslider is displayed
                              If bool:
                                      True : Makes it visible
                              if dict:
                                      Rangeslider object
                              Example:
                                      {'bgcolor':('blue',.3),'autorange':True}
  
              Annotations
                      fontcolor : str
                              Text color for annotations
                      fontsize : int
                              Text size for annotations
                      textangle : int
                              Textt angle
                      See https://plot.ly/python/reference/#layout-annotations
                      for a complete list of valid parameters.
      """
  
      for key in list(kwargs.keys()):
          if key not in __LAYOUT_KWARGS:
              raise Exception("Invalid keyword : '{0}'".format(key))
  
      if not theme:
          theme = auth.get_config_file()["theme"]
  
      theme_data = getTheme(theme)
      layout = theme_data["layout"]
      try:
          layout["xaxis"]["title"].update({"text": xTitle})
          layout["yaxis"]["title"].update({"text": yTitle})
      except:
          layout["xaxis"].update({"title": xTitle})
          layout["yaxis"].update({"title": yTitle})
  
      fontfamily = kwargs.pop("fontfamily", None)
      if fontfamily:
          deep_update(layout, {"font": {"family": fontfamily}})
  
      if barmode:
          layout.update({"barmode": barmode})
      if bargroupgap:
          layout.update({"bargroupgap": bargroupgap})
      if bargap:
          layout.update(bargap=bargap)
      if title:
          try:
              layout["title"].update({"text": title})
          except:
              layout.update({"title": title})
      if annotations:
          layout.update({"annotations": annotations})
  
      def update_axis(layout, axis="xy", **vals):
          for _x in axis:
              for k, v in list(vals.items()):
                  if v == None:
                      vals.pop(k)
              for k in layout:
                  if "{0}{1}".format(_x, "axis") in k:
                      layout[k].update(**vals)
          return layout
  
      axis_kwargs = check_kwargs(kwargs, __LAYOUT_AXIS, {}, True)
      xaxis_kwargs = kwargs_from_keyword(kwargs, {}, "xaxis", True)
      yaxis_kwargs = kwargs_from_keyword(kwargs, {}, "yaxis", True)
  
      for _x, _vals in (
          ("xy", axis_kwargs),
          ("x", xaxis_kwargs),
          ("y", yaxis_kwargs),
      ):
          layout = update_axis(layout, _x, **_vals)
  
      if margin:
          if isinstance(margin, dict):
              margin = margin
          else:
              margin = dict(list(zip(("l", "r", "b", "t"), margin)))
          layout.update(margin=margin)
  
      if dimensions:
          layout.update(width=dimensions[0])
          layout.update(height=dimensions[1])
  
      if height:
          layout.update(height=height)
      if width:
          layout.update(width=width)
      if is3d:
          if "3d" in theme_data:
              layout = deep_update(layout, theme_data["3d"])
          zaxis = layout["xaxis"].copy()
          zaxis.update(title=zTitle)
          scene = dict(
              xaxis=layout["xaxis"].copy(),
              yaxis=layout["yaxis"].copy(),
              zaxis=zaxis,
          )
          layout.update(scene=scene)
          del layout["xaxis"]
          del layout["yaxis"]
  
      ## Axis Range
      for r in ["x", "y", "z"]:
          if "{0}range".format(r) in kwargs:
              if is3d:
                  layout["scene"]["{0}axis".format(r)].update(
                      range=kwargs["{0}range".format(r)]
                  )
              else:
                  layout["{0}axis".format(r)].update(
                      range=kwargs["{0}range".format(r)]
                  )
  
      # Need to update this for an add_axis approach.
      if kind in ("candlestick", "ohlc", "candle"):
          layout["yaxis2"] = layout["yaxis"].copy()
          layout["yaxis"].update(showticklabels=False)
  
      ## Kwargs
  
      if "legend" in kwargs:
          if type(kwargs["legend"]) == bool:
              layout["showlegend"] = kwargs["legend"]
          elif type(kwargs["legend"]) == str:
              if kwargs["legend"] == "top":
                  layout["legend"].update(
                      orientation="h", yanchor="bottom", x=0.3, y=0.95
                  )
              elif kwargs["legend"] == "bottom":
                  layout["legend"].update(
                      orientation="h", yanchor="bottom", x=0.3, y=-0.5
                  )
              layout["showlegend"] = True
          else:
              layout["legend"] = kwargs["legend"]
              layout["showlegend"] = True
  
      if "showlegend" in kwargs:
          layout["showlegend"] = kwargs["showlegend"]
  
      # Logarithmic Axis
      for _ in ["x", "y", "z"]:
          if "log{0}".format(_) in kwargs:
              if is3d:
                  if kwargs["log{0}".format(_)]:
                      layout["scene"]["{0}axis".format(_)][
                          "type"
                      ] = "log"
              else:
                  if kwargs["log{0}".format(_)]:
                      layout["{0}axis".format(_)]["type"] = "log"
  
      # Shapes
  
      if any(
          k in kwargs
          for k in ["vline", "hline", "shapes", "hspan", "vspan"]
      ):
          shapes = []
  
          def get_shapes(xline):
              orientation = xline[0]
              xline = kwargs[xline]
              if isinstance(xline, list):
                  for x_i in xline:
                      if isinstance(x_i, dict):
                          x_i["kind"] = "line"
                          shapes.append(get_shape(**x_i))
                      else:
                          if orientation == "h":
                              shapes.append(
                                  get_shape(kind="line", y=x_i)
                              )
                          else:
                              shapes.append(
                                  get_shape(kind="line", x=x_i)
                              )
              elif isinstance(xline, dict):
                  shapes.append(get_shape(**xline))
              else:
                  if orientation == "h":
                      shapes.append(get_shape(kind="line", y=xline))
                  else:
                      shapes.append(get_shape(kind="line", x=xline))
  
          def get_span(xspan):
              orientation = xspan[0]
              xspan = kwargs[xspan]
              if isinstance(xspan, list):
                  for x_i in xspan:
                      if isinstance(x_i, dict):
                          x_i["kind"] = "rect"
                          shapes.append(get_shape(**x_i))
                      else:
                          v0, v1 = x_i
                          if orientation == "h":
                              shapes.append(
                                  get_shape(
                                      kind="rect",
                                      y0=v0,
                                      y1=v1,
                                      fill=True,
                                      opacity=0.5,
                                  )
                              )
                          else:
                              shapes.append(
                                  get_shape(
                                      kind="rect",
                                      x0=v0,
                                      x1=v1,
                                      fill=True,
                                      opacity=0.5,
                                  )
                              )
              elif isinstance(xspan, dict):
                  xspan["kind"] = "rect"
                  shapes.append(get_shape(**xspan))
              elif isinstance(xspan, tuple):
                  v0, v1 = xspan
                  if orientation == "h":
                      shapes.append(
                          get_shape(
                              kind="rect",
                              y0=v0,
                              y1=v1,
                              fill=True,
                              opacity=0.5,
                          )
                      )
                  else:
                      shapes.append(
                          get_shape(
                              kind="rect",
                              x0=v0,
                              x1=v1,
                              fill=True,
                              opacity=0.5,
                          )
                      )
              else:
                  raise Exception(
                      "Invalid value for {0}span: {1}".format(
                          orientation, xspan
                      )
                  )
  
          if "hline" in kwargs:
              get_shapes("hline")
          if "vline" in kwargs:
              get_shapes("vline")
          if "hspan" in kwargs:
              get_span("hspan")
          if "vspan" in kwargs:
              get_span("vspan")
          if "shapes" in kwargs:
              shapes_ = kwargs["shapes"]
              if isinstance(shapes_, list):
                  for i in shapes_:
                      shp = i if "type" in i else get_shape(**i)
                      shapes.append(shp)
              elif isinstance(shapes_, dict):
                  shp = (
                      shapes_
                      if "type" in shapes_
                      else get_shape(**shapes_)
                  )
                  shapes.append(shp)
              else:
                  raise Exception(
                      "Shapes need to be either a dict or list of dicts"
                  )
  
          layout["shapes"] = shapes
  
      # Maps
      if kind in ("choropleth", "scattergeo"):
          kw = check_kwargs(kwargs, __GEO_KWARGS)
          defaults = {
              "projection": {"type": "equirectangular"},
              "showframe": False,
              "showcoastlines": False,
          }
          for k, v in list(defaults.items()):
              if k not in kw:
                  kw[k] = v
          kw_ = kwargs_from_keyword(kw, {}, "projection")
          deep_update(kw, kw_)
          layout["geo"] = kw
          del layout["xaxis"]
          del layout["yaxis"]
          if not margin:
              layout["margin"] = {"autoexpand": True}
  
      # Range Selector
      if "rangeselector" in kwargs:
          rs = kwargs["rangeselector"]
          if "axis" in rs:
              axis = rs["axis"]
              del rs["axis"]
          else:
              axis = "xaxis"
          layout[axis]["rangeselector"] = get_range_selector(**rs)
  
      # Range Slider
      if "rangeslider" in kwargs:
          if type(kwargs["rangeslider"]) == bool:
              if kwargs["rangeslider"]:
                  layout["xaxis"]["rangeslider"] = dict(
                      visible=kwargs["rangeslider"]
                  )
              else:
                  layout["xaxis"]["rangeslider"] = dict(visible=False)
                  # layout['yaxis1'].update(domain=(0,0))
          else:
              layout["xaxis"]["rangeslider"] = kwargs["rangeslider"]
      else:
          if kind in ("ohlc", "candle", "candlestick"):
              layout["xaxis"]["rangeslider"] = dict(visible=False)
              # layout['yaxis1'].update(domain=(0,0))
  
      # Explicit Updates
  
      if "layout_update" in kwargs:
          layout = deep_update(layout, kwargs["layout_update"])
  
      return layout
  
imports: import copy
  import numpy
  import pandas
  import plotly.offline
  import plotly.figure_factory
  from plotly.graph_objs import Figure, Scatter, Line
  from plotly.subplots import make_subplots
  from .None import themes
  from .None import auth, ta
  from .colors import normalize, to_rgba
  from .utils import check_kwargs, deep_update, dict_replace_keyword, kwargs_from_keyword, merge_dict, is_list, make_list
label_desc: Use image node_id 4 for calling a global function with example usage: getLayout(kind, theme, title, xTitle, yTitle, zTitle, barmode, bargap, bargroupgap, margin, dimensions, width, height, annotations, is3d) and returns: layout, layout