Using ggplot2 with Julia pluto notebook - ggplot2

I am working with a Pluto.jl notebook. I would like to use the ggplot2 R library to make some plots.
Following this example, if I run the following code in the Julia REPL then I can get a ggplot2 graph output.
using RCall
#rlibrary ggplot2
using DataFrames
df = DataFrame(v = [3,4,5], w = [5,6,7], x = [1,2,3], y = [4,5,6], z = [1,1,2])
ggplot(df, aes(x=:x,y=:y)) + geom_line()
Now, when I use the same code in a pluto.jl notebook (with each line being a separate cell), then I get the following error message:
Is there a way to get the ggplot2 image to appear inside the pluto notebook?
Similarly, if I just enter ggplot() into a cell, I get the same error, but ggplot not defined.

With #library Pluto.jl seems to be unable to find the R package.
However Pluto can handle this format:
#rimport ggplot2 as ggplot2
I managed to see the picture after clicking the "play" button 3 or 4 times. That is the end of good news - the Plut-RCall integration is kind of unstable. The graph shows in a separate Window that seems to hang - this is perhaps a story for opening an issue.
However what you can try to do is to save the image to a file and than visualize it:
begin
ggplot2.ggplot(df, ggplot2.aes(x=:x, y=:y)) + ggplot2.geom_line()
ggplot2.ggsave("myplot.png")
im1 = Images.load("myplot.png")
end

As a workaround, it is possible to override Base.show manually (see Pluto.jl/sample/test1.jl) with
function Base.show(io::IO, ::MIME"image/png", p::RObject{VecSxp})
(path, _) = mktemp()
R"ggsave($path, plot=$p, device = 'png')"
im = read(path)
rm(path)
write(io, im)
end
After that, cells which output anything of the type RObject{VecSxp} will show a PNG image:

Related

How to plot julia inline when using Jupyter in vscode?

I am trying to use Jupyter for Julia in vscode:
using PyPlot
a = [1,2]
b = [2,3]
fig=figure(1)
PyPlot.plot(a, b, linewidth=1)
PyPlot.scatter(a, b)
show()
When I run this a new window will pop up. What I want to do is to prevent it to pop up and see the picture below my codes. After doing some search it seems in Python you can solve it by %matplotlib inline, but how do I sovle it in Julia?
Try gcf() instead of show.
gcf yields the current PyPlot Figure object and it will be automatically rendered by Jupyter:

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!

Convert date/time index of external dataset so that pandas would plot clearly

When you already have time series data set but use internal dtype to index with date/time, you seem to be able to plot the index cleanly as here.
But when I already have data files with columns of date&time in its own format, such as [2009-01-01T00:00], is there a way to have this converted into the object that the plot can read? Currently my plot looks like the following.
Code:
dir = sorted(glob.glob("bsrn_txt_0100/*.txt"))
gen_raw = (pd.read_csv(file, sep='\t', encoding = "utf-8") for file in dir)
gen = pd.concat(gen_raw, ignore_index=True)
gen.drop(gen.columns[[1,2]], axis=1, inplace=True)
#gen['Date/Time'] = gen['Date/Time'][11:] -> cause error, didnt work
filter = gen[gen['Date/Time'].str.endswith('00') | gen['Date/Time'].str.endswith('30')]
filter['rad_tot'] = filter['Direct radiation [W/m**2]'] + filter['Diffuse radiation [W/m**2]']
lis = np.arange(35040) #used the number of rows, checked by printing. THis is for 2009-2010.
plt.xticks(lis, filter['Date/Time'])
plt.plot(lis, filter['rad_tot'], '.')
plt.title('test of generation 2009')
plt.xlabel('Date/Time')
plt.ylabel('radiation total [W/m**2]')
plt.show()
My other approach in mind was to use plotly. Yet again, its main purpose seems to feed in data on the internet. It would be best if I am familiar with all the modules and try for myself, but I am learning as I go to use pandas and matplotlib.
So I would like to ask whether there are anyone who experienced similar issues as I.
I think you need set labels to not visible by loop:
ax = df.plot(...)
spacing = 10
visible = ax.xaxis.get_ticklabels()[::spacing]
for label in ax.xaxis.get_ticklabels():
if label not in visible:
label.set_visible(False)

Graphics Plotting ggplot

I'm trying to make a grid in ggplot to plot 4 graphs, as if it were a basic pair (mfrow = c (2,2)). However, I can not execute the code. I have already tried with gridExtra and cowplot with the functions plot_grid, grid.arrange, ggplot2.multiplot and also tried with the multiplot function. The error that appears is as follows:
Error: Aesthetics must be either length 1 or the same as the data (8598): alpha, x, y, group
gridExtra::grid.arrange(ggplot(),ggplot(),ggplot(),ggplot(), nrow=2)
produces
you may want to debug your code for each individual plot first.

%matplotlib inline rescale figure after xlim / ylim on hist2d plot [duplicate]

I'm trying to conciliate dots annotation in a Matplotlib scatter plot with a manual limit setting, but I either got an error message or I get a design problem.
Here is my code :
fig, ax = plt.subplots(figsize = (20,10)) #manual limit setting
plt.axis([-2,3,-2.5,5])
plt.scatter(x, y)
for i, txt in enumerate(n): #dot annotation
ax.annotate(txt, (x[i], y[i]))
Here is a screen cap of the output (I got the final scatter plot as a small rectangle located in the left corner of a big white rectangle :
I tried this also :
fig, ax = plt.subplots(figsize = (20,10))
ax = plt.axis([-2,3,-2.5,5])
plt.scatter(x, y)
for i, txt in enumerate(n):
ax.annotate(txt, (x[i], y[i]))
But of course I got the following error message (even though the chart correctly displays, but without the labels next to each corresponding dot).
AttributeError: 'list' object has no attribute 'annotate'
The error arises because my loop tries to iterate through ax = plt.axis([-2,3,-2.5,5]), which doesn't make sense indeed.
Any solution to overcome this issue ?
Thank you
The problem occurs because of the special casing of texts when it comes to clipping. Usually you might want text outside the axes to be shown. Therefore annotations and text have a annotation_clip argument. However, this interferes with the bbox_inches="tight" option when saving annotations, because the annotations is then still considered part of the layout and hence the figure takes annotations outside the axes still into account.
Two solutions:
Set annotation_clip and clip_on. I.e. You may explicitely tell the annotation to clip at the axes:
ax.annotate(txt, (x[i], y[i]), annotation_clip=True, clip_on=True)
Set bbox_inches to None. When using the IPython inline backend you can tell it not to expand the figure via
%config InlineBackend.print_figure_kwargs = {'bbox_inches':None}
in a cell before starting to create your content. (This is seen in this answer)
I can't replicate the first issue (tried in versions 2.2.3, 3.1.1, 3.1.2) - I get this (using random data). Try upgrading your version of matplotlib or using
plt.savefig('/path/to/output/image.png')
To save the figure to the disk instead of showing it directly and see if the problem persists.
I can however explain the error
AttributeError: 'list' object has no attribute 'annotate'
This occurs because plt.axis() returns [xmin, xmax, ymin, ymax], not an axes instance (fig, ax = plt.subplots(figsize=(20,10) returns an axes instance to ax).