Using gaussian plots as a error bars in pyplot
I was wondering if it is possible to draw a scatter graph in matplotlib such that the error bars on each are represented as Gaussian distributions themselves.
Each scatter point had several repeats and a standard deviation, which I wanted to emphasize on the graph.
I thought this could be achieved by overlaying a separate, smaller plot over each point (scaled as appropriate), but I cannot find any help on StackOverflow or otherwise on the web.
I apologise if I was unclear, this is the first time I'm asking for help online.
Thank you very much in advance.
python numpy matplotlib
add a comment |
I was wondering if it is possible to draw a scatter graph in matplotlib such that the error bars on each are represented as Gaussian distributions themselves.
Each scatter point had several repeats and a standard deviation, which I wanted to emphasize on the graph.
I thought this could be achieved by overlaying a separate, smaller plot over each point (scaled as appropriate), but I cannot find any help on StackOverflow or otherwise on the web.
I apologise if I was unclear, this is the first time I'm asking for help online.
Thank you very much in advance.
python numpy matplotlib
2
At which point are you stuck? How exactly do you envision this to look?
– ImportanceOfBeingErnest
Nov 25 '18 at 19:37
Would a violin plot would be appropriate? Matplotlib has a couple example in its gallery: matplotlib.org/gallery/statistics/…, matplotlib.org/gallery/statistics/…
– Warren Weckesser
Nov 25 '18 at 21:02
add a comment |
I was wondering if it is possible to draw a scatter graph in matplotlib such that the error bars on each are represented as Gaussian distributions themselves.
Each scatter point had several repeats and a standard deviation, which I wanted to emphasize on the graph.
I thought this could be achieved by overlaying a separate, smaller plot over each point (scaled as appropriate), but I cannot find any help on StackOverflow or otherwise on the web.
I apologise if I was unclear, this is the first time I'm asking for help online.
Thank you very much in advance.
python numpy matplotlib
I was wondering if it is possible to draw a scatter graph in matplotlib such that the error bars on each are represented as Gaussian distributions themselves.
Each scatter point had several repeats and a standard deviation, which I wanted to emphasize on the graph.
I thought this could be achieved by overlaying a separate, smaller plot over each point (scaled as appropriate), but I cannot find any help on StackOverflow or otherwise on the web.
I apologise if I was unclear, this is the first time I'm asking for help online.
Thank you very much in advance.
python numpy matplotlib
python numpy matplotlib
asked Nov 25 '18 at 19:21
Franek PauwelsFranek Pauwels
41
41
2
At which point are you stuck? How exactly do you envision this to look?
– ImportanceOfBeingErnest
Nov 25 '18 at 19:37
Would a violin plot would be appropriate? Matplotlib has a couple example in its gallery: matplotlib.org/gallery/statistics/…, matplotlib.org/gallery/statistics/…
– Warren Weckesser
Nov 25 '18 at 21:02
add a comment |
2
At which point are you stuck? How exactly do you envision this to look?
– ImportanceOfBeingErnest
Nov 25 '18 at 19:37
Would a violin plot would be appropriate? Matplotlib has a couple example in its gallery: matplotlib.org/gallery/statistics/…, matplotlib.org/gallery/statistics/…
– Warren Weckesser
Nov 25 '18 at 21:02
2
2
At which point are you stuck? How exactly do you envision this to look?
– ImportanceOfBeingErnest
Nov 25 '18 at 19:37
At which point are you stuck? How exactly do you envision this to look?
– ImportanceOfBeingErnest
Nov 25 '18 at 19:37
Would a violin plot would be appropriate? Matplotlib has a couple example in its gallery: matplotlib.org/gallery/statistics/…, matplotlib.org/gallery/statistics/…
– Warren Weckesser
Nov 25 '18 at 21:02
Would a violin plot would be appropriate? Matplotlib has a couple example in its gallery: matplotlib.org/gallery/statistics/…, matplotlib.org/gallery/statistics/…
– Warren Weckesser
Nov 25 '18 at 21:02
add a comment |
1 Answer
1
active
oldest
votes
I have some code lying around that does something similar to what you describe (EDIT: I cleaned up/improved the code significantly). The code provides a gaussianScatter
function that can produce plots like these (the color bar and the error lines extending from each point are optional):
You'll have to play around with the styling and such to adapt it to your needs, but it should get you started.
Here's the code I used to produce the example figure above:
import numpy as np
N = 10
testpoints = np.random.randint(0, 10, size=(2, N))
testnoise = np.random.uniform(.25, .75, size=(2, N))
fig,ax = gaussianScatter(*testpoints, *testnoise, docbar=True, doerrbar=True, c='C3')
and here's the complete implementation of gaussianScatter
:
import numpy as np
from matplotlib.colors import ListedColormap, LinearSegmentedColormap
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import scipy.stats as sts
def cmapwhite(cmap, p=.05):
"""Modifies a named cmap so that its smallest values blend into white
"""
N = 256
Nold = int((1 - p)*N/p)
old = plt.cm.get_cmap(cmap)
cnames = ('red', 'green', 'blue')
wdict = {cname: [[0, 1, 1],
[.5, 1, 1],
[1, c, c]] for cname,c in zip(cnames, old(0))}
white = LinearSegmentedColormap(cmap + '_white', segmentdata=wdict, N=N)
colorComb = np.vstack((
white(np.linspace(0, 1, N)),
old(np.linspace(0, 1, Nold))
))
return ListedColormap(colorComb, name=cmap + '_white')
def datalimits(*data, err=None, pad=None):
if err is not None:
dmin,dmax = min((d - err).min() for d in data), max((d + err).max() for d in data)
else:
dmin,dmax = min(d.min() for d in data), max(d.max() for d in data)
if pad is not None:
spad = pad*(dmax - dmin)
dmin,dmax = dmin - spad, dmax + spad
return dmin,dmax
def getcov(xerr, yerr):
cov = np.array([
[xerr, 0],
[0, yerr]
])
return cov
def mvpdf(x, y, xerr, yerr, xlim, ylim):
"""Creates a grid of data that represents the PDF of a multivariate normal distribution (ie an ND Gaussian).
x, y: The center of the returned PDF
(xy)lim: The extent of the returned PDF
(xy)err: The noise the PDF is meant to represent. Will scale pdf in the appropriate direction
returns: X, Y, PDF. X and Y hold the coordinates of the PDF.
"""
# create the coordinate grids
X,Y = np.meshgrid(np.linspace(*xlim), np.linspace(*ylim))
# stack them into the format expected by the multivariate pdf
XY = np.stack([X, Y], 2)
# get the covariance matrix with the appropriate transforms
cov = getcov(xerr, yerr)
# generate the data grid that represents the PDF
PDF = sts.multivariate_normal([x, y], cov).pdf(XY)
return X, Y, PDF
def gaussianScatter(x, y, xerr, yerr, xlim=None, ylim=None, cmap='Blues', fig=None, ax=None, docbar=False, doerrbar=False, doclines=False, donorm=False, cfkwargs=None, **pltkwargs):
"""
x,y: sequence of coordinates to be plotted
(x,y)err: sequence of error/noise associated with each plotted coordinate
(x,y)lim: sequence of (start, end). Determines extents of data displayed in plot
cmap: str of named cmap, or cmap instance
fig: the figure to be plotted on
ax: the axes to be plotted on
docbar: add a color bar
doerrbar: plot the error bars associated with each point as lines
doclines: plot the contour lines of the gaussians
donorm: normalize each plotted gaussian so that its largest value is 1
cfkwargs: a dict of arguments that will be passed to the `contourf` function used to plot the gaussians
pltkwargs: a dict of arguments that will be passed to the `plot` function used to plot the xy points
"""
if xlim is None: xlim = datalimits(x, err=2*xerr)
if ylim is None: ylim = datalimits(y, err=2*yerr)
if cfkwargs is None: cfkwargs = {}
if fig is None:
fig = plt.figure(figsize=(8,8))
ax = fig.add_axes([0, 0, 1, 1])
elif ax is None:
ax = fig.add_axes([0, 0, 1, 1])
if isinstance(cmap, str):
cmap = cmapwhite(cmap)
cfDefault = {'cmap': cmap, 'levels': 100}
pltDefault = {'marker': '.', 'ms': 20, 'ls': 'None', 'c': 'C1'}
# plot gaussians
PDFs =
for _x,_y,_xeta,_yeta in zip(x, y, xerr, yerr):
X, Y, PDF = mvpdf(_x, _y, _xeta, _yeta, xlim, ylim)
PDFs.append(PDF)
if donorm:
# norm the individual PDFs
PDFs = [(PDF - PDF.min())/(PDF.max() - PDF.min()) for PDF in PDFs]
# combine PDFs by treating them like 3D structures. At each xy point, we pick the "tallest" one
PDFcomb = np.max(PDFs, axis=0)
# plot the filled contours that will represent the gaussians.
cfDefault.update(cfkwargs)
cfs = ax.contourf(X, Y, PDFcomb, **cfDefault)
if doclines:
# plot and label the contour lines of the 2D gaussian
cs = ax.contour(X, Y, PDFcomb, levels=6, colors='w', alpha=.5)
ax.clabel(cs, fmt='%.3f', fontsize=12)
# plot scatter
pltDefault.update(pltkwargs)
if doerrbar:
ax.errorbar(x, y, xerr=xerr, yerr=yerr, **pltDefault)
else:
ax.plot(x, y, **pltDefault)
# ensure that x vs y scaling doesn't disrupt the transforms applied to the 2D gaussian
ax.set_aspect('equal', 'box')
if docbar:
# create the colorbar
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.2)
cbar = fig.colorbar(cfs, ax=ax, cax=cax, format='%.2f')
cbar.set_ticks(np.linspace(0, PDFcomb.max(), num=6))
return fig,ax
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53471028%2fusing-gaussian-plots-as-a-error-bars-in-pyplot%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
I have some code lying around that does something similar to what you describe (EDIT: I cleaned up/improved the code significantly). The code provides a gaussianScatter
function that can produce plots like these (the color bar and the error lines extending from each point are optional):
You'll have to play around with the styling and such to adapt it to your needs, but it should get you started.
Here's the code I used to produce the example figure above:
import numpy as np
N = 10
testpoints = np.random.randint(0, 10, size=(2, N))
testnoise = np.random.uniform(.25, .75, size=(2, N))
fig,ax = gaussianScatter(*testpoints, *testnoise, docbar=True, doerrbar=True, c='C3')
and here's the complete implementation of gaussianScatter
:
import numpy as np
from matplotlib.colors import ListedColormap, LinearSegmentedColormap
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import scipy.stats as sts
def cmapwhite(cmap, p=.05):
"""Modifies a named cmap so that its smallest values blend into white
"""
N = 256
Nold = int((1 - p)*N/p)
old = plt.cm.get_cmap(cmap)
cnames = ('red', 'green', 'blue')
wdict = {cname: [[0, 1, 1],
[.5, 1, 1],
[1, c, c]] for cname,c in zip(cnames, old(0))}
white = LinearSegmentedColormap(cmap + '_white', segmentdata=wdict, N=N)
colorComb = np.vstack((
white(np.linspace(0, 1, N)),
old(np.linspace(0, 1, Nold))
))
return ListedColormap(colorComb, name=cmap + '_white')
def datalimits(*data, err=None, pad=None):
if err is not None:
dmin,dmax = min((d - err).min() for d in data), max((d + err).max() for d in data)
else:
dmin,dmax = min(d.min() for d in data), max(d.max() for d in data)
if pad is not None:
spad = pad*(dmax - dmin)
dmin,dmax = dmin - spad, dmax + spad
return dmin,dmax
def getcov(xerr, yerr):
cov = np.array([
[xerr, 0],
[0, yerr]
])
return cov
def mvpdf(x, y, xerr, yerr, xlim, ylim):
"""Creates a grid of data that represents the PDF of a multivariate normal distribution (ie an ND Gaussian).
x, y: The center of the returned PDF
(xy)lim: The extent of the returned PDF
(xy)err: The noise the PDF is meant to represent. Will scale pdf in the appropriate direction
returns: X, Y, PDF. X and Y hold the coordinates of the PDF.
"""
# create the coordinate grids
X,Y = np.meshgrid(np.linspace(*xlim), np.linspace(*ylim))
# stack them into the format expected by the multivariate pdf
XY = np.stack([X, Y], 2)
# get the covariance matrix with the appropriate transforms
cov = getcov(xerr, yerr)
# generate the data grid that represents the PDF
PDF = sts.multivariate_normal([x, y], cov).pdf(XY)
return X, Y, PDF
def gaussianScatter(x, y, xerr, yerr, xlim=None, ylim=None, cmap='Blues', fig=None, ax=None, docbar=False, doerrbar=False, doclines=False, donorm=False, cfkwargs=None, **pltkwargs):
"""
x,y: sequence of coordinates to be plotted
(x,y)err: sequence of error/noise associated with each plotted coordinate
(x,y)lim: sequence of (start, end). Determines extents of data displayed in plot
cmap: str of named cmap, or cmap instance
fig: the figure to be plotted on
ax: the axes to be plotted on
docbar: add a color bar
doerrbar: plot the error bars associated with each point as lines
doclines: plot the contour lines of the gaussians
donorm: normalize each plotted gaussian so that its largest value is 1
cfkwargs: a dict of arguments that will be passed to the `contourf` function used to plot the gaussians
pltkwargs: a dict of arguments that will be passed to the `plot` function used to plot the xy points
"""
if xlim is None: xlim = datalimits(x, err=2*xerr)
if ylim is None: ylim = datalimits(y, err=2*yerr)
if cfkwargs is None: cfkwargs = {}
if fig is None:
fig = plt.figure(figsize=(8,8))
ax = fig.add_axes([0, 0, 1, 1])
elif ax is None:
ax = fig.add_axes([0, 0, 1, 1])
if isinstance(cmap, str):
cmap = cmapwhite(cmap)
cfDefault = {'cmap': cmap, 'levels': 100}
pltDefault = {'marker': '.', 'ms': 20, 'ls': 'None', 'c': 'C1'}
# plot gaussians
PDFs =
for _x,_y,_xeta,_yeta in zip(x, y, xerr, yerr):
X, Y, PDF = mvpdf(_x, _y, _xeta, _yeta, xlim, ylim)
PDFs.append(PDF)
if donorm:
# norm the individual PDFs
PDFs = [(PDF - PDF.min())/(PDF.max() - PDF.min()) for PDF in PDFs]
# combine PDFs by treating them like 3D structures. At each xy point, we pick the "tallest" one
PDFcomb = np.max(PDFs, axis=0)
# plot the filled contours that will represent the gaussians.
cfDefault.update(cfkwargs)
cfs = ax.contourf(X, Y, PDFcomb, **cfDefault)
if doclines:
# plot and label the contour lines of the 2D gaussian
cs = ax.contour(X, Y, PDFcomb, levels=6, colors='w', alpha=.5)
ax.clabel(cs, fmt='%.3f', fontsize=12)
# plot scatter
pltDefault.update(pltkwargs)
if doerrbar:
ax.errorbar(x, y, xerr=xerr, yerr=yerr, **pltDefault)
else:
ax.plot(x, y, **pltDefault)
# ensure that x vs y scaling doesn't disrupt the transforms applied to the 2D gaussian
ax.set_aspect('equal', 'box')
if docbar:
# create the colorbar
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.2)
cbar = fig.colorbar(cfs, ax=ax, cax=cax, format='%.2f')
cbar.set_ticks(np.linspace(0, PDFcomb.max(), num=6))
return fig,ax
add a comment |
I have some code lying around that does something similar to what you describe (EDIT: I cleaned up/improved the code significantly). The code provides a gaussianScatter
function that can produce plots like these (the color bar and the error lines extending from each point are optional):
You'll have to play around with the styling and such to adapt it to your needs, but it should get you started.
Here's the code I used to produce the example figure above:
import numpy as np
N = 10
testpoints = np.random.randint(0, 10, size=(2, N))
testnoise = np.random.uniform(.25, .75, size=(2, N))
fig,ax = gaussianScatter(*testpoints, *testnoise, docbar=True, doerrbar=True, c='C3')
and here's the complete implementation of gaussianScatter
:
import numpy as np
from matplotlib.colors import ListedColormap, LinearSegmentedColormap
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import scipy.stats as sts
def cmapwhite(cmap, p=.05):
"""Modifies a named cmap so that its smallest values blend into white
"""
N = 256
Nold = int((1 - p)*N/p)
old = plt.cm.get_cmap(cmap)
cnames = ('red', 'green', 'blue')
wdict = {cname: [[0, 1, 1],
[.5, 1, 1],
[1, c, c]] for cname,c in zip(cnames, old(0))}
white = LinearSegmentedColormap(cmap + '_white', segmentdata=wdict, N=N)
colorComb = np.vstack((
white(np.linspace(0, 1, N)),
old(np.linspace(0, 1, Nold))
))
return ListedColormap(colorComb, name=cmap + '_white')
def datalimits(*data, err=None, pad=None):
if err is not None:
dmin,dmax = min((d - err).min() for d in data), max((d + err).max() for d in data)
else:
dmin,dmax = min(d.min() for d in data), max(d.max() for d in data)
if pad is not None:
spad = pad*(dmax - dmin)
dmin,dmax = dmin - spad, dmax + spad
return dmin,dmax
def getcov(xerr, yerr):
cov = np.array([
[xerr, 0],
[0, yerr]
])
return cov
def mvpdf(x, y, xerr, yerr, xlim, ylim):
"""Creates a grid of data that represents the PDF of a multivariate normal distribution (ie an ND Gaussian).
x, y: The center of the returned PDF
(xy)lim: The extent of the returned PDF
(xy)err: The noise the PDF is meant to represent. Will scale pdf in the appropriate direction
returns: X, Y, PDF. X and Y hold the coordinates of the PDF.
"""
# create the coordinate grids
X,Y = np.meshgrid(np.linspace(*xlim), np.linspace(*ylim))
# stack them into the format expected by the multivariate pdf
XY = np.stack([X, Y], 2)
# get the covariance matrix with the appropriate transforms
cov = getcov(xerr, yerr)
# generate the data grid that represents the PDF
PDF = sts.multivariate_normal([x, y], cov).pdf(XY)
return X, Y, PDF
def gaussianScatter(x, y, xerr, yerr, xlim=None, ylim=None, cmap='Blues', fig=None, ax=None, docbar=False, doerrbar=False, doclines=False, donorm=False, cfkwargs=None, **pltkwargs):
"""
x,y: sequence of coordinates to be plotted
(x,y)err: sequence of error/noise associated with each plotted coordinate
(x,y)lim: sequence of (start, end). Determines extents of data displayed in plot
cmap: str of named cmap, or cmap instance
fig: the figure to be plotted on
ax: the axes to be plotted on
docbar: add a color bar
doerrbar: plot the error bars associated with each point as lines
doclines: plot the contour lines of the gaussians
donorm: normalize each plotted gaussian so that its largest value is 1
cfkwargs: a dict of arguments that will be passed to the `contourf` function used to plot the gaussians
pltkwargs: a dict of arguments that will be passed to the `plot` function used to plot the xy points
"""
if xlim is None: xlim = datalimits(x, err=2*xerr)
if ylim is None: ylim = datalimits(y, err=2*yerr)
if cfkwargs is None: cfkwargs = {}
if fig is None:
fig = plt.figure(figsize=(8,8))
ax = fig.add_axes([0, 0, 1, 1])
elif ax is None:
ax = fig.add_axes([0, 0, 1, 1])
if isinstance(cmap, str):
cmap = cmapwhite(cmap)
cfDefault = {'cmap': cmap, 'levels': 100}
pltDefault = {'marker': '.', 'ms': 20, 'ls': 'None', 'c': 'C1'}
# plot gaussians
PDFs =
for _x,_y,_xeta,_yeta in zip(x, y, xerr, yerr):
X, Y, PDF = mvpdf(_x, _y, _xeta, _yeta, xlim, ylim)
PDFs.append(PDF)
if donorm:
# norm the individual PDFs
PDFs = [(PDF - PDF.min())/(PDF.max() - PDF.min()) for PDF in PDFs]
# combine PDFs by treating them like 3D structures. At each xy point, we pick the "tallest" one
PDFcomb = np.max(PDFs, axis=0)
# plot the filled contours that will represent the gaussians.
cfDefault.update(cfkwargs)
cfs = ax.contourf(X, Y, PDFcomb, **cfDefault)
if doclines:
# plot and label the contour lines of the 2D gaussian
cs = ax.contour(X, Y, PDFcomb, levels=6, colors='w', alpha=.5)
ax.clabel(cs, fmt='%.3f', fontsize=12)
# plot scatter
pltDefault.update(pltkwargs)
if doerrbar:
ax.errorbar(x, y, xerr=xerr, yerr=yerr, **pltDefault)
else:
ax.plot(x, y, **pltDefault)
# ensure that x vs y scaling doesn't disrupt the transforms applied to the 2D gaussian
ax.set_aspect('equal', 'box')
if docbar:
# create the colorbar
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.2)
cbar = fig.colorbar(cfs, ax=ax, cax=cax, format='%.2f')
cbar.set_ticks(np.linspace(0, PDFcomb.max(), num=6))
return fig,ax
add a comment |
I have some code lying around that does something similar to what you describe (EDIT: I cleaned up/improved the code significantly). The code provides a gaussianScatter
function that can produce plots like these (the color bar and the error lines extending from each point are optional):
You'll have to play around with the styling and such to adapt it to your needs, but it should get you started.
Here's the code I used to produce the example figure above:
import numpy as np
N = 10
testpoints = np.random.randint(0, 10, size=(2, N))
testnoise = np.random.uniform(.25, .75, size=(2, N))
fig,ax = gaussianScatter(*testpoints, *testnoise, docbar=True, doerrbar=True, c='C3')
and here's the complete implementation of gaussianScatter
:
import numpy as np
from matplotlib.colors import ListedColormap, LinearSegmentedColormap
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import scipy.stats as sts
def cmapwhite(cmap, p=.05):
"""Modifies a named cmap so that its smallest values blend into white
"""
N = 256
Nold = int((1 - p)*N/p)
old = plt.cm.get_cmap(cmap)
cnames = ('red', 'green', 'blue')
wdict = {cname: [[0, 1, 1],
[.5, 1, 1],
[1, c, c]] for cname,c in zip(cnames, old(0))}
white = LinearSegmentedColormap(cmap + '_white', segmentdata=wdict, N=N)
colorComb = np.vstack((
white(np.linspace(0, 1, N)),
old(np.linspace(0, 1, Nold))
))
return ListedColormap(colorComb, name=cmap + '_white')
def datalimits(*data, err=None, pad=None):
if err is not None:
dmin,dmax = min((d - err).min() for d in data), max((d + err).max() for d in data)
else:
dmin,dmax = min(d.min() for d in data), max(d.max() for d in data)
if pad is not None:
spad = pad*(dmax - dmin)
dmin,dmax = dmin - spad, dmax + spad
return dmin,dmax
def getcov(xerr, yerr):
cov = np.array([
[xerr, 0],
[0, yerr]
])
return cov
def mvpdf(x, y, xerr, yerr, xlim, ylim):
"""Creates a grid of data that represents the PDF of a multivariate normal distribution (ie an ND Gaussian).
x, y: The center of the returned PDF
(xy)lim: The extent of the returned PDF
(xy)err: The noise the PDF is meant to represent. Will scale pdf in the appropriate direction
returns: X, Y, PDF. X and Y hold the coordinates of the PDF.
"""
# create the coordinate grids
X,Y = np.meshgrid(np.linspace(*xlim), np.linspace(*ylim))
# stack them into the format expected by the multivariate pdf
XY = np.stack([X, Y], 2)
# get the covariance matrix with the appropriate transforms
cov = getcov(xerr, yerr)
# generate the data grid that represents the PDF
PDF = sts.multivariate_normal([x, y], cov).pdf(XY)
return X, Y, PDF
def gaussianScatter(x, y, xerr, yerr, xlim=None, ylim=None, cmap='Blues', fig=None, ax=None, docbar=False, doerrbar=False, doclines=False, donorm=False, cfkwargs=None, **pltkwargs):
"""
x,y: sequence of coordinates to be plotted
(x,y)err: sequence of error/noise associated with each plotted coordinate
(x,y)lim: sequence of (start, end). Determines extents of data displayed in plot
cmap: str of named cmap, or cmap instance
fig: the figure to be plotted on
ax: the axes to be plotted on
docbar: add a color bar
doerrbar: plot the error bars associated with each point as lines
doclines: plot the contour lines of the gaussians
donorm: normalize each plotted gaussian so that its largest value is 1
cfkwargs: a dict of arguments that will be passed to the `contourf` function used to plot the gaussians
pltkwargs: a dict of arguments that will be passed to the `plot` function used to plot the xy points
"""
if xlim is None: xlim = datalimits(x, err=2*xerr)
if ylim is None: ylim = datalimits(y, err=2*yerr)
if cfkwargs is None: cfkwargs = {}
if fig is None:
fig = plt.figure(figsize=(8,8))
ax = fig.add_axes([0, 0, 1, 1])
elif ax is None:
ax = fig.add_axes([0, 0, 1, 1])
if isinstance(cmap, str):
cmap = cmapwhite(cmap)
cfDefault = {'cmap': cmap, 'levels': 100}
pltDefault = {'marker': '.', 'ms': 20, 'ls': 'None', 'c': 'C1'}
# plot gaussians
PDFs =
for _x,_y,_xeta,_yeta in zip(x, y, xerr, yerr):
X, Y, PDF = mvpdf(_x, _y, _xeta, _yeta, xlim, ylim)
PDFs.append(PDF)
if donorm:
# norm the individual PDFs
PDFs = [(PDF - PDF.min())/(PDF.max() - PDF.min()) for PDF in PDFs]
# combine PDFs by treating them like 3D structures. At each xy point, we pick the "tallest" one
PDFcomb = np.max(PDFs, axis=0)
# plot the filled contours that will represent the gaussians.
cfDefault.update(cfkwargs)
cfs = ax.contourf(X, Y, PDFcomb, **cfDefault)
if doclines:
# plot and label the contour lines of the 2D gaussian
cs = ax.contour(X, Y, PDFcomb, levels=6, colors='w', alpha=.5)
ax.clabel(cs, fmt='%.3f', fontsize=12)
# plot scatter
pltDefault.update(pltkwargs)
if doerrbar:
ax.errorbar(x, y, xerr=xerr, yerr=yerr, **pltDefault)
else:
ax.plot(x, y, **pltDefault)
# ensure that x vs y scaling doesn't disrupt the transforms applied to the 2D gaussian
ax.set_aspect('equal', 'box')
if docbar:
# create the colorbar
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.2)
cbar = fig.colorbar(cfs, ax=ax, cax=cax, format='%.2f')
cbar.set_ticks(np.linspace(0, PDFcomb.max(), num=6))
return fig,ax
I have some code lying around that does something similar to what you describe (EDIT: I cleaned up/improved the code significantly). The code provides a gaussianScatter
function that can produce plots like these (the color bar and the error lines extending from each point are optional):
You'll have to play around with the styling and such to adapt it to your needs, but it should get you started.
Here's the code I used to produce the example figure above:
import numpy as np
N = 10
testpoints = np.random.randint(0, 10, size=(2, N))
testnoise = np.random.uniform(.25, .75, size=(2, N))
fig,ax = gaussianScatter(*testpoints, *testnoise, docbar=True, doerrbar=True, c='C3')
and here's the complete implementation of gaussianScatter
:
import numpy as np
from matplotlib.colors import ListedColormap, LinearSegmentedColormap
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import scipy.stats as sts
def cmapwhite(cmap, p=.05):
"""Modifies a named cmap so that its smallest values blend into white
"""
N = 256
Nold = int((1 - p)*N/p)
old = plt.cm.get_cmap(cmap)
cnames = ('red', 'green', 'blue')
wdict = {cname: [[0, 1, 1],
[.5, 1, 1],
[1, c, c]] for cname,c in zip(cnames, old(0))}
white = LinearSegmentedColormap(cmap + '_white', segmentdata=wdict, N=N)
colorComb = np.vstack((
white(np.linspace(0, 1, N)),
old(np.linspace(0, 1, Nold))
))
return ListedColormap(colorComb, name=cmap + '_white')
def datalimits(*data, err=None, pad=None):
if err is not None:
dmin,dmax = min((d - err).min() for d in data), max((d + err).max() for d in data)
else:
dmin,dmax = min(d.min() for d in data), max(d.max() for d in data)
if pad is not None:
spad = pad*(dmax - dmin)
dmin,dmax = dmin - spad, dmax + spad
return dmin,dmax
def getcov(xerr, yerr):
cov = np.array([
[xerr, 0],
[0, yerr]
])
return cov
def mvpdf(x, y, xerr, yerr, xlim, ylim):
"""Creates a grid of data that represents the PDF of a multivariate normal distribution (ie an ND Gaussian).
x, y: The center of the returned PDF
(xy)lim: The extent of the returned PDF
(xy)err: The noise the PDF is meant to represent. Will scale pdf in the appropriate direction
returns: X, Y, PDF. X and Y hold the coordinates of the PDF.
"""
# create the coordinate grids
X,Y = np.meshgrid(np.linspace(*xlim), np.linspace(*ylim))
# stack them into the format expected by the multivariate pdf
XY = np.stack([X, Y], 2)
# get the covariance matrix with the appropriate transforms
cov = getcov(xerr, yerr)
# generate the data grid that represents the PDF
PDF = sts.multivariate_normal([x, y], cov).pdf(XY)
return X, Y, PDF
def gaussianScatter(x, y, xerr, yerr, xlim=None, ylim=None, cmap='Blues', fig=None, ax=None, docbar=False, doerrbar=False, doclines=False, donorm=False, cfkwargs=None, **pltkwargs):
"""
x,y: sequence of coordinates to be plotted
(x,y)err: sequence of error/noise associated with each plotted coordinate
(x,y)lim: sequence of (start, end). Determines extents of data displayed in plot
cmap: str of named cmap, or cmap instance
fig: the figure to be plotted on
ax: the axes to be plotted on
docbar: add a color bar
doerrbar: plot the error bars associated with each point as lines
doclines: plot the contour lines of the gaussians
donorm: normalize each plotted gaussian so that its largest value is 1
cfkwargs: a dict of arguments that will be passed to the `contourf` function used to plot the gaussians
pltkwargs: a dict of arguments that will be passed to the `plot` function used to plot the xy points
"""
if xlim is None: xlim = datalimits(x, err=2*xerr)
if ylim is None: ylim = datalimits(y, err=2*yerr)
if cfkwargs is None: cfkwargs = {}
if fig is None:
fig = plt.figure(figsize=(8,8))
ax = fig.add_axes([0, 0, 1, 1])
elif ax is None:
ax = fig.add_axes([0, 0, 1, 1])
if isinstance(cmap, str):
cmap = cmapwhite(cmap)
cfDefault = {'cmap': cmap, 'levels': 100}
pltDefault = {'marker': '.', 'ms': 20, 'ls': 'None', 'c': 'C1'}
# plot gaussians
PDFs =
for _x,_y,_xeta,_yeta in zip(x, y, xerr, yerr):
X, Y, PDF = mvpdf(_x, _y, _xeta, _yeta, xlim, ylim)
PDFs.append(PDF)
if donorm:
# norm the individual PDFs
PDFs = [(PDF - PDF.min())/(PDF.max() - PDF.min()) for PDF in PDFs]
# combine PDFs by treating them like 3D structures. At each xy point, we pick the "tallest" one
PDFcomb = np.max(PDFs, axis=0)
# plot the filled contours that will represent the gaussians.
cfDefault.update(cfkwargs)
cfs = ax.contourf(X, Y, PDFcomb, **cfDefault)
if doclines:
# plot and label the contour lines of the 2D gaussian
cs = ax.contour(X, Y, PDFcomb, levels=6, colors='w', alpha=.5)
ax.clabel(cs, fmt='%.3f', fontsize=12)
# plot scatter
pltDefault.update(pltkwargs)
if doerrbar:
ax.errorbar(x, y, xerr=xerr, yerr=yerr, **pltDefault)
else:
ax.plot(x, y, **pltDefault)
# ensure that x vs y scaling doesn't disrupt the transforms applied to the 2D gaussian
ax.set_aspect('equal', 'box')
if docbar:
# create the colorbar
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.2)
cbar = fig.colorbar(cfs, ax=ax, cax=cax, format='%.2f')
cbar.set_ticks(np.linspace(0, PDFcomb.max(), num=6))
return fig,ax
edited Nov 26 '18 at 22:23
answered Nov 25 '18 at 21:17
teltel
7,43621431
7,43621431
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53471028%2fusing-gaussian-plots-as-a-error-bars-in-pyplot%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
2
At which point are you stuck? How exactly do you envision this to look?
– ImportanceOfBeingErnest
Nov 25 '18 at 19:37
Would a violin plot would be appropriate? Matplotlib has a couple example in its gallery: matplotlib.org/gallery/statistics/…, matplotlib.org/gallery/statistics/…
– Warren Weckesser
Nov 25 '18 at 21:02