0

I am trying to plot 4d plot using splot (x y z value). I would like to have 4th column shown as heat color. Up to this point, I am fine. What I can't figure out, after searching answers online, is to have the color of the dots being transparent but with different transparency based on their value.

For example, let's say I have the following data set:

0 0 0 0.1
0 0 1 0.2

0 1 0 0.2
0 1 1 2

1 0 0 1
1 0 1 3

1 1 0 0.5
1 1 1 4

Now, I want to make the colorbar (for the 4th column) to be as such: the closer the 4th column value is to 1, the more transparent the dot/point in the figure it will be. All the places I've look can only give me uniform transparency for the entire colorbar.

I wonder if anyone has dealt with this before, or has an idea how to do this. Thank you very much!

James
  • 1
  • I think you need not gnuplot, but Matlab or Octave. It's much easier to do what you want with these programs. – Michael Nov 11 '17 at 17:51
  • Do you want the fourth column to determine both color and transparency? What do you want to happen when it is not between 0 and 1? – user8153 Nov 12 '17 at 00:42
  • @user8153 I'd like the fourth column to determine both color and transparency. The fourth column value will always be positive for my data, and could be smaller or larger than 1. If it's larger than 1, then I'd still like them to be more transparent if they are closer to 1. If we plot the fourth column in log scale, and assuming the log scale is symmetric around 1, meaning that it's from 10^-n to 10^n, where n is the power, then it'll be that the middle of the color bar would be 1, and most transparent. – James Nov 12 '17 at 05:08

1 Answers1

0

I did not fully understand how you want the transparency to depend on the value, so I will give a general answer, where you can substitute the transparency function for your own.

While you can specify transparency for line colors, this appears to not be possible when using palette, which would be the most straightforward way to achieve what you want. The furthest you can go with only using gnuplot is to make the colors appear transparent, as in the following script, where in.data is a file with your sample data.

#!/usr/bin/env gnuplot

set term pngcairo
in_data = "in.data"
set out "out.png"

# function to combine color and alpha channels with white background
# 0: no transparency, 1: fully transparent
make_transparent(x1, t) = (1-t)*x1 + t

# a function to decide transparency
# the input and output must be in range of [0,1]
#get_transparency(x1) = 0      # no transparency
#get_transparency(x1) = 1      # fully transparent
get_transparency(x1) = 1 - x1  # smaller values are more transparent

# convenience function to truncate values
minval(x1, x2) = x1<x2?x1:x2
maxval(x1, x2) = x1>x2?x1:x2
truncval(x1, xmin, xmax) = maxval(minval(x1, xmax), xmin)
trunc(x1) = truncval(x1, 0, 1)

# the default palette consists of rgbfunctions 7,5,15
# we redefine their transparency enabled versions here
# the input and output must be in range of [0,1]
# see other formulae with "show palette rgbformulae" command in gnuplot
f7(x1)  = make_transparent(sqrt(x1)           , get_transparency(x1))
f5(x1)  = make_transparent(x1**3              , get_transparency(x1))
f15(x1) = make_transparent(trunc(sin(2*pi*x1)), get_transparency(x1))

set palette model RGB functions f7(gray),f5(gray),f15(gray)

splot in_data palette  

This script assumes that the background is white, but can be adapted to any other solid background. It falls apart once the points start overlapping however.

To get real transparency, you would need to plot each data point as a separate line and give it a distinct line color. This could be achieved by pre-processing the data, as in the following bash script.

#!/usr/bin/env bash

set -eu

in_data="in.data"
out_png="out.png"

pi=3.141592653589793

# function to convert data value into rgba value
function value2rgba()
{
  # arguments to function
  local val="${1}"
  local min="${2}"
  local max="${3}"

  # normalized value
  local nval=$( bc -l <<< "(${val}-${min})/(${max}-${min})" )

  #### alpha channel value ####
  local alpha="$( bc -l <<< "255 * (1-${nval})" )"
  # round to decimal
  alpha=$( printf "%0.f" "${alpha}" )

  #### red channel value ####
  # rgbformulae 7 in gnuplot
  local red="$( bc -l <<< "255 * sqrt(${nval})" )"
  # round to decimal
  red=$( printf "%0.f" "${red}" )

  #### green channel value ####
  # rgbformulae 5 in gnuplot
  local red="$( bc -l <<< "255 * sqrt(${nval})" )"
  local green="$( bc -l <<< "255 * ${nval}^3" )"
  # round to decimal
  green=$( printf "%0.f" "${green}" )

  #### blue channel value ####
  # rgbformulae 15 in gnuplot
  local blue="$( bc -l <<< "255 * s(2*${pi}*${nval})" )"
  # round to decimal
  blue=$( printf "%0.f" "${blue}" )
  # make sure blue is positive
  if (( blue < 0 ))
  then
    blue=0
  fi

  ### whole rgba value
  local rgba="#"
  rgba+="$( printf "%02x" "${alpha}" )"
  rgba+="$( printf "%02x" "${red}" )"
  rgba+="$( printf "%02x" "${green}" )"
  rgba+="$( printf "%02x" "${blue}" )"

  echo "${rgba}"

}

# data without blank lines
data="$( sed -E  "/^[[:space:]]*$/d" "${in_data}" )"

# number of lines
nline=$( wc -l <<< "${data}" )

# get the minimum and maximum value of the 4-th column
min_max=( $( awk '{ print $4 }' <<< "${data}" | sort -g | sed -n '1p;$p' ) )

# array of colors for each point
colors=()
while read -r line
do
  colors+=( $( value2rgba "${line}" "${min_max[@]}" ) )
done < <( awk '{ print $4 }' <<< "${data}" )

# gather coordinates into one row
coords=( $( awk '{ print $1,$2,$3 }' <<< "${data}" ) )

gnuplot << EOF

set term pngcairo

set out "${out_png}"

\$DATA << EOD
${coords[@]}
EOD

nline=${nline}
colors="${colors[@]}"

unset key

splot for [i=0:nline-1] \$DATA \
  u (column(3*i+1)):(column(3*i+2)):(column(3*i+3)) \
  pt 1 lc rgb word(colors, i+1)

EOF 

These scripts were tested with gnuplot 5.

none_00
  • 196
  • 5