{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Comparison of Charting Libraries Performance" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "execution": { "iopub.execute_input": "2024-04-26T11:56:24.230758Z", "iopub.status.busy": "2024-04-26T11:56:24.230758Z", "iopub.status.idle": "2024-04-26T11:56:25.157640Z", "shell.execute_reply": "2024-04-26T11:56:25.157640Z" } }, "outputs": [], "source": [ "import pandas as pd\n", "\n", "from lets_plot import *\n", "from lets_plot.mapping import as_discrete" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "execution": { "iopub.execute_input": "2024-04-26T11:56:25.157640Z", "iopub.status.busy": "2024-04-26T11:56:25.157640Z", "iopub.status.idle": "2024-04-26T11:56:25.173766Z", "shell.execute_reply": "2024-04-26T11:56:25.173766Z" } }, "outputs": [ { "data": { "text/html": [ "\n", "
\n", " \n", " " ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "LetsPlot.setup_html()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Preliminaries" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "execution": { "iopub.execute_input": "2024-04-26T11:56:25.189498Z", "iopub.status.busy": "2024-04-26T11:56:25.189498Z", "iopub.status.idle": "2024-04-26T11:56:25.220806Z", "shell.execute_reply": "2024-04-26T11:56:25.220806Z" }, "scrolled": false }, "outputs": [], "source": [ "def get_json_data(file_path):\n", " from requests import get\n", "\n", " r = get(file_path, stream=True)\n", " if r.status_code == 200:\n", " return r.json()\n", " else:\n", " return {}\n", "\n", "def get_data(file_path):\n", " colors = {\n", " 'LightningChart': '#e41a1c',\n", " 'Plotly.js': '#4daf4a',\n", " 'Canvas.js': '#ff7f00',\n", " 'eCharts': '#ffff33',\n", " 'Lets-Plot groups': '#377eb8',\n", " 'Lets-Plot layers': '#984ea3',\n", " }\n", " data = {\n", " 'test': [],\n", " 'lib': [],\n", " 'channels_count': [],\n", " 'channel_data_points_per_second': [],\n", " 'time_domain_interval': [],\n", " 'loadup_speed_ms': [],\n", " 'fps_avg': [],\n", " 'fps_median': [],\n", " 'frame_time_avg': [],\n", " 'frame_time_median': [],\n", " 'color': [],\n", " }\n", " for test, test_data in get_json_data(file_path).items():\n", " for lib, test_lib_data in test_data.items():\n", " data['test'].append(test)\n", " data['lib'].append(lib)\n", " data['channels_count'].append(test_lib_data['config']['channelsCount'])\n", " data['channel_data_points_per_second'].append(test_lib_data['config']['channelDataPointsPerSecond'])\n", " data['time_domain_interval'].append(test_lib_data['config']['timeDomainInterval'])\n", " data['loadup_speed_ms'].append(test_lib_data['loadupSpeedMs'])\n", " data['fps_avg'].append(test_lib_data['fps']['avg'])\n", " data['fps_median'].append(test_lib_data['fps']['median'])\n", " data['frame_time_avg'].append(test_lib_data['frameTime']['avg'])\n", " data['frame_time_median'].append(test_lib_data['frameTime']['median'])\n", " data['color'].append(colors[lib])\n", " return pd.DataFrame.from_dict(data)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "execution": { "iopub.execute_input": "2024-04-26T11:56:25.220806Z", "iopub.status.busy": "2024-04-26T11:56:25.220806Z", "iopub.status.idle": "2024-04-26T11:56:25.755221Z", "shell.execute_reply": "2024-04-26T11:56:25.755221Z" } }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
testlibchannels_countchannel_data_points_per_secondtime_domain_intervalloadup_speed_msfps_avgfps_medianframe_time_avgframe_time_mediancolorload
0ALightningChart110001000101.758.41247458.25953817.25850116.90#e41a1c1000
1APlotly.js11000100092.740.25255440.92249730.02580324.25#4daf4a1000
2ACanvas.js110001000101.523.04557923.11695443.77210043.10#ff7f001000
3AeCharts11000100048.059.15581559.05369216.94137017.00#ffff331000
4ALets-Plot groups11000100068.149.92831851.29171919.02122418.00#377eb81000
5ALets-Plot layers110001000104.957.00231958.00730717.05707817.00#984ea31000
\n", "
" ], "text/plain": [ " test lib channels_count channel_data_points_per_second \\\n", "0 A LightningChart 1 1000 \n", "1 A Plotly.js 1 1000 \n", "2 A Canvas.js 1 1000 \n", "3 A eCharts 1 1000 \n", "4 A Lets-Plot groups 1 1000 \n", "5 A Lets-Plot layers 1 1000 \n", "\n", " time_domain_interval loadup_speed_ms fps_avg fps_median \\\n", "0 1000 101.7 58.412474 58.259538 \n", "1 1000 92.7 40.252554 40.922497 \n", "2 1000 101.5 23.045579 23.116954 \n", "3 1000 48.0 59.155815 59.053692 \n", "4 1000 68.1 49.928318 51.291719 \n", "5 1000 104.9 57.002319 58.007307 \n", "\n", " frame_time_avg frame_time_median color load \n", "0 17.258501 16.90 #e41a1c 1000 \n", "1 30.025803 24.25 #4daf4a 1000 \n", "2 43.772100 43.10 #ff7f00 1000 \n", "3 16.941370 17.00 #ffff33 1000 \n", "4 19.021224 18.00 #377eb8 1000 \n", "5 17.057078 17.00 #984ea3 1000 " ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df = get_data(\"https://raw.githubusercontent.com/JetBrains/lets-plot-docs/master/data/lib_comparison.json\")\n", "df['load'] = df['channels_count'] * df['time_domain_interval']\n", "df.head(6)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here \"Lets-Plot groups\" is a realization of the benchmark in which each data channel corresponds to a group in aesthetics. In \"Lets-Plot layers\" each data channel corresponds to a plot layer." ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "execution": { "iopub.execute_input": "2024-04-26T11:56:25.755221Z", "iopub.status.busy": "2024-04-26T11:56:25.755221Z", "iopub.status.idle": "2024-04-26T11:56:25.771365Z", "shell.execute_reply": "2024-04-26T11:56:25.771365Z" } }, "outputs": [], "source": [ "def comparison1(col):\n", " return ggplot(df) + \\\n", " geom_line(aes('load', col, color='color'), size=2, \\\n", " tooltips=layer_tooltips().line('@lib').format(col, '.2f').line('{0}|@{0}'.format(col))) + \\\n", " scale_x_log10() + scale_color_identity() + \\\n", " ggtitle('Comparison of {0} through load increasing'.format(col))\n", "\n", "def comparison2(col):\n", " return ggplot(df) + \\\n", " geom_bar(aes(as_discrete('lib', order_by=col, order=1), col, fill='color'), stat='identity', \\\n", " tooltips=layer_tooltips().line('@lib').format(col, '.2f').line('{0}|@{0}'.format(col))) + \\\n", " facet_grid(x='test') + \\\n", " scale_fill_identity() + \\\n", " coord_flip() + \\\n", " ggtitle('Comparison of {0} through tests'.format(col)) + \\\n", " theme_void()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Comparison Charts" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "execution": { "iopub.execute_input": "2024-04-26T11:56:25.771365Z", "iopub.status.busy": "2024-04-26T11:56:25.771365Z", "iopub.status.idle": "2024-04-26T11:56:25.865836Z", "shell.execute_reply": "2024-04-26T11:56:25.865836Z" } }, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "comparison1('loadup_speed_ms')" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "execution": { "iopub.execute_input": "2024-04-26T11:56:25.867454Z", "iopub.status.busy": "2024-04-26T11:56:25.867454Z", "iopub.status.idle": "2024-04-26T11:56:25.882125Z", "shell.execute_reply": "2024-04-26T11:56:25.882125Z" } }, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "comparison1('fps_avg')" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "execution": { "iopub.execute_input": "2024-04-26T11:56:25.882125Z", "iopub.status.busy": "2024-04-26T11:56:25.882125Z", "iopub.status.idle": "2024-04-26T11:56:25.897928Z", "shell.execute_reply": "2024-04-26T11:56:25.897928Z" } }, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "comparison1('frame_time_avg')" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "execution": { "iopub.execute_input": "2024-04-26T11:56:25.897928Z", "iopub.status.busy": "2024-04-26T11:56:25.897928Z", "iopub.status.idle": "2024-04-26T11:56:25.913582Z", "shell.execute_reply": "2024-04-26T11:56:25.913582Z" } }, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "comparison2('loadup_speed_ms')" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "execution": { "iopub.execute_input": "2024-04-26T11:56:25.913582Z", "iopub.status.busy": "2024-04-26T11:56:25.913582Z", "iopub.status.idle": "2024-04-26T11:56:25.929153Z", "shell.execute_reply": "2024-04-26T11:56:25.929153Z" } }, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "comparison2('fps_avg')" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "execution": { "iopub.execute_input": "2024-04-26T11:56:25.929153Z", "iopub.status.busy": "2024-04-26T11:56:25.929153Z", "iopub.status.idle": "2024-04-26T11:56:25.944786Z", "shell.execute_reply": "2024-04-26T11:56:25.944786Z" } }, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "comparison2('frame_time_avg')" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.13" } }, "nbformat": 4, "nbformat_minor": 2 }