I'm running an IPython Notebook:
$ ipython notebook --pylab inline
Is it possible to scale plots or images which are inline?
E.g. I have
pylab.xlabel("Label X")
pylab.ylabel("Label Y")
pylab.scatter(range(2,15,2), [2, 3, 5, 7, 11, 13, 17], c="r")
and I want to have it bigger.
Sure, I can try to manually change parameters, e.g.
pylab.figure(figsize=(12, 8))
pylab.xlabel("Label X", fontsize = 20)
pylab.ylabel("Label Y", fontsize = 20)
pylab.scatter(range(2,15,2), [2, 3, 5, 7, 11, 13, 17], c="r", s=100)
but it's neither convenient nor exact.
In Python v2.7.4 running IPython v0.13 with matplotlib v1.2.0 32-bit on Windows 8, I get a "handle" in the lower right corner to manually resize (keep aspect ratio and resolution) the inline plot, at least when the figure_format in use is 'png'. As for the other formats I'm not sure, but it appears that this behavior is not present when 'svg' is used.
You can change the default figure_format by uncommenting the line starting with
# c.InlineBackend.figure_format
in the config-file ipython_notebook_config.py in your profile-folder for IPython, and set this parameter to whatever format you want to use when running the notebook, e.g. 'png'.
If you want to change the default size of all inline plots, you can change the parameter c.InlineBackend.rc in the same config-file. If you e.g. want to set the figsize to (12, 8), you simply uncomment the relevant line in the file, making it say
c.InlineBackend.rc = {'figure.figsize': (12, 8)}
This parameter can also change the default fontsize, dpi, etc.
Related
My goal is to create a stratigraphic column (colored stacked rectangles) using matplotlib like the example below.
Data is in this format:
depth = [1,2,3,4,5,6,7,8,9,10] #depth (feet) below ground surface
lithotype = [4,4,4,5,5,5,6,6,6,2] #lithology type. 4 = clay, 6 = sand, 2 = silt
I tried matplotlib.patches.Rectangle but it's cumbersome. Wondering if someone has another suggestion.
Imho using Rectangle is not so difficult nor cumbersome.
from numpy import ones
from matplotlib.pyplot import show, subplots
from matplotlib.cm import get_cmap
from matplotlib.patches import Rectangle as r
# a simplification is to use, for the lithology types, a qualitative colormap
# here I use Paired, but other qualitative colormaps are displayed in
# https://matplotlib.org/stable/tutorials/colors/colormaps.html#qualitative
qcm = get_cmap('Paired')
# the data, augmented with type descriptions
# note that depths start from zero
depth = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # depth (feet) below ground surface
lithotype = [4, 4, 4, 5, 5, 5, 6, 1, 6, 2] # lithology type.
types = {1:'swiss cheese', 2:'silt', 4:'clay', 5:'silty sand', 6:'sand'}
# prepare the figure
fig, ax = subplots(figsize = (4, 8))
w = 2 # a conventional width, used to size the x-axis and the rectangles
ax.set(xlim=(0,2), xticks=[]) # size the x-axis, no x ticks
ax.set_ylim(ymin=0, ymax=depth[-1])
ax.invert_yaxis()
fig.suptitle('Soil Behaviour Type')
fig.subplots_adjust(right=0.5)
# plot a series of dots, that eventually will be covered by the Rectangle\s
# so that we can draw a legend
for lt in set(lithotype):
ax.scatter(lt, depth[1], color=qcm(lt), label=types[lt], zorder=0)
fig.legend(loc='center right')
ax.plot((1,1), (0,depth[-1]), lw=0)
# do the rectangles
for d0, d1, lt in zip(depth, depth[1:], lithotype):
ax.add_patch(
r( (0, d0), # coordinates of upper left corner
2, d1-d0, # conventional width on x, thickness of the layer
facecolor=qcm(lt), edgecolor='k'))
# That's all, folks!
show()
As you can see, placing the rectangles is not complicated, what is indeed cumbersome is to properly prepare the Figure and the Axes.
I know that I omitted part of the qualifying details from my solution, but I hope these omissions won't stop you from profiting from my answer.
I made a package called striplog for handling this sort of data and making these kinds of plots.
The tool can read CSV, LAS, and other formats directly (if the format is rather particular), but we can also construct a Striplog object manually. First let's set up the basic data:
depth = [1,2,3,4,5,6,7,8,9,10]
lithotype = [4,4,4,5,5,5,6,6,6,2]
KEY = {2: 'silt', 4: 'clay', 5: 'mud', 6: 'sand'}
Now you need to know that a Striplog is composed of Interval objects, each of which can have one or more Component elements:
from striplog import Striplog, Component, Interval
intervals = []
for top, base, lith in zip(depth, depth[1:], lithotype):
comp = Component({'lithology': KEY[lith]})
iv = Interval(top, base, components=[comp])
intervals.append(iv)
s = Striplog(intervals).merge_neighbours() # Merge like with like.
This results in Striplog(3 Intervals, start=1.0, stop=10.0). Now we'd like to make a plot using an appropriate Legend object.
from striplog import Legend
legend_csv = u"""colour, width, component lithology
#F7E9A6, 3, Sand
#A68374, 2.5, Silt
#99994A, 2, Mud
#666666, 1, Clay"""
legend = Legend.from_csv(text=legend_csv)
s.plot(legend=legend, aspect=2, label='lithology')
Which gives:
Admittedly the plotting is a little limited, but it's just matplotlib so you can always add more code. To be honest, if I were to build this tool today, I think I'd probably leave the plotting out entirely; it's often easier for the user to do their own thing.
Why go to all this trouble? Fair question. striplog lets you merge zones, make thickness or lithology histograms, make queries ("show me sandstone beds thicker than 2 m"), make 'flags', export LAS or CSV, and even do Markov chain sequence analysis. But even if it's not what you're looking for, maybe you can recycle some of the plotting code! Good luck.
I'm having a problem with matplotlib. I'm using the linux Chrome OS distro. When I try to creat a graph, it doesn't show me anything, just this:
Graph
This is the script:
import matplotlib.pyplot as plt
x = [10,20,30,40,50,60]
bin = [10]
plt.hist(x,bin)
plt.show()
My IDE is Vim
This happened because you supplied the wrong argument to plt.hist. According to the documentation:
bins : int or sequence or str, default: :rc:`hist.bins`
If *bins* is an integer, it defines the number of equal-width bins
in the range.
If *bins* is a sequence, it defines the bin edges, including the
left edge of the first bin and the right edge of the last bin;
in this case, bins may be unequally spaced. All but the last
(righthand-most) bin is half-open. In other words, if *bins* is::
[1, 2, 3, 4]
then the first bin is ``[1, 2)`` (including 1, but excluding 2) and
the second ``[2, 3)``. The last bin, however, is ``[3, 4]``, which
*includes* 4.
If *bins* is a string, it is one of the binning strategies
supported by `numpy.histogram_bin_edges`: 'auto', 'fd', 'doane',
'scott', 'stone', 'rice', 'sturges', or 'sqrt'.
So by supplying [10], you haven't supplied the end of a bin, only the start, and nothing is generated. You can fix this with plt.hist(x,10) or plt.hist(x, [10, 20, 30 <rest>]).
In addition, try to avoid overwriting builtin functions like bin. It won't affect you now, but might haunt you later.
I'm creating a scatterplot with seaborn like this:
plt.figure(figsize=(20,5))
ax = sns.scatterplot(x=x,
y=y,
hue=errors,
s=errors*20,
alpha=0.8,
edgecolors='w')
ax.set(xlabel='X', ylabel='Y')
ax.legend(title="Error (m)", loc='upper right')
My errors contain values between approximately 0.1 and 12.5. However, for my legend seaborn automatically generates labels 0, 5, 10, 15. This makes my algorithm look worse than it is. I would like to change the step size in the legend while maintaining a correct mapping between colors and error magnitudes. For example 0, 4, 8, 12.5. Is this possible?
I want to use ipython to display plots. I start it as:
ipython qtconsole --pylab=inline
the plots are drawn inline, and seem to have fixed size. Is there any way, once the plot is drawn, to drag the plot element with the mouse in the corner, and enlarge it? What I have in mind is similar functionality as Mathematica has
There is no way (currently) to resize the plots by simple mouse drags. I think most of us find the default figure size to be too small. This can be changed by modifying the ipython profiles.
You can resize the plot by mouse in ipython notebook.
Locate:
# Subset of matplotlib rcParams that should be different for the inline backend.
# c.InlineBackend.rc = {'font.size': 10, 'figure.figsize': (6.0, 4.0), 'figure.facecolor': (1, 1, 1, 0), 'savefig.dpi': 72, 'figure.subplot.bottom': 0.125, 'figure.edgecolor': (1, 1, 1, 0)}
Uncomment the 2nd line and change the figure size (6.4, 4.0) to desired size.
For ipython-notebook, modify the ipython_notebook_config.py file. For ipython-qtconsole, change the ipython_qtconsole_config.py file.
If you're using Spyder, you can set figures to draw in their own pop-up window, and then you can resize them freely from there. Check out this guide for details:
https://www.scivision.co/spyder-with-ipython-make-matplotlib-plots-appear-in-own-window/
I have set
import matplotlib as mpl
AXES_COLOR = '#333333'
mpl.rc('axes', edgecolor=AXES_COLOR, labelcolor=AXES_COLOR, grid=True)
mpl.rc('xtick', color=AXES_COLOR)
mpl.rc('ytick', color=AXES_COLOR)
mpl.rc('grid', color=AXES_COLOR)
The color of the axes labels and the ticks are properly set both in 2D and in 3D. However, the edgecolor doesn't apply to 3D axes and they remain black. Likewise, the grid isn't affected.
I think figured out how to access the individual axes of a 3D plot:
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d # Needed for 3d projection.
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.w_zaxis # <- the z axis
The documentation mentions a property that we can use until the developers have finished refactoring their 3D code:
import pprint
pprint.pprint(ax.w_xaxis._AXINFO)
{'x': {'color': (0.95, 0.95, 0.95, 0.5),
'i': 0,
'juggled': (1, 0, 2),
'tickdir': 1},
'y': {'color': (0.9, 0.9, 0.9, 0.5),
'i': 1,
'juggled': (0, 1, 2),
'tickdir': 0},
'z': {'color': (0.925, 0.925, 0.925, 0.5),
'i': 2,
'juggled': (0, 2, 1),
'tickdir': 0}}
However, the color parameter changes the color of the background of the axes planes (between the wired of the grid), not the color of the edges of these planes.
Am I digging too deep ?
Instead of changing axis3d.py try this: ax.w_xaxis.line.set_color("red")
Turns out it's impossible since these values are hard-coded. This archived email from the matplotlib-users mailing list helped me. Here's the relevant part:
Unfortunately, you have stumbled upon one of the ugliness of the mplot3d
implementation. I am hoping to have more control available for the next
release. But right now, there is no way to turn off the axes spines
(because they aren't implemented as spines). If you really want to dig into
the source code, you could change the color argument to the Line2D call in
the init3d() method in matplotlib/lib/mpl_toolkits/axis3d.py
Although this answer was addressing another concern, it sent me to the direction of axis3d.py. I found it in /usr/lib/pymodules/python2.7/mpl_toolkits/mplot3d. I made a backup of the original axis3d.py and I moved axis3d.pyc away.
Since the code is pretty short and fairly well written it didn't take long to locate the two lines I had to change.
To change the color of the edges of the individual axes, I modified the self.line=... in __init__: just replace color=(0, 0, 0, 1) by color=(1, 0, 0, 1) for a horribly flashy red. Components of the tuple are red, green, blue, alpha, all floats from 0 to 1.
To change the color of the grid, I modified the draw method. I replaced the color self.gridlines.set_color([(0.9,0.9,0.9,1)] * len(lines)) by something of my choosing.
And that's it, it just works. Not the most convenient, but it's not more work than editing a rc configuration file.
I did not recreate a .pyc file. It does not recreate itself because I do not run my python code as root. I don't mind the extra milliseconds that python needs to recompile the .py each time.