Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

layout does not work properly with Plots #15

Open
XilinJia opened this issue Sep 20, 2018 · 15 comments
Open

layout does not work properly with Plots #15

XilinJia opened this issue Sep 20, 2018 · 15 comments

Comments

@XilinJia
Copy link

using Plots
inspectdr()
# gr()

function testPlot()
	P1 = plot(Plots.fakedata(50,5))
	P2 = plot(Plots.fakedata(50,5))
	plot(P1, P2, layout=(2,1), size=(1200,600))
	gui()
end

Instead of getting two plots arranged vertically, got two horizontally.

@ma-laforge
Copy link
Collaborator

ma-laforge commented Sep 20, 2018

Short Answer

For the moment: InspectDR only supports Plot.jl's layout functionnality when you save a figure. It does not support this feature on with the interactive GUI mode.

To save a figure, add the following line to your code:

savefig("outfile.png")

Long Answer

Though you simply specified a (# row, # column) format for your plot's layout, Plots.jl supports very arbitrary layouts. Sadly, this flexibility in layouts is not very conducive to the way the Gtk gridding widget works.

So for that reason, I have opted not to support the layout feature from the GUI mode.

The GUI is very much targeting interactive use - where presentation is not as important as making each plot easy to "explore".

Workaround

In its GUI, InspectDR currently only plots row-by-row - but it does allow the user to change the amount of columns used when displaying plots.

To modify this number of columns, you must access the plot object directly:

p = plot(P1, P2, layout=(2,1), size=(1200,600))
mplot = p.o.mplot; #*** Get ref to plot object
mplot.layout.values[:ncolumns]=1 #Use 1 column only
display(InspectDR.GtkDisplay(), mplot) #Display directly from InspectDR - not Plots.jl

*** Note the use of ";" to supress show()-ing mplot - thus avoiding a current bug with the deprecated showcompact() function.

@XilinJia
Copy link
Author

I need the vertical layout (multiple rows of plots) because the data share the same x but with y values in different scales. Are there other ways of doing it?

I don't quite understand your words "InspectDR currently only plots row-by-row". As I can see, it only has one row of plots. I tried your workaround, but it doesn't seem to change anything on the plots.

@ma-laforge
Copy link
Collaborator

"InspectDR currently only plots row-by-row":

The InspectDR GUI creates subplots from left-to-right, filling all slots in a row up until the maximum number of columns (given by mplot.layout.values[:ncolumns]) is reached.

Once "ncolumns" is reached, InspectDR creates a new row, and starts filling that one from left-to-right, [repeat for other rows].

For example, plotting 4 subplots with values[:ncolumns] = 1, you get:
1
2
3
4

Plotting 4 subplots with values[:ncolumns] = 2, you get:
1 2
3 4

Plotting 4 subplots with values[:ncolumns] = 3, you get:
1 2 3
4

Workaround

@LeoK987: I tried your workaround, but it doesn't seem to change anything on the plots.

  1. Did you succeed at saving a .png/.svg file using savefig("outfile.png")? Did the exported image outfile.png not have the correct layout?

  2. You did not succeed at changing the # of columns using mplot.layout.values[:ncolumns]=1? That's odd. Are you certain you displayed the plot using the display(InspectDR.GtkDisplay(), mplot) command? The gui() function would probably not work to display things properly.

@ma-laforge
Copy link
Collaborator

Multiple y axes:

InspectDR natively supports multiple y axes (called "strips"). You can see a few examples here:

  1. https://github.com/ma-laforge/FileRepo/blob/master/InspectDR/sampleplots/demo5.png
  2. https://github.com/ma-laforge/FileRepo/blob/master/InspectDR/sampleplots/demo7.png

You can find the code used to generate these plots under the sample directory:

  1. sample/demo5.jl
  2. sample/demo7.jl

The neat thing about using these y "strips" is that InspectDR always keeps the x axes of the strips tied together - even when interactively zooming with the mouse!!

Sadly, Plots.jl does not natively support this feature - so you would have to use InspectDR directly.

...but on the bright side, InspectDR runs much faster if you do not have to load Plots.jl (especially its time-to-first-plot).

PS Though I find the Plots.jl interface to be much better (simpler) when plotting from the command line, the InspectDR API is often adequate when you build scripts.

@XilinJia
Copy link
Author

XilinJia commented Sep 20, 2018

This is how I tried your workaround:

using Plots
inspectdr()
# gr()

function testPlot()
	P1 = plot(Plots.fakedata(50,5))
	P2 = plot(Plots.fakedata(50,5))
	p = plot(P1, P2, layout=(2,1), size=(1200,600))
	mplot = p.o.mplot; #*** Get ref to plot object
	mplot.layout.values[:ncolumns]=1 #Use 1 column only
	display(InspectDR.GtkDisplay(), mplot) #Display directly from InspectDR - not Plots.jl
	gui()
end

I still get two plots in one row. Actually, I got two windows one behind the other. The plots are on the front window, and in the back window there are some text -(x,y) = (,). If I comment out the gui() line, then there is only the window with text.

Do I still need to save the figure here? If that is the case, then perhaps I don't want to do that because it defies the purpose of interactivity, doesn't it?

@XilinJia
Copy link
Author

The strips feature sounds very neat. I was actually just looking at it. Perhaps I should adopt InspectDR directly in my script.

@ma-laforge
Copy link
Collaborator

Correct. the gui() command is not necessary (and you should not use it) when you display with display(InspectDR.GtkDisplay(), mplot).

Do I still need to save the figure here?

No. as you say, a saved image has zero-interactivity... but that's the thing about InspectDR at the moment. It is either supports layout, or interactivity (unless you use the vertically stacked "strips").

Note, however, that the image exported with savefig() typically looks a bit better for publications, etc - because you have more control over the plot positions (ex: top plot could be made 2x higher than the bottom plot) - and the GUI widgets are not drawn.

@ma-laforge
Copy link
Collaborator

I think most people would really like the strips feature. I wish all plotting packages had this. I find I often want to use this pattern to display plots - and that plotting apps are much easier to use if they support strips natively.

PLUS: The neat thing about the strips in InspectDR is that every subplot can be drawn with strips. So, for example, you can easily generate a "multi-plot" window where plots sample/demo5.jl & sample/demo7.jl are shown side-by-side... and the interactive GUI will work perfectly!

FYI

@ma-laforge
Copy link
Collaborator

Very sorry. I tried your snippet above and saw your problem. Here is the solution:

using Plots
backend(:inspectdr)

function testPlot()
	P1 = plot(Plots.fakedata(50,5));
	P2 = plot(Plots.fakedata(50,5));
	p = plot(P1, P2, layout=(2,1), size=(1200,600));
	Plots.prepare_output(p)
	mplot = p.o.mplot
	mplot.layout.values[:ncolumns]=1 #Use 1 column only
	
	display(InspectDR.GtkDisplay(), mplot) #Display directly from InspectDR - not Plots.jl
end

Note that the line Plots.prepare_output(p) is needed to get Plots.jl to trigger InspectDR to generate the mplot object. After that, you can overwrite value[:ncolumns] & display.

@ma-laforge
Copy link
Collaborator

...And I just realize you can make the process less invasive (use more of Plots.jl's normal flow) by using the following:

function testPlot()
	P1 = plot(Plots.fakedata(50,5))
	P2 = plot(Plots.fakedata(50,5))
	plot(P1, P2, layout=(2,1), size=(1200,600))
	p = gui()
	p.src.layout.values[:ncolumns]=1 #Use 1 column only
	InspectDR.refresh(p)
	return p
end

Note that you might see glitch using this "flow" - because Plots.jl first displays the plot with 2 columns, then we overwrite that setting & refresh.

@ma-laforge
Copy link
Collaborator

I wanted to send you a minimum working example for using InspectDR directly:

using InspectDR
using Colors

function testPlot2()
	y1 = rand(50,5)
	y2 = rand(50,5)
	x = collect(1.0:size(y1,1))
	add = InspectDR.add #Alias
	line = InspectDR.line #Alias
		COLOR_RED = RGB24(1, 0, 0)
		COLOR_GREEN = RGB24(0, 1, 0)
		COLOR_BLUE = RGB24(0, 0, 1)
		COLOR_YELLOW = RGB24(1, 1, 0)
		COLOR_CYAN = RGB24(0, 1, 1)

	clist = [COLOR_RED, COLOR_GREEN, COLOR_BLUE, COLOR_YELLOW, COLOR_CYAN]

	#Using Plot2D simplified "template" constructor:
	p = InspectDR.Plot2D(:lin, [:lin, :lin],
		title = "Some Fake Data", xlabel = "X",
		ylabels = ["Y1", "Y2"]
	)
	p.layout[:enable_legend] = true
	for i in 1:size(y1,2)
		wfrm = add(p, x, y1[:,i], id="y$i", strip=1)
		wfrm.line = line(color=clist[i], width=2)
	end
	for i in 1:size(y2,2)
		wfrm=add(p, x, y2[:,i], id="y$i", strip=2)
		wfrm.line = line(color=clist[i], width=2)
	end

	gplot = display(InspectDR.GtkDisplay(), p)
	return gplot
end

Note that this is significantly more verbose than what you get with Plots.jl. For example, you have to manually control the colors of your lines.

But it is much easier to explore the data afterwards given that the two x axes are tied together. The plots are also drawn in a slightly more compact fashion. See plot comparison below:
image

(Results from Plots.jl are on the left. On the right is an example of InspectDR's "strips".)
Note the differences in default fonts & preset color schemes

@XilinJia
Copy link
Author

Thanks so much for your kind guidance.

Another question: how to draw line segments?

@ma-laforge
Copy link
Collaborator

I am probably not answering the right question, but here goes:

A line segment is typically drawn as a two-point dataset that represents {(x1, y1), (x2,y2)}. You can add it to a plot (so that InspectDR draws it) using the same add function as before:

xseg = [1, 10]; yseg = [2, 20]
wfrm = add(p, xseg, yseg, id="line segment", strip=1)
		wfrm.line = line(color=clist[i], width=2) #Set line properties

...But something tells me this is not what you are asking.

Maybe you are asking how I added the H/V marker lines in demo7.jl (ie the dashed black lines)?:
https://github.com/ma-laforge/FileRepo/blob/master/InspectDR/sampleplots/demo7.png

Please be more specific with your question if I have not answered it.

@XilinJia
Copy link
Author

Sorry for not being very clear.

Say I have 4 points, each being defined as (xi, yi), and I want to connect Pts 1 and 2, and 3 and 4, but leave Pts 2 and 3 unconnected.

So I can draw Pts 1 and 2 with the statements you outlined above, and draw Pts 3 and 4 separately with the statements. Or are there better ways?

@ma-laforge
Copy link
Collaborator

Well, just in case I what you really want is to create a coarser dashed line that what I currently support:

Making coarser (longer) dashes

You can hack in a longer dashed line style by adding to the _setlinestyle() function in src/cairo_ext.jl. In case you don't know how to set the line style to dashed, you would simply add an argument to the line() function:

wfrm.line = line(color=COLOR_BLUE, width=3, style=:dash)

Actual line segments

If what you want to draw are actual line segments that start/stop at specific coordinates, you can embed NaN values in your vectors, for example:

xseg = [1, 10, NaN, 10, 20]; yseg = [2, 20, NaN, 10, 30]

That way, InspectDR can know which adjacent points are not connected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants