diff --git a/.gitignore b/.gitignore index 7f4e44b..eae999f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,145 @@ -.venv/ -.qoder/ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db \ No newline at end of file diff --git a/app/static/js/simulation.js b/app/static/js/simulation.js index a70dafe..f39c0b4 100644 --- a/app/static/js/simulation.js +++ b/app/static/js/simulation.js @@ -252,6 +252,11 @@ function initializeCharts() { // Wealth Distribution Chart const distributionCtx = document.getElementById('distributionChart'); + console.log('Initializing distribution chart:', { + hasCanvas: !!distributionCtx, + canvasId: distributionCtx ? distributionCtx.id : 'not found' + }); + if (distributionCtx) { charts.distribution = new Chart(distributionCtx, { type: 'bar', @@ -293,6 +298,9 @@ function initializeCharts() { } } }); + console.log('✅ Distribution chart initialized successfully'); + } else { + console.error('❌ Distribution chart canvas not found!'); } } @@ -605,9 +613,23 @@ function updateSimulationProgress(data) { currentSimulation.data.top10Share.push(data.wealth_concentration_top10 || 0); // Update distribution data if available + console.log('Received simulation progress data:', { + hasDistribution: !!data.distribution, + distribution: data.distribution + }); + if (data.distribution && data.distribution.labels && data.distribution.counts) { - currentSimulation.data.distribution.labels = data.distribution.labels; - currentSimulation.data.distribution.counts = data.distribution.counts; + console.log('Updating distribution data:', { + labelsLength: data.distribution.labels.length, + countsLength: data.distribution.counts.length, + labels: data.distribution.labels, + counts: data.distribution.counts + }); + + currentSimulation.data.distribution.labels = [...data.distribution.labels]; + currentSimulation.data.distribution.counts = [...data.distribution.counts]; + } else { + console.log('No valid distribution data in progress update'); } updateCharts(); @@ -635,10 +657,28 @@ function updateCharts() { } // Wealth Distribution Chart - if (charts.distribution && currentSimulation.data.distribution.labels.length > 0) { - charts.distribution.data.labels = currentSimulation.data.distribution.labels; - charts.distribution.data.datasets[0].data = currentSimulation.data.distribution.counts; - charts.distribution.update('none'); + if (charts.distribution) { + const distData = currentSimulation.data.distribution; + console.log('Updating distribution chart with data:', { + hasLabels: !!(distData.labels && distData.labels.length > 0), + hasCounts: !!(distData.counts && distData.counts.length > 0), + labelsLength: distData.labels ? distData.labels.length : 0, + countsLength: distData.counts ? distData.counts.length : 0, + labels: distData.labels, + counts: distData.counts + }); + + if (distData.labels && distData.labels.length > 0 && + distData.counts && distData.counts.length > 0) { + charts.distribution.data.labels = distData.labels; + charts.distribution.data.datasets[0].data = distData.counts; + charts.distribution.update('none'); + console.log('✅ Distribution chart updated successfully'); + } else { + console.log('❌ Distribution chart not updated - insufficient data'); + } + } else { + console.log('❌ Distribution chart not found'); } } @@ -678,10 +718,17 @@ async function onSimulationComplete(data) { // Fetch complete simulation data and populate charts try { + console.log('Fetching complete simulation data...'); const response = await window.MarkovEconomics.utils.apiRequest( `/api/simulation/${currentSimulation.id}/data?include_evolution=true&include_distribution=true` ); + console.log('Complete simulation data received:', { + hasEvolution: !!response.evolution, + hasDistribution: !!response.distribution, + distribution: response.distribution + }); + if (response.evolution) { // Clear and populate with complete data currentSimulation.data.iterations = response.evolution.iterations; @@ -691,9 +738,31 @@ async function onSimulationComplete(data) { currentSimulation.data.capitalShare = response.evolution.capital_shares || []; // Update distribution data - if (response.distribution) { - currentSimulation.data.distribution.labels = response.distribution.labels; - currentSimulation.data.distribution.counts = response.distribution.counts; + if (response.distribution && response.distribution.labels && response.distribution.counts) { + console.log('Setting final distribution data:', { + labelsLength: response.distribution.labels.length, + countsLength: response.distribution.counts.length, + labels: response.distribution.labels, + counts: response.distribution.counts + }); + + currentSimulation.data.distribution.labels = [...response.distribution.labels]; + currentSimulation.data.distribution.counts = [...response.distribution.counts]; + } else { + console.log('No distribution data in final response'); + // Fallback: try to get distribution data from dedicated endpoint + try { + const distResponse = await window.MarkovEconomics.utils.apiRequest( + `/api/simulation/${currentSimulation.id}/distribution?bins=10` + ); + if (distResponse.histogram && distResponse.histogram.labels && distResponse.histogram.counts) { + console.log('Got distribution data from dedicated endpoint:', distResponse.histogram); + currentSimulation.data.distribution.labels = [...distResponse.histogram.labels]; + currentSimulation.data.distribution.counts = [...distResponse.histogram.counts]; + } + } catch (distError) { + console.error('Failed to fetch distribution data from dedicated endpoint:', distError); + } } // Update charts with complete data