plotly / plotly.rs

Plotly for Rust

Home Page:https://docs.rs/plotly

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Plot `show` Method Not Working on Windows 10

M-NK-Y opened this issue · comments

MWE is given from excerpt within plot.rs:

use plotly::common::Mode;
use plotly::{Layout, Plot, Scatter};

fn line_and_scatter_plot() {
    let trace1 = Scatter::new(vec![1, 2, 3, 4], vec![10, 15, 13, 17])
        .name("trace1")
        .mode(Mode::Markers);
    let trace2 = Scatter::new(vec![2, 3, 4, 5], vec![16, 5, 11, 9])
        .name("trace2")
        .mode(Mode::Lines);
    let trace3 = Scatter::new(vec![1, 2, 3, 4], vec![12, 9, 15, 12])
        .name("trace3");

    let mut plot = Plot::new();
    plot.add_trace(trace1);
    plot.add_trace(trace2);
    plot.add_trace(trace3);

    let layout = Layout::new().title("<b>Line and Scatter Plot</b>".into());
    plot.set_layout(layout);

   # if false {  // We don't actually want to try and display the plot in a browser when running a doctest.
   plot.show();                                                                                            
   # }                                                                                                     
}

fn main() -> std::io::Result<()> {
    line_and_scatter_plot();
    Ok(())
}

Expected: Generated HTML to be opened using the user's default browser.
Actual: System exits with code 0, though no process is spawned/made apparent.


At a glance the issue here seems to be with the parameters used when attempting to open the browser and more specifically their formatting (possibly a quirk of using the older syntax affected by the now closed issue #29494 or alternatively, regarding how the output method is being handled on Windows).

As an aside I'd imagine this probably went undetected for some time courtesy of:

"// We don't actually want to try and display the plot in a browser when running a doctest."

but this is just speculation and fortunately this can be hastily remedied and I'll open a PR for shortly.

Thanks! ❤️

Just thought I'd leave an addendum here, I think there could be some kind of versioning issue because per #131 this should be fixed but unfortunately this appears to still be an issue as of version 0.8.4.

Edit: Updated description within PR, but may be duplicate of #129 if updated args syntax isn't desirable.

commented

Confirmed not working on Windows 11 as well.

I have the same problem.
https://github.com/igiagkiozis/plotly/blob/8903ff03ce9e8183624c40ccf7ddf863799cb92e/plotly/src/plot.rs#L274

https://github.com/igiagkiozis/plotly/blob/8903ff03ce9e8183624c40ccf7ddf863799cb92e/plotly/src/plot.rs#L470-L478

I didn't try this out here, but in my own project and using explorer.exe instead of cmd.exe works for me.
So

 #[cfg(target_os = "windows")] 
 fn show_with_default_app(temp_path: &str) { 
     use std::process::Command; 
     Command::new("explorer") 
         .arg(temp_path) 
         .output() 
         .expect(DEFAULT_HTML_APP_NOT_FOUND); 
 } 

should technically work?

edit: Oh, just noticed the PR - if #133 works fine, then that's great!

@Foobin @fsktom - would you be able to confirm whether #133 fixes your problem?

@mfreeborn just tried it out and the plot is opened without any problems in the browser on Windows 11 :D

Don’t work out the box on my Windows 11. Seems like a problem with temp files, if I supply my own html file, it works fine. I use this workaround for now.

Windows 11 23H2

Since show_html has been added in in v0.9.1 with #217 I've tested out some things again.

Seems like the current Windows implementation for Plot::show_with_default_app is not working with ampersands & in the filename

Minimal example to demonstrate error:

fn main() {
    let plot = plotly::Plot::new();
    plot.show_html("te&st.html");
}

(on a Windows machine)

Returns a

The system cannot find the file te.
'st.html' is not recognized as an internal or external command,
operable program or batch file.

The current implementation

#[cfg(target_os = "windows")]
fn show_with_default_app(temp_path: &str) {
use std::process::Command;
Command::new("cmd")
.args(&["/C", "start", &format!(r#"{}"#, temp_path)])
.spawn()
.expect(DEFAULT_HTML_APP_NOT_FOUND);
}

uses
cmd /C start '.\te&st.html'
which for some reason not known to me interprets the & in the filename as the separator between current and next command

Using explorer '.\te&st.html' instead works (like mentioned in #132 (comment))

It's technically a different issue to this one, but kinda adjacent imo
Should I just open another issue or leave it in this?

This seems to be a Windows specific parsing problem, not a plotly problem. For cmd.exe, the & symbols seems to mean chaning of commands. Based on this superuser answer this has to do with how Windows API parses the arguments for cmd.exe . More info as linked in that answer can be found here.

@fsktom, I have no way of testing on Windows. Could you try the suggestion in that answer, prepending the path with \\?\ and see if that works.

Yeah, it's most definitely a Windows issue, just wanted to mention it here since it will occur if you use a file path with an ampersand on Windows. We could just say to not use & in the filename in the function docs, but I think it should work since it's not a forbidden Windows filename symbol.

@andrei-ng thanks for doing this bit of research, I've tried it out and... it's weird (like everything with Windows...).

Command I used: cmd /C start "" "\\?\Q:\plotlyerr\te&st.html"

  1. The provided solution seems to only work with absolute paths (bad)
  2. It seems to only work when you execute it directly in the Windows command prompt
    i. not in PowerShell (which I think is the default prompt in newer Windows versions, though I'm not sure)
    ii. more relevant: not when you put in the code :))

Executing this command in PowerShell or via std::process::Command still parses the & as a chain of commands.
Which shouldn't surprise me since it states in the docs that the prefix won't always work heh

Many but not all file I/O APIs support "\?"; you should look at the reference topic for each API to be sure.

Changing cmd to explorer works for my use case

#[cfg(target_os = "windows")]
fn show_with_default_app(temp_path: &str) {
    use std::process::Command;
    Command::new("explorer")
        .arg(temp_path)
        .spawn()
        .expect(DEFAULT_HTML_APP_NOT_FOUND);
    }

Thanks for looking into it further. I hoped that there was a quick workardound somehow. But indeed ... Windows ... nothing is simple.

I think we should keep all the discussion here and not open a new issue (to reply to a previous comment of yours). They are not one and the same issue, but kind of related.