mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-22 20:11:24 +01:00
Graph of temperature changes for the year in the burg
I'm bad at writing in English. Please excuse me for this. It seems illogical to me the parameter of the average temperature for the year in the burg. Therefore, I found a database of meteorological measurements at https://ru.climate-data.org/ And I analyzed it. With the help of a neural network. I approximately established the dependence of Dy[X] and Dd[X], Md[X] = f(t,p,l). Dy[X] - how much the temperature in winter differs from the temperature in summer Md[X] - how much the temperature during the day differs from the temperature at night, on average per year Dd[X] - how much the temperature difference between day and night is not constant in winter and summer t - average temperature for the year p - average rainfall for the year l - latitude Now, for each city, you can plot the temperature change. Based on t,p and l. ATTENTION!!! The characteristics of the planet and its orbit coincide with those of the earth! Further, I will use the Russian language, if you want to know my reasoning, please use the Google Translate capabilities. Я изменил свою первоначальную идею и доработал её. Что касается качества и используемых функций - жду критики. JavaScript - не знакомый мне язык и я не уверен, что выполнил всё верно. Что касается самой идеи - её реализация пока далека от совершенства. Я понял, что если установить в настройках мира температуру на экваторе ниже, чем на Земле, то графики получаются слишком далекими от реальности. Эта ошибка связана с тем, что Dy[X] зависит от широты, а не среднегодовой температуры. К сожалению добиться хорошей сходимости удалось только расширением нейросети - ещё больше магических чисел. Теперь, на основе прошлой выборки из 899 городов, попущенных через нейросеть миллион раз среднеквадратичная ошибка стала 3%. Входными данными для сети являются широта и влажность, а средняя температура иcпользуется только как ориентир при построении графиков.
This commit is contained in:
parent
6fea480fad
commit
465016a66d
3 changed files with 198 additions and 0 deletions
|
|
@ -2085,6 +2085,7 @@
|
|||
<button id="burglLegend" data-tip="Edit free text notes (legend) for this burg" class="icon-edit"></button>
|
||||
<button id="burgLock" class="icon-lock-open" onmouseover="showElementLockTip(event)"></button>
|
||||
<button id="burgRemove" data-tip="Remove non-capital burg. Shortcut: Delete" class="icon-trash fastDelete"></button>
|
||||
<button id="burgTemperatureGraph" data-tip="Shows the temperature graph in the burg" class="icon-chart-area"></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -4426,6 +4427,7 @@
|
|||
<script defer src="modules/ui/cultures-editor.js"></script>
|
||||
<script defer src="modules/ui/namesbase-editor.js"></script>
|
||||
<script defer src="modules/ui/elevation-profile.js"></script>
|
||||
<script defer src="modules/ui/temperature-graph.js"></script>
|
||||
<script defer src="modules/ui/routes-editor.js"></script>
|
||||
<script defer src="modules/ui/ice-editor.js"></script>
|
||||
<script defer src="modules/ui/lakes-editor.js"></script>
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ function editBurg(id) {
|
|||
document.getElementById("burglLegend").addEventListener("click", editBurgLegend);
|
||||
document.getElementById("burgLock").addEventListener("click", toggleBurgLockButton);
|
||||
document.getElementById("burgRemove").addEventListener("click", removeSelectedBurg);
|
||||
document.getElementById("burgTemperatureGraph").addEventListener("click", showTemperatureGraphs);
|
||||
|
||||
function updateBurgValues() {
|
||||
const id = +elSelected.attr("data-id");
|
||||
|
|
@ -542,6 +543,11 @@ function editBurg(id) {
|
|||
const name = elSelected.text();
|
||||
editNotes("burg" + id, name);
|
||||
}
|
||||
function showTemperatureGraphs() {
|
||||
const id = elSelected.attr("data-id");
|
||||
showTGForBurg(id);
|
||||
}
|
||||
|
||||
|
||||
function removeSelectedBurg() {
|
||||
const id = +elSelected.attr("data-id");
|
||||
|
|
|
|||
190
modules/ui/temperature-graph.js
Normal file
190
modules/ui/temperature-graph.js
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
"use strict";
|
||||
|
||||
function showTGForBurg(id) {
|
||||
const b = pack.burgs[id];
|
||||
const lat = mapCoordinates.latN - (b.y / graphHeight) * mapCoordinates.latT;
|
||||
const temperature = grid.cells.temp[pack.cells.g[b.cell]];
|
||||
const prec = grid.cells.prec[pack.cells.g[b.cell]];
|
||||
|
||||
const weights = [
|
||||
[//Layer0
|
||||
//IN0 IN1
|
||||
[1.7032805665330064, 9.76344839973784], //Neyron0
|
||||
[78.11570897168328, 14.601126748769655], //Neyron1...
|
||||
[-17.86260543967271, -18.89959889983629],
|
||||
[-5.096416157498042, -3.239101608785143],
|
||||
[15.135359078936663, -8.21750087038963],
|
||||
[2.89070853797873, 0.748597154917318],
|
||||
[-7.071033124823327, 1.0694133212613257],
|
||||
[30.89625278090631, -29.58412597781861],
|
||||
[8.83742206727876, 2.925882228813251],
|
||||
[-23.105918821529457, 59.975819969733955]
|
||||
],
|
||||
[//Layer1
|
||||
[-24.660066638519528, -6.444388451540001, 6.096317239481185, -28.634935067425154, 8.866490165643159, 25.542783838925033, 17.570826750545905, -6.67295071629475, -8.77729799869443, -88.98038329450236],
|
||||
[6.38376320044125, -2.7182778686238724, -1.9865485601337416, 10.917347591979627, 34.144968406291774, -32.11415334678534, -38.15179026431855, -11.51948938610541, 0.5380355040386701, -0.607356926268642],
|
||||
[-2.7768468273633093, -48.37419296453233, -62.61815919593951, -19.513164468492786, 93.1761828264018, 14.132428867566691, 17.590766480352126, -14.424771379214942, -40.16821165163309, -0.4757635185201129],
|
||||
[0.7126339045981811, 1.3807870964549949, -4.52694413868832, 8.859114020044535, -25.542800936427525, -17.052646819490533, -13.45262248737299, 19.04927696239682, 4.3772665027214215, 10.673504480995467],
|
||||
[-0.9901713313063913, 1.1537165068921644, 0.7627751991455828, -8.862080579381123, 4.095960737251427, 5.010172336857094, 10.078303996053119, -1.4715229465851472, -8.840479073062008, -0.35367530438937667],
|
||||
[3.004754427223695, -3.406260869341714, -18.468433323078546, 51.77036802551895, 65.24063311909613, -7.050118290901991, -29.013152721648716, -131.7678338510577, -32.49691343209261, 2.484670717084914]
|
||||
],
|
||||
[//Layer2
|
||||
[1.7430650921661213, -0.2869375191565024, -0.8484945138945511, -0.9256615130832988, -6.319047898501307, 4.494914932369445],
|
||||
[0.9505278662318376, -1.1656186389912937, -2.578920014335076, -1.2897962843278608, -1.57363345004906, 0.937571776650802],
|
||||
[1.1869391990570621, 1.214292485154762, -3.0748452401175337, -2.6279324686504615, -0.6747453940846205, 1.1011366399902536]
|
||||
]
|
||||
];
|
||||
|
||||
//From (-∞,∞) to ~[-1,1]
|
||||
const In1 = [(lat - 12.976592977893368)/81.9224728505465,(prec - 15.12743823146944)/38.5286376102066];
|
||||
|
||||
let lastIn = In1;
|
||||
let lstOut = [];
|
||||
for (let levelN = 0; levelN < weights.length ; levelN++) {
|
||||
let layerN = weights[levelN];
|
||||
for (let i = 0; i < layerN.length ; i++) {
|
||||
lstOut[i] = 0;
|
||||
for (let j = 0; j < layerN[i].length ; j++)
|
||||
lstOut[i] = lstOut[i] + lastIn[j]*layerN[i][j] ;
|
||||
//Sigmoid
|
||||
lstOut[i] = 1/(1+Math.exp(-lstOut[i]));
|
||||
}
|
||||
lastIn = lstOut.slice(0);
|
||||
}
|
||||
|
||||
//From [0,1] to [min,max]
|
||||
//Standard deviation for average temperature for the year
|
||||
const yearSig = lstOut[0]*62;
|
||||
//Standard deviation for the difference between the minimum and maximum temperatures for the year
|
||||
const yearDelTmpSig = lstOut[1]*12;
|
||||
//Expected value for the difference between the minimum and maximum temperatures for the year
|
||||
const yearDelTmpMu = lstOut[2]*15+1;
|
||||
|
||||
//Temperature change shape
|
||||
//const formTmp = -Math.cos(data*2*Math.PI) / 2;
|
||||
const delT = yearDelTmpMu/2+0.5*yearDelTmpSig/2;
|
||||
|
||||
const chartWidth = window.innerWidth/2,
|
||||
chartHeight = 300; // height of our land/sea profile, excluding the biomes data below
|
||||
const xOffset = 80,
|
||||
yOffset = 10; // this is our drawing starting point from top-left (y = 0) of SVG
|
||||
|
||||
const xscale = d3.scaleLinear().domain([0,360]).range([0, chartWidth]);
|
||||
const yscale = d3.scaleLinear().domain([temperature-yearSig-delT, temperature+yearSig+delT]).range([chartHeight, 0]);
|
||||
const yscale_inv = d3.scaleLinear().domain([chartHeight, 0]).range([temperature-yearSig-delT, temperature+yearSig+delT]);
|
||||
|
||||
const dataAverTmp = [];
|
||||
const dataMinTmp = [];
|
||||
const dataMaxTmp = [];
|
||||
for (let i = 0; i < 360 ; i++) {
|
||||
let formTmp = Math.cos(i/360*2*Math.PI) / 2;
|
||||
if(lat > 0) formTmp = -formTmp;
|
||||
const averT = formTmp * yearSig + temperature;
|
||||
const delT = yearDelTmpMu/2+formTmp*yearDelTmpSig/2;
|
||||
dataAverTmp.push({x:xscale(i) + xOffset,y:yscale(averT) + yOffset});
|
||||
dataMinTmp.push({x:xscale(i) + xOffset,y:yscale(averT-delT) + yOffset});
|
||||
dataMaxTmp.push({x:xscale(i) + xOffset,y:yscale(averT+delT) + yOffset});
|
||||
}
|
||||
|
||||
document.getElementById("epControls").style.visibility = "hidden";
|
||||
|
||||
$("#elevationProfile").dialog({
|
||||
title: "Seasonal temperature schedule",
|
||||
resizable: false,
|
||||
width: window.width,
|
||||
close: closeTGForBurg,
|
||||
position: {my: "left top", at: "left+20 bottom-500", of: window, collision: "fit"}
|
||||
});
|
||||
|
||||
draw();
|
||||
|
||||
function draw() {
|
||||
|
||||
document.getElementById("elevationGraph").innerHTML = "";
|
||||
|
||||
const chart = d3
|
||||
.select("#elevationGraph")
|
||||
.append("svg")
|
||||
.attr("width", chartWidth + 120)
|
||||
.attr("height", chartHeight + yOffset + 40)
|
||||
.attr("id", "elevationSVG")
|
||||
.attr("class", "epbackground");
|
||||
// arrow-head definition
|
||||
chart.append("defs").append("marker").attr("id", "arrowhead").attr("orient", "auto").attr("markerWidth", "2").attr("markerHeight", "4").attr("refX", "0.1").attr("refY", "2");
|
||||
|
||||
// land
|
||||
let Gen = d3.line().curve(d3.curveBasis).x((p) => p.x).y((p) => p.y);
|
||||
|
||||
chart.append("g").append("path").attr("d", Gen(dataAverTmp)).attr("fill", "none").attr("stroke", "orange").on("mousemove", printVal).style("stroke-width", "2");
|
||||
chart.append("g").append("path").attr("d", Gen(dataMinTmp)).attr("fill", "none").attr("stroke", "blue").on("mousemove", printVal).style("stroke-width", "2");
|
||||
chart.append("g").append("path").attr("d", Gen(dataMaxTmp)).attr("fill", "none").attr("stroke", "red").on("mousemove", printVal).style("stroke-width", "2");
|
||||
//print title
|
||||
let timerId = setTimeout(() => chart.attr("data-tip", "Seasonal temperature schedule"), 1000);
|
||||
//Val under line
|
||||
function printVal(){
|
||||
let m = d3.mouse(this);
|
||||
let val = convertTemperature(yscale_inv(m[1]-yOffset).toFixed(1));
|
||||
chart.attr("data-tip", val);
|
||||
clearTimeout(timerId);
|
||||
timerId = setTimeout(() => chart.attr("data-tip", "Seasonal temperature schedule"), 1000);
|
||||
}
|
||||
|
||||
const months = ["January","February","March","April","May","June","July","August","September","October","November","December"];
|
||||
|
||||
const xAxis = d3
|
||||
.axisBottom(xscale)
|
||||
.ticks(10)
|
||||
.tickFormat(function (d) {
|
||||
return months[parseInt(d/360*12)];
|
||||
});
|
||||
const yAxis = d3
|
||||
.axisLeft(yscale)
|
||||
.ticks(5)
|
||||
.tickFormat(function (d) {
|
||||
return convertTemperature(d);
|
||||
});
|
||||
|
||||
const xGrid = d3.axisBottom(xscale).ticks(10).tickSize(-chartHeight).tickFormat("");
|
||||
const yGrid = d3.axisLeft(yscale).ticks(5).tickSize(-chartWidth).tickFormat("");
|
||||
|
||||
chart
|
||||
.append("g")
|
||||
.attr("id", "epxaxis")
|
||||
.attr("transform", "translate(" + xOffset + "," + parseInt(chartHeight + +yOffset + 20) + ")")
|
||||
.call(xAxis)
|
||||
.selectAll("text")
|
||||
.style("text-anchor", "center")
|
||||
.attr("transform", function (d) {
|
||||
return "rotate(0)"; // used to rotate labels, - anti-clockwise, + clockwise
|
||||
});
|
||||
|
||||
chart
|
||||
.append("g")
|
||||
.attr("id", "epyaxis")
|
||||
.attr("transform", "translate(" + parseInt(+xOffset - 10) + "," + parseInt(+yOffset) + ")")
|
||||
.call(yAxis);
|
||||
|
||||
// add the X gridlines
|
||||
chart
|
||||
.append("g")
|
||||
.attr("id", "epxgrid")
|
||||
.attr("class", "epgrid")
|
||||
.attr("stroke-dasharray", "4 1")
|
||||
.attr("transform", "translate(" + xOffset + "," + parseInt(chartHeight + +yOffset) + ")")
|
||||
.call(xGrid);
|
||||
|
||||
// add the Y gridlines
|
||||
chart
|
||||
.append("g")
|
||||
.attr("id", "epygrid")
|
||||
.attr("class", "epgrid")
|
||||
.attr("stroke-dasharray", "4 1")
|
||||
.attr("transform", "translate(" + xOffset + "," + yOffset + ")")
|
||||
.call(yGrid);
|
||||
}
|
||||
function closeTGForBurg() {
|
||||
document.getElementById("epControls").style.visibility = "visible";
|
||||
document.getElementById("elevationGraph").innerHTML = "";
|
||||
modules.elevation = false;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue