SharpPlot graph into a Windows Form

General APL language issues

Re: SharpPlot graph into a Windows Form

Postby Tomas Gustafsson on Sun Jan 30, 2022 8:27 pm

Beautiful tones, thank you Pierre! I was unaware of the ElementHost control.

In fact I think short samples of both might be valuable for the community? For me personally, ⎕WC is the preferred one for now. If you are willing to spend a few moments on this, I'd be most grateful as might many others too!
Tomas Gustafsson
 
Posts: 101
Joined: Mon Sep 19, 2011 6:43 pm

Re: SharpPlot graph into a Windows Form

Postby PGilbert on Mon Jan 31, 2022 2:14 am

Here are 2 ways to show the Xaml obtained.

Get a WPF Viewbox from the Xaml representation of the Graph:

Code: Select all
⍝ Empty namespace to put the .Net objects.
 #.NET←⎕NS''

⍝ Prepare a sample Graph
 #.NET.⎕USING∪←',sharpplot.dll' ',system.drawing.dll'

 #.NET.sp1←⎕NEW #.NET.Causeway.SharpPlot

 #.NET.sp1.Heading←'This is a XAML demo'
 #.NET.sp1.XAxisStyle←#.NET.Causeway.XAxisStyles.(GridLines+CenteredCaption)
 #.NET.sp1.XTickStyle←#.NET.Causeway.XTickStyles.MinorTicks
 #.NET.sp1.XCaption←'X Caption'

 #.NET.sp1.YAxisStyle←#.NET.Causeway.YAxisStyles.(GridLines+CenteredCaption)
 #.NET.sp1.YTickStyle←#.NET.Causeway.YTickStyles.MinorTicks
 #.NET.sp1.YCaption←'Y Caption'

 #.NET.sp1.DrawLineGraph(,⊂⍳10)(⍳10)

⍝ Render the above Graph as a Xaml text file with 96 dpi
 xamlPlot←#.NET.sp1.RenderXaml 96

⍝ Get the WPF Canvas object from the Xaml.
 #.NET.⎕USING∪←⊂'System.Windows.Markup,WPF/PresentationFramework.dll'
 #.NET.canvasObj←#.NET.XamlReader.Parse(⊂xamlPlot)

⍝ Get a WPF Viewbox object with the Canvas object as its child.
 #.NET.⎕USING∪←⊂'System.Windows.Controls,WPF/PresentationFramework.dll'
 #.NET.vb←⎕NEW #.NET.Viewbox
 #.NET.vb.Child←#.NET.canvasObj


To show the WPF Viewbox natively in a WPF Window:

Code: Select all
#.NET.⎕USING∪←⊂'System.Windows,WPF/PresentationFramework.dll'
 #.NET.win←⎕NEW #.NET.Window
 #.NET.win.Title←'This is the Title of the Window'
 #.NET.win.Content←#.NET.vb
 #.NET.win.Show


To show the WPF Viewbox in a Dyalog Form:

Code: Select all
⎕USING∪←⊂'System.Windows.Forms.Integration,WPF/WindowsFormsIntegration.dll'
 'Form'⎕WC'Form'('Coord' 'Pixel')
 'Form.eh'⎕WC'NetControl' 'ElementHost'('Size' #.NET.canvasObj.(Height Width))
 Form.eh.Child←#.NET.vb


The Xaml generated is a WPF Canvas that cannot be scaled, but if you put it in a WPF Viewbox then you can.

It was suggested in the forum to put all the .Net objects of the workspace in a namespace (#.NET) this is what I did here.

The Viewbox object can only be used once. You need to generate a new one for each Window/Form in this example.

Hopefully, this will be a good start to what you want to do.
User avatar
PGilbert
 
Posts: 436
Joined: Sun Dec 13, 2009 8:46 pm
Location: Montréal, Québec, Canada

Re: SharpPlot graph into a Windows Form

Postby Tomas Gustafsson on Mon Jan 31, 2022 11:46 pm

Pierre, many thanks for this. It does work, and paints nicely. I couldn't have easily resolved the correct way to do it in ⎕WC/WPF/.net!

There is unfortunately a problem, though (surprise :-)). It throws OutOfMemoryExceptions, appearing after having created ca 150 graphs, and then again after 100-200 more graphs, until exceptions gets more dense, and evetually it completely fails at attempt nr. one. Comes from:

Code: Select all
canvasObj←XamlReader.Parse(⊂xamlPlot)

but I'm in no way sure that's actually the faulty place, perhaps it's only the place telling about memory problems.

The only thing that helps is closing the APL session and starting it again. I've tried all possible ways to clean up in the code, assign ⎕NULLs etc., really tried to guarantee that nothing is left hanging, but without success so far. The involved objects do not have Dispose methods so it's about ⎕EX, ⎕NULL, localising. Perhaps I'm missing something there, but it's the APL interpreter itself that gets filled, and eventually Task Manager reports 1.3 GB for the APL process although there is nothing new in the workspace.

Yet another "feature" is the size of the XAML. A linechart with three data ranges (say 1500 values along X) and markers easily grow into 1 megabyte, and that already takes time to parse and process. I can count to 4 (rapidly, though) while the graph is thinking.

Still need to check out Pierre's solution, as it does a high quality graphical output, but I'd like to address Dyalog again:

As SharpPlot comes with Dyalog, and is so tightly integrated that it's even seen in the toolbar, is there really no connection between SharpPlot rendering (the SharpPlotViewer object that resides inside sharpplot.dll itself) and a GUI embedding made in APL, may it then even be a .net GUI? No RenderToHwnd() or RenderToControl()? Should I completely stop thinking about it?

Simply put: I have a hard time believing that I'd be the first one ever wanting to have a SharpPlot graph in an APL form?
Tomas Gustafsson
 
Posts: 101
Joined: Mon Sep 19, 2011 6:43 pm

Re: SharpPlot graph into a Windows Form

Postby PGilbert on Tue Feb 01, 2022 1:35 am

While we wait for the official answer from Dyalog on how to insert a vector version of a SharpPlot graph into a Dyalog form, here is my answer to help you realize your plan B:

1. We are told in the .Net literature that there is a 'garbage collector' that is cleaning up the disposed .Net objects from the memory. This is not instantaneous however, it is taking some time after an object has been 'flagged' to be disposed by the garbage collector (it is not explained how much time it takes).

2. We are told also that the best way to 'flagged' an object is to assign ⎕NULL to it first and then erase it (when there is no .dispose method).

3. In the Dyalog IDE if you do: File -> Close AppDomain it will instantaneously cleanup the .Net objects from the Dyalog memory.

So after each graph the proper way to dispose of the .Net objects you created would be based on my previous code:

#.NET.canvasObj ← #.NET.vb ← ⎕NULL
⎕ex '#.NET.canvasObj' '#.NET.vb'

I don't know if this is necessary but you could 'flag' also the element host of the Form before erasing the form:

Form.eh.Child ← ⎕NULL

Try this and wait to see (1-2 minutes) if the garbage collector is picking up your garbage or not. It could be that it is not picking it up and Dyalog will have to tell us what to do to flag properly your garbage or it could be that you are making too much garbage in a too short time for the garbage collector.

If you want to do programmatically Close AppDomain you can do: {}2101⌶0
This will remove out of the Dyalog memory all the .Net objects erased or not by brute force.

Side note: You wanting to show your customers a vector form of a graph is my problem also with my customers. They will buy a 4K monitor now to display the GUI of our application and they want the GUI to expand nicely and having a bitmap graph is not accepted anymore. What is the best way to do that is a nice subject of discussion.
User avatar
PGilbert
 
Posts: 436
Joined: Sun Dec 13, 2009 8:46 pm
Location: Montréal, Québec, Canada

Re: SharpPlot graph into a Windows Form

Postby PGilbert on Wed Feb 02, 2022 4:43 pm

Question to Dyalog: How to make this work ?

Code: Select all
      ⎕USING∪ ← ⊂'Causeway,sharpplot.dll'

      ⎕NEW SharpPlotViewer
Causeway.SharpPlotViewer, Text: SharpPlot chart viewer  ⍝ This is working

      'Form' ⎕WC 'Form' ('Coord' 'Pixel')

      'Form.spv' ⎕WC 'NetControl' 'SharpPlotViewer'    ⍝ This is NOT working
LIMIT ERROR: The object could not be created
      'Form.spv' ⎕WC 'NetControl' 'SharpPlotViewer'
                ∧


Once the 'SharpPlotViewer' is created it could be populated with the method 'Void set_SharpPlot(Causeway.SharpPlot)' and the graph would be in a Dyalog Form.
User avatar
PGilbert
 
Posts: 436
Joined: Sun Dec 13, 2009 8:46 pm
Location: Montréal, Québec, Canada

Re: SharpPlot graph into a Windows Form

Postby PGilbert on Wed Feb 02, 2022 5:46 pm

Looks like the SharpPlotImage class can be integrated into a Dyalog Form this way:

Code: Select all
 ⎕USING∪←⊂',sharpplot.dll'

 sp1←⎕NEW Causeway.SharpPlot

 sp1.Heading←'This is a Dyalog demo'
 sp1.XAxisStyle←Causeway.XAxisStyles.(GridLines+CenteredCaption)
 sp1.XTickStyle←Causeway.XTickStyles.MinorTicks
 sp1.XCaption←'X Caption'

 sp1.YAxisStyle←Causeway.YAxisStyles.(GridLines+CenteredCaption)
 sp1.YTickStyle←Causeway.YTickStyles.MinorTicks
 sp1.YCaption←'Y Caption'

 sp1.DrawLineGraph(,⊂⍳10)(⍳10)

 'Form'⎕WC'Form'('Coord' 'Pixel')

 'Form.spi'⎕WC'NetControl' 'Causeway.SharpPlotImage'('Size' 500 500)

 Form.spi.SharpPlot←sp1


Let us know if this is working for you.

Side Note: This was found by trial and error. If Dyalog has a better way of doing this please let us know.
User avatar
PGilbert
 
Posts: 436
Joined: Sun Dec 13, 2009 8:46 pm
Location: Montréal, Québec, Canada

Re: SharpPlot graph into a Windows Form

Postby Tomas Gustafsson on Thu Feb 03, 2022 7:11 am

PGilbert wrote:So after each graph the proper way to dispose of the .Net objects you created would be based on my previous code:

#.NET.canvasObj ← #.NET.vb ← ⎕NULL
⎕ex '#.NET.canvasObj' '#.NET.vb'

I don't know if this is necessary but you could 'flag' also the element host of the Form before erasing the form:

Form.eh.Child ← ⎕NULL

Try this and wait to see (1-2 minutes) if the garbage collector is picking up your garbage or not. It could be that it is not picking it up and Dyalog will have to tell us what to do to flag properly your garbage or it could be that you are making too much garbage in a too short time for the garbage collector.

Ya, that's about what I do (all of it). It does not clean up sufficiently, each graph still adds 10-20MB in task manager.

If you want to do programmatically Close AppDomain you can do: {}2101⌶0
This will remove out of the Dyalog memory all the .Net objects erased or not by brute force.

This removes ca 1/2 of the memory consumption added in task manager, ie. if I made graphs that added 600MB to task manager, executing {}2101⌶0 gives back 300MB. The lost 300MB must be elsewhere in the dyalog.exe process.
Tomas Gustafsson
 
Posts: 101
Joined: Mon Sep 19, 2011 6:43 pm

Re: SharpPlot graph into a Windows Form

Postby Tomas Gustafsson on Thu Feb 03, 2022 7:23 am

PGilbert wrote:Looks like the SharpPlotImage class can be integrated into a Dyalog Form this way:

Code: Select all
 ⎕USING∪←⊂',sharpplot.dll'

 sp1←⎕NEW Causeway.SharpPlot

 sp1.Heading←'This is a Dyalog demo'
 sp1.XAxisStyle←Causeway.XAxisStyles.(GridLines+CenteredCaption)
 sp1.XTickStyle←Causeway.XTickStyles.MinorTicks
 sp1.XCaption←'X Caption'

 sp1.YAxisStyle←Causeway.YAxisStyles.(GridLines+CenteredCaption)
 sp1.YTickStyle←Causeway.YTickStyles.MinorTicks
 sp1.YCaption←'Y Caption'

 sp1.DrawLineGraph(,⊂⍳10)(⍳10)

 'Form'⎕WC'Form'('Coord' 'Pixel')

 'Form.spi'⎕WC'NetControl' 'Causeway.SharpPlotImage'('Size' 500 500)

 Form.spi.SharpPlot←sp1


Let us know if this is working for you.

Side Note: This was found by trial and error. If Dyalog has a better way of doing this please let us know.

Good work! This solution renders very fast, however it is apparently a bitmap, as the resulting picture quality is much worse than with the XAML option?

dyalog_sharpplot_aa_vs_bitmap.jpg
Upper: XAML, lower: Bitmap ('Form.spi'⎕WC'NetControl' 'Causeway.SharpPlotImage')

'Form.spv' ⎕WC 'NetControl' 'SharpPlotViewer' ⍝ This is NOT working

This would by far be the best solution! Hopefully Dyalog could comment on this!
Tomas Gustafsson
 
Posts: 101
Joined: Mon Sep 19, 2011 6:43 pm

Re: SharpPlot graph into a Windows Form

Postby Nicolas|Dyalog on Sat Feb 19, 2022 1:29 pm

The undocumented SharpPlotViewer has an undocumented SharpPlotImage cousin. The former derives from a Form, the latter derives from an ImageBox.

      ⎕USING←',sharpplot.dll'
sp←⎕NEW Causeway.SharpPlot
sp.DrawBarChart ⊂1 3 2
'f'⎕WC'Form'
'f.g'⎕WC'NetControl' ('ClassName' 'Causeway.SharpPlotImage')
f.g.SharpPlot←sp


Cheers,

Nicolas.
Nicolas|Dyalog
 
Posts: 17
Joined: Wed Sep 10, 2008 9:39 am

Re: SharpPlot graph into a Windows Form

Postby Tomas Gustafsson on Sat Feb 19, 2022 6:00 pm

Thank you Nic, but your reply gives me somewhat mixed feelings. You didn't read the prevoius posts? PGilbert has just pointed out the SharpPlotImage option, and I have replied that it worsens the ending image quality significantly. The bitmap pixels do not scale correctly into screen pixels, and AA is lost.

Nicolas|Dyalog wrote:The undocumented SharpPlotViewer has an undocumented SharpPlotImage cousin. The former derives from a Form, the latter derives from an ImageBox.

      ⎕USING←',sharpplot.dll'
sp←⎕NEW Causeway.SharpPlot
sp.DrawBarChart ⊂1 3 2
'f'⎕WC'Form'
'f.g'⎕WC'NetControl' ('ClassName' 'Causeway.SharpPlotImage')
f.g.SharpPlot←sp


Cheers,

Nicolas.
Tomas Gustafsson
 
Posts: 101
Joined: Mon Sep 19, 2011 6:43 pm

PreviousNext

Return to Language

Who is online

Users browsing this forum: Bing [Bot] and 1 guest