code: def _get_monthly_risk_analysis_with_report(
      report_normal_df: pd.DataFrame,
  ) -> pd.DataFrame:
      """Get monthly analysis data
  
      :param report_normal_df:
      # :param report_long_short_df:
      :return:
      """
  
      # Group by month
      report_normal_gp = report_normal_df.groupby(
          [report_normal_df.index.year, report_normal_df.index.month]
      )
      # report_long_short_gp = report_long_short_df.groupby(
      #     [report_long_short_df.index.year, report_long_short_df.index.month]
      # )
  
      gp_month = sorted(set(report_normal_gp.size().index))
  
      _monthly_df = pd.DataFrame()
      for gp_m in gp_month:
          _m_report_normal = report_normal_gp.get_group(gp_m)
          # _m_report_long_short = report_long_short_gp.get_group(gp_m)
  
          if len(_m_report_normal) < 3:
              # The month's data is less than 3, not displayed
              # FIXME: If the trading day of a month is less than 3 days, a breakpoint will appear in the graph
              continue
          month_days = pd.Timestamp(
              year=gp_m[0], month=gp_m[1], day=1
          ).days_in_month
          _temp_df = _get_risk_analysis_data_with_report(
              _m_report_normal,
              # _m_report_long_short,
              pd.Timestamp(year=gp_m[0], month=gp_m[1], day=month_days),
          )
          _monthly_df = pd.concat([_monthly_df, _temp_df], sort=False)
  
      return _monthly_df
  
file_path: qlib/qlib/contrib/report/analysis_position/risk_analysis.py
imports: from typing import Iterable
  import pandas
  import plotly.graph_objs
  from ...evaluate import risk_analysis
  from ..graph import SubplotsGraph, ScatterGraph
label_desc: Use image node_id 3 for calling a global function with example usage: _get_monthly_risk_analysis_with_report(report_normal_df) and returns: _monthly_df