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

Headless Plotting #74

Closed
cranst0n opened this issue Mar 30, 2016 · 21 comments
Closed

Headless Plotting #74

cranst0n opened this issue Mar 30, 2016 · 21 comments

Comments

@cranst0n
Copy link
Contributor

Is it possible to generate a plot and save it to file without needing to open a window? I'm trying to generate a few thousand plot images and I'm blocked at the moment.

(0 until 2) foreach { zone =>

  val myData = // Generate data

  val canvas = ScatterPlot.plot(myData, '*', Color.BLACK)
  val plotFile = s"/tmp/channelPlots/$zone.png".toFile

  // (1)
  canvas.save(plotFile.toJava)

  // (2)
  val imageSize = 750
  val bi = new BufferedImage(imageSize, imageSize, BufferedImage.TYPE_INT_ARGB)
  val g2d = bi.createGraphics()
  canvas.print(g2d)
  g2d.dispose()

  ImageIO.write(bi, "png", plotFile.toJava)

  // (3)
  plot(myData)

}
  1. Fails with: [error] Exception in thread "main" java.lang.IllegalArgumentException: Width (0) and height (0) cannot be <= 0
  2. Results in a solid colored image written to file
  3. Works fine but requires an opened window

Any help would be greatly appreciated!

@haifengl
Copy link
Owner

Try this

val window = plot(data)
window.canvas.save(new java.io.File("test.png"))
window.close

@cranst0n
Copy link
Contributor Author

That also throws the same exception. I'm guessing because the window hasn't really opened 'fully' and the width/height of the plot canvas still thinks it's zero.

@haifengl
Copy link
Owner

I see. Maybe we need to add new interface for your use case.

@haifengl
Copy link
Owner

As a quick work around, you may pause a little bit before calling save, which make sure the window is properly initialized.

@haifengl
Copy link
Owner

Read your first message again. Do you mean #2 approach works? Thanks!

@cranst0n
Copy link
Contributor Author

No it just results in a solid image of the color as if fillRect(0, 0, width, height) were called.

@haifengl
Copy link
Owner

What platform do you use?

@cranst0n
Copy link
Contributor Author

Linux 3.19.0-32-generic #37~14.04.1-Ubuntu SMP Thu Oct 22 09:41:40 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
java version "1.8.0_77"
Java(TM) SE Runtime Environment (build 1.8.0_77-b03)
Java HotSpot(TM) 64-Bit Server VM (build 25.77-b03, mixed mode)

@haifengl
Copy link
Owner

Can you try approach 2 on windows? Swing has al it of issues on Linux and Mac. Thanks!

@cranst0n
Copy link
Contributor Author

Would be happy to except I don't have access to a Window machine.

@haifengl
Copy link
Owner

Have you tried pausing a little bit before save?

@haifengl
Copy link
Owner

haifengl commented Apr 7, 2016

Any updates? Did you try pause a little bit.

@cranst0n
Copy link
Contributor Author

cranst0n commented Apr 7, 2016

Ah. Sorry about that. I've haven't had time to try it out. I suspect it will work when I get a chance but it's not really a viable option in my specific use case since I was generating 100's of plots. Introducing even a small delay (i.e. a few seconds per plot) would be a show stopper.

@haifengl
Copy link
Owner

haifengl commented Apr 7, 2016

The problem is that graphics projection depends on the PlotCanvas size. Because the canvas is not materialized, nothing works as expected. If you create a multithreaded program that shows the canvas, save it, and closes automatically, I guess that it may be not too bad for your use cases.

@chhh
Copy link
Contributor

chhh commented Apr 7, 2016

I think the correct solution for this is to use Graphics2D implementation
that supports printing not only to the screen but to images(files:
vector/bitmap... etc) -- just call
smile.plot.PlotCanvas#paintComponent(Graphics g) providing the capable
implementation of graphics.I believe, there must be a constructor of
PlotCanvas that doesn't call setVisible anywhere.

For example of non-standard Graphics2D implementation, see e.g. this one:
https://github.com/freehep/freehep-vectorgraphics (
http://freehep.github.io/freehep-vectorgraphics/)

Specifically check out this example of headless painting:
https://github.com/freehep/freehep-vectorgraphics/blob/master/freehep-graphics2d-headless-example/src/main/java/org/freehep/graphics2d/example/HeadlessExample.java

On Thu, Apr 7, 2016 at 3:52 PM, Haifeng Li notifications@github.com wrote:

The problem is that graphics projection depends on the PlotCanvas size.
Because the canvas is not materialized, nothing works as expected. If you
create a multithreaded program that shows the canvas, save it, and closes
automatically, I guess that it may be not too bad for your use cases.


You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub
#74 (comment)

@haifengl
Copy link
Owner

haifengl commented Apr 7, 2016

Would you like to take the lead on fixing it? Thanks!

@chhh
Copy link
Contributor

chhh commented Apr 8, 2016

@haifengl I'll think about it, so far I've checked out the code and tried to explore it a little bit. It seems like it should be doable.

When I imported the code into IntelliJ IDEA there were a couple of problems, the most notable of which I guess was that SLF4J wasn't set as a dependency in pom.xml files.

@haifengl
Copy link
Owner

haifengl commented Apr 8, 2016

We use sbt now. Pom files will be deleted. Please install sbt plugin and import it again.

@haifengl
Copy link
Owner

haifengl commented May 3, 2016

Following @chhh suggestion, I add headless support now. You need to do a git pull and build smile by yourself to use it for now.

val toy = readTable("shell/src/universal/data/classification/toy/toy-train.txt", Some((new NominalAttribute("class"), 0)))
val (x, y) = toy.unzipInt

val canvas = ScatterPlot.plot(x, '.', java.awt.Color.BLACK)

val headless = new Headless(canvas);
headless.pack();
headless.setVisible(true);

canvas.save(new java.io.File("zone.png"))

@haifengl
Copy link
Owner

haifengl commented May 3, 2016

It works for me. Please let me know if it works for you too. Thanks!

@haifengl
Copy link
Owner

haifengl commented May 3, 2016

BTW, you show run JVM with option -Djava.awt.headless=true

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

No branches or pull requests

3 participants