diff --git a/gui/src/components/Actions.js b/gui/src/components/Actions.js
index 52e56248fdcadb4b9bec51df3f2fb751895bd036..7edf874b5b149305de99d0d5df7afe98e62d6c19 100644
--- a/gui/src/components/Actions.js
+++ b/gui/src/components/Actions.js
@@ -195,7 +195,7 @@ export const ActionSelect = React.memo(({value, options, tooltip, onChange}) =>
       onChange={(event) => onChange && onChange(event.target.value)}
     >
       {Object.entries(items).map(([key, value]) =>
-        <MenuItem key={key} value={value}>{key}</MenuItem>
+        <MenuItem key={key} value={key}>{value}</MenuItem>
       )}
     </Select>
   </Action>
diff --git a/gui/src/components/plotting/Plot.js b/gui/src/components/plotting/Plot.js
index edbfcf661d1131e302a2d5f725dba0d22511642a..9b9d027fec4e8eb493eeee6b1a24ec94d60bbc22 100644
--- a/gui/src/components/plotting/Plot.js
+++ b/gui/src/components/plotting/Plot.js
@@ -685,7 +685,7 @@ Plot.propTypes = {
 }
 Plot.defaultProps = {
   floatTitle: '',
-  fixedMargins: true,
+  fixedMargins: true, // If set to true, the margins will be fixed after first render.
   throttleResize: false
 }
 
diff --git a/gui/src/components/plotting/PlotAxis.js b/gui/src/components/plotting/PlotAxis.js
index 6a925ffcc5712023f0016c3dfbe7ee1a7f127827..9713f427d31ba9c8023b7b9ec4482fc2c2d1dc3d 100644
--- a/gui/src/components/plotting/PlotAxis.js
+++ b/gui/src/components/plotting/PlotAxis.js
@@ -158,11 +158,18 @@ const PlotAxis = React.memo(({
       return labels.map((tick) => ({...tick, label: formatTick(tick.label), pos: scaler(tick.pos) / axisSize}))
     }
 
-    // Determine the number of ticks that fits. Calculated with formula:
-    //    axisSize - scaler(max - max/nLabels) = labelSize
-    // -> nLabels = max / (max - scaler.invert(axisHeight - labelSize)
-    const nItemsFit = Math.floor((max - min) / (max - scaler.invert(axisSize - labelSize)))
-    const nItems = Math.min(labels, Math.max(2, nItemsFit))
+    // On linear and log axes, the labels are spaced evenly, and the number of
+    // labels is calculated from the available space. On non-linearly spaced
+    // axes, we calculate the number of labels with formula:
+    // axisSize - scaler(max - (max-min) / nLabels) = labelSize
+    // -> nLabels = (max-min) / (max - scaler.invert(axisSize - labelSize)
+    const padding = 10
+    let nItems = (scale === 'linear' || scale === 'log')
+      ? Math.floor(axisSize / (labelSize + padding))
+      : Math.floor((max - min) / (max - scaler.invert(axisSize - (labelSize + padding))))
+
+    // At least two labels should be attempted to be shown
+    nItems = Math.max(2, nItems)
 
     // If the scale length is zero, show only one tick
     if (min === max) {
@@ -175,14 +182,14 @@ const PlotAxis = React.memo(({
     // Get reasonable, human-readable ticks. the .ticks function from d3-scale
     // does not guarantee an upper limit to the number of ticks, so it cannot be
     // directly used.
-    return getTicks(min, max, nItems, dtype, mode, decimals)
+    return getTicks(min, max, nItems, scale, dtype, mode, decimals)
       .map(({tick, value}) => {
         return {
           label: tick,
           pos: scaler(value) / axisSize
         }
       })
-  }, [axisSize, dtype, labelSize, labels, max, min, scaler, mode, decimals])
+  }, [axisSize, dtype, labelSize, labels, max, min, scaler, mode, decimals, scale])
 
   // Here we estimate the maximum label width. This is a relatively simple
   // approximattion calculated using the font size. A more reliable way would to
@@ -242,7 +249,7 @@ PlotAxis.propTypes = {
   scale: PropTypes.string,
   mode: PropTypes.oneOf(['scientific', 'SI', 'standard']),
   decimals: PropTypes.number,
-  labels: PropTypes.oneOfType([PropTypes.number, PropTypes.array]),
+  labels: PropTypes.array,
   placement: PropTypes.oneOf(['left', 'bottom']),
   labelHeight: PropTypes.number,
   labelWidth: PropTypes.number,
diff --git a/gui/src/components/plotting/PlotAxis.spec.js b/gui/src/components/plotting/PlotAxis.spec.js
index b019b9c75c6d6096c4f4afc82a3304e65ecebe3a..558d3eac7f220bd607944db3d16eb24730c0931e 100644
--- a/gui/src/components/plotting/PlotAxis.spec.js
+++ b/gui/src/components/plotting/PlotAxis.spec.js
@@ -17,12 +17,12 @@
  */
 import React from 'react'
 import { format, getTime } from 'date-fns'
-import { render, screen } from '../conftest.spec'
+import { renderNoAPI, screen } from '../conftest.spec'
 import PlotAxis from './PlotAxis'
 import { DType } from '../../utils'
 
-const mockHeight = 50
-const mockWidth = 300
+const mockHeight = 70
+const mockWidth = 200
 const labelHeight = 12
 const labelWidth = 50
 const yearFormat = 'yyyy'
@@ -44,25 +44,25 @@ function getTs(...args) {
 }
 
 test.each([
-  ['only two ticks', 'left', 'linear', 0, 1, DType.Int, 'SI', 2, ['0', '1']],
-  ['do not show fractional ticks for integers', 'left', 'linear', 0, 1, DType.Int, 'SI', 6, ['0', '1']],
-  ['show fractional ticks for floats', 'left', 'linear', 0, 1, DType.Float, 'scientific', 6, ['0', '0.5', '1']],
-  ['do not not show more ticks than fit vertically', 'left', 'linear', 0, 100, DType.Int, 'SI', 20, ['0', '50', '100']],
-  ['do not not show more ticks than fit horizontally', 'bottom', 'linear', 0, 100, DType.Int, 'SI', 20, ['0', '20', '40', '60', '80', '100']],
-  ['thousands SI format', 'left', 'linear', 0, 5000, DType.Int, 'SI', 3, ['0', '2.5k', '5k']],
-  ['thousands scientific format', 'left', 'linear', 0, 5000, DType.Int, 'scientific', 3, ['0', '2.5e+3', '5e+3']],
-  ['millions SI format', 'left', 'linear', 0, 5000000, DType.Int, 'SI', 3, ['0', '2.5M', '5M']],
-  ['millions scientific format', 'left', 'linear', 0, 5000000, DType.Int, 'scientific', 3, ['0', '2.5e+6', '5e+6']],
-  ['negative numbers', 'left', 'linear', -5000, 0, DType.Int, 'SI', 3, ['-5k', '-2.5k', '0']],
-  ['timestamp seconds', 'bottom', 'linear', 0, 2000, DType.Timestamp, undefined, 3, [0, 1000, 2000].map(x => format(x, secondFormat))],
-  ['timestamp fifteen seconds', 'bottom', 'linear', 0, 30000, DType.Timestamp, undefined, 3, [0, 15000, 30000].map(x => format(x, secondFormat))],
-  ['timestamp thirty seconds', 'bottom', 'linear', 0, 60000, DType.Timestamp, undefined, 3, [0, 30000, 60000].map(x => format(x, secondFormat))],
-  ['timestamp minutes', 'bottom', 'linear', 0, 120000, DType.Timestamp, undefined, 3, [0, 60000, 120000].map(x => format(x, minuteFormat))],
-  ['timestamp fifteen minutes', 'bottom', 'linear', 0, 1800000, DType.Timestamp, undefined, 3, [0, 900000, 1800000].map(x => format(x, minuteFormat))],
-  ['timestamp thirty minutes', 'bottom', 'linear', 0, 3600000, DType.Timestamp, undefined, 3, [0, 1800000, 3600000].map(x => format(x, minuteFormat))],
-  ['timestamp hours', 'bottom', 'linear', 0, 7200000, DType.Timestamp, undefined, 3, [0, 3600000, 7200000].map(x => format(x, hourFormat))],
-  ['timestamp six hours', 'bottom', 'linear', getTs(1970, 0, 0, 3), getTs(1970, 0, 0, 15), DType.Timestamp, undefined, 2, ['6:00', '12:00']],
-  ['timestamp twelve hours', 'bottom', 'linear', getTs(1970, 0, 0, 6), getTs(1970, 0, 1, 6), DType.Timestamp, undefined, 2, ['12:00', '24:00']],
+  ['log axis full', 'left', 'log', 0, 1000, DType.Int, 'SI', ['10', '100', '1k']],
+  ['log axis reduced', 'left', 'log', 0, 1000000, DType.Int, 'SI', ['10', '1k', '100k']],
+  ['log axis unsupported range', 'left', 'log', 0, 1, DType.Int, 'SI', []],
+  ['do not show fractional ticks for integers', 'left', 'linear', 0, 1, DType.Int, 'SI', ['0', '1']],
+  ['show fractional ticks for floats', 'left', 'linear', 0, 1, DType.Float, 'scientific', ['0', '0.5', '1']],
+  ['thousands SI format', 'left', 'linear', 0, 5000, DType.Int, 'SI', ['0', '2.5k', '5k']],
+  ['thousands scientific format', 'left', 'linear', 0, 5000, DType.Int, 'scientific', ['0', '2.5e+3', '5e+3']],
+  ['millions SI format', 'left', 'linear', 0, 5000000, DType.Int, 'SI', ['0', '2.5M', '5M']],
+  ['millions scientific format', 'left', 'linear', 0, 5000000, DType.Int, 'scientific', ['0', '2.5e+6', '5e+6']],
+  ['negative numbers', 'left', 'linear', -5000, 0, DType.Int, 'SI', ['-5k', '-2.5k', '0']],
+  ['timestamp seconds', 'bottom', 'linear', 0, 2000, DType.Timestamp, undefined, [0, 1000, 2000].map(x => format(x, secondFormat))],
+  ['timestamp fifteen seconds', 'bottom', 'linear', 0, 30000, DType.Timestamp, undefined, [0, 15000, 30000].map(x => format(x, secondFormat))],
+  ['timestamp thirty seconds', 'bottom', 'linear', 0, 60000, DType.Timestamp, undefined, [0, 30000, 60000].map(x => format(x, secondFormat))],
+  ['timestamp minutes', 'bottom', 'linear', 0, 120000, DType.Timestamp, undefined, [0, 60000, 120000].map(x => format(x, minuteFormat))],
+  ['timestamp fifteen minutes', 'bottom', 'linear', 0, 1800000, DType.Timestamp, undefined, [0, 900000, 1800000].map(x => format(x, minuteFormat))],
+  ['timestamp thirty minutes', 'bottom', 'linear', 0, 3600000, DType.Timestamp, undefined, [0, 1800000, 3600000].map(x => format(x, minuteFormat))],
+  ['timestamp hours', 'bottom', 'linear', 0, 7200000, DType.Timestamp, undefined, [0, 3600000, 7200000].map(x => format(x, hourFormat))],
+  ['timestamp six hours', 'bottom', 'linear', getTs(1970, 0, 0, 3), getTs(1970, 0, 0, 15), DType.Timestamp, undefined, ['6:00', '12:00']],
+  ['timestamp twelve hours', 'bottom', 'linear', getTs(1970, 0, 0, 6), getTs(1970, 0, 1, 6), DType.Timestamp, undefined, ['12:00', '24:00']],
   [
     'timestamp days',
     'bottom',
@@ -71,7 +71,6 @@ test.each([
     getTs(1970, 0, 3, 12),
     DType.Timestamp,
     undefined,
-    3,
     [getTs(1970, 0, 1), getTs(1970, 0, 2), getTs(1970, 0, 3)].map(x => format(x, dayFormat))],
   [
     'timestamp weeks',
@@ -81,7 +80,6 @@ test.each([
     getTs(1970, 0, 22, 12),
     DType.Timestamp,
     undefined,
-    3,
     [getTs(1970, 0, 4, 12), getTs(1970, 0, 11, 12), getTs(1970, 0, 18, 12)].map(x => format(x, dayFormat))
   ],
   [
@@ -92,7 +90,6 @@ test.each([
     getTs(1970, 3, 15, 12),
     DType.Timestamp,
     undefined,
-    3,
     [getTs(1970, 1, 1, 12), getTs(1970, 2, 1, 12), getTs(1970, 3, 1, 12)].map(x => format(x, monthFormat))
   ],
   [
@@ -103,7 +100,6 @@ test.each([
     getTs(1973, 10, 1),
     DType.Timestamp,
     undefined,
-    3,
     [getTs(1971, 4, 1), getTs(1971, 7, 1), getTs(1972, 10, 1)].map(x => format(x, yearFormat))
   ],
   [
@@ -114,14 +110,32 @@ test.each([
     getTs(1973, 6, 1),
     DType.Timestamp,
     undefined,
-    3,
-    [getTs(1971, 0, 1, 12), getTs(1971, 0, 1, 12), getTs(1972, 0, 1, 12)].map(x => format(x, yearFormat))
+    [getTs(1971, 0, 1, 12), getTs(1972, 0, 1, 12), getTs(1973, 0, 1, 12)].map(x => format(x, yearFormat))
+  ],
+  [
+    'timestamp two years',
+    'bottom',
+    'linear',
+    getTs(1969, 6, 1),
+    getTs(1974, 6, 1),
+    DType.Timestamp,
+    undefined,
+    [getTs(1970, 0, 1, 12), getTs(1972, 0, 1, 12), getTs(1974, 0, 1, 12)].map(x => format(x, yearFormat))
+  ],
+  [
+    'timestamp five years',
+    'bottom',
+    'linear',
+    getTs(1969, 6, 1),
+    getTs(1981, 6, 1),
+    DType.Timestamp,
+    undefined,
+    [getTs(1970, 0, 1, 12), getTs(1975, 0, 1, 12), getTs(1980, 0, 1, 12)].map(x => format(x, yearFormat))
   ]
-])('%s', async (msg, placement, scale, min, max, dtype, mode, nLabels, labels) => {
-  render(<PlotAxis
+])('%s', async (msg, placement, scale, min, max, dtype, mode, labels) => {
+  renderNoAPI(<PlotAxis
     min={min}
     max={max}
-    labels={nLabels}
     labelWidth={placement === 'left' ? undefined : labelWidth}
     labelHeight={labelHeight}
     mode={mode}
diff --git a/gui/src/components/plotting/PlotHistogram.js b/gui/src/components/plotting/PlotHistogram.js
index 245c67e62a86c4ba4b47939a05297bfb190899f1..1414a77e6d699e8ce976143b2058f5c28e7f6ed9 100644
--- a/gui/src/components/plotting/PlotHistogram.js
+++ b/gui/src/components/plotting/PlotHistogram.js
@@ -154,11 +154,11 @@ const useStyles = makeStyles(theme => ({
 }))
 const PlotHistogram = React.memo(({
   xAxis,
+  yAxis,
   bins,
   range,
   step,
   nBins,
-  scale,
   discretization,
   dtypeY,
   disabled,
@@ -206,7 +206,7 @@ const PlotHistogram = React.memo(({
     }
   })
   const dynamicStyles = useDynamicStyles()
-  const scaler = useMemo(() => getScaler(scale), [scale])
+
   const aggIndicator = useRecoilValue(guiState('aggIndicator'))
   const oldRangeRef = useRef()
   const artificialRange = 1
@@ -230,16 +230,17 @@ const PlotHistogram = React.memo(({
     }
     const minY = 0
     const maxY = Math.max(...bins.map(item => item.count))
+    const scaler = getScaler(yAxis.scale, [minY, maxY])
     const finalBins = bins.map((bucket) => {
       return {
         ...bucket,
         start: bucket.value,
         end: bucket.value + step,
-        scale: scaler(bucket.count / maxY) || 0
+        scale: scaler(bucket.count)
       }
     })
     return [finalBins, minY, maxY]
-  }, [bins, scaler, step])
+  }, [bins, step, yAxis.scale])
 
   // Transforms the original range into an internal range used for
   // visualization.
@@ -340,20 +341,17 @@ const PlotHistogram = React.memo(({
     if (isNil(finalBins) || isNil(xAxis.min) || isNil(maxX)) {
       return null
     }
-
     let labels
-    // Automatic labelling is used for continuous values
-    if (!discretization && !isArtificial) {
-      labels = 10
+
     // One bin is shown for the artificial values
-    } else if (isArtificial) {
+    if (isArtificial) {
       const offset = discretization ? 0.5 * step : 0
       labels = [{
         label: finalBins[0].start,
         pos: finalBins[0].start + offset
       }]
     // Discrete values get label at the center of the bin.
-    } else {
+    } else if (discretization) {
       const start = step * Math.ceil(xAxis.min / step)
       const end = step * Math.floor(maxX / step)
       labels = rangeLodash(start, end).map(x => ({
@@ -487,12 +485,11 @@ const PlotHistogram = React.memo(({
       min={minY}
       max={maxY}
       mode='SI'
-      labels={5}
-      scale={scale}
+      scale={yAxis.scale}
       dtype={dtypeY}
       className={styles.yaxis}
     />
-  }, [dtypeY, maxY, minY, scale, styles.yaxis])
+  }, [dtypeY, maxY, minY, yAxis.scale, styles.yaxis])
 
   // Determine the final component to show.
   let histComp
@@ -578,6 +575,7 @@ const PlotHistogram = React.memo(({
 
 PlotHistogram.propTypes = {
   xAxis: PropTypes.object,
+  yAxis: PropTypes.object,
   /* The bins data to show. */
   bins: PropTypes.arrayOf(PropTypes.shape({
     value: PropTypes.number,
@@ -591,7 +589,6 @@ PlotHistogram.propTypes = {
   /* Discretization of the values. */
   discretization: PropTypes.number,
   dtypeY: PropTypes.string,
-  scale: PropTypes.string,
   disabled: PropTypes.bool,
   /* The label to show for the tooltips */
   tooltipLabel: PropTypes.string,
diff --git a/gui/src/components/plotting/PlotScatter.js b/gui/src/components/plotting/PlotScatter.js
index 085e878296416489b228adcfa2c0feae50f566c0..a74666ef20090ad0f3304c6f695a1ca8cd2ec25b 100644
--- a/gui/src/components/plotting/PlotScatter.js
+++ b/gui/src/components/plotting/PlotScatter.js
@@ -126,6 +126,7 @@ const PlotScatter = React.memo(forwardRef((
       template = template + `<extra></extra>`
       return template
     }
+    const scatterType = hasWebGL ? 'scattergl' : 'scatter'
 
     // If dealing with a quantized color, each group is separated into it's own
     // trace which has a legend as well.
@@ -155,7 +156,7 @@ const PlotScatter = React.memo(forwardRef((
           name: option,
           text: colorArray,
           mode: 'markers',
-          type: hasWebGL ? 'scattergl' : 'scatter',
+          type: scatterType,
           textposition: 'top center',
           showlegend: true,
           hovertemplate: hoverTemplate(
@@ -185,7 +186,7 @@ const PlotScatter = React.memo(forwardRef((
         text: data.color,
         entry_id: data.id,
         mode: 'markers',
-        type: 'scattergl',
+        type: scatterType,
         textposition: 'top center',
         showlegend: false,
         hoverinfo: "text",
@@ -223,7 +224,7 @@ const PlotScatter = React.memo(forwardRef((
         y: data.y,
         entry_id: data.id,
         mode: 'markers',
-        type: 'scattergl',
+        type: scatterType,
         textposition: 'top center',
         showlegend: false,
         hoverinfo: "text",
@@ -267,10 +268,12 @@ const PlotScatter = React.memo(forwardRef((
         y: 1
       },
       xaxis: {
+        type: xAxis.scale,
         fixedrange: false,
         autorange: autorange
       },
       yaxis: {
+        type: yAxis.scale,
         fixedrange: false,
         autorange: autorange
       },
@@ -288,7 +291,7 @@ const PlotScatter = React.memo(forwardRef((
   // both. This is a general problem in trying to 'reactify' a non-react library
   // like Plotly.
   // eslint-disable-next-line react-hooks/exhaustive-deps
-  }, [autorange])
+  }, [autorange, xAxis.scale, yAxis.scale])
 
   // Change dragmode
   useEffect(() => {
diff --git a/gui/src/components/plotting/common.js b/gui/src/components/plotting/common.js
index 50fb1a8a9476f7f9ddd09dbc8df954fc247233d7..e9c3086e5faea720faf86c6019a23660fa75ee9d 100644
--- a/gui/src/components/plotting/common.js
+++ b/gui/src/components/plotting/common.js
@@ -15,8 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import { range, size, isNil } from 'lodash'
-import { scalePow } from 'd3-scale'
+import { range, size } from 'lodash'
+import { scalePow, scaleLog } from 'd3-scale'
 import {
   format,
   getTime,
@@ -39,36 +39,64 @@ import {
   eachQuarterOfInterval
 } from 'date-fns'
 import { scale as chromaScale } from 'chroma-js'
-import { scale, add, DType, formatNumber } from '../../utils.js'
+import { scale as scaleUtils, add, DType, formatNumber } from '../../utils.js'
 
-// The available scaling options
 export const scales = {
-  'linear': 1,
-  '1/2': 0.5,
-  '1/4': 0.25,
-  '1/8': 0.125
+  'linear': 'linear',
+  'log': 'log',
+  '1/2': '1/2',
+  '1/4': '1/4',
+  '1/8': '1/8'
+}
+
+export const scalesLimited = {
+  'linear': 'linear',
+  'log': 'log'
 }
 
 /**
- * Returns a d3-scale object for the given scaling type, domain and range.
+ * Creates a scaling function based on the provided type.
  *
- * @param {str} type Type of scaling.
- * @param {array} domain The input domain.
- * @param {array} range The output range.
- * @returns A function that when given a number between [0, 1] will transform
- * it to the given output range with the given type of scaling.
+ * @param {string} type - The type of scaling function ('linear', '1/2', '1/4', '1/8', 'log').
+ * @param {number[]} [domain=[0, 1]] - The input domain for the scale.
+ * @param {number[]} [range=[0, 1]] - The output range for the scale.
+ * @returns {function} - The scaling function with added properties and methods.
+ * @throws {Error} - Throws an error if the scaling type is invalid.
  */
 export function getScaler(type, domain = [0, 1], range = [0, 1]) {
-  const scale = scales[type]
-  if (isNil(scale)) {
-    throw Error('Invalid scaling type.')
+  let scaler
+
+  const powScales = {
+    'linear': 1,
+    '1/2': 0.5,
+    '1/4': 0.25,
+    '1/8': 0.125
+  }
+
+  const powscale = powScales[type]
+
+  if (powscale !== undefined) {
+    scaler = scalePow()
+      .exponent(powscale)
+      .domain(domain)
+      .range(range)
+  } else if (type === 'log') {
+    const adjustedDomain = [Math.max(domain[0], 1), domain[1]]
+    scaler = scaleLog()
+      .base(10)
+      .domain(adjustedDomain)
+      .range(range)
+  } else {
+    throw new Error('Invalid scaling type.')
   }
-  const scaler = scalePow()
-    .exponent(scale)
-    .domain(domain)
-    .range(range)
 
-  return scaler
+  // Invalid values are mapped to zero. Important especially for log scales.
+  const func = (value) => scaler(value) || 0
+
+  // Copy all properties and methods from scaler to func
+  Object.assign(func, scaler)
+
+  return func
 }
 
 /**
@@ -87,7 +115,7 @@ export function getInterval(value, steps, dtype, cap = true) {
   const interval = value / steps
   const degree = Math.pow(10, (Math.round(Math.log10(interval))))
   const multipliers = [0.1, 0.2, 0.25, 0.5, 1, 2, 2.5, 5, 10]
-  const intervals = scale(multipliers, degree).filter(x => {
+  const intervals = scaleUtils(multipliers, degree).filter(x => {
     const capped = cap ? (x >= interval) : true
     const valid = dtype === DType.Int ? x % 1 === 0 : true
     return capped && valid
@@ -116,7 +144,7 @@ export const argMin = (iMin, x, i, arr) => {
  *
  * @returns Array of tick objects containing value and tick.
  */
-export function getTicks(min, max, n, dtype, mode = 'scientific', decimals = 3) {
+export function getTicks(min, max, n, scale = 'linear', dtype, mode = 'scientific', decimals = 3) {
   if (dtype === DType.Timestamp) {
     const start = fromUnixTime(millisecondsToSeconds(min))
     const end = fromUnixTime(millisecondsToSeconds(max))
@@ -138,6 +166,13 @@ export function getTicks(min, max, n, dtype, mode = 'scientific', decimals = 3)
         }),
         format: 'yyyy'
       },
+      twoyears: {
+        difference: (end, start) => differenceInYears(end, start) / 2,
+        split: (interval) => eachYearOfInterval(interval).filter(x => {
+          return !(x.getFullYear() % 2)
+        }),
+        format: 'yyyy'
+      },
       years: {
         difference: differenceInYears,
         split: eachYearOfInterval,
@@ -247,27 +282,39 @@ export function getTicks(min, max, n, dtype, mode = 'scientific', decimals = 3)
     // value.
     return ticks.map(x => ({value: getTime(x), tick: format(x, setup.format)}))
   } else {
-    // Calculate minimum number of ticks for each option
-    const tickRange = max - min
-    const multipliers = [0.1, 0.2, 0.25, 0.5, 1, 2, 2.5, 5, 10]
-    const degree = Math.pow(10, (Math.round(Math.log10(tickRange))))
-    const closestDuration = scale(multipliers, degree)
-      .filter(x => dtype === DType.Int ? x % 1 === 0 : true) // Filter out invalid intervals
-      .map(x => [x, Math.floor(tickRange / x)]) // Calculate minimum number of ticks
-      .filter(([interval, nMin]) => nMin <= n) // Filter out values where the minimum number of ticks is beyond the target.
-      .map(([interval, nMin]) => { // Calculate actual ticks
-        const startRound = Math.ceil(min / interval)
-        const endRound = Math.floor(max / interval)
-        const ticks = range(startRound, endRound + 1).map(x => {
-          const value = (x * interval)
-          return {value, tick: formatNumber(value, dtype, mode, decimals)}
-        })
-        return ticks
+    // Log scale ticks are divided into evenly spaced intervals in the log scale
+    if (scale === 'log') {
+      const tickRange = max - min
+      const degree = Math.floor(Math.log10(tickRange))
+      const reduction = Math.ceil(degree / n)
+      const degrees = range(1, degree + 1, degree > n ? reduction : 1)
+      return degrees.map(x => {
+        const value = Math.pow(10, x)
+        return {value, tick: formatNumber(value, dtype, mode, decimals)}
       })
-      .filter((ticks) => ticks.length <= n) // Filter out options with more ticks than requested
-      .map((ticks) => [ticks, Math.abs(ticks.length - n)]) // Calculate abs difference to n
-      .reduce((prev, curr) => prev[1] < curr[1] ? prev : curr) // Select best option
-    return closestDuration[0]
+    // Calculate reasonable ticks for other scales
+    } else {
+      const tickRange = max - min
+      const multipliers = [0.1, 0.2, 0.25, 0.5, 1, 2, 2.5, 5, 10]
+      const degree = Math.pow(10, (Math.round(Math.log10(tickRange))))
+      const closestDuration = scaleUtils(multipliers, degree)
+        .filter(x => dtype === DType.Int ? x % 1 === 0 : true) // Filter out invalid intervals
+        .map(x => [x, Math.floor(tickRange / x)]) // Calculate minimum number of ticks
+        .filter(([interval, nMin]) => nMin <= n) // Filter out values where the minimum number of ticks is beyond the target.
+        .map(([interval, nMin]) => { // Calculate actual ticks
+          const startRound = Math.ceil(min / interval)
+          const endRound = Math.floor(max / interval)
+          const ticks = range(startRound, endRound + 1).map(x => {
+            const value = (x * interval)
+            return {value, tick: formatNumber(value, dtype, mode, decimals)}
+          })
+          return ticks
+        })
+        .filter((ticks) => ticks.length <= n) // Filter out options with more ticks than requested
+        .map((ticks) => [ticks, Math.abs(ticks.length - n)]) // Calculate abs difference to n
+        .reduce((prev, curr) => prev[1] < curr[1] ? prev : curr) // Select best option
+      return closestDuration[0]
+    }
   }
 }
 
diff --git a/gui/src/components/plotting/common.spec.js b/gui/src/components/plotting/common.spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..e269f3b7902fea0397a403261a7f2da9eeb814da
--- /dev/null
+++ b/gui/src/components/plotting/common.spec.js
@@ -0,0 +1,32 @@
+/*
+ * Copyright The NOMAD Authors.
+ *
+ * This file is part of NOMAD. See https://nomad-lab.eu for further info.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { getScaler } from './common'
+
+describe('test getScaler', () => {
+  test.each([
+    ['linear scale', 'linear', [0, 1], [0, 1], [[0, 0], [1, 1]]],
+    ['log scale', 'log', [0, 1000], [0, 1], [[0, 0], [1, 0], [10, 1 / 3], [100, 2 / 3], [1000, 1]]]
+  ]
+  )('%s', async (name, type, domain, range, values) => {
+    const scaler = getScaler(type, domain, range)
+    for (const [a, b] of values) {
+        expect(scaler(a)).toBeCloseTo(b, 10)
+    }
+  })
+})
diff --git a/gui/src/components/search/FilterRegistry.js b/gui/src/components/search/FilterRegistry.js
index 92795100d516040d62df82b9e2c86c901de8bea7..ecab46a84f81547d0e62e3ecf22b29e1b32f9fbc 100644
--- a/gui/src/components/search/FilterRegistry.js
+++ b/gui/src/components/search/FilterRegistry.js
@@ -182,7 +182,7 @@ registerFilter(
   idStructure,
   {
     ...termQuantity,
-    scale: '1/4',
+    scale: 'log',
     label: "Dimensionality",
     options: getEnumOptions('results.material.structural_type', ['not processed', 'unavailable'])
   }
@@ -285,21 +285,21 @@ registerFilter(
     {name: 'degeneracy', ...termQuantity}
   ]
 )
-registerFilter('results.method.method_name', idMethod, {...termQuantity, scale: '1/4'})
-registerFilter('results.method.workflow_name', idMethod, {...termQuantity, scale: '1/4'})
-registerFilter('results.method.simulation.program_name', idMethod, {...termQuantity, scale: '1/4'})
+registerFilter('results.method.method_name', idMethod, {...termQuantity, scale: 'log'})
+registerFilter('results.method.workflow_name', idMethod, {...termQuantity, scale: 'log'})
+registerFilter('results.method.simulation.program_name', idMethod, {...termQuantity, scale: 'log'})
 registerFilter('results.method.simulation.program_version', idMethod, termQuantity)
 registerFilter('results.method.simulation.program_version_internal', idMethod, termQuantity)
 registerFilter('results.method.simulation.precision.native_tier', idPrecision, {...termQuantity, placeholder: "E.g. VASP - accurate", label: 'Code-specific tier'})
-registerFilter('results.method.simulation.precision.k_line_density', idPrecision, {...numberHistogramQuantity, scale: '1/2', label: 'k-line density'})
-registerFilter('results.method.simulation.precision.basis_set', idPrecision, {...termQuantity, scale: '1/4'})
-registerFilter('results.method.simulation.precision.planewave_cutoff', idPrecision, {...numberHistogramQuantity, label: 'Plane-wave cutoff', scale: '1/2'})
-registerFilter('results.method.simulation.precision.apw_cutoff', idPrecision, {...numberHistogramQuantity, label: 'APW cutoff', scale: '1/2'})
+registerFilter('results.method.simulation.precision.k_line_density', idPrecision, {...numberHistogramQuantity, scale: 'log', label: 'k-line density'})
+registerFilter('results.method.simulation.precision.basis_set', idPrecision, {...termQuantity, scale: 'log'})
+registerFilter('results.method.simulation.precision.planewave_cutoff', idPrecision, {...numberHistogramQuantity, label: 'Plane-wave cutoff', scale: 'log'})
+registerFilter('results.method.simulation.precision.apw_cutoff', idPrecision, {...numberHistogramQuantity, label: 'APW cutoff', scale: 'log'})
 registerFilter('results.method.simulation.dft.core_electron_treatment', idDFT, termQuantity)
-registerFilter('results.method.simulation.dft.jacobs_ladder', idDFT, {...termQuantity, scale: '1/2', label: 'Jacob\'s ladder'})
+registerFilter('results.method.simulation.dft.jacobs_ladder', idDFT, {...termQuantity, scale: 'log', label: 'Jacob\'s ladder'})
 registerFilter('results.method.simulation.dft.xc_functional_type', idDFT, {
   ...termQuantity,
-  scale: '1/2',
+  scale: 'log',
   label: 'Jacob\'s ladder',
   options: {
     'LDA': {label: 'LDA'},
@@ -309,16 +309,16 @@ registerFilter('results.method.simulation.dft.xc_functional_type', idDFT, {
     'hybrid': {label: 'Hybrid'}
   }
 })
-registerFilter('results.method.simulation.dft.xc_functional_names', idDFT, {...termQuantityNonExclusive, scale: '1/2', label: 'XC functional names'})
-registerFilter('results.method.simulation.dft.exact_exchange_mixing_factor', idDFT, {...numberHistogramQuantity, scale: '1/2'})
-registerFilter('results.method.simulation.dft.hubbard_kanamori_model.u_effective', idDFT, {...numberHistogramQuantity, scale: '1/2'})
+registerFilter('results.method.simulation.dft.xc_functional_names', idDFT, {...termQuantityNonExclusive, scale: 'log', label: 'XC functional names'})
+registerFilter('results.method.simulation.dft.exact_exchange_mixing_factor', idDFT, {...numberHistogramQuantity, scale: 'log'})
+registerFilter('results.method.simulation.dft.hubbard_kanamori_model.u_effective', idDFT, {...numberHistogramQuantity, scale: 'log'})
 registerFilter('results.method.simulation.dft.relativity_method', idDFT, termQuantity)
-registerFilter('results.method.simulation.tb.type', idTB, {...termQuantity, scale: '1/2'})
-registerFilter('results.method.simulation.tb.localization_type', idTB, {...termQuantity, scale: '1/2'})
+registerFilter('results.method.simulation.tb.type', idTB, {...termQuantity, scale: 'log'})
+registerFilter('results.method.simulation.tb.localization_type', idTB, {...termQuantity, scale: 'log'})
 registerFilter('results.method.simulation.gw.type', idGW, {...termQuantity, label: 'GW type'})
 registerFilter('results.method.simulation.gw.starting_point_type', idGW, {
   ...termQuantity,
-  scale: '1/2',
+  scale: 'log',
   options: {
     'LDA': {label: 'LDA'},
     'GGA': {label: 'GGA'},
@@ -328,12 +328,12 @@ registerFilter('results.method.simulation.gw.starting_point_type', idGW, {
     'HF': {label: 'HF'}
   }
 })
-registerFilter('results.method.simulation.gw.basis_set_type', idGW, {...termQuantity, scale: '1/4'})
+registerFilter('results.method.simulation.gw.basis_set_type', idGW, {...termQuantity, scale: 'log'})
 registerFilter('results.method.simulation.bse.type', idBSE, termQuantity)
 registerFilter('results.method.simulation.bse.solver', idBSE, termQuantity)
 registerFilter('results.method.simulation.bse.starting_point_type', idBSE, {
   ...termQuantity,
-  scale: '1/2',
+  scale: 'log',
   options: {
     'LDA': {label: 'LDA'},
     'GGA': {label: 'GGA'},
@@ -343,13 +343,13 @@ registerFilter('results.method.simulation.bse.starting_point_type', idBSE, {
     'HF': {label: 'HF'}
   }
 })
-registerFilter('results.method.simulation.bse.basis_set_type', idBSE, {...termQuantity, scale: '1/4'})
-registerFilter('results.method.simulation.bse.gw_type', idBSE, {...termQuantity, scale: '1/4', label: `GW type`})
+registerFilter('results.method.simulation.bse.basis_set_type', idBSE, {...termQuantity, scale: 'log'})
+registerFilter('results.method.simulation.bse.gw_type', idBSE, {...termQuantity, scale: 'log', label: `GW type`})
 registerFilter('results.method.simulation.dmft.impurity_solver_type', idDMFT, {...termQuantity})
 registerFilter('results.method.simulation.dmft.magnetic_state', idDMFT, {...termQuantity})
-registerFilter('results.method.simulation.dmft.inverse_temperature', idDMFT, {...numberHistogramQuantity, scale: '1/2'})
-registerFilter('results.method.simulation.dmft.u', idDMFT, {...numberHistogramQuantity, scale: '1/2'})
-registerFilter('results.method.simulation.dmft.jh', idDMFT, {...numberHistogramQuantity, label: `JH`, scale: '1/2'})
+registerFilter('results.method.simulation.dmft.inverse_temperature', idDMFT, {...numberHistogramQuantity, scale: 'log'})
+registerFilter('results.method.simulation.dmft.u', idDMFT, {...numberHistogramQuantity, scale: 'log'})
+registerFilter('results.method.simulation.dmft.jh', idDMFT, {...numberHistogramQuantity, label: `JH`, scale: 'log'})
 registerFilter('results.method.simulation.dmft.analytical_continuation', idDMFT, {...termQuantity})
 registerFilter('results.eln.sections', idELN, termQuantity)
 registerFilter('results.eln.tags', idELN, termQuantity)
@@ -358,10 +358,10 @@ registerFilter('results.eln.instruments', idELN, termQuantity)
 registerFilter('results.eln.lab_ids', idELN, {...termQuantity, label: 'Lab IDs'})
 registerFilter('results.eln.names', idELN, noAggQuantity)
 registerFilter('results.eln.descriptions', idELN, noAggQuantity)
-registerFilter('external_db', idAuthor, {...termQuantity, label: 'External database', scale: '1/4'})
+registerFilter('external_db', idAuthor, {...termQuantity, label: 'External database', scale: 'log'})
 registerFilter('authors.name', idAuthor, {...termQuantityNonExclusive, label: 'Author name'})
-registerFilter('upload_create_time', idAuthor, {...numberHistogramQuantity, scale: '1/2'})
-registerFilter('entry_create_time', idAuthor, {...numberHistogramQuantity, scale: '1/2'})
+registerFilter('upload_create_time', idAuthor, {...numberHistogramQuantity, scale: 'log'})
+registerFilter('entry_create_time', idAuthor, {...numberHistogramQuantity, scale: 'log'})
 registerFilter('datasets.dataset_name', idAuthor, {...termQuantityLarge, label: 'Dataset name'})
 registerFilter('datasets.doi', idAuthor, {...termQuantity, label: 'Dataset DOI'})
 registerFilter('datasets.dataset_id', idAuthor, termQuantity)
@@ -442,7 +442,7 @@ registerFilter(
   nestedQuantity,
   [
     {name: 'type', ...termQuantity},
-    {name: 'value', ...numberHistogramQuantity, scale: '1/4'}
+    {name: 'value', ...numberHistogramQuantity, scale: 'log'}
   ]
 )
 registerFilter(
@@ -451,7 +451,7 @@ registerFilter(
   nestedQuantity,
   [
     {name: 'type', ...termQuantity},
-    {name: 'value', ...numberHistogramQuantity, scale: '1/4'}
+    {name: 'value', ...numberHistogramQuantity, scale: 'log'}
   ]
 )
 registerFilter('results.properties.electronic.band_gap.provenance.label', idElectronic, termQuantity)
@@ -460,12 +460,12 @@ registerFilter(
   idSolarCell,
   nestedQuantity,
   [
-    {name: 'efficiency', ...numberHistogramQuantity, scale: '1/4'},
-    {name: 'fill_factor', ...numberHistogramQuantity, scale: '1/4'},
-    {name: 'open_circuit_voltage', ...numberHistogramQuantity, scale: '1/4'},
-    {name: 'short_circuit_current_density', ...numberHistogramQuantity, scale: '1/4'},
-    {name: 'illumination_intensity', ...numberHistogramQuantity, scale: '1/4'},
-    {name: 'device_area', ...numberHistogramQuantity, scale: '1/4'},
+    {name: 'efficiency', ...numberHistogramQuantity, scale: 'log'},
+    {name: 'fill_factor', ...numberHistogramQuantity, scale: 'log'},
+    {name: 'open_circuit_voltage', ...numberHistogramQuantity, scale: 'log'},
+    {name: 'short_circuit_current_density', ...numberHistogramQuantity, scale: 'log'},
+    {name: 'illumination_intensity', ...numberHistogramQuantity, scale: 'log'},
+    {name: 'device_area', ...numberHistogramQuantity, scale: 'log'},
     {name: 'device_architecture', ...termQuantity},
     {name: 'absorber_fabrication', ...termQuantity},
     {name: 'device_stack', ...termQuantityAllNonExclusive},
@@ -482,7 +482,7 @@ registerFilter(
   nestedQuantity,
   [
     {name: 'characterization_methods', ...termQuantity},
-    {name: 'surface_area', ...numberHistogramQuantity, scale: '1/4'},
+    {name: 'surface_area', ...numberHistogramQuantity, scale: 'log'},
     {name: 'catalyst_name', ...termQuantity},
     {name: 'catalyst_type', ...termQuantity},
     {name: 'preparation_method', ...termQuantity}
@@ -502,9 +502,9 @@ registerFilter(
   idCatalyst,
   nestedQuantity,
   [
-    {name: 'temperature', ...numberHistogramQuantity, scale: '1/4'},
+    {name: 'temperature', ...numberHistogramQuantity, scale: 'log'},
     {name: 'pressure', ...numberHistogramQuantity, scale: 'linear'},
-    {name: 'weight_hourly_space_velocity', ...numberHistogramQuantity, scale: '1/4'}
+    {name: 'weight_hourly_space_velocity', ...numberHistogramQuantity, scale: 'log'}
   ]
 )
 registerFilter(
@@ -514,7 +514,7 @@ registerFilter(
   [
     {name: 'name', ...termQuantityAllNonExclusive},
     {name: 'gas_concentration_out', ...numberHistogramQuantity, scale: 'linear'},
-    {name: 'selectivity', ...numberHistogramQuantity, scale: '1/4'}
+    {name: 'selectivity', ...numberHistogramQuantity, scale: 'log'}
   ]
 )
 registerFilter(
@@ -572,9 +572,9 @@ registerFilter(
   idGeometryOptimization,
   nestedQuantity,
   [
-    {name: 'final_energy_difference', ...numberHistogramQuantity, scale: '1/8'},
-    {name: 'final_displacement_maximum', ...numberHistogramQuantity, scale: '1/8'},
-    {name: 'final_force_maximum', ...numberHistogramQuantity, scale: '1/8'}
+    {name: 'final_energy_difference', ...numberHistogramQuantity, scale: 'log'},
+    {name: 'final_displacement_maximum', ...numberHistogramQuantity, scale: 'log'},
+    {name: 'final_force_maximum', ...numberHistogramQuantity, scale: 'log'}
   ]
 )
 registerFilter(
@@ -632,7 +632,7 @@ registerFilter(
     widget: {
       quantity: 'results.material.elements',
       type: 'periodictable',
-      scale: '1/2',
+      scale: 'log',
       layout: {
         sm: {w: 12, h: 8, minW: 12, minH: 8},
         md: {w: 12, h: 8, minW: 12, minH: 8},
diff --git a/gui/src/components/search/input/InputHeader.js b/gui/src/components/search/input/InputHeader.js
index c05ad831b2e7c9eccfd60accbf1716dcfef4d723..a6c0cd1e10fd229f6aa16890f98c9f76e5794eff 100644
--- a/gui/src/components/search/input/InputHeader.js
+++ b/gui/src/components/search/input/InputHeader.js
@@ -131,7 +131,7 @@ const InputHeader = React.memo(({
             onChange={onChangeScale ? (event, value) => onChangeScale(value) : undefined}
           >
             {Object.entries(scales).map(([key, value]) =>
-              <FormControlLabel key={key} value={key} label={key} control={<Radio/>} />
+              <FormControlLabel key={key} value={key} label={value} control={<Radio/>} />
             )}
           </RadioGroup>
         </FormControl>
@@ -139,7 +139,7 @@ const InputHeader = React.memo(({
     </>
     : <ActionSelect
       value={scale}
-      options={Object.keys(scales)}
+      options={scales}
       tooltip="Statistics scaling"
       onChange={onChangeScale}
     />
diff --git a/gui/src/components/search/input/InputPeriodicTable.js b/gui/src/components/search/input/InputPeriodicTable.js
index 0115b720ee734da3971d730ada7df83bdebe87cf..7d74f53b67c96f7cd9099ff07c9a589baac02d4a 100644
--- a/gui/src/components/search/input/InputPeriodicTable.js
+++ b/gui/src/components/search/input/InputPeriodicTable.js
@@ -80,9 +80,9 @@ const Element = React.memo(({
 }) => {
   const styles = useElementStyles()
   const theme = useTheme()
-  const scaler = useMemo(() => getScaler(scale, undefined, [0.2, 1]), [scale])
+  const scaler = useMemo(() => getScaler(scale, [0, max], [0.2, 1]), [scale, max])
   const finalCount = useMemo(() => approxInteger(count || 0), [count])
-  const finalScale = useMemo(() => scaler(count / max) || 0, [count, max, scaler])
+  const finalScale = useMemo(() => scaler(count), [count, scaler])
   const disabledFinal = disabled && !selected
   const color = selected
     ? theme.palette.secondary.main
diff --git a/gui/src/components/search/input/InputRange.js b/gui/src/components/search/input/InputRange.js
index 17c04950b0fafe6717ccadd86ec643c6f50ca87b..16bce845d5147caea222c7055d2350ed29476f42 100644
--- a/gui/src/components/search/input/InputRange.js
+++ b/gui/src/components/search/input/InputRange.js
@@ -47,9 +47,9 @@ const useStyles = makeStyles(theme => ({
 }))
 export const Range = React.memo(({
   xAxis,
+  yAxis,
   nSteps,
   visible,
-  scale,
   nBins,
   disableHistogram,
   disableXTitle,
@@ -68,7 +68,7 @@ export const Range = React.memo(({
   const [filter, setFilter] = useFilterState(xAxis.quantity)
   const [minLocal, setMinLocal] = useState()
   const [maxLocal, setMaxLocal] = useState()
-  const [plotData, setPlotData] = useState({xAxis})
+  const [plotData, setPlotData] = useState({xAxis, yAxis})
   const loading = useRef(false)
   const firstRender = useRef(true)
   const validRange = useRef()
@@ -257,10 +257,11 @@ export const Range = React.memo(({
         min: minLocal,
         max: maxLocal
       },
+      yAxis,
       step: stepHistogram,
       data: agg.data
     })
-  }, [loading, nBins, agg, minLocal, maxLocal, stepHistogram, unitStorage, xAxis.quantity, xAxis.unit, xAxis.dtype, xAxis.title])
+  }, [loading, nBins, agg, minLocal, maxLocal, stepHistogram, unitStorage, xAxis.quantity, xAxis.unit, xAxis.dtype, xAxis.title, xAxis.scale, yAxis])
 
   // Function for converting search values into the currently selected unit
   // system.
@@ -501,11 +502,11 @@ export const Range = React.memo(({
     <PlotHistogram
       bins={plotData?.data}
       xAxis={plotData?.xAxis}
+      yAxis={plotData?.yAxis}
       step={plotData?.step}
       minXInclusive={minInclusive}
       maxXInclusive={maxInclusive}
       disabled={disabled}
-      scale={scale}
       nBins={nBins}
       range={range}
       highlight={highlight}
@@ -542,6 +543,7 @@ export const Range = React.memo(({
 
 Range.propTypes = {
   xAxis: PropTypes.object,
+  yAxis: PropTypes.object,
   /* Target number of steps for the slider that is shown when statistics are
    * disabled. The actual number may vary, as the step is chosen to be a
    * human-readable value that depends on the range and the unit. */
@@ -550,8 +552,6 @@ Range.propTypes = {
    * enabled. */
   nBins: PropTypes.number,
   visible: PropTypes.bool,
-  /* The statistics scaling */
-  scale: PropTypes.string,
   /* Whether the histogram is disabled */
   disableHistogram: PropTypes.bool,
   /* Whether the x title is disabled */
@@ -613,6 +613,7 @@ const InputRange = React.memo(({
       unit: new Unit(filterData[quantity]?.unit || 'dimensionless').toSystem(units)
     }
   ), [quantity, filterData, dtype, units])
+  const y = useMemo(() => ({scale: scale}), [scale])
 
   // Determine the description and title
   const def = filterData[quantity]
@@ -639,9 +640,9 @@ const InputRange = React.memo(({
     />
     <Range
       xAxis={x}
+      yAxis={y}
       nSteps={nSteps}
       visible={visible}
-      scale={scale}
       nBins={nBins}
       disableHistogram={disableHistogram}
       disableXTitle
diff --git a/gui/src/components/search/widgets/Dashboard.js b/gui/src/components/search/widgets/Dashboard.js
index 105ed46fd557134defaeb74ccf1bb5c6a213a027..7a6f526e67652a1875d519e71a5a955cf6b468ca 100644
--- a/gui/src/components/search/widgets/Dashboard.js
+++ b/gui/src/components/search/widgets/Dashboard.js
@@ -107,6 +107,8 @@ const Dashboard = React.memo(() => {
         xl: {...layout},
         xxl: {...layout}
       },
+      // x: {scale: 'linear'},
+      // y: {scale: 'linear'},
       size: 1000,
       autorange: true,
       type: 'scatterplot'
@@ -155,7 +157,7 @@ const Dashboard = React.memo(() => {
       },
       autorange: false,
       nbins: 30,
-      scale: 'linear',
+      y: {scale: 'linear'},
       type: 'histogram'
     }
     addWidget(id, value)
diff --git a/gui/src/components/search/widgets/Dashboard.spec.js b/gui/src/components/search/widgets/Dashboard.spec.js
index efe82a3d82a632d89651534549d1d57f12fe8662..80078fb1d8f266b70aa74669faf4bd7e007ac734 100644
--- a/gui/src/components/search/widgets/Dashboard.spec.js
+++ b/gui/src/components/search/widgets/Dashboard.spec.js
@@ -71,7 +71,7 @@ describe('displaying an initial widget and removing it', () => {
         type: 'histogram',
         title: 'Test title',
         x: {quantity: 'results.material.n_elements'},
-        scale: 'linear',
+        y: {scale: 'linear'},
         editing: false,
         visible: true,
         layout: {
diff --git a/gui/src/components/search/widgets/StatisticsBar.js b/gui/src/components/search/widgets/StatisticsBar.js
index 9495cf0e2bd1f50b5afdc90c3e9babaefe0a60b6..78ad58daa7dd19579fb77e99f0d634c930f1fe68 100644
--- a/gui/src/components/search/widgets/StatisticsBar.js
+++ b/gui/src/components/search/widgets/StatisticsBar.js
@@ -71,9 +71,9 @@ const StatisticsBar = React.memo(({
   const theme = useTheme()
 
   // Calculate the approximated count and the final scaled value
-  const scaler = useMemo(() => scale ? getScaler(scale) : (value) => value, [scale])
+  const scaler = useMemo(() => scale ? getScaler(scale, [0, max]) : (value) => value, [scale, max])
   const finalCount = useMemo(() => approxInteger(value || 0), [value])
-  const finalScale = useMemo(() => scaler(value / max) || 0, [value, max, scaler])
+  const finalScale = useMemo(() => scaler(value), [value, scaler])
 
   return <div onClick={onClick} className={clsx(className, styles.root)} data-testid={testID}>
     <Tooltip placement="bottom" enterDelay={0} title={tooltip || ''}>
diff --git a/gui/src/components/search/widgets/Widget.js b/gui/src/components/search/widgets/Widget.js
index 37ccc97705f999555e89bb557f08afdf1931dc3e..a6be7bb7050e61a385dea382367c4c96d9831c5d 100644
--- a/gui/src/components/search/widgets/Widget.js
+++ b/gui/src/components/search/widgets/Widget.js
@@ -110,15 +110,20 @@ export const schemaWidget = object({
   editing: string().strip(),
   visible: string().strip()
 })
+export const schemaAxisBase = object({
+  scale: string().nullable()
+})
 export const schemaAxis = object({
   quantity: string().required(),
   unit: string().nullable(),
-  title: string().nullable()
+  title: string().nullable(),
+  scale: string().nullable()
 })
 export const schemaAxisOptional = object({
   quantity: string().nullable(),
   unit: string().nullable(),
-  title: string().nullable()
+  title: string().nullable(),
+  scale: string().nullable()
 })
 export const schemaMarkers = object({
   color: schemaAxisOptional
diff --git a/gui/src/components/search/widgets/WidgetHistogram.js b/gui/src/components/search/widgets/WidgetHistogram.js
index e0fbdf1f3f1a72285f9deb731cb1e19fb6f46484..1f54766891b8247b4e74873815ad203135394059 100644
--- a/gui/src/components/search/widgets/WidgetHistogram.js
+++ b/gui/src/components/search/widgets/WidgetHistogram.js
@@ -36,8 +36,8 @@ export const WidgetHistogram = React.memo((
   title,
   description,
   x,
+  y,
   nbins,
-  scale,
   autorange,
   showinput,
   className
@@ -68,7 +68,7 @@ export const WidgetHistogram = React.memo((
   }, [setWidget])
 
   const handleChangeScale = useCallback((value) => {
-    setWidget(old => { return {...old, scale: value} })
+    setWidget(old => { return {...old, y: {...old.y, scale: value}} })
   }, [setWidget])
 
   return <Widget
@@ -85,8 +85,8 @@ export const WidgetHistogram = React.memo((
         onChange={(value) => setWidget(old => ({...old, autorange: value}))}
       />
       <ActionSelect
-        value={scale}
-        options={Object.keys(scales)}
+        value={y.scale}
+        options={scales}
         tooltip="Statistics scaling"
         onChange={handleChangeScale}
       />
@@ -94,9 +94,9 @@ export const WidgetHistogram = React.memo((
   >
     <Range
       xAxis={xAxis}
+      yAxis={y}
       visible={true}
       nBins={nbins}
-      scale={scale}
       anchored={true}
       autorange={autorange}
       showinput={showinput}
@@ -110,8 +110,8 @@ WidgetHistogram.propTypes = {
   title: PropTypes.string,
   description: PropTypes.string,
   x: PropTypes.object,
+  y: PropTypes.object,
   nbins: PropTypes.number,
-  scale: PropTypes.string,
   autorange: PropTypes.bool,
   showinput: PropTypes.bool,
   className: PropTypes.string
diff --git a/gui/src/components/search/widgets/WidgetHistogramEdit.js b/gui/src/components/search/widgets/WidgetHistogramEdit.js
index 9e557923b9a967d438a72e3fdfa4587e8252bb01..5b1bbe1f5d47f5eb46d2fcd1c4e6f5e581e804da 100644
--- a/gui/src/components/search/widgets/WidgetHistogramEdit.js
+++ b/gui/src/components/search/widgets/WidgetHistogramEdit.js
@@ -17,7 +17,7 @@
  */
 import React, { useState, useCallback } from 'react'
 import PropTypes from 'prop-types'
-import { string, number, bool, reach } from 'yup'
+import { number, bool, reach } from 'yup'
 import { cloneDeep } from 'lodash'
 import {
   TextField,
@@ -29,7 +29,7 @@ import { useSearchContext } from '../SearchContext'
 import { InputMetainfo } from '../input/InputMetainfo'
 import { InputTextField } from '../input/InputText'
 import UnitInput from '../../units/UnitInput'
-import { schemaWidget, schemaAxis } from './Widget'
+import { schemaWidget, schemaAxis, schemaAxisBase } from './Widget'
 import { WidgetEditDialog, WidgetEditGroup, WidgetEditOption } from './WidgetEdit'
 import { DType, parseJMESPath, setDeep, isEmptyString } from '../../../utils'
 import { scales } from '../../plotting/common'
@@ -150,29 +150,31 @@ export const WidgetHistogramEdit = React.memo(({widget}) => {
           />
         </WidgetEditOption>
       </WidgetEditGroup>
-      <WidgetEditGroup title="general">
-        <WidgetEditOption>
-          <InputTextField
-            label="title"
-            fullWidth
-            value={settings?.title}
-            onChange={(event) => handleChange('title', event.target.value)}
-          />
-        </WidgetEditOption>
+      <WidgetEditGroup title="y axis">
         <WidgetEditOption>
           <TextField
             select
             fullWidth
-            label="Statistics scaling"
+            label="scale"
             variant="filled"
-            value={settings.scale}
-            onChange={(event) => { handleChange('scale', event.target.value) }}
+            value={settings.y?.scale}
+            onChange={(event) => { handleChange('y.scale', event.target.value) }}
           >
             {Object.keys(scales).map((key) =>
               <MenuItem value={key} key={key}>{key}</MenuItem>
             )}
           </TextField>
         </WidgetEditOption>
+      </WidgetEditGroup>
+      <WidgetEditGroup title="general">
+        <WidgetEditOption>
+          <InputTextField
+            label="title"
+            fullWidth
+            value={settings?.title}
+            onChange={(event) => handleChange('title', event.target.value)}
+          />
+        </WidgetEditOption>
         <WidgetEditOption>
           <TextField
             select
@@ -212,8 +214,8 @@ WidgetHistogramEdit.propTypes = {
 }
 
 export const schemaWidgetHistogram = schemaWidget.shape({
-  x: schemaAxis.required('Quantity for the x axis is required.'),
-  scale: string().required('Scale is required.'),
+  x: schemaAxis.required('X-axis configuration is required.'),
+  y: schemaAxisBase.required('Y-axis configuration is required.'),
   nbins: number().integer().required(),
   autorange: bool(),
   showinput: bool()
diff --git a/gui/src/components/search/widgets/WidgetPeriodicTable.js b/gui/src/components/search/widgets/WidgetPeriodicTable.js
index a27aedfea4b3567c6f94e8f62638c43761b28f36..5055fc0fe45a6d546e72f4a9fef25a69fa88ee31 100644
--- a/gui/src/components/search/widgets/WidgetPeriodicTable.js
+++ b/gui/src/components/search/widgets/WidgetPeriodicTable.js
@@ -60,7 +60,7 @@ export const WidgetPeriodicTable = React.memo((
     actions={
       <ActionSelect
         value={scale}
-        options={Object.keys(scales)}
+        options={scales}
         tooltip="Statistics scaling"
         onChange={handleChangeScale}
       />
diff --git a/gui/src/components/search/widgets/WidgetScatterPlotEdit.js b/gui/src/components/search/widgets/WidgetScatterPlotEdit.js
index 909a3506467b5d28a684e8d9572a7f6eea57ab95..04ecdf417545640011d5bfd0d093b6df70c54bf5 100644
--- a/gui/src/components/search/widgets/WidgetScatterPlotEdit.js
+++ b/gui/src/components/search/widgets/WidgetScatterPlotEdit.js
@@ -21,7 +21,9 @@ import { number, bool, reach } from 'yup'
 import { cloneDeep } from 'lodash'
 import {
   Checkbox,
-  FormControlLabel
+  FormControlLabel,
+  MenuItem,
+  TextField
 } from '@material-ui/core'
 import { InputJMESPath } from '../input/InputMetainfo'
 import { schemaWidget, schemaAxis, schemaMarkers } from './Widget'
@@ -30,6 +32,7 @@ import { useSearchContext } from '../SearchContext'
 import { autorangeDescription } from './WidgetHistogram'
 import { DType, setDeep, parseJMESPath, isEmptyString } from '../../../utils'
 import { InputTextField } from '../input/InputText'
+import { scalesLimited } from '../../plotting/common'
 import UnitInput from '../../units/UnitInput'
 
 // Predefined in order to not break memoization
@@ -157,6 +160,20 @@ export const WidgetScatterPlotEdit = React.memo(({widget}) => {
             disableGroup
           />
         </WidgetEditOption>
+        <WidgetEditOption>
+          <TextField
+            select
+            fullWidth
+            label="scale"
+            variant="filled"
+            value={settings.x?.scale}
+            onChange={(event) => { handleChange('x.scale', event.target.value) }}
+          >
+            {Object.keys(scalesLimited).map((key) =>
+              <MenuItem value={key} key={key}>{key}</MenuItem>
+            )}
+          </TextField>
+        </WidgetEditOption>
       </WidgetEditGroup>
       <WidgetEditGroup title="y axis">
         <WidgetEditOption>
@@ -194,6 +211,20 @@ export const WidgetScatterPlotEdit = React.memo(({widget}) => {
             disableGroup
           />
         </WidgetEditOption>
+        <WidgetEditOption>
+          <TextField
+            select
+            fullWidth
+            label="scale"
+            variant="filled"
+            value={settings.y?.scale}
+            onChange={(event) => { handleChange('y.scale', event.target.value) }}
+          >
+            {Object.keys(scalesLimited).map((key) =>
+              <MenuItem value={key} key={key}>{key}</MenuItem>
+            )}
+          </TextField>
+        </WidgetEditOption>
       </WidgetEditGroup>
       <WidgetEditGroup title="marker color">
         <WidgetEditOption>
diff --git a/gui/src/components/search/widgets/WidgetTerms.js b/gui/src/components/search/widgets/WidgetTerms.js
index a4289f5ec9c653c43789ab1fc3187539b51b59da..889587224392deb5c3cc875f8fe18aff5eb5347e 100644
--- a/gui/src/components/search/widgets/WidgetTerms.js
+++ b/gui/src/components/search/widgets/WidgetTerms.js
@@ -196,7 +196,7 @@ export const WidgetTerms = React.memo((
     actions={
       <ActionSelect
         value={scale}
-        options={Object.keys(scales)}
+        options={scales}
         tooltip="Statistics scaling"
         onChange={handleChangeScale}
       />
diff --git a/gui/tests/env.js b/gui/tests/env.js
index 2d4351f800bb579cd6c8d93c450be4a7b269e8df..e917a871b6c849a8187fb47ab0f0b675a5584e7d 100644
--- a/gui/tests/env.js
+++ b/gui/tests/env.js
@@ -1049,7 +1049,7 @@ window.nomadEnv = {
                   }
                 },
                 "quantity": "results.material.structural_type",
-                "scale": "1/8",
+                "scale": "log",
                 "showinput": false
               },
               {
@@ -1097,7 +1097,7 @@ window.nomadEnv = {
                   }
                 },
                 "quantity": "results.method.simulation.program_name",
-                "scale": "1/4",
+                "scale": "log",
                 "showinput": true
               },
               {
@@ -2128,7 +2128,11 @@ window.nomadEnv = {
                 },
                 "x": {
                   "unit": "ml/(g*s)",
-                  "quantity": "results.properties.catalytic.reaction.reaction_conditions.weight_hourly_space_velocity"
+                  "quantity": "results.properties.catalytic.reaction.reaction_conditions.weight_hourly_space_velocity",
+                  "scale": "linear"
+                },
+                "y": {
+                  "scale": "linear"
                 },
                 "scale": "linear",
                 "autorange": false,
@@ -2182,14 +2186,17 @@ window.nomadEnv = {
                 },
                 "x": {
                   "title": "gas concentration (%)",
-                  "quantity": "results.properties.catalytic.reaction.reactants[*].gas_concentration_in"
+                  "quantity": "results.properties.catalytic.reaction.reactants[*].gas_concentration_in",
+                  "scale": "linear"
                 },
                 "y": {
-                  "quantity": "results.properties.catalytic.reaction.reaction_conditions.temperature"
+                  "quantity": "results.properties.catalytic.reaction.reaction_conditions.temperature",
+                  "scale": "linear"
                 },
                 "markers": {
                   "color": {
-                    "quantity": "results.properties.catalytic.reaction.reactants[*].name"
+                    "quantity": "results.properties.catalytic.reaction.reactants[*].name",
+                    "scale": "linear"
                   }
                 },
                 "size": 1000,
@@ -2242,7 +2249,11 @@ window.nomadEnv = {
                 },
                 "x": {
                   "unit": "bar",
-                  "quantity": "results.properties.catalytic.reaction.reaction_conditions.pressure"
+                  "quantity": "results.properties.catalytic.reaction.reaction_conditions.pressure",
+                  "scale": "linear"
+                },
+                "y": {
+                  "scale": "linear"
                 },
                 "scale": "linear",
                 "autorange": false,
@@ -2295,15 +2306,18 @@ window.nomadEnv = {
                   }
                 },
                 "x": {
-                  "quantity": "results.properties.catalytic.reaction.reaction_conditions.temperature"
+                  "quantity": "results.properties.catalytic.reaction.reaction_conditions.temperature",
+                  "scale": "linear"
                 },
                 "y": {
                   "title": "Conversion (%)",
-                  "quantity": "results.properties.catalytic.reaction.reactants[*].conversion"
+                  "quantity": "results.properties.catalytic.reaction.reactants[*].conversion",
+                  "scale": "linear"
                 },
                 "markers": {
                   "color": {
-                    "quantity": "results.properties.catalytic.reaction.reactants[*].name"
+                    "quantity": "results.properties.catalytic.reaction.reactants[*].name",
+                    "scale": "linear"
                   }
                 },
                 "size": 1000,
@@ -2355,15 +2369,18 @@ window.nomadEnv = {
                   }
                 },
                 "x": {
-                  "quantity": "results.properties.catalytic.reaction.reaction_conditions.temperature"
+                  "quantity": "results.properties.catalytic.reaction.reaction_conditions.temperature",
+                  "scale": "linear"
                 },
                 "y": {
                   "title": "Selectivity (%)",
-                  "quantity": "results.properties.catalytic.reaction.products[*].selectivity"
+                  "quantity": "results.properties.catalytic.reaction.products[*].selectivity",
+                  "scale": "linear"
                 },
                 "markers": {
                   "color": {
-                    "quantity": "results.properties.catalytic.reaction.products[*].name"
+                    "quantity": "results.properties.catalytic.reaction.products[*].name",
+                    "scale": "linear"
                   }
                 },
                 "size": 1000,
@@ -2415,15 +2432,18 @@ window.nomadEnv = {
                 },
                 "x": {
                   "title": "Oxygen Conversion (%)",
-                  "quantity": "results.properties.catalytic.reaction.reactants[? name=='molecular oxygen'].conversion"
+                  "quantity": "results.properties.catalytic.reaction.reactants[? name=='molecular oxygen'].conversion",
+                  "scale": "linear"
                 },
                 "y": {
                   "title": "Acetic Acid Selectivity (%)",
-                  "quantity": "results.properties.catalytic.reaction.products[? name=='acetic acid'].selectivity"
+                  "quantity": "results.properties.catalytic.reaction.products[? name=='acetic acid'].selectivity",
+                  "scale": "linear"
                 },
                 "markers": {
                   "color": {
-                    "quantity": "results.properties.catalytic.reaction.name"
+                    "quantity": "results.properties.catalytic.reaction.name",
+                    "scale": "linear"
                   }
                 },
                 "size": 1000,
@@ -2475,15 +2495,18 @@ window.nomadEnv = {
                 },
                 "x": {
                   "title": "Carbon Monoxide Conversion (%)",
-                  "quantity": "results.properties.catalytic.reaction.reactants[? name=='carbon monoxide'].conversion"
+                  "quantity": "results.properties.catalytic.reaction.reactants[? name=='carbon monoxide'].conversion",
+                  "scale": "linear"
                 },
                 "y": {
                   "title": "Ethanol Selectivity (%)",
-                  "quantity": "results.properties.catalytic.reaction.products[? name=='ethanol'].selectivity"
+                  "quantity": "results.properties.catalytic.reaction.products[? name=='ethanol'].selectivity",
+                  "scale": "linear"
                 },
                 "markers": {
                   "color": {
-                    "quantity": "results.properties.catalytic.catalyst.preparation_method"
+                    "quantity": "results.properties.catalytic.catalyst.preparation_method",
+                    "scale": "linear"
                   }
                 },
                 "size": 1000,
@@ -2536,9 +2559,13 @@ window.nomadEnv = {
                 },
                 "x": {
                   "unit": "m^2/g",
-                  "quantity": "results.properties.catalytic.catalyst.surface_area"
+                  "quantity": "results.properties.catalytic.catalyst.surface_area",
+                  "scale": "linear"
+                },
+                "y": {
+                  "scale": "log"
                 },
-                "scale": "1/4",
+                "scale": "linear",
                 "autorange": false,
                 "showinput": false,
                 "nbins": 30
@@ -3144,7 +3171,11 @@ window.nomadEnv = {
                     }
                   },
                   "x": {
-                    "quantity": "results.material.topology.pore_limiting_diameter"
+                    "quantity": "results.material.topology.pore_limiting_diameter",
+                    "scale": "linear"
+                  },
+                  "y": {
+                    "scale": "linear"
                   },
                   "scale": "linear",
                   "autorange": true,
@@ -3196,7 +3227,11 @@ window.nomadEnv = {
                     }
                   },
                   "x": {
-                    "quantity": "results.material.topology.largest_cavity_diameter"
+                    "quantity": "results.material.topology.largest_cavity_diameter",
+                    "scale": "linear"
+                  },
+                  "y": {
+                    "scale": "linear"
                   },
                   "scale": "linear",
                   "autorange": true,
@@ -3248,7 +3283,11 @@ window.nomadEnv = {
                     }
                   },
                   "x": {
-                    "quantity": "results.material.topology.accessible_surface_area"
+                    "quantity": "results.material.topology.accessible_surface_area",
+                    "scale": "linear"
+                  },
+                  "y": {
+                    "scale": "linear"
                   },
                   "scale": "linear",
                   "autorange": true,
@@ -3300,7 +3339,11 @@ window.nomadEnv = {
                     }
                   },
                   "x": {
-                    "quantity": "results.material.topology.void_fraction"
+                    "quantity": "results.material.topology.void_fraction",
+                    "scale": "linear"
+                  },
+                  "y": {
+                    "scale": "linear"
                   },
                   "scale": "linear",
                   "autorange": true,
@@ -4081,16 +4124,19 @@ window.nomadEnv = {
                     }
                   },
                   "x": {
-                    "quantity": "results.properties.optoelectronic.solar_cell.open_circuit_voltage"
+                    "quantity": "results.properties.optoelectronic.solar_cell.open_circuit_voltage",
+                    "scale": "linear"
                   },
                   "y": {
                     "title": "Efficiency (%)",
-                    "quantity": "results.properties.optoelectronic.solar_cell.efficiency"
+                    "quantity": "results.properties.optoelectronic.solar_cell.efficiency",
+                    "scale": "linear"
                   },
                   "markers": {
                     "color": {
                       "unit": "mA/cm^2",
-                      "quantity": "results.properties.optoelectronic.solar_cell.short_circuit_current_density"
+                      "quantity": "results.properties.optoelectronic.solar_cell.short_circuit_current_density",
+                      "scale": "linear"
                     }
                   },
                   "size": 1000,
@@ -4141,15 +4187,18 @@ window.nomadEnv = {
                     }
                   },
                   "x": {
-                    "quantity": "results.properties.optoelectronic.solar_cell.open_circuit_voltage"
+                    "quantity": "results.properties.optoelectronic.solar_cell.open_circuit_voltage",
+                    "scale": "linear"
                   },
                   "y": {
                     "title": "Efficiency (%)",
-                    "quantity": "results.properties.optoelectronic.solar_cell.efficiency"
+                    "quantity": "results.properties.optoelectronic.solar_cell.efficiency",
+                    "scale": "linear"
                   },
                   "markers": {
                     "color": {
-                      "quantity": "results.properties.optoelectronic.solar_cell.device_architecture"
+                      "quantity": "results.properties.optoelectronic.solar_cell.device_architecture",
+                      "scale": "linear"
                     }
                   },
                   "size": 1000,
@@ -4248,9 +4297,13 @@ window.nomadEnv = {
                     }
                   },
                   "x": {
-                    "quantity": "results.properties.optoelectronic.solar_cell.illumination_intensity"
+                    "quantity": "results.properties.optoelectronic.solar_cell.illumination_intensity",
+                    "scale": "linear"
+                  },
+                  "y": {
+                    "scale": "1/4"
                   },
-                  "scale": "1/4",
+                  "scale": "linear",
                   "autorange": true,
                   "showinput": true,
                   "nbins": 30
@@ -4349,9 +4402,13 @@ window.nomadEnv = {
                     }
                   },
                   "x": {
-                    "quantity": "results.properties.electronic.band_structure_electronic.band_gap.value"
+                    "quantity": "results.properties.electronic.band_structure_electronic.band_gap.value",
+                    "scale": "linear"
+                  },
+                  "y": {
+                    "scale": "1/4"
                   },
-                  "scale": "1/4",
+                  "scale": "linear",
                   "autorange": false,
                   "showinput": false,
                   "nbins": 30
diff --git a/nomad/config/defaults.yaml b/nomad/config/defaults.yaml
index 9aadfb889a5ddf8641f0f7e58400ecde9301c8d8..4629ce57deadc2998efc0d35311312fdd08e70b2 100644
--- a/nomad/config/defaults.yaml
+++ b/nomad/config/defaults.yaml
@@ -973,7 +973,7 @@ ui:
               xl: {h: 11, minH: 3, minW: 3, w: 5, x: 19, y: 0}
               xxl: {h: 9, minH: 3, minW: 3, w: 6, x: 19, y: 0}
             quantity: results.material.structural_type
-            scale: 1/8
+            scale: log
             showinput: false
             type: terms
           - layout:
@@ -983,7 +983,7 @@ ui:
               xl: {h: 11, minH: 3, minW: 3, w: 5, x: 14, y: 0}
               xxl: {h: 9, minH: 3, minW: 3, w: 6, x: 13, y: 0}
             quantity: results.method.simulation.program_name
-            scale: 1/4
+            scale: log
             showinput: true
             type: terms
           - layout:
@@ -1518,7 +1518,7 @@ ui:
               quantity: results.properties.catalytic.catalyst.surface_area
               unit: 'm^2/g'
             title: 'Catalyst Surface Area'
-            scale: 1/4
+            scale: log
             showinput: false
             type: histogram
           - layout:
diff --git a/nomad/config/models/ui.py b/nomad/config/models/ui.py
index 388209989e303a85e28e89d3fdc185b210e42fae..705ebd18af024ffec6181aaed52aad25a8063605 100644
--- a/nomad/config/models/ui.py
+++ b/nomad/config/models/ui.py
@@ -427,12 +427,20 @@ class Layout(ConfigBaseModel):
 
 
 class ScaleEnum(str, Enum):
+    LINEAR = 'linear'
+    LOG = 'log'
+    # TODO: The following should possibly be deprecated.
     POW1 = 'linear'
     POW2 = '1/2'
     POW4 = '1/4'
     POW8 = '1/8'
 
 
+class ScaleEnumPlot(str, Enum):
+    LINEAR = 'linear'
+    LOG = 'log'
+
+
 class BreakpointEnum(str, Enum):
     SM = 'sm'
     MD = 'md'
@@ -441,7 +449,18 @@ class BreakpointEnum(str, Enum):
     XXL = 'xxl'
 
 
-class Axis(ConfigBaseModel):
+# NOTE: Once the old power scaling options (1/2, 1/4, 1/8) are deprecated, the
+# axis models here can be simplified.
+class AxisScale(ConfigBaseModel):
+    """Basic configuration for a plot axis."""
+
+    scale: Optional[ScaleEnum] = Field(
+        ScaleEnum.LINEAR,
+        description="""Defines the axis scaling. Defaults to linear scaling.""",
+    )
+
+
+class AxisQuantity(ConfigBaseModel):
     """Configuration for a plot axis."""
 
     title: Optional[str] = Field(description="""Custom title to show for the axis.""")
@@ -458,6 +477,19 @@ class Axis(ConfigBaseModel):
     )
 
 
+class Axis(AxisScale, AxisQuantity):
+    """Configuration for a plot axis with limited scaling options."""
+
+
+class AxisLimitedScale(AxisQuantity):
+    """Configuration for a plot axis with limited scaling options."""
+
+    scale: Optional[ScaleEnumPlot] = Field(
+        ScaleEnumPlot.LINEAR,
+        description="""Defines the axis scaling. Defaults to linear scaling.""",
+    )
+
+
 class Markers(ConfigBaseModel):
     """Configuration for plot markers."""
 
@@ -504,7 +536,12 @@ class WidgetHistogram(Widget):
     x: Union[Axis, str] = Field(
         description='Configures the information source and display options for the x-axis.'
     )
-    scale: ScaleEnum = Field(description='Statistics scaling.')
+    y: Union[AxisScale, str] = Field(
+        description='Configures the information source and display options for the y-axis.'
+    )
+    scale: Optional[ScaleEnum] = Field(
+        ScaleEnum.LINEAR, description='Statistics scaling.'
+    )
     autorange: bool = Field(
         True,
         description='Whether to automatically set the range according to the data limits.',
@@ -522,14 +559,26 @@ class WidgetHistogram(Widget):
 
     @root_validator(pre=True)
     def __validate(cls, values):
-        """Ensures backwards compatibility for quantity."""
-        quantity = values.get('quantity')
-        x = values.get('x')
-        if quantity and not x:
-            values['x'] = {'quantity': quantity}
-            del values['quantity']
-        elif isinstance(x, str):
-            values['x'] = {'quantity': x}
+        """Ensures backwards compatibility for quantity and scale."""
+        # X-axis
+        x = values.get('x', {})
+        if isinstance(x, str):
+            x = {'quantity': x}
+        if isinstance(x, dict):
+            quantity = values.get('quantity')
+            if quantity and not x.get('quantity'):
+                x['quantity'] = quantity
+                del values['quantity']
+            values['x'] = x
+
+        # Y-axis
+        y = values.get('y', {})
+        if isinstance(y, dict):
+            scale = values.get('scale')
+            if scale:
+                y['scale'] = scale
+                del values['scale']
+            values['y'] = y
 
         return values
 
@@ -550,10 +599,10 @@ class WidgetScatterPlot(Widget):
     type: Literal['scatterplot'] = Field(
         'scatterplot', description='Set as `scatterplot` to get this widget type.'
     )
-    x: Union[Axis, str] = Field(
+    x: Union[AxisLimitedScale, str] = Field(
         description='Configures the information source and display options for the x-axis.'
     )
-    y: Union[Axis, str] = Field(
+    y: Union[AxisLimitedScale, str] = Field(
         description='Configures the information source and display options for the y-axis.'
     )
     markers: Optional[Markers] = Field(