From 97a260215e38dd56a76cc39ca5652b6342952323 Mon Sep 17 00:00:00 2001 From: JohT <7671054+JohT@users.noreply.github.com> Date: Sun, 20 Apr 2025 22:18:46 +0200 Subject: [PATCH] Improve git history rendering --- jupyter/GitHistoryGeneral.ipynb | 180 +++++++++++++++++------------- scripts/executeJupyterNotebook.sh | 7 +- 2 files changed, 107 insertions(+), 80 deletions(-) diff --git a/jupyter/GitHistoryGeneral.ipynb b/jupyter/GitHistoryGeneral.ipynb index 6192d4ce3..a100e5c95 100644 --- a/jupyter/GitHistoryGeneral.ipynb +++ b/jupyter/GitHistoryGeneral.ipynb @@ -56,7 +56,12 @@ "# it would require to execute the notebook twice: Once including interactivity and once for static Markdown and PDF.\n", "# Therefore, command line executed notebooks (nbconvert) will contain static graphics (here using svg).\n", "def is_command_line_execution():\n", - " return 'NBCONVERT' in os.environ\n", + " return 'NBCONVERT_PATH' in os.environ\n", + "\n", + "def get_offline_path():\n", + " print(\"os.path.abspath=\" + os.path.abspath(''))\n", + " print(\"os.path.curdir=\" + os.path.curdir)\n", + " return os.environ.get('NBCONVERT_PATH', '')\n", "\n", "default_renderer = None\n", "\n", @@ -177,15 +182,9 @@ "metadata": {}, "outputs": [], "source": [ - "# The first part provides functions that provide basic functionality for the following parts." - ] - }, - { - "cell_type": "markdown", - "id": "01da524e", - "metadata": {}, - "source": [ - "### Treemap Layout Functions and Constants" + "# --------------------------------------------------------------------------------\n", + "# Shared Treemap Layout Functions and Constants\n", + "# --------------------------------------------------------------------------------" ] }, { @@ -208,8 +207,9 @@ ")\n", "plotly_treemap_figure_show_settings = dict(\n", " renderer=\"svg\" if is_command_line_execution() else None,\n", - " width=1080,\n", - " height=1080\n", + " width=680 if is_command_line_execution() else 1080,\n", + " height=680 if is_command_line_execution() else 1080,\n", + " config={'scrollZoom': False, 'displaylogo': False, 'displayModeBar': False} if is_command_line_execution() else {}\n", ")\n", "\n", "plotly_treemap_marker_base_style = dict(\n", @@ -222,6 +222,27 @@ ")" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "03ee42af", + "metadata": {}, + "outputs": [], + "source": [ + "def get_plotly_figure_write_image_settings(name: str):\n", + " \"\"\"\n", + " Returns the settings for the plotly figure write_image method\n", + " :param name: Name of the figure\n", + " :return: Dictionary with settings for the write_image method\n", + " \"\"\"\n", + " return dict(\n", + " file=get_offline_path() + \"/\" + name + \".svg\", \n", + " format=\"svg\", \n", + " width=1080, \n", + " height=1080\n", + " )" + ] + }, { "cell_type": "code", "execution_count": null, @@ -280,11 +301,15 @@ ] }, { - "cell_type": "markdown", - "id": "acacc415", + "cell_type": "code", + "execution_count": null, + "id": "c37c64a4", "metadata": {}, + "outputs": [], "source": [ - "### Visualization Data Preparation Functions" + "# --------------------------------------------------------------------------------\n", + "# Shared Visualization Data Preparation Functions\n", + "# --------------------------------------------------------------------------------" ] }, { @@ -330,11 +355,15 @@ ] }, { - "cell_type": "markdown", - "id": "da109679", + "cell_type": "code", + "execution_count": null, + "id": "fb368425", "metadata": {}, + "outputs": [], "source": [ - "### File Data Preparation Functions" + "# --------------------------------------------------------------------------------\n", + "# Shared File Data Preparation Functions\n", + "# --------------------------------------------------------------------------------" ] }, { @@ -490,11 +519,15 @@ ] }, { - "cell_type": "markdown", - "id": "09aeae9b", + "cell_type": "code", + "execution_count": null, + "id": "69fc63ff", "metadata": {}, + "outputs": [], "source": [ - "### File Data Preparation " + "# --------------------------------------------------------------------------------\n", + "# Main File Data Preparation\n", + "# --------------------------------------------------------------------------------" ] }, { @@ -659,7 +692,9 @@ " **plotly_treemap_layout_base_settings,\n", " title='Directories and their file count'\n", ")\n", - "figure.show(**plotly_treemap_figure_show_settings)" + "figure.show(**plotly_treemap_figure_show_settings)\n", + "if is_command_line_execution():\n", + " figure.write_image(**get_plotly_figure_write_image_settings(\"NumberOfFilesPerDirectory\"))" ] }, { @@ -695,7 +730,9 @@ " **plotly_treemap_layout_base_settings,\n", " title='Most frequent file extension per directory'\n", ")\n", - "figure.show(**plotly_treemap_figure_show_settings)" + "figure.show(**plotly_treemap_figure_show_settings)\n", + "if is_command_line_execution():\n", + " figure.write_image(**get_plotly_figure_write_image_settings(\"MostFrequentFileExtensionPerDirectory\"))" ] }, { @@ -729,7 +766,9 @@ " **plotly_treemap_layout_base_settings,\n", " title='Number of git commits',\n", ")\n", - "figure.show(**plotly_treemap_figure_show_settings)" + "figure.show(**plotly_treemap_figure_show_settings)\n", + "if is_command_line_execution():\n", + " figure.write_image(**get_plotly_figure_write_image_settings(\"NumberOfGitCommits\"))" ] }, { @@ -763,7 +802,9 @@ " **plotly_treemap_layout_base_settings,\n", " title='Number of distinct commit authors',\n", ")\n", - "figure.show(**plotly_treemap_figure_show_settings)" + "figure.show(**plotly_treemap_figure_show_settings)\n", + "if is_command_line_execution():\n", + " figure.write_image(**get_plotly_figure_write_image_settings(\"NumberOfDistinctCommitAuthors\"))" ] }, { @@ -805,48 +846,9 @@ " title='Number of distinct commit authors (red/black = only one or very few authors)',\n", ")\n", "\n", - "figure.show(**plotly_treemap_figure_show_settings)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e11947c5", - "metadata": {}, - "outputs": [], - "source": [ - "import plotly.graph_objects as go\n", - "\n", - "# Example data\n", - "labels = [\"A\", \"B\", \"C\", \"D\", \"E\"]\n", - "parents = [\"\", \"A\", \"A\", \"B\", \"B\"]\n", - "values = [10, 20, 30, 40, 50] # Color scale values\n", - "max_value = max(values)\n", - "\n", - "# Create treemap\n", - "fig = go.Figure(go.Treemap(\n", - " labels=labels,\n", - " parents=parents,\n", - " values=values,\n", - " marker=dict(\n", - " colors=values,\n", - " colorscale=\"Blues\",\n", - " colorbar=dict(\n", - " title=\"Value\",\n", - " tickmode=\"auto\", # Let Plotly auto-select ticks\n", - " ticklabelposition=\"outside top\",\n", - " tickformat=\",\", # Use default formatting\n", - " ticklabeloverflow=\"allow\", # Ensure long labels are displayed\n", - " ticklabelstep=1 # Show all labels\n", - " )\n", - " )\n", - "))\n", - "\n", - "# Add an alias for the highest tick value dynamically\n", - "fig.update_layout(coloraxis_colorbar_tickvals=[max_value])\n", - "fig.update_layout(coloraxis_colorbar_ticktext=[f\"{max_value} or more\"])\n", - "\n", - "fig.show()\n" + "figure.show(**plotly_treemap_figure_show_settings)\n", + "if is_command_line_execution():\n", + " figure.write_image(**get_plotly_figure_write_image_settings(\"NumberOfDistinctCommitAuthorsLowFocus\"))" ] }, { @@ -882,7 +884,9 @@ " **plotly_treemap_layout_base_settings,\n", " title='Main authors with highest number of commits'\n", ")\n", - "figure.show(**plotly_treemap_figure_show_settings)" + "figure.show(**plotly_treemap_figure_show_settings)\n", + "if is_command_line_execution():\n", + " figure.write_image(**get_plotly_figure_write_image_settings(\"MainAuthorsWithHighestNumberOfCommits\"))" ] }, { @@ -919,7 +923,9 @@ " **plotly_treemap_layout_base_settings,\n", " title='Second author with the second highest number of commits'\n", ")\n", - "figure.show(**plotly_treemap_figure_show_settings)" + "figure.show(**plotly_treemap_figure_show_settings)\n", + "if is_command_line_execution():\n", + " figure.write_image(**get_plotly_figure_write_image_settings(\"SecondAuthorWithTheSecondHighestNumberOfCommits\"))" ] }, { @@ -954,7 +960,9 @@ " **plotly_treemap_layout_base_settings,\n", " title='Days since last commit',\n", ")\n", - "figure.show(**plotly_treemap_figure_show_settings)" + "figure.show(**plotly_treemap_figure_show_settings)\n", + "if is_command_line_execution():\n", + " figure.write_image(**get_plotly_figure_write_image_settings(\"DaysSinceLastCommit\"))" ] }, { @@ -989,7 +997,9 @@ " **plotly_treemap_layout_base_settings,\n", " title='Rank of days since last commit',\n", ")\n", - "figure.show(**plotly_treemap_figure_show_settings)" + "figure.show(**plotly_treemap_figure_show_settings)\n", + "if is_command_line_execution():\n", + " figure.write_image(**get_plotly_figure_write_image_settings(\"DaysSinceLastCommitRanked\"))" ] }, { @@ -1023,7 +1033,9 @@ " **plotly_treemap_layout_base_settings,\n", " title='Days since last file creation',\n", ")\n", - "figure.show(**plotly_treemap_figure_show_settings)" + "figure.show(**plotly_treemap_figure_show_settings)\n", + "if is_command_line_execution():\n", + " figure.write_image(**get_plotly_figure_write_image_settings(\"DaysSinceLastFileCreation\"))" ] }, { @@ -1057,7 +1069,9 @@ " **plotly_treemap_layout_base_settings,\n", " title='Rank of days since last file creation',\n", ")\n", - "figure.show(**plotly_treemap_figure_show_settings)" + "figure.show(**plotly_treemap_figure_show_settings)\n", + "if is_command_line_execution():\n", + " figure.write_image(**get_plotly_figure_write_image_settings(\"DaysSinceLastFileCreationRanked\"))" ] }, { @@ -1091,7 +1105,9 @@ " **plotly_treemap_layout_base_settings,\n", " title='Days since last file modification',\n", ")\n", - "figure.show(**plotly_treemap_figure_show_settings)" + "figure.show(**plotly_treemap_figure_show_settings)\n", + "if is_command_line_execution():\n", + " figure.write_image(**get_plotly_figure_write_image_settings(\"DaysSinceLastFileModification\"))" ] }, { @@ -1125,7 +1141,9 @@ " **plotly_treemap_layout_base_settings,\n", " title='Rank of days since last file modification',\n", ")\n", - "figure.show(**plotly_treemap_figure_show_settings)" + "figure.show(**plotly_treemap_figure_show_settings)\n", + "if is_command_line_execution():\n", + " figure.write_image(**get_plotly_figure_write_image_settings(\"DaysSinceLastFileModificationRanked\"))" ] }, { @@ -1212,7 +1230,9 @@ " **plotly_treemap_layout_base_settings,\n", " title='Pairwise file changes',\n", ")\n", - "figure.show(**plotly_treemap_figure_show_settings)" + "figure.show(**plotly_treemap_figure_show_settings)\n", + "if is_command_line_execution():\n", + " figure.write_image(**get_plotly_figure_write_image_settings(\"PairwiseFileChanges\"))" ] }, { @@ -1278,7 +1298,9 @@ " xaxis_title='file count',\n", " yaxis_title='commit count'\n", " )\n", - " figure.show(**plotly_treemap_figure_show_settings)" + " figure.show(**plotly_treemap_figure_show_settings)\n", + " if is_command_line_execution():\n", + " figure.write_image(**get_plotly_figure_write_image_settings(\"ChangedFilesPerCommit\"))" ] }, { @@ -1384,7 +1406,9 @@ " xaxis_title='commit count',\n", " yaxis_title='dependency weight',\n", " )\n", - " figure.show(**plotly_treemap_figure_show_settings)" + " figure.show(**plotly_treemap_figure_show_settings)\n", + " if is_command_line_execution():\n", + " figure.write_image(**get_plotly_figure_write_image_settings(\"PairwiseChangedFilesVsDependencyWeight\"))" ] }, { diff --git a/scripts/executeJupyterNotebook.sh b/scripts/executeJupyterNotebook.sh index 476d1e5e6..7dbf3ef9d 100755 --- a/scripts/executeJupyterNotebook.sh +++ b/scripts/executeJupyterNotebook.sh @@ -88,9 +88,12 @@ source "${SCRIPTS_DIR}/activateCondaEnvironment.sh" jupyter --version || exit 1 # Execute the Jupyter Notebook and write it to the output file name -# The environment variable NBCONVERT is needed to be able to detect a command line execution in the Jupyter Notebook. +# The environment variable NBCONVERT_PATH is needed to be able to detect a command line execution in the Jupyter Notebook. +# Additionally, it is used to store the offline rendered images in the directory "${jupyter_notebook_file_name}_files". echo "executeJupyterNotebook: Executing Jupyter Notebook ${jupyter_notebook_output_file_name}..." -NBCONVERT=true jupyter nbconvert --to notebook \ + +mkdir -p "${jupyter_notebook_file_name}_files" +NBCONVERT_PATH="$(pwd)/${jupyter_notebook_file_name}_files" jupyter nbconvert --to notebook \ --execute "${jupyter_notebook_file}" \ --output "$jupyter_notebook_output_file_name" \ --output-dir="./" \