Python-style plots in Mathematica

In this answer, I will concentrate on the colors only to create something like this

Mathematica graphics


Copying the colors from python is a very fast way to get similar results. Nevertheless, the best way to understand what's happening is still to read the underlying publication that was used in seaborn:

  • A colour scheme for the display of astronomical intensity images

There, you find exact explanations about what the author intended to create and how he achieved it. The whole point of such color schemes is to get a color gradient that starts from zero brightness (black) and ends in white. In between those two extremes, it tries to give the viewer the impression of a linearly growing brightness.

Making this way from black to white somewhat colorful is not easy, because the human eye has different perceptions for different colors. So what the author does is to choose a way in the rgb-color cube that spirals around the gray-line resulting in a nice color gradient with linearly growing perceived brightness.

Now, you can understand the name of the colors in python: cubehelix because the way inside the color-cube describes a helix around the gray line. Please read the publication.

Taking the essence out of it (eq. 2) and packing it in a Mathematica function gives:

astroIntensity[l_, s_, r_, h_, g_] := 
 With[{psi = 2 Pi (s/3 + r l), a = h l^g (1 - l^g)/2},
  l^g + a*{{-0.14861, 1.78277}, {-0.29227, -0.90649}, 
    {1.97294, 0.0}}.{Cos[psi], Sin[psi]}]

In short:

  • l ranges from 0 to 1 and gives the color-value. 0 is black, 1 is white and everything between is a color depending on the other settings
  • s is the color direction to start with
  • r defines how many rounds we circle around the gray line on our way to white
  • h defines how saturated the colors are
  • g is a gamma parameters that influences whether the color gradient is more dark or more bright

After calling astroIntensity you have to wrap RGBColor around it, but then, you can use it as color function. Try to play with this here

Manipulate[
 Plot[1/2, {x, 0, 1}, Filling -> Axis,
  ColorFunction -> (RGBColor[astroIntensity[#, s, r, h, g]] &), 
  Axes -> False, PlotRange -> All],
 {s, 0, 3},
 {r, 0, 5},
 {h, 0, 2},
 {{g, 1}, 0.1, 2}
]

Mathematica graphics

Or play with your example

data = BinCounts[
   Select[RandomReal[
     NormalDistribution[0, 1], {10^5, 
      2}], -3 <= #[[1]] <= 3 && -3 <= #[[2]] <= 3 &], 0.1, 0.1];

Manipulate[
 ListContourPlot[data, 
  ColorFunction -> (RGBColor[astroIntensity[1 - #, s, r, h, g]] &), 
  InterpolationOrder -> 3, ContourStyle -> None],
 {s, 0, 3},
 {r, 0, 5},
 {h, 0, 2},
 {{g, 1}, 0.1, 2}
 ]

Styling closer to your example, using The Toad's colors:

colors = {RGBColor[{0.9312692223325372, 0.8201921796082118, 0.7971480974663592}], 
   RGBColor[{0.8822898168737189, 0.695820866705742, 0.7065457119485431}], 
   RGBColor[{0.8135380254700676, 0.5705055182357822, 0.639280859468155}], 
   RGBColor[{0.7195800708349119, 0.45537982893127477`, 0.5861062995810926}], 
   RGBColor[{0.6046906802634469, 0.35739308184976665`, 0.5337407853692406}], 
   RGBColor[{0.46496993672552045`, 0.26868986121314253`, 0.4636527763640647}], 
   RGBColor[{0.3210194743259347, 0.19303051265196464`, 0.3707881677724792}], 
   RGBColor[{0.1750865648952205, 0.11840023306916837`, 0.24215989137836502`}]};
colfn = colors /. x_ :> (Blend[x, #] &);

d1 = {RandomReal[LogNormalDistribution[0, 1], 10^6], 
    RandomReal[JohnsonDistribution["SB", -1, 2, 1.1, 1.5], 10^6]}\[Transpose];
data = BinCounts[Select[d1, 0 <= #[[1]] <= 3 && 0 <= #[[2]] <= 3 &], 0.1, 0.1];

{spX, spY} = 
  ListLinePlot[Mean@#, InterpolationOrder -> 2, PlotStyle -> colors[[6]], Filling -> 0, 
     FillingStyle -> colors[[2]], Frame -> False, Axes -> False, AspectRatio -> 1/5, 
     PlotRangePadding -> 0, ImageMargins -> 0, ImagePadding -> 0, 
     PlotRange -> Full] & /@ {data, Reverse@data\[Transpose]};

ListContourPlot[data, DataRange -> {{0, 3}, {0, 3}}, InterpolationOrder -> 3, 
   PlotRange -> All, ColorFunction -> colfn,
   PlotRangePadding -> 0, FrameStyle -> Thick, ContourStyle -> None,
   FrameTicksStyle -> Directive[Opacity[0], FontSize -> 14, FontOpacity -> 1], 
   FrameTicks -> {{Range[0, 3], None}, {Range[0, 3], None}},
   Prolog -> {Inset[spX, Scaled[{0, 1}], Scaled[{0, 0}], Scaled[{1, 1}]], 
   Inset[spY, Scaled[{1, 1}], Scaled[{0, 0}], Scaled[{1, 1}], {0, -1}]}, 
   ImagePadding -> {{40, 100}, {50, 100}}, PlotRangeClipping -> False,
   FrameLabel -> Array[Style[Subscript["X", #], 20, "TI"] &, 2]]

enter image description here


Using color functions efficiently in data visualizations is more of an art than a recipe, so don't worry if you're not "good" at it yet. It's only a matter of time :)

Copying the color schemes from seaborn:

The best way to mimic those color schemes in Mathematica would be to copy the RGB values from seaborn for your preferred color scheme. You can find them like so (in python):

import seaborn as sns
cols = sns.cubehelix_palette(8)
sns.palplot(cols)

cols
#[[0.9312692223325372, 0.8201921796082118, 0.7971480974663592],
# [0.8822898168737189, 0.695820866705742, 0.7065457119485431],
# [0.8135380254700676, 0.5705055182357822, 0.639280859468155],
# [0.7195800708349119, 0.45537982893127477, 0.5861062995810926],
# [0.6046906802634469, 0.35739308184976665, 0.5337407853692406],
# [0.46496993672552045, 0.26868986121314253, 0.4636527763640647],
# [0.3210194743259347, 0.19303051265196464, 0.3707881677724792],
# [0.1750865648952205, 0.11840023306916837, 0.24215989137836502]]

Now copy those RGB values (your terminal/ipython notebook won't have the #) and pass them as a string to the following function in Mathematica:

palette = RGBColor /@ ToExpression@StringReplace[#, {"[" -> "{", "]" -> "}"}] &;

Mathematica graphics

Now all that remains is to turn this into a color function:

cf = Blend[colors, #]&

where colors is the output of the palette function. Replace "DeepSeaColors" in your plot with cf and you should get this:

You can probably even write a wrapper function in Mathematica that runs a shell process, calls python, gets the RGB list from seaborn and converts it into a color function.

Lazily mimicking the color scheme in Mathematica:

If you're too lazy to dig into python/seaborn internals and get the triplets, you can take the easy route — DominantColors. This might work for any arbitrary color function as long as it's reasonably linear. Just take a tight screenshot of the color function you're interested in and use the following:

(I'm posting the code above as an image because the argument is a screenshot.)

Note that the first (lightest) color is white, which we don't want. So let's exclude that and create a color function with

cf = Blend[Rest@colors, #] &;

Using this in your code as before will give you a similar looking plot.