Gridlines in Julia PyPlot - matplotlib

I'm using the "PyPlot" package in Julia, and I want to add gridlines at specified locations. I'm not familiar enough with Python/Matlab to use their documentation pages to help - the commands differ in Julia. I want a basic plot, with gridlines on both axes at intervals of 1:
using PyPlot
fig=figure("Name")
grid("on")
scatter([1,2,3,4],[4,5,6,7])
Help appreciated...

PyPlot is just an interface to Matplotlib, so the commands
to customize the grid are Matplotlib's commands.
One way to configure the gridlines on both axes at intervals of 1 (for the given data) is:
using PyPlot
fig=figure(figsize=[6,3])
ax1=subplot(1,1,1) # creates a subplot with just one graphic
ax1[:xaxis][:set_ticks](collect(1:4)) # configure x ticks from 1 to 4
ax1[:yaxis][:set_ticks](collect(4:7)) # configure y ticks from 4 to 7
grid("on")
scatter([1,2,3,4],[4,5,6,7])
This code was tested inside an IJulia's notebook, and produces the following output:
Take a look at Various Julia plotting examples using PyPlot.
tested with Julia Version 0.4.3

The values where grid lines are drawn can be controlled by passing an array to the xticks() and yticks() functions.
A simple example:
using PyPlot
fig=figure("Name")
grid("on")
xticks(0:5)
yticks(3:8)
scatter([1,2,3,4],[4,5,6,7])
If you want it to be more flexible you can figure out the limits based on your data and set the tick interval to something else.
One little more dynamic way to configure the x-axis of the grid could be:
x_data = [1,2,3,4]
x_tick_interval = 2;
x_tick_start = minimum(xdata)
x_tick_end = maximum(xdata)
xticks(x_tick_start:x_tick_interval:x_tick_end)

Related

Difference between matplotlib.countourf and matlab.contourf() - odd sharp edges in matplotlib

I am a recent migrant from Matlab to Python and have recently worked with Numpy and Matplotlib. I recoded one of my scripts from Matlab, which employs Matlab's contourf-function, into Python using matplotlib's corresponding contourf-function. I managed to replicate the output in Python, apart that the contourf-plots are not exacly the same, for a reason that is unknown to me. As I run the contourf-function in matplotlib, I get this otherwise nice figure but it has these sharp edges on the contour-levels on top and bottom, which should not be there (see Figure 1 below, matplotlib-output). Now, when I export the arrays I used in Python to Matlab (i.e. the exactly same data set that was used to generate the matplotlib-contourf-plot) and use Matlab's contourf-function, I get a slightly different output, without those sharp contour-level edges (see Figure 2 below, Matlab-output). I used the same number of levels in both figures. In figure 3 I have made a scatterplot of the same data, which shows that there are no such sharp edges in the data as shown in the contourf-plot (I added contour-lines just for reference). Example dataset can be downloaded through Dropbox-link given below. The data set contains three txt-files: X, Y, Z. Each of them are an 500x500 arrays, which can be directly used with contourf(), i.e. plt.contourf(X,Y,Z,...). The code that used was
plt.contourf(X,Y,Z,10, cmap=plt.cm.jet)
plt.contour(X,Y,Z,10,colors='black', linewidths=0.5)
plt.axis('equal')
plt.axis('off')
Does anyone have an idea why this happens? I would appreciate any insight on this!
Cheers,
Jussi
Below are the details of my setup:
Python 3.7.0
IPython 6.5.0
matplotlib 2.2.3
Matplotlib output
Matlab output
Matplotlib-scatter
Link to data set
The confusing thing about the matlab plot is that its colorbar shows much more levels than there are actually in the plot. Hence you don't see the actual intervals that are contoured.
You would achieve the same result in matplotlib by choosing 12 instead of 11 levels.
import numpy as np
import matplotlib.pyplot as plt
X, Y, Z = [np.loadtxt("data/roundcontourdata/{}.txt".format(i)) for i in list("XYZ")]
levels = np.linspace(Z.min(), Z.max(), 12)
cntr = plt.contourf(X,Y,Z,levels, cmap=plt.cm.jet)
plt.contour(X,Y,Z,levels,colors='black', linewidths=0.5)
plt.colorbar(cntr)
plt.axis('equal')
plt.axis('off')
plt.show()
So in conclusion, both plots are correct and show the same data. Just the levels being automatically chosen are different. This can be circumvented by choosing custom levels depending on the desired visual appearance.

matplotlib figure tiny when using subplots

I'm trying to get a plot with custom aspect ratio to display properly. I am using Jupyter notebooks for the rendering, but the way I've normally done this is to adjust the 'figsize' attribute in the subplots. I've done it like below:
from matplotlib import pyplot as plt
fig,axes = plt.subplots(1,1,figsize=(16.0,8.0),frameon=False)
The problem is that, while the aspect ratio seems to come out correct (judging by eye), the figure does not use up even close to the whole page width, and is therefore tiny and hard to read.
I guess it's behaving like there are some sort of margins set on the left and right, but I can't find the global setting that controls this. I have been using the list of settings here, with no success finding a relevant one.
My question(s) are
How do I adjust the aspect ratio without impacting the overall size of the figure (think font sizes of the axis labels)? I don't need the width of my screen to be a constraint, I'd be perfectly happy for Jupyter notebooks to give me a horizontal scroll bar.
Is there a place with a more comprehensive and well-written documentation of all the matplotlib parameters that are available? The one I linked above is awkward because it gives the parameters in the form of an example matplotlibrc file. I'd like to know if a single page with (good) descriptions of all the parameters exists.
EDIT: it has been pointed out that this could be a jupyter problem and that I am setting the aspect ratio correctly. I'm using Jupyter version 1.0.0. Below is a picture of the output of a simplified notebook.
It's easy to see that the figure does not use even close to the available horizontal space.
The code in the notebook is:
#imports
import numpy as np
#set up a plot
import matplotlib as mpl
from matplotlib import pyplot as plt
#got smarter about the mpl config: see mplstyles/ directory
plt.style.use('standard')
#set up a 2-d plot
fig,axes = plt.subplots(1,1,figsize=(16.0,8.0),frameon=False)
ax1 = axes
#need to play with axis
mpl.rcParams['ytick.minor.visible'] = False
xmin = -10
xmax = 10
ymin = -10
ymax = 10
x = np.random.normal(0,5,(20000,))
y = np.random.normal(0,5,(20000,))
h = ax1.hist2d(x,y, bins=200, cmap='inferno')
ax1.set_xlim(xmin,xmax)
ax1.set_ylim(ymin,ymax)
ax1.set_xlabel('epoch time [Unix]',**axis_font)
ax1.set_ylabel(r'relative time [$\mu$s]',**axis_font)
ax1.grid(True)
#lgnd= ax1.legend(loc=2,prop={'size':22})
for axis in ['top','bottom','left','right']:
ax1.spines[axis].set_linewidth(2)
plt.tight_layout()
#plt.savefig('figures/thefigure.eps')
plt.show()
The mpl style file that I use in the plt.style.use command is:
#trying to customize here, see:
#https://matplotlib.org/users/customizing.html
#matplotlib.rc('figure', figsize=(3.4, 3.4*(4/6)))
lines.linewidth : 2
#ticks
xtick.top : False
xtick.bottom : True
xtick.minor.visible : True
xtick.direction : in
xtick.major.size : 8
xtick.minor.size : 4
xtick.major.width : 2
xtick.minor.width : 1
xtick.labelsize : 22
ytick.left : True
ytick.right : False
ytick.minor.visible : True
ytick.direction : in
ytick.major.size : 8
ytick.minor.size : 4
ytick.major.width : 2
ytick.minor.width : 1
ytick.labelsize : 22
#error bars
#errorbar.capsize : 3
#axis stuff
axes.labelsize : 22
EDIT 2: restricting the range of the vectors to the range of the axes before plotting results in the desired output. See the below figure:
The added/modified lines were:
xnew = x[(np.abs(x)<10) & (np.abs(y)<10)]
ynew = y[(np.abs(x)<10) & (np.abs(y)<10)]
h = ax1.hist2d(xnew,ynew, bins=200, cmap='inferno')
Apparently there was a bug in matplotlib 2.2.2 which got fixed by now in the development version. You may of course install the current development version from github.
The Problem comes from setting axes limits (ax1.set_xlim(-10,10)) which are smaller than the initial image. For some reason the original limits still got used to calculate the tight bbox for saving as png.
The workaround would be not to set any axes limits manually, but let the histogram plot be calculated directly with the desired limits in mind. In this case -10,10, e.g.:
x = np.random.normal(0,5,(20000,))
y = np.random.normal(0,5,(20000,))
bins = np.linspace(-10,10,201)
h = ax1.hist2d(x,y, bins=bins, cmap='inferno')
To change the font sizes of the axis label's, you'd have to use plt.rc or plt.rcParams (more on this here), so you needn't worry about doing that when using figsize.
I don't see any problems with the code you posted, could you post a picture of what you get and what you'd like to get? This is what I get using that configuration, on Jupyter notebooks, just plotting a very simple graph:
Do note, however, Jupyter limits the size of your plots automatically (see below):
And I'm afraid I can't help you with your second question, as I've always found matplotlib's documentation sufficient for all my needs... good luck!

Accessing backend specific functionality with Julia Plots

Plots is simple and powerful but sometimes I would like to have a little bit more control over individual elements of the plot to fine-tune its appearance.
Is it possible to update the plot object of the backend directly?
E.g., for the default pyplot backend, I tried
using Plots
p = plot(sin)
p.o[:axes][1][:xaxis][:set_ticks_position]("top")
but the plot does not change. Calling p.o[:show]() afterwards does not help, either.
In other words: Is there a way to use the PyPlot interface for a plot that was initially created with Plots?
Edit:
The changes to the PyPlot object become visible (also in the gui) when saving the figure:
using Plots
using PyPlot
p = Plots.plot(sin, top_margin=1cm)
gui() # not needed when using the REPL
gca()[:xaxis][:set_ticks_position]("top")
PyPlot.savefig("test.png")
Here, I used p.o[:axes][1] == gca(). One has to set top_margin=1cm because the plot area is not adjusted automatically (for my actual fine-tuning, this doesn't matter).
This also works for subsequent updates as long as only the PyPlot interface is used. E.g., after the following commands, the plot will have a red right border in addition to labels at the top:
gca()[:spines]["right"][:set_color]("red")
PyPlot.savefig("test.png")
However, when a Plots command like plot!(xlabel="foo") is used, all previous changes made with PyPlot are overwritten (which is not suprising).
The remaining question is how to update the gui interactively without having to call PyPlot.savefig explicitly.
No - the plot is a Plots object, not a PyPlot object. In your specific example you can do plot(sin, xmirror = true).
I'm trying to do the same but didn't find a solution to update an existing plot. But here is a partial answer: you can query information from the PyPlot axes object
julia> Plots.plot(sin, 1:4)
julia> Plots.PyPlot.plt[:xlim]()
(1.0,4.0)
julia> Plots.plot(sin, 20:24)
julia> ax = Plots.PyPlot.plt[:xlim]()
(20.0,24.0)
and it gets updated.

Logarithmic scaling / colorbar in Julia using PyPlot (matplotlib)

I am using Julia 0.5 and the latest version of PyPlot.
I am printing an 2D-Array using plot.pcolorand it works pretty good. But now I have data that needs a logarithmic scaling. I searched on the web and what I found was an example using
plt.pcolor(X, Y, Z1, norm=LogNorm(vmin=Z1.min(), vmax=Z1.max()), cmap='PuBu_r')
But since LogNorm seems to be a python function ist doesn't work in Julia. Does anyone have an idea what I can hand over to norm=to get a logarithmic scaling?
An example would be:
using PyPlot
A = rand(20,20)
figure()
PyPlot.pcolor(A, cmap="PuBu_r")
colorbar()
Matplotlib fields and methods can be accessed using the
matplotlib[:colors][:LogNorm]
syntax (i.e. for the corresponding matplotlib.colors.LogNorm object).
UPDATE: Thank you for your mwe. Based on that example, I managed to make it work like this:
PyPlot.pcolor(A, norm=matplotlib[:colors][:LogNorm](vmin=minimum(A), vmax=maximum(A)), cmap="PuBu_r")

Multiplot with matplotlib without knowing the number of plots before running

I have a problem with Matplotlib's subplots. I do not know the number of subplots I want to plot beforehand, but I know that I want them in two rows. so I cannot use
plt.subplot(212)
because I don't know the number that I should provide.
It should look like this:
Right now, I plot all the plots into a folder and put them together with illustrator, but there has to be a better way with Matplotlib. I can provide my code if I was unclear somewhere.
My understanding is that you only know the number of plots at runtime and hence are struggling with the shorthand syntax, e.g.:
plt.subplot(121)
Thankfully, to save you having to do some awkward math to figure out this number programatically, there is another interface which allows you to use the form:
plt.subplot(n_cols, n_rows, plot_num)
So in your case, given you want n plots, you can do:
n_plots = 5 # (or however many you programatically figure out you need)
n_cols = 2
n_rows = (n_plots + 1) // n_cols
for plot_num in range(n_plots):
ax = plt.subplot(n_cols, n_rows, plot_num)
# ... do some plotting
Alternatively, there is also a slightly more pythonic interface which you may wish to be aware of:
fig, subplots = plt.subplots(n_cols, n_rows)
for ax in subplots:
# ... do some plotting
(Notice that this was subplots() not the plain subplot()). Although I must admit, I have never used this latter interface.
HTH