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

[WIP] [Feature] Plotly extension #693

Open
wants to merge 9 commits into
base: develop
Choose a base branch
from

Conversation

sudo-panda
Copy link
Contributor

I have currently added support for 3D points. Support for others will be added soon.

This extension just outputs json. If you want to view it you will require to wrap it in html.

@awulkiew
Copy link
Member

Do I understand correctly that Plotly is only able to draw plots, so it is not for drawing geometries and what this PR does is allowing to represent Boost.Geometry linear geometry as a scattered line plot?

If that's the case I don't understand how this is useful. A linestring, a geometry, is not a plot line. Plus AFAIU it is not possible to draw other geometries. What is the purpose of using Plotly with Boost.Geometry?

@mloskot
Copy link
Member

mloskot commented Apr 20, 2020

I started brainstorming use of plotly (or others) for general shapes drawing, see https://gitter.im/boostorg/geometry?at=5e6d0b8e17d3e742347c5346

Since plotly can draw geometric shapes, https://plotly.com/python/shapes/, as well as can draw on top of popular maps, https://plotly.com/python/maps/, evaluating its API for general purpose visualisation of geometries seems to me like a valid idea.

@sudo-panda
Copy link
Contributor Author

Do I understand correctly that Plotly is only able to draw plots, so it is not for drawing geometries and what this PR does is allowing to represent Boost.Geometry linear geometry as a scattered line plot?

If that's the case I don't understand how this is useful. A linestring, a geometry, is not a plot line. Plus AFAIU it is not possible to draw other geometries. What is the purpose of using Plotly with Boost.Geometry?

The main purpose of using plotly is for its mesh plot and it's UI. We can represent every geometry as a plot except that polygons won't be filled in the 2D plot. But plotly is great for showing 3D plots and mesh plots too. And if someone really wants the polygon to be filled, (which can only be done in 2D) they can use the existing svg_mapper. This plugin adds the functionality of displaying 3D geometries which is unavailable in svg mapper.

@sudo-panda
Copy link
Contributor Author

I started brainstorming use of plotly (or others) for general shapes drawing, see https://gitter.im/boostorg/geometry?at=5e6d0b8e17d3e742347c5346

Since plotly can draw geometric shapes, https://plotly.com/python/shapes/, as well as can draw on top of popular maps, https://plotly.com/python/maps/, evaluating its API for general purpose visualisation of geometries seems to me like a valid idea.

Thanks I needed this. The chart-studio of plotly creates area charts with the the x and y-axis as borders. So I thought it isn't possible to fill polygons. Maybe there is some other way. I will look into that. Thanks a lot.

@awulkiew
Copy link
Member

@mloskot Right, I'm not familiar with Plotly, thanks. So it is possible to represent geometries and (I saw gitter discussion) @sudo-panda needs to display 3D geometries.

as well as can draw on top of popular maps

Do I understand correctly that Plotly use their own data format based on Json? Or did they adapt some well known format for representing geometrical data?

Why not use widely known solution for that (at least according to my limited knowledge of the subject), i.e. GeoJSON? Aside from displaying on maps it would allow to import geometries in various databases and GIS programs?

I have nothing against adding Plotly IO. I'm just confused why this particular format was chosen. I also don't know how widely used it is. If it is well known and popular it could be added it in the official release instead of extensions.


class json_plotter : boost::noncopyable
{
std::ostream& m_stream;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, so the stream has to live outside this class. It is like in svg_mapper so I understand that you replicated the existing design. This is error-prone since when the object outside is destroyed then this is a dangling reference.

So I'm wondering about a different design, i.e. owning the stream instead of the reference. E.g.:

template <typename Stream>
class plotly_plotter
{
public:
    template <typename ...Ts>
    plotly_stream(Ts &&... params)
        : m_stream(std::forward<Ts>(params)...)
    {}
private:
    Stream m_stream;
};

What do you think? Do you have different ideas?

Copy link
Contributor Author

@sudo-panda sudo-panda Apr 21, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that seems better. I was thinking why the above design was implemented in svg_mapper. The only reason I could find is if some external changes are required by the user that isn't supported by svg_mapper. This isn't required by plotly_plotter at all then. Can you tell me that actual reason for this design?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you tell me that actual reason for this design?

I don't really know I have only a few ideas though. @barendgehrels do you remember why exactly does the svg_mapper store the reference to the stream instead of owning it?

Back then perfect forwarding was impossible. The code in my previous comment requires C++11 but Boost.Geometry right now requires C++03 (this will change soon). And various streams can have various interfaces, e.g. no open() member function so there must be a way of passing parameters into its constructor.

In some cases the stream objects are already created, e.g. std::cout, std::cerr, etc. AFAIU it is possible to account for that by creating a std::ostream from another stream's streambuf:

plotly_plotter<std::ostream> plotter(std::cout.rdbuf());

But this would be more confusing than simply calling:

plotly_plotter plotter(std::cout);

With non-owning relationship the same stream can be shared by several mappers/plotters. I don't know if that makes sense but it is possible nevertheless.

The user can keep and e.g. close and reopen ofstream buffer instead of creating the svg_mapper/plotly_plotter object each time.

The only reason I could find is if some external changes

Right, though the owned stream could be exposed with some getter function if needed.

Btw, I'm not saying that you should start implementing what I have proposed above. I'm only brainstorming. E.g. now after listing the potential reasons above I'm not sure whether or not my proposal was good.

On the other hand maybe passing a reference as a template parameter could work with the design I proposed. So the user would be able to do both things, store a stream object or a reference. Unless there are some issues I'm not taking into account.

plotly_plotter<std::ostream &> plotter(std::cout);

And last but not least I'm not sure if the design should be different than svg_mapper because the users may expect that the tools work the same and either expect that a reference is stored in plotly_plotter or that an object is stored in svg_mapper. We should probably be consistent one way or another.

@mloskot do you have some thoughts about it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now I have put it inside the class itself as I think it's better to make it safe than just copy the existing design as:

  1. It is an extension so the design need not be matched with integral parts of Boost Geometry.
  2. I see no possible requirement for keeping it outside other than the one mentioned above as we are going to shift to C++11 soon.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although I can't remember exactly, I think @awulkiew has figured it out right.
It was to allow user to plug in a stream object of their choice, and with simple interface.

@mloskot
Copy link
Member

mloskot commented Apr 20, 2020

@awulkiew

Why not use widely known solution for that (at least according to my limited knowledge of the subject), i.e. GeoJSON? Aside from displaying on maps it would allow to import geometries in various databases and GIS programs?

I did not suggest plotly as replacement for GeoJSON which on its own is a preferred geo format indeed.

I considered plotly more as an alternative to SVG, for nice rendering of geometries, with axis, with scaling possibility, loadable into plotly-aware viewers, etc. I don't know if plotly does support GeoJSON well.

By the way, there is also MapML, e.g. GDAL/OGR has just received support for it OSGeo/gdal#2374

I just thought exploring new ways to visualise geometries may be of interest to those looking for ways to start digging Boost.Geometry, who are keen in visualisations, I/O formats, etc.

@sudo-panda sudo-panda requested review from mloskot and awulkiew May 12, 2020 09:45
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

Successfully merging this pull request may close these issues.

None yet

3 participants