code: def plot(  # noqa C901
      df_in,
      x=None,
      y=None,
      kind="line",
      figsize=None,
      use_index=True,
      title="",
      legend="top_right",
      logx=False,
      logy=False,
      xlabel=None,
      ylabel=None,
      xticks=None,
      yticks=None,
      xlim=None,
      ylim=None,
      fontsize_title=None,
      fontsize_label=None,
      fontsize_ticks=None,
      fontsize_legend=None,
      color=None,
      colormap=None,
      category=None,
      histogram_type=None,
      stacked=False,
      weights=None,
      bins=None,
      normed=False,
      cumulative=False,
      show_average=False,
      plot_data_points=False,
      plot_data_points_size=5,
      number_format=None,
      disable_scientific_axes=None,
      show_figure=True,
      return_html=False,
      panning=True,
      zooming=True,
      sizing_mode="fixed",
      toolbar_location="right",
      hovertool=True,
      hovertool_string=None,
      rangetool=False,
      vertical_xlabel=False,
      x_axis_location="below",
      webgl=True,
      reuse_plot=None,  # This keyword is not used by Pandas-Bokeh, but pandas plotting API adds it for series object calls
      **kwargs,
  ):
      """Method for creating a interactive with 'Bokeh' as plotting backend. Available
      plot kinds are:
  
      * line
      * point
      * scatter
      * bar / barh
      * hist
      * area
      * pie
      * map
  
      Examples
      --------
      >>> df.plot_bokeh.line()
      >>> df.plot_bokeh.scatter(x='x',y='y')
  
      These plotting methods can also be accessed by calling the accessor as a
      method with the ``kind`` argument (except of "map" plot):
      ``df.plot_bokeh(kind='line')`` is equivalent to ``df.plot_bokeh.line()``
  
      For more information about the individual plot kind implementations, have a
      look at the underlying method accessors (like df.plot_bokeh.line) or visit
      https://github.com/PatrikHlobil/Pandas-Bokeh.
  
      If `sizing_mode` is not fixed (default), it will overide the set plot width or height
      depending on which axis it is scaled on.
  
      """
  
      # Make a local copy of the DataFrame:
      df = df_in.copy()
      if isinstance(df, pd.Series):
          df = pd.DataFrame(df)
  
      if kind == "map":
          return mapplot(
              df,
              x=x,
              y=y,
              figsize=figsize,
              title=title,
              legend=legend,
              xlabel=xlabel,
              ylabel=ylabel,
              xlim=xlim,
              color=color,
              colormap=colormap,
              category=category,
              show_figure=show_figure,
              return_html=return_html,
              panning=panning,
              zooming=zooming,
              toolbar_location=toolbar_location,
              hovertool=hovertool,
              hovertool_string=hovertool_string,
              webgl=webgl,
              **kwargs,
          )
  
      # Check plot kind input:
      allowed_kinds = [
          "line",
          "step",
          "point",
          "scatter",
          "bar",
          "barh",
          "hist",
          "area",
          "pie",
          "map",
      ]
  
      rangetool_allowed_kinds = ["line", "step"]
  
      if kind not in allowed_kinds:
          allowed_kinds = "', '".join(allowed_kinds)
          raise ValueError(f"Allowed plot kinds are '{allowed_kinds}'.")
  
      if rangetool and kind not in rangetool_allowed_kinds:
          allowed_rangetool_kinds = "', '".join(rangetool_allowed_kinds)
          raise ValueError(
              f"For using the rangetool, the allowed plot kinds are '{allowed_rangetool_kinds}'."
          )
  
      if rangetool:
          x_axis_location = "above"
  
      # Get and check options for base figure:
      figure_options = {
          "title": title,
          "toolbar_location": toolbar_location,
          "active_scroll": "wheel_zoom",
          "width": 600,
          "height": 400,
          "output_backend": "webgl",
          "sizing_mode": sizing_mode,
          "x_axis_location": x_axis_location,
      }
      # Initializing rangetool plot variable:
      p_rangetool = None
  
      if figsize is not None:
          width, height = figsize
          figure_options["width"] = width
          figure_options["height"] = height
      if logx:
          figure_options["x_axis_type"] = "log"
      if logy:
          figure_options["y_axis_type"] = "log"
      if xlabel is not None:
          figure_options["x_axis_label"] = xlabel
      if ylabel is not None:
          figure_options["y_axis_label"] = ylabel
      if xlim is not None:
          if not isinstance(xlim, (tuple, list)):
              raise ValueError(
                  "<xlim> must be a list/tuple of form (x_min, x_max)."
              )
          elif len(xlim) != 2:
              raise ValueError(
                  "<xlim> must be a list/tuple of form (x_min, x_max)."
              )
          else:
              figure_options["x_range"] = xlim
      if ylim is not None:
          if not isinstance(ylim, (tuple, list)):
              raise ValueError(
                  "<ylim> must be a list/tuple of form (y_min, y_max)."
              )
          elif len(ylim) != 2:
              raise ValueError(
                  "<ylim> must be a list/tuple of form (y_min, y_max)."
              )
          else:
              figure_options["y_range"] = ylim
      if webgl:
          figure_options["output_backend"] = "webgl"
      if number_format is None:
          number_format = ""
      else:
          number_format = "{%s}" % number_format
  
      # Check hovertool_string and define additional columns to keep in source:
      additional_columns = _extract_additional_columns(
          df, hovertool_string
      )
  
      # Set standard linewidth:
      if "line_width" not in kwargs:
          kwargs["line_width"] = 2
  
      # Get x-axis Name and Values:
      delete_in_y = None
      if x is not None:
          if issubclass(x.__class__, pd.Index) or issubclass(
              x.__class__, pd.Series
          ):
              if x.name is not None:
                  name = str(x.name)
              else:
                  name = ""
              x = x.values
          elif x in df.columns:
              delete_in_y = x
              name = str(x)
              x = df[x].values
          elif isinstance(x, (tuple, list, type(np.array))):
              if len(x) == len(df):
                  x = x
                  name = ""
              else:
                  raise Exception(
                      "Length of provided <x> argument does not fit length of DataFrame or Series."
                  )
          else:
              raise Exception(
                  "Please provide for the <x> parameter either a column name of the DataFrame/Series or an array of the same length."
              )
      else:
          if use_index:
              x = df.index.values
              if df.index.name is not None:
                  name = str(df.index.name)
              else:
                  name = ""
          else:
              x = np.linspace(0, len(df) - 1, len(df))
              name = ""
  
      # Define name of axis of x-values (for horizontal plots like barh, this corresponds
      # to y-axis):
      if kind == "barh":
          if "y_axis_label" not in figure_options:
              figure_options["y_axis_label"] = name
  
      else:
          if "x_axis_label" not in figure_options:
              figure_options["x_axis_label"] = name
  
      # Check type of x-axis:
      if check_type(x) == "datetime":
          figure_options["x_axis_type"] = "datetime"
          xaxis_type = "datetime"
          if xlim is not None:
              starttime, endtime = xlim
              try:
                  starttime = pd.to_datetime(starttime)
              except ParserError:
                  raise ValueError(
                      "Could not parse x_min input of <xlim> as datetime."
                  )
              try:
                  endtime = pd.to_datetime(endtime)
              except ParserError:
                  raise ValueError(
                      "Could not parse x_max input of <xlim> as datetime."
                  )
              figure_options["x_range"] = (starttime, endtime)
  
      elif check_type(x) == "numeric":
          xaxis_type = "numerical"
      else:
          xaxis_type = "categorical"
  
      if kind in ["bar", "barh", "pie"]:
          xaxis_type = "categorical"
  
      x_old = x
      x_labels_dict = None
      if xaxis_type == "categorical":
          if check_type(x) == "datetime":
              x = _times_to_string(x)
          else:
              x = [str(el) for el in x]
          if kind != "hist":
              x_labels_dict = dict(zip(range(len(x)), x))
              x = list(range(len(x)))
          if "x_axis_type" in figure_options:
              del figure_options["x_axis_type"]
  
      # Determine data cols to plot (only plot numeric data):
      data_cols = _determine_data_columns(y, df)
  
      # Convert y-column names into string representation:
      df.rename(
          columns={col: str(col) for col in data_cols}, inplace=True
      )
      data_cols = [str(col) for col in data_cols]
  
      # Delete x column if it appears in y columns:
      if delete_in_y is not None:
          if delete_in_y in data_cols:
              data_cols.remove(delete_in_y)
      N_cols = len(data_cols)
      if len(data_cols) == 0:
          raise Exception(
              f"The only numeric column is the column {delete_in_y} that is already used on the x-axis."
          )
  
      # Autodetect y-label if no y-label is provided by user and only one y-column exists:
      if N_cols == 1:
          if kind == "barh":
              if "x_axis_label" not in figure_options:
                  figure_options["x_axis_label"] = data_cols[0]
          else:
              if "y_axis_label" not in figure_options:
                  figure_options["y_axis_label"] = data_cols[0]
  
      # Get Name of x-axis data:
      if kind == "barh":
          xlabelname = (
              figure_options["y_axis_label"]
              if figure_options.get("y_axis_label", "") != ""
              else "x"
          )
      else:
          xlabelname = (
              figure_options["x_axis_label"]
              if figure_options.get("x_axis_label", "") != ""
              else "x"
          )
  
      # Create Figure for plotting:
      p = figure(**figure_options)
      if "x_axis_type" not in figure_options:
          figure_options["x_axis_type"] = None
  
      # For categorical plots, set the xticks:
      if x_labels_dict is not None:
          p.xaxis.formatter = FuncTickFormatter(
              code="""
                                  var labels = %s;
                                  return labels[tick];
                                  """
              % x_labels_dict
          )
  
      # Define ColumnDataSource for Plot if kind != "hist":
      if kind != "hist":
          source = {col: df[col].values for col in data_cols}
          source["__x__values"] = x
          source["__x__values_original"] = x_old
          for kwarg, value in kwargs.items():
              if value in df.columns:
                  source[value] = df[value].values
          for add_col in additional_columns:
              source[add_col] = df[add_col].values
  
      # Define colormap
      if kind not in ["scatter", "pie"]:
          colormap = get_colormap(colormap, N_cols)
  
      if color is not None:
          colormap = get_colormap([color], N_cols)
  
      # Add Glyphs to Plot:
      if kind == "line":
          p, p_rangetool = lineplot(
              p,
              source,
              data_cols,
              colormap,
              hovertool,
              xlabelname,
              figure_options["x_axis_type"],
              plot_data_points,
              plot_data_points_size,
              hovertool_string,
              number_format,
              rangetool,
              **kwargs,
          )
  
      if kind == "step":
          p, p_rangetool = stepplot(
              p,
              source,
              data_cols,
              colormap,
              hovertool,
              xlabelname,
              figure_options["x_axis_type"],
              plot_data_points,
              plot_data_points_size,
              hovertool_string,
              number_format,
              rangetool,
              **kwargs,
          )
  
      if kind == "point":
          p = pointplot(
              p,
              source,
              data_cols,
              colormap,
              hovertool,
              hovertool_string,
              xlabelname,
              figure_options["x_axis_type"],
              number_format,
              **kwargs,
          )
  
      if kind == "scatter":
          if N_cols > 2:
              raise Exception(
                  "For scatterplots <x> and <y> values can only be a single column of the DataFrame, not a list of columns. Please specify both <x> and <y> columns for a scatterplot uniquely."
              )
  
          # Get and set y-labelname:
          y_column = data_cols[0]
          if "y_axis_label" not in figure_options:
              p.yaxis.axis_label = y_column
  
          # Get values for y-axis:
          y = df[y_column].values
  
          # Delete additionally created values by pandas.plotting:
          for add_param in ["s", "c"]:
              if add_param in kwargs:
                  del kwargs[add_param]
  
          # Get values for categorical colormap:
          category_values = None
          if category in df.columns:
              category_values = df[category].values
          elif category is not None:
              raise Exception(
                  "<category> parameter has to be either None or the name of a single column of the DataFrame"
              )
  
          scatterplot(
              p,
              df,
              x,
              x_old,
              y,
              category,
              category_values,
              colormap,
              hovertool,
              hovertool_string,
              additional_columns,
              x_axis_type=figure_options["x_axis_type"],
              xlabelname=xlabelname,
              ylabelname=y_column,
              **kwargs,
          )
  
      if kind == "bar" or kind == "barh":
          # Define data source for barplot:
          data = {col: df[col].values for col in data_cols}
          data["__x__values"] = x
          data["__x__values_original"] = x_old
          source = ColumnDataSource(data)
          for kwarg, value in kwargs.items():
              if value in df.columns:
                  source.data[value] = df[value].values
          for add_col in additional_columns:
              source.data[add_col] = df[add_col].values
  
          # Create Figure (just for categorical barplots):
          del figure_options["x_axis_type"]
          if "y_axis_label" not in figure_options and kind == "barh":
              figure_options["y_axis_label"] = xlabelname
          p = figure(**figure_options)
          figure_options["x_axis_type"] = None
  
          # Set xticks:
          if kind == "bar":
              p.xaxis.formatter = FuncTickFormatter(
                  code="""
                                      var labels = %s;
                                      return labels[tick];
                                      """
                  % x_labels_dict
              )
          elif kind == "barh":
              p.yaxis.formatter = FuncTickFormatter(
                  code="""
                                      var labels = %s;
                                      return labels[tick];
                                      """
                  % x_labels_dict
              )
  
          if not stacked:
              if N_cols >= 3:
                  base_width = 0.5
              else:
                  base_width = 0.35
              width = base_width / (N_cols - 0.5)
              if N_cols == 1:
                  shifts = [0]
              else:
                  delta_shift = base_width / (N_cols - 1)
                  shifts = [
                      -base_width / 2 + i * delta_shift
                      for i in range(N_cols)
                  ]
  
              for i, name, color, shift in zip(
                  range(N_cols), data_cols, colormap, shifts
              ):
                  if kind == "bar":
                      glyph = p.vbar(
                          x=dodge(
                              "__x__values", shift, range=p.x_range
                          ),
                          top=name,
                          width=width,
                          source=source,
                          color=color,
                          legend_label=" " + name,
                          **kwargs,
                      )
                      hovermode = "vline"
  
                  elif kind == "barh":
                      glyph = p.hbar(
                          y=dodge(
                              "__x__values", shift, range=p.y_range
                          ),
                          right=name,
                          height=width,
                          source=source,
                          color=color,
                          legend_label=" " + name,
                          **kwargs,
                      )
                      hovermode = "hline"
  
                  if hovertool:
                      my_hover = HoverTool(
                          mode=hovermode, renderers=[glyph]
                      )
                      if hovertool_string is None:
                          my_hover.tooltips = [
                              (xlabelname, "@__x__values_original"),
                              (name, "@{%s}" % name),
                          ]
                      else:
                          my_hover.tooltips = hovertool_string
                      p.add_tools(my_hover)
  
          if stacked:
              if kind == "bar":
                  glyph = p.vbar_stack(
                      data_cols,
                      x="__x__values",
                      width=0.8,
                      source=source,
                      color=colormap,
                      legend_label=data_cols,
                      **kwargs,
                  )
                  hovermode = "vline"
  
              elif kind == "barh":
                  glyph = p.hbar_stack(
                      data_cols,
                      y="__x__values",
                      height=0.8,
                      source=source,
                      color=colormap,
                      legend_label=data_cols,
                      **kwargs,
                  )
                  hovermode = "hline"
  
              if hovertool:
                  my_hover = HoverTool(
                      mode=hovermode, renderers=[glyph[-1]]
                  )
                  if hovertool_string is None:
                      my_hover.tooltips = [
                          (xlabelname, "@__x__values_original")
                      ] + [(col, "@{%s}" % col) for col in data_cols]
                  else:
                      my_hover.tooltips = hovertool_string
                  p.add_tools(my_hover)
  
      if kind == "hist":
          # Disable line_color (for borders of histogram bins) per default:
          if "line_color" not in kwargs:
              kwargs["line_color"] = None
          elif kwargs["line_color"] is True:
              del kwargs["line_color"]
  
          if "by" in kwargs and y is None:
              y = kwargs["by"]
              del kwargs["by"]
  
          # Check for stacked keyword:
          if stacked and histogram_type not in [None, "stacked"]:
              warnings.warn(
                  f"<histogram_type> was set to '{histogram_type}', but was overriden by <stacked>=True parameter."
              )
              histogram_type = "stacked"
          elif stacked and histogram_type is None:
              histogram_type = "stacked"
  
          # Set xlabel if only one y-column is given and user does not override this via
          # xlabel parameter:
          if len(data_cols) == 1 and xlabel is None:
              p.xaxis.axis_label = data_cols[0]
  
          # If Histogram should be plotted, calculate bins, aggregates and
          # averages:
  
          # Autocalculate bins if bins are not specified:
          if bins is None:
              values = df[data_cols].values
              values = values[~np.isnan(values)]
              data, bins = np.histogram(values)
  
          # Calculate bins if number of bins is given:
          elif isinstance(bins, int):
              if bins < 1:
                  raise ValueError(
                      "<bins> can only be an integer>0, a list or a range of numbers."
                  )
              values = df[data_cols].values
              values = values[~np.isnan(values)]
              v_min, v_max = values.min(), values.max()
              bins = np.linspace(v_min, v_max, bins + 1)
  
          if not isinstance(bins, str):
              bins = list(bins)
  
          if weights is not None:
              if weights not in df.columns:
                  raise ValueError(
                      "Columns '%s' for <weights> is not in provided DataFrame."
                  )
              else:
                  weights = df[weights].values
  
          aggregates = []
          averages = []
          for col in data_cols:
              values = df[col].values
              if weights is not None:
                  not_nan = ~(np.isnan(values) | np.isnan(weights))
                  values_not_nan = values[not_nan]
                  weights_not_nan = weights[not_nan]
                  if sum(not_nan) < len(not_nan):
                      warnings.warn(
                          f"There are NaN values in column '{col}' or in the <weights> column. For the histogram, these rows have been neglected.",
                          Warning,
                      )
              else:
                  not_nan = ~np.isnan(values)
                  values_not_nan = values[not_nan]
                  weights_not_nan = None
                  if sum(not_nan) < len(not_nan):
                      warnings.warn(
                          f"There are NaN values in column '{col}'. For the histogram, these rows have been neglected.",
                          Warning,
                      )
  
              average = np.average(
                  values_not_nan, weights=weights_not_nan
              )
              averages.append(average)
  
              data, bins = np.histogram(
                  values_not_nan, bins=bins, weights=weights_not_nan
              )
              if normed:
                  data = data / np.sum(data) * normed
              if cumulative:
                  data = np.cumsum(data)
              aggregates.append(data)
  
          p = histogram(
              p,
              df,
              data_cols,
              colormap,
              aggregates,
              bins,
              averages,
              hovertool,
              hovertool_string,
              additional_columns,
              normed,
              cumulative,
              show_average,
              histogram_type,
              logy,
              **kwargs,
          )
  
      if kind == "area":
          p = areaplot(
              p,
              source,
              data_cols,
              colormap,
              hovertool,
              hovertool_string,
              xlabelname,
              figure_options["x_axis_type"],
              stacked,
              normed,
              **kwargs,
          )
  
      if kind == "pie":
          source["__x__values"] = x_old
          p = pieplot(
              source,
              data_cols,
              colormap,
              hovertool,
              hovertool_string,
              figure_options,
              xlabelname,
              **kwargs,
          )
  
      # Set xticks and yticks:
      if xticks is not None:
          p.xaxis[0].ticker = list(xticks)
      elif x_labels_dict is not None and kind != "barh":
          p.xaxis.ticker = x
      elif kind == "barh":
          p.yaxis.ticker = x
      if yticks is not None:
          p.yaxis.ticker = list(yticks)
  
      # Format datetime ticks correctly:
      if figure_options["x_axis_type"] == "datetime":
          p.xaxis.formatter = DatetimeTickFormatter(
              milliseconds=["%H:%M:%S.%f"],
              seconds=["%H:%M:%S"],
              minutes=["%H:%M:%S"],
              hours=["%H:%M:%S"],
              days=["%d %B %Y"],
              months=["%d %B %Y"],
              years=["%d %B %Y"],
          )
  
      # Rotate xlabel if wanted:
      if vertical_xlabel:
          p.xaxis.major_label_orientation = np.pi / 2
  
      # Set panning option:
      if panning is False:
          p.toolbar.active_drag = None
  
      # Set zooming option:
      if zooming is False:
          p.toolbar.active_scroll = None
  
      # Set click policy for legend:
      if not stacked and kind != "pie":
          p.legend.click_policy = "hide"
  
      # Hide legend if wanted:
      if not legend:
          p.legend.visible = False
  
      # Modify legend position:
      else:
          if legend is True:
              p.legend.location = "top_right"
          elif legend in [
              "top_left",
              "top_center",
              "top_right",
              "center_left",
              "center",
              "center_right",
              "bottom_left",
              "bottom_center",
              "bottom_right",
          ]:
              p.legend.location = legend
          else:
              raise ValueError(
                  "Legend can only be True/False or one of 'top_left', 'top_center', 'top_right', 'center_left', 'center', 'center_right', 'bottom_left', 'bottom_center', 'bottom_right'"
              )
  
      # Set fontsizes:
      set_fontsizes_of_figure(
          figure=p,
          fontsize_title=fontsize_title,
          fontsize_label=fontsize_label,
          fontsize_ticks=fontsize_ticks,
          fontsize_legend=fontsize_legend,
      )
  
      # Scientific formatting for axes:
      if disable_scientific_axes is None:
          pass
      elif disable_scientific_axes == "x":
          p.xaxis[0].formatter.use_scientific = False
      elif disable_scientific_axes == "y":
          p.yaxis[0].formatter.use_scientific = False
      elif disable_scientific_axes in ["xy", True]:
          p.xaxis[0].formatter.use_scientific = False
          p.yaxis[0].formatter.use_scientific = False
      else:
          raise ValueError(
              """Keyword parameter <disable_scientific_axes> only accepts "xy", True, "x", "y" or None."""
          )
  
      # If rangetool is used, add it to layout:
      if p_rangetool is not None:
          p = column(p, p_rangetool)
  
      # Display plot if wanted
      if show_figure:
          show(p)
  
      # Return as (embeddable) HTML if wanted:
      if return_html:
          return embedded_html(p)
  
      # Return plot:
      return p
  
imports: import datetime
  import numbers
  import warnings
  from copy import deepcopy
  from typing import Iterable, List, Optional, Union
  import numpy
  import pandas
  from bokeh.layouts import column
  from bokeh.models import ColorBar, ColumnDataSource, DatetimeTickFormatter, FuncTickFormatter, HoverTool, LinearColorMapper, RangeTool
  from bokeh.models.ranges import Range1d
  from bokeh.palettes import Inferno256, all_palettes
  from bokeh.plotting import figure
  from bokeh.transform import cumsum, dodge
  from pandas.core.base import PandasObject
  from pandas.errors import ParserError
  from .base import embedded_html, set_fontsizes_of_figure, show
  from .geoplot import geoplot
  from .utils import _extract_additional_columns
label_desc: Use image node_id 4 for calling a global function with example usage: plot(df_in, x, y, kind, figsize, use_index, title, legend, logx, logy, xlabel, ylabel, xticks, yticks, xlim, ylim, fontsize_title, fontsize_label, fontsize_ticks, fontsize_legend, color, colormap, category, histogram_type, stacked, weights, bins, normed, cumulative, show_average, plot_data_points, plot_data_points_size, number_format, disable_scientific_axes, show_figure, return_html, panning, zooming, sizing_mode, toolbar_location, hovertool, hovertool_string, rangetool, vertical_xlabel, x_axis_location, webgl, reuse_plot) and returns: p, mapplot, embedded_html