File Exchange

image thumbnail

gramm (complete data visualization toolbox, ggplot2/R-like)

version 2.25 (2.3 MB) by Pierre Morel
Quickly create publication-quality plots: automatic colors & subplots, stats, violin/box plots, etc.


Updated 31 May 2020

GitHub view license on GitHub

Editor's Note: This file was selected as MATLAB Central Pick of the Week

Gramm is a powerful plotting toolbox which allows to quickly create complex, publication-quality figures in Matlab, and is inspired by R's ggplot2 library. As a reference to this inspiration, gramm stands for GRAMmar of graphics for Matlab.

For quick help use the cheat sheet:

Morel, (2018). Gramm: grammar of graphics plotting in Matlab. Journal of Open Source Software, 3(23), 568,

The typical workflow to generate a figure with gramm is the following (the example figures in the vignette are generated using 6 lines of code):

- In a first step, provide gramm with the relevant data for the figure: X and Y variables, but also grouping variables that will determine color, subplot rows/columns, etc.

- In the next steps, add graphical layers to your figure: raw data layers (directly plot data as points, lines...) or statistical layers (plot fits, histograms, densities, summaries with confidence intervals...). One instruction is enough to add each layer, and all layers offer many customization options.

- In the last step, gramm draws the figure, and takes care of all the annoying parts: no need to loop over colors or subplots, colors and legends are generated automatically, axes limits are taken care of, etc.

- Accepts X,Y and Z data as arrays, matrices or cells of arrays
- Accepts grouping data as arrays or cellstr. Gramm works best with table-like data: separate variables/fields/columns for the variables of interest, with each variable having as many elements as observations.

- Multiple ways of separating data by groups:
- Colors, lightness, point markers, line styles, and point/line size ('color', 'lightness', 'marker', 'linestyle', 'size')
- Subplots by row and/or columns, or wrapping columns (facet_grid() and facet_wrap()). Multiple options for consistent axis limits across facets, rows, columns, etc. (using 'scale' and 'space').

- Multiple ways of directly plotting the data:
- scatter plots (geom_point()) and jittered scatter plot (geom_jitter())
- lines (geom_line())
- confidence intervals (geom_interval())
- bars plots (geom_bar())
- raster plots (geom_raster())
- point counts (point_count())

- Multiple ways of plotting statistical visualizations of the data:
- y data summarized by x values (uniques or binned) with confidence intervals (stat_summary())
- histograms and density plots of x values (stat_bin() and stat_density())
- histograms of x-y differences (stat_cornerhist())
- box and whisker plots (stat_boxplot())
- violin plots (stat_violin())
- quantile-quantile plots (stat_qq()) of x data distribution against theoretical distribution or y data distribution.
- spline-smoothed y data with optional confidence interval (stat_smooth())
- 2D binning with contour or heatmap output (stat_bin2d())
- GLM fits (stat_glm(), requires statistics toolbox)
- Custom fits with user-provided anonymous function (stat_fit(), requires curve fitting toolbox)
- Ellipses of confidence (stat_ellipse())

- Subplots are created without too much empty space in between (and resize properly !)
- Polar coordinates (set_polar())
- 'z' input data in gramm() creates 3D plots when using geom_point() or geom_line()
- Color data can also be displayed as a continous variable, not as a grouping factor (set_continuous_color())
- X and Y axes can be flipped to get horizontal statistics visualizations (coord_flip())
- Color generation can be customized in the LCH color space, or can use alternative/custom colormaps (set_color_options())
- Marker shapes and sizes can be customized with set_point_options()
- Line styles and width can be customized with set_line_options()
- Text elements aspect can be customized with set_text_options()
- Confidence intervals as shaded areas, error bars or thin lines
- Set the width and dodging of graphical elements in geom_ functions, stat_bin(), stat_summary(), and stat_boxplot(), with 'width' and 'dodge' arguments
- The member structure results contains the results of computations from stat_ plots as well as graphic handles for all plotted elements
- Global title (set_title)
- Multiple gramm plots can be combined in the same figure by creating a matrix of gramm objects and calling the draw() method on the whole matrix. An overarching title can be added by calling set_title on the whole matrix.
- Different groupings can be used for different stat_ and geom_ layers with the update() method
- Matlab axes properties are acessible through the method axe_property
- Custom legend labels with set_names
- Plot reference elements on the plots with geom_abline, geom_vline, geom_hline, and geom_polygon
- Date ticks with set_datetick
- Draw in a specific figure or uipanel/uitab with set_parent()

Cite As

Morel, Pierre. “Gramm: Grammar of Graphics Plotting in Matlab.” The Journal of Open Source Software, vol. 3, no. 23, The Open Journal, Mar. 2018, p. 568, doi:10.21105/joss.00568.

View more styles

Comments and Ratings (105)

Yaren Sever

Hi, I have a problem using gramm with App Designer. I want to show gramm graphics on the app.UIAxes. How can I do it?

Hi. It is very cool package! I have a problem with X Tick though! The X Tick change the order of my Ticks alphabetically. I want to reorder the X Tick to the same order of the input labels. Could you help me with that?

thank you, good job !

ishak abdi

Great package, is it possible to use geom_point() for a group and geom_line() for another, for example, I have to scatter plot Observed vs simulated, and I want to draw a line using geom_line() for the perfect fit with an error band of 15%, then use geom_point() for observed values. how can I do that please ?

ishak abdi

Thank you, this is a very convenient tool for plotting data in a very controlled and clearly arranged way!

Xiaohu Zhu

I am trying to plot a biomedical signal, and I would like to represent samples of the signal corresponding to times of 'activation' in one color, and times at 'rest' in another color. I tried several workarounds, but I seem to run into the same problem. That is, when using geom_line(), automatic line drawing occurs between, for example, two 'rest' blocks. I tried more or less the following:

activation_times; rest_times; % vectors containing x values corresponding to times of activation/rest respectively
activation_signal; rest_signal; % vectors containing amplitudes at corresponding times of activation/rest

X = [activation_times rest_times];
Y = [activation_signal rest_signal];

% set grouping variable
G = zeros(size(X,2)); G(1:length(activation_times)) = 1;

g(1,1) = gramm('x',X,'y',Y,'color',G);


Thanks for any help or suggestions!

Thank you so much Pierre this toolbox is really helpful, and I know it will save me a lot of time :)

What is the best way to include p-values on graphs created with Gramm? For example, to indicate the statistical significance in means of different groups on boxplots.

Thank you again!

Neil Mason

@Pierre, using both R2017b and R2019b, I cannot get examples.m to run. I've followed the instructions in the for adding the folder path to my environment, and I can clearly invoke a gramm. Here's the error:

>> examples
Undefined variable "GeneralizedLinearModel" or class "".

Error in gramm/stat_glm>my_glm (line 39)
mdl =,comby,'Distribution',params.distribution);

Error in gramm/stat_glm>@(dobj,dd)my_glm(dobj,dd,p.Results) (line 27)

Error in gramm/draw (line 548)

Error in examples (line 35)

Any chance you can help out? Thanks!

Wee-Lih Lee

Thank you very much for the excellent tool!!! I just wonder whether we could manually set the ylim for each plot.

Marius Klug


Further to my previous comment, I have found the set_parent method, however, trying to use GUI Layout Toolbox containers as parents leads to very strange behaviour and lots of warnings. Is there a way to use these toolboxes together?



This should be included in the official release!

Pierre Morel

This type of problem generally arises when gramm has been installed improperly, or paths have been changed. Make sure you are following the steps of the README.

Fanny La

Hi Pierre,

Thank you for this toolbox.
If you haven t come across this yet :
I am trying to use gramm and I have this error

Error using gramm/set_names
Method 'set_names' is not defined for class 'gramm' or is removed from MATLAB's search path.

Error in gramm (line 182)
What should I do ??
%Run the set_xx_options() functions without arguments to set
LINE 182 = set_names(obj);

Pierre Morel

gramm support log scale on its axes by setting the corresponding Matlab axes properties using g.axe_property(). In your case, g.axe_property('YScale','log') . However, keep in mind that all stat_ functions keep on working in the linear space.


Is it possible to plot semilogx?
I tried the ggplot syntax: + scale_y_continuous(formatter='log10')
and g.scale_y_continuous(formatter='log10')


@ Pierre,

Thank you very much! The constant support you provide is very encouraging.

Pierre Morel

Thanks for the report. I just fixed that in the latest update. The bug was due to set_datetick() using the 'keepticks' option of datetick() by default. Now it's not the case anymore, and it is possible to give 'keepticks' or 'keeplimits' as arguments of set_datetick().

Hi Pierre,
Thanks for the work. Not sure if you've come across this bug yet. When plotting a time series, all works fine except when g.set_datetick is applied. For some reason the x-axis (time) is truncated on the left side. Tried different datasets with same result. If I plot using Matlab's scatter and apply datetick() it works fine. Any known fixes?

Hakan Kaya

This is one of those jaw-dropping projects. Many thanks for sharing this with the community. Please continue to maintain it.

Jorge Felix


Pierre Morel

Hi @Razvan. Yes it's possible to do so after the plotting as you have access to the handles of every plotted object. So after your g.draw() call you can just do set([g.results.stat_boxplot.outliers_handle],'visible','off')


Great plotting tool!
I have a question about the bar plots. Is it possible to turn off the outliers, so to plot only the box and whiskers?

michael wu

Rob Campbell



This is awesome! Thanks for sharing!

Pierre Morel

@Matthew Morriss: set_title() takes a string argument, it will thus work *exactly* like title() in your example.

One more naive question. I wanted to add the value of a variable to a title for my plots made using gramm. I would typically do this with something like title(['xxx' num2str(var) 'km']);. However, I have been unable to determine the proper syntax for adding a variable to a title using g.set_title(....).

Thanks for your help!

Pierre Morel

@Matthew Morriss: Hi Matthew, I don't have plans to add hexagonal bins at the moment, but if you do have some existing code for it, it should be pretty easy to add by only modifying stat_bin2d() and I'll be happy to integrate these changes. You can open an issue or a pull request on GitHub so we can look into it!

This is a very useful package! Question: do you intend to add a hexagonal binning method similar to what's available for ggplot as a heatmap?

Mathijs Cox


WOW! I've been using ggplot2 and R for some time. Excellent to have this in MATLAB!

Pierre Morel

@Seyyed: It's not possible in gramm yet, but it might be a feature that I add in the future (far from trivial to implement well though).

Seyyed Ali

Hi Pierre,
Is it possible to have a corner histogram of either X or Y axis in a plot? something similar to scatterhist() of MATLAB.

Pierre Morel

@allison :
- Results of stat_summary() can be displayed as bars with 'geom','bar', and staggering is done with the 'dodge' option. It's both in the documentation of stat_summary() and in examples.m, mainly in the section "Options for dodging and spacing graphic elements in stat_summary() and stat_boxplot()".
- Labels on mean values can not be done directly by stat_summary(), but there is a very easy workaround using tables+rowfun() in order to compute the means outside of gramm and then displaying them or any other text with geom_label(). There is an example of this in examples.m, section "Plotting text or labeling with geom_label()".

Is there a way to either overlay bars or stagger them in stat_summary so means with the same x-value can be displayed as a bar instead of a point? Also is there a way to put text labels on mean values generated by stat_summary?

Seyyed Ali

@Pierre: Excellent package. I have been using MATLAB for more than 15 years and I always were looking for a package or a native improvement for MATLAB graphics. I never found it until now. This is an excellent product, well-documented, and comprehensive. Just wanted to thank you for creating this package

Liu Huayuan


Awesome! Forked.

Thank you, Pierre, it is now working.
Much appreciated.

YF shen

Pierre Morel

Hi Kevin,
Thank you for the feedback. This is something you'd normally do in Matlab by setting the 'CLim' property of the axes. You can thus do the same in gramm by using g.axe_property('CLim',[min_custom_range max_custom_range]) on all your plots. However this override will make the legends wrong. Ultimately I should create an create an option in set_continuous_color, can you create and issue on GitHub to follow that?

Thanks for creating this package, very useful. Quick question, I may be missing it, but is there a way to set the limits for a continuous color value so that the colormap spans a fixed range, even if the data does not fill the whole range. It would be helpful for visual comparisons between different plots.

Pierre Morel

Hi Cecilia,
Thank you for the feedback.
In the octane examples, 'y' is indeed of size 60 x 401 , and 'color' of size 60 x 1, but I also provide 'x', which is 1 x 401. Make sure that you have all three inputs with consistent sizes. If the error persists, please open an issue on GitHub.

Hi Pierre,
First I would like to thank you for the wonderful package.
I am experiencing a problem, though. I am trying to visualise spectral data ( ASD Spectral) with response (chlorophyll concentration) however I am getting an error about the length of X and Y not being the same. I don't understand the reason for the error because in your example you used NIR with 60 rows and 401 columns (60x40 matrix1) and octane which is 60 x 1 vector.
And in my case, I am using 49x 701 ASD spectral and 49x1 vector of my response.
Please assisst.

Pierre Morel

Dear Elliot, It is already possible to get CDF estimates with both stat_bin() (using 'normalization','cdf' or 'cumcount'), and with stat_density('function','cdf')


Thanks for this great package. Would it be possible to add a stat_ecdf method?

Pierre Morel

Pat and vdg, thanks for the questions, normally gitHub is more suited to that but here you go:

1. I added the functionality recently, it's not documented yet. You can use g.set_text_options('interpreter','tex')
2. The corner histogram should move automatically with the axis when you resize the window (the examples.m part works for me). But you are talking about the axis... Can you create example code for your problem and create an issue on github?

As they are now, densities can only be displayed as lines. I'll look into adding the same kind of functionality as stat_bin. You can create an issue on gitHub to follow progress on that.


Hi Piere,

Thank you so much for a very nice package.
I have few questions:

1. How to specify the latex interpreter with the xlabel, ylabel, title etc. in gramm ?

2. How to reposition the corner histogram in the example file? I notice that when I change the size/reposition of the axis, the corner does not move with the axis.

Thank you,


I am trying to get transparent densities using stat_density, is that possible? I did find how to do with stat_bin but stat_density look nicer...

fantastic job. thank you


Pierre Morel

Hi Francisco,

I do see why you would want to provide two independent continuous variables for statistics, but gramm is for visualization: there is only a single X axis on the plot, so it is logical that the provided X must have the same size as Y (and thus stat_glm in gramm only fits equations of the form y = a + b x for each of the groups). Moreover, there are cases where gramm uses matrices for X and Y (look at examples.m)

If you want to fit a custom curve to the data, in your case a second order polynomial, you could however use stat_fit with a custom anonymous function. Provide X and Y in the gramm() call and then use g.stat_fit('fun',@(a,b,c,x) a + b .* x + c .* x.^2 ).

Is it possible, for stat_glm, to specify a two column independent variable and a 1 column dependent variable? Even if only one of the columns in 'x' is used for plotting.

I tried something like this:
g=gramm('x',[X X.^2], 'y', Y, 'group',G )
and got an error: Data inputs have different lengths !



hao wang

Excellent work

dhaba india

Anne Urai

Great library ... I used it for many quick visualization, it reduces amount of coding significantly

Pierre Morel

Hi E,

Could you submit a bug report in github, and include minimal code that reproduces the issue? I can't reproduce the bug with what you provide here: x,y and colors are not known, and you did not specify an equation to fit for stat_fit().

This code works without graphical problem for me in R2016a:
g.set_color_options('map',[0.2 0.2 0.2]);

If you are under windows, try changing your renderer options, this could be a Matlab bug.


Thanks, this is an awesome project. One problematic bug: on R2016a, I get weird vertical bars of shading (in addition to the correct shading) when I plot a regression on 4,000 points using:
g = gramm('x', x, 'y', y);
g.set_color_options('map', colors);


Pierre Morel

Hi Anand, thanks for the feedback. Legend position adjustment is already a requested feature (see for possible workaround), but as I'm sure you noticed, gramm doesn't use Matlab's legend() function... so it's not that straightforward to add. For now the easiest is to do it in a vector editing software after export.


Great code, thanks for sharing. How do I change the location of legend to say 'southoutside' with for example horizontal orientation ?


Pierre Morel

Hi Tawanda, thanks for the feedback. The formula interpreter for the labels is indeed deactivated in the current version! I'll probably fix that or provide an easy option, but in the meantime you can use the following code after drawing the figure:


You can have more fine grained control using the handle properties of the gramm object (facet_axes_handles, legend_axe_handle)

A good job demonstrated here. How can I superscript units for my labels. I have tried this g.set_names('x','Canopy position','y','N cm.^2','color','Species'); to no avail.

Thank you in advance

Pierre Morel

Hi Pablo & MooMin, the possibility to customize text font and size is coming in the next update this weekend, along with the possibility to customize line/marker styles order.

I'll see what I can do for the geom_/h/v/ab/line() order. For now they are all drawn at the end because that's when the final axes limits are known.

Great toolbox, it makes plotting very intuitive (especially if you're used to ggplot2), and the plots on their own look much better than the default Matlab plots. However, as other users have noted, this toolbox should include functionality for independently changing font size for the axis titles.

Additionally, (unless I'm doing something incorrect), functions like geom_hline/vline always seem to draw the line on top of the plotted data. In ggplot2 in R, plotted items would be plotted in order of when they were called. For example, if geom_hline/vline were called before geom_line, they would appear behind the product of geom_line. Unless I'm doing something wrong, hopefully this functionality will be integrated into future releases.


I love this toolbox, it's fantastic and very simple to use, with one exception - in order to change the font size or font name of the axis+legend+titles in my graphs I am forced to write an external function to cycle through all the text objects in the figure which is redundant and messy.
Is there a chance to implement such a functionality in the future?



Brilliant! 5 starts just for implementation of JPSTH!

hu qiwei

That's good.Thanks, so much


Yang Wang

Thanks a lot, very helpful !

Cheng Xue



Really nice and flexible, very quick to get complex plots displaying well. I hope this will grow towards the fuller ggplot2 functionality over time!


I continue to use and enjoy this submission. All functionality appears to work okay (I can't speak for stat_fit(); at it requires curve fitting toolbox).

Keep up the good work Pierre!


I really like this submission because
1. It is subversive,
2. It has been continuously updated,
3. It works (mostly).

Does it expose the underlying structure of visualizations that produce quantitative graphics from data? No.

Does it rival ggplot2 in R-lang? No.



Great submission and beautiful plots.

Hope you will have the time expand functionality further with other stuff available in ggplot2.

Great submission, really sped up some of my plotting, but I cannot get the datetick option to work correctly. It works nicely on the y axis, but not on the x.




Added full tab auto-complete for arguments and options with functionSignatures.json

Updated description

- Added JOSS paper and DOI information
- Fixed set_datetick() behavior

Preparation for JOSS submission

Added set_layout_options() allowing to fully customize figure layout in gramm

Corrected bug in geom_bar() when used with the 'stacked' option

- Overhaul of legend and colormap support
- Allows for non LCH luminance/color colormaps
- Added new built-in colormaps
- Added new legend options

Added toggles for row/column labels, improved handling of empty subsets

- Added more customization options to geom_bar
- Fixed automatic continuous colors
- Various fixes

Gramm now merges color and marker/size/linestyle legend if they are the same

- Added continuous color support to 3D lines and points
- Added colorbrewer license file

- Possibility to set ‘CLim’ in set_continuous_color() in order to force color limits.
- Fixed bug on continuous colors when a unique value was provided
- Documentation updates

Added geom_polygon() method to add custom polygons on plots

- Improved graphic fixes for old matlab versions
- Updated geom_abline() , geom_vline(), geom_hline() functions
- Bug fixes
- Added missing documentation

- Added export() method
- Added 'interpreter' to set_text_options()

Added coord_flip(), which can be used to generate horizontal box plots, violin plots, error bars, etc.

- Added the possibility to provide a custom function to stat_summary()
- Removed unnecessary computation when stat_smooth() was used with default options (2x speedup!)

- stat_smooth() now provides more smoothing algorithms, better documentation and more conservative CI estimates
- Enhancements and better documentation for set_order_options()
- Bug fixes in edge cases (empty elements in cells, etc.)

- Added fig() function to separate data across figures
- Improved copy() behavior

Corrected bug in stat_summary() polar interpolation when x data didn't start at zero radians. Added safety checks.

- Corrected absence of y ticks if single facet when using facet_wrap()
- Corrected behavior of stat_cornerhist() when ‘DataAspectRatio’ is set to [1 1 1] using axe_property()

Added 'alpha' option to geom_point(), geom_jitter() and geom_line()

- Added geom_label() to plot text
- Added additional examples
- Modified continuous color legend

- Added set_stat_options() to specify alpha level and N bootstrap samples in all stat_ functions
- Added 'viridis' colormap
- Default confidence interval in stat_summary is now corrected for normal distributions with small N
- Other improvements

Added customization options for text, lines and points:
- Added set_line_options(): style, size
- Added set_point_options(): markers, size
- Added set_text_options(): font, sizes
- Corrected bug with iscategorical() on old matlab versions

- Added corner histogram of x-y difference stat_cornerhist()
- Improved speed on large datasets with many non-unique x values

- Added notch option to stat_boxplot()
- Corrected bug in stat_ellipse() for 2014a and earlier versions

- Added stat_violin() to create violin plots
- BETA of stat_cornerhist to plot an histogram of the x-y difference in an inset axis (has an intermittent sizing bug).

Added functionality to edit legend axes

- Corrected rare error on y limit computation
- Simplified code in draw()
- Changed thumbnail

Corrected error with geom_line() and 3D data

- Represent user-provided confidence intervals with geom_interval()
- Improved dodging: now takes in account the number of colors per x values
- Dodging supported in additional geom_ methods
- Improved geom_bar() stacking

- Corrected errorbar thickness
- Improved update() behavior

- Added set_parent() method
- Improved dodging for categorical x
- Improved update() behavior

Updated description

- Full refactor from a single file to a @gramm class folder
- examples.m is now a proper how-to and can be published
- With the update() method, use different groupings for different layers
- Support for categorical variables in faceting

Corrected stat_summary() to prevent erroneous line/area interruptions

- Added 'space' option to facet_grid()
- Updated examples and Readme

- Improved legend layout
- Harmonized 'width' and 'dodge' arguments
- Improved stat_summary() behavior for missing elements
- Optimizations

- Changed Picture

- ‘z’ input data in gramm() creates 3D plots when using geom_point() or geom_line()
- Corrected bugs in box plot and corrected whisker length
- Added possibility to superimpose gramm plots
- Corrected support for categorical data

Added possibility to set a global title with set_title()

Description correction

Added simpler way to set ordering with set_order_options()

- Added set_order_options()
- Added ‘map’ option to set_color_options()
- Customization functions can be called on arrays of gramm objects
- Bug fixes

Added box and whiskers plots, Quantile-Quantile plots
Other modifications and corrections (see Github: )

Added cheat sheet, added geom_funline(), added 'dodge' option to stat_summary()

- Results from stat_ plots are now returned in the results member structure.
- Corrected bugs with pre 2014b versions

Changing manually the limits (using pan or zoom) of a facet in a gramm generated figure will now automatically change the scale of the other facets according to the ‘scale’ facet preferences

- Added stat_fit() for custom fits (requires curve fitting toolbox)
- Added more generic ‘fill’ options to stat_bin()
- stat_bin() and stat_density() now behave when using polar plots
- Added documentation
- Reduced clutter
- Added examples

Plenty of new features (separation by lightness, confidence ellipses, color options, geom_hline, geom_vline)

Bug corrrection

Enhancements and bug fixes for continuous colors, which can now be forced and customized using set_continuous_color()

Added ‘edges’ option for custom bins to stat_bin2d() and stat_bin()
Added ‘bar_color’ and ‘bar_spacing’ options, ‘overlaid_bar’ geom to stat_bin()
Now possible to set multiple properties at once in axe_property()
Corrected behavior of facet scaling

Greatly improved geom_raster() speed when used with option 'geom','line'

Additional usage examples

Corrected set_datetick() issue, corrected initialization of faceting variables

MATLAB Release Compatibility
Created with R2012b
Compatible with any release
Platform Compatibility
Windows macOS Linux

Inspired by: plotboxpos, subtightplot

Inspired: MatPlotLib Perceptually Uniform Colormaps