matplotlib-haskell icon indicating copy to clipboard operation
matplotlib-haskell copied to clipboard

Adding plot style sheet

Open umeshu opened this issue 1 year ago • 3 comments

Since matplotlib offers easy plot customization using style sheets (https://matplotlib.org/stable/gallery/style_sheets/style_sheets_reference.html), I am looking for a way to include that in matplotlib-haskell.

I tried to use Combinator # e.g. mp # "matplotlib.pyplot.style.use('ggplot')", but when executed, the style was ignored although no error was reported.

So I'm wondering if anyone could point out a direction on how I could solve it.

Thank you.

umeshu avatar Jan 05 '24 03:01 umeshu

Hey! Can you give me a runnable example? Makes my life a lot easier to figure out what's wrong.

If you want to debug this, the simple solution is to output to a python file instead of running the code. Then you can look at it and see why that statement is being lost. The generated python is quite clean and readable.

abarbu avatar Jan 16 '24 19:01 abarbu

Thanks @abarbu for the response.

Sure, here is the example:

{-# LANGUAGE ExtendedDefaultRules #-}

import           Graphics.Matplotlib

xs :: [Double]
xs = [1, 2, 3, 4, 5, 6]

ys :: [Double]
ys = [1, 3, 2, 5, 2, 8]

main :: IO ()
main = do
  let mpStyle =  mp # "matplotlib.pyplot.style.use('ggplot')"
  let myPlot = plot xs ys @@ [o1 "bo-", o2 "linewidth" 1.5]
  let xLabel =  xlabel "$x$"
  let yLabel =  ylabel "$y$"
  let toRender =  mpStyle <> myPlot <> xLabel <> yLabel
  onscreen toRender
  pythonCode <- code toRender
  writeFile "testPlotStyle.py" pythonCode

The generated python file is shown below:

import matplotlib
matplotlib.use('agg')
import matplotlib.path as mpath
import matplotlib.patches as mpatches
import matplotlib.pyplot as plot
import matplotlib.cm as cm
import matplotlib.colors as mcolors
import matplotlib.collections as mcollections
import matplotlib.ticker as mticker
import matplotlib.image as mpimg
from mpl_toolkits.mplot3d import axes3d
import numpy as np
from scipy import interpolate
import os
import io
import sys
import json
import random, datetime
from matplotlib.dates import DateFormatter, WeekdayLocator
plot.rcParams['pcolor.shading'] ='auto'
fig = plot.gcf()
axes = [plot.gca()]
ax = axes[0]
matplotlib.pyplot.style.use('ggplot')
data = json.loads(open('/tmp/data535825-25.json').read())
p = ax.plot(data[0], data[1],'bo-',linewidth=1.5)
ax.set_xlabel(r'$x$')
ax.set_ylabel(r'$y$')
plot.draw()
plot.show()

The problem is that matplotlib.pyplot.style.use('ggplot') should be placed before fig = plot.gcf() for python to process that; if there is a way to correct the placement, the issue is solved

umeshu avatar Jan 21 '24 06:01 umeshu

Ah, yeah, I should add clearer support for this use case in the future.

But the simple solution is to write your own onscreen and code functions. Then you can customize the preamble added to each plot. https://github.com/abarbu/matplotlib-haskell/blob/f85bb16bffc746d62b22c1e30c9c75501af5d81c/src/Graphics/Matplotlib.hs#L82

They're just 1 line each. pyIncludes takes as input one argument, the backend, but it's really just a placeholder for inserting arbitrary code very early in the process. You can insert "matplotlib.pyplot.style.use('ggplot')" right after the agg backend.

https://github.com/abarbu/matplotlib-haskell/blob/f85bb16bffc746d62b22c1e30c9c75501af5d81c/src/Graphics/Matplotlib/Internal.hs#L332

abarbu avatar Jan 21 '24 06:01 abarbu