code: def feature_distribution_traces(
      train_column: Union[np.ndarray, pd.Series],
      test_column: Union[np.ndarray, pd.Series],
      column_name: str,
      is_categorical: bool = False,
      max_num_categories: int = 10,
      show_categories_by: CategoriesSortingKind = "largest_difference",
      quantile_cut: float = 0.02,
      dataset_names: Tuple[str] = DEFAULT_DATASET_NAMES,
  ) -> Tuple[List[BaseTraceType], Dict, Dict]:
      """Create traces for comparison between train and test column.
  
      Parameters
      ----------
      train_column
          Train data used to trace distribution.
      test_column
          Test data used to trace distribution.
      column_name
          The name of the column values on the x axis.
      is_categorical : bool , default: False
          State if column is categorical.
      max_num_categories : int , default: 10
          Maximum number of categories to show in plot (default: 10).
      show_categories_by: str, default: 'largest_difference'
          Specify which categories to show for categorical features' graphs, as the number of shown categories is limited
          by max_num_categories_for_display. Possible values:
          - 'train_largest': Show the largest train categories.
          - 'test_largest': Show the largest test categories.
          - 'largest_difference': Show the largest difference between categories.
      quantile_cut : float , default: 0.02
          In which quantile to cut the edges of the plot.
      dataset_names: tuple, default: DEFAULT_DATASET_NAMES
          The names to show in the display for the first and second datasets.
  
      Returns
      -------
      List[Union[go.Bar, go.Scatter]]
          list of plotly traces.
      Dict
          layout of x axis
      Dict
          layout of y axis
      """
      if is_categorical:
          traces, y_layout = _create_distribution_bar_graphs(
              train_column,
              test_column,
              max_num_categories,
              show_categories_by,
              dataset_names=dataset_names,
          )
  
          # NOTE:
          # the range, in this case, is needed to fix a problem with
          # too wide bars when there are only one or two of them`s on
          # the plot, plus it also centralizes them`s on the plot
          # The min value of the range (range(min. max)) is bigger because
          # otherwise bars will not be centralized on the plot, they will
          # appear on the left part of the plot (that is probably because of zero)
          range_max = (
              max_num_categories
              if len(set(train_column).union(test_column))
              > max_num_categories
              else len(set(train_column).union(test_column))
          )
          xaxis_layout = dict(
              type="category", range=(-3, range_max + 2)
          )
          return traces, xaxis_layout, y_layout
      else:
          train_uniques, train_uniques_counts = np.unique(
              train_column, return_counts=True
          )
          test_uniques, test_uniques_counts = np.unique(
              test_column, return_counts=True
          )
  
          x_range = (
              min(train_column.min(), test_column.min()),
              max(train_column.max(), test_column.max()),
          )
          x_width = x_range[1] - x_range[0]
  
          # If there are less than 20 total unique values, draw bar graph
          train_test_uniques = np.unique(
              np.concatenate([train_uniques, test_uniques])
          )
          if train_test_uniques.size < MAX_NUMERICAL_UNIQUE_FOR_BARS:
              traces, y_layout = _create_distribution_bar_graphs(
                  train_column,
                  test_column,
                  20,
                  show_categories_by,
                  dataset_names=dataset_names,
              )
              x_range = (
                  x_range[0] - x_width * 0.2,
                  x_range[1] + x_width * 0.2,
              )
              xaxis_layout = dict(
                  ticks="outside",
                  tickmode="array",
                  tickvals=train_test_uniques,
                  range=x_range,
              )
              return traces, xaxis_layout, y_layout
  
          x_range_to_show = (
              min(
                  np.quantile(train_column, quantile_cut),
                  np.quantile(test_column, quantile_cut),
              ),
              max(
                  np.quantile(train_column, 1 - quantile_cut),
                  np.quantile(test_column, 1 - quantile_cut),
              ),
          )
          # Heuristically take points on x-axis to show on the plot
          # The intuition is the graph will look "smooth" wherever we will zoom it
          # Also takes mean and median values in order to plot it later accurately
          mean_train_column = np.mean(train_column)
          mean_test_column = np.mean(test_column)
          median_train_column = np.median(train_column)
          median_test_column = np.median(test_column)
          xs = sorted(
              np.concatenate(
                  (
                      np.linspace(x_range[0], x_range[1], 50),
                      np.quantile(
                          train_column, q=np.arange(0.02, 1, 0.02)
                      ),
                      np.quantile(
                          test_column, q=np.arange(0.02, 1, 0.02)
                      ),
                      [
                          mean_train_column,
                          mean_test_column,
                          median_train_column,
                          median_test_column,
                      ],
                  )
              )
          )
  
          train_density = get_density(train_column, xs)
          test_density = get_density(test_column, xs)
          bars_width = (x_range_to_show[1] - x_range_to_show[0]) / 100
  
          traces: List[go.BaseTraceType] = []
          if (
              train_uniques.size
              <= MAX_NUMERICAL_UNIQUES_FOR_SINGLE_DIST_BARS
          ):
              traces.append(
                  go.Bar(
                      x=train_uniques,
                      y=_create_bars_data_for_mixed_kde_plot(
                          train_uniques_counts, np.max(test_density)
                      ),
                      width=[bars_width] * train_uniques.size,
                      marker=dict(
                          color=colors[DEFAULT_DATASET_NAMES[0]]
                      ),
                      name=dataset_names[0] + " Dataset",
                  )
              )
          else:
              traces.extend(
                  _create_distribution_scatter_plot(
                      xs,
                      train_density,
                      mean_train_column,
                      median_train_column,
                      is_train=True,
                      dataset_names=dataset_names,
                  )
              )
  
          if (
              test_uniques.size
              <= MAX_NUMERICAL_UNIQUES_FOR_SINGLE_DIST_BARS
          ):
              traces.append(
                  go.Bar(
                      x=test_uniques,
                      y=_create_bars_data_for_mixed_kde_plot(
                          test_uniques_counts, np.max(train_density)
                      ),
                      width=[bars_width] * test_uniques.size,
                      marker=dict(
                          color=colors[DEFAULT_DATASET_NAMES[1]]
                      ),
                      name=dataset_names[1] + " Dataset",
                  )
              )
          else:
              traces.extend(
                  _create_distribution_scatter_plot(
                      xs,
                      test_density,
                      mean_test_column,
                      median_test_column,
                      is_train=False,
                      dataset_names=dataset_names,
                  )
              )
  
          xaxis_layout = dict(
              fixedrange=False, range=x_range_to_show, title=column_name
          )
          yaxis_layout = dict(
              title="Probability Density", fixedrange=True
          )
          return traces, xaxis_layout, yaxis_layout
  
file_path: deepchecks/deepchecks/utils/distribution/plot.py
imports: from functools import cmp_to_key
  from numbers import Number
  from typing import Any, Dict, List, Tuple, Union
  import numpy
  import pandas
  import plotly.graph_objs
  from plotly.basedatatypes import BaseTraceType
  from scipy.stats import gaussian_kde
  from typing_extensions import Literal
  from deepchecks.core.errors import DeepchecksValueError
  from deepchecks.utils.dataframes import un_numpy
  from deepchecks.utils.distribution.preprocessing import preprocess_2_cat_cols_to_same_bins
  from deepchecks.utils.plot import DEFAULT_DATASET_NAMES, colors
label_desc: Use image node_id 3 for calling a global function with example usage: feature_distribution_traces(train_column, test_column, column_name, is_categorical, max_num_categories, show_categories_by, quantile_cut, dataset_names) and returns: traces,  xaxis_layout,  y_layout, traces,  xaxis_layout,  yaxis_layout, traces,  xaxis_layout,  y_layout