2
$\begingroup$

Consider an array of triplets: specup={{x1,y1,z1},{x2,y2,z2},...{xn,yn,zn}}. The dimensions for specup are {1506006, 3}. The ranges for the variables are as follows: x->{0,5},y->{-14,14},z->{0,1300}. The idea is to do a density plot where z dictates the color. I use

ListDensityPlot[
 specup
 , ColorFunction -> {Black, Blue, Cyan, Green, Yellow, Orange, White}
 , PlotLegends -> Automatic
 , Frame -> True
 , InterpolationOrder -> 1
 ]

However, due to the sheer number of entries the plot never finishes, I gave it 2 plus hours. Is there a way to optimize the plotting?

Data is available at: https://drive.google.com/open?id=1yDtyzjf4GgurIE0GGCkH5qAQvLuNixjn

$\endgroup$
  • 1
    $\begingroup$ Are your {x,y,z} points a regular grid? If so you would be better off rearranging the data from a list of {x, y, z} tuples into a 3-dimensional array of z values. ListDensityPlot just handles this input format better. Once you've rearranged the data, if you find it is still slow because of the size of the data, you can use ArrayResample to make the data size more manageable. $\endgroup$ – Jason B. Jun 19 '18 at 16:42
  • $\begingroup$ So the grid I have is constant x, dy, z. It goes down the line of y values then shifts x and goes again. Wont I lose the information of x and y in the 3-dimensional array? For example {x1,y1,z1} -> TestArray[[1,1]], which returns z1. However I wont be able to get the x,y coordinates or am I wrong in the understanding? $\endgroup$ – Giovanni Baez Jun 19 '18 at 16:55
  • 1
    $\begingroup$ Did you check the PerformanceGoal -> "Speed" option? Access to the data could allow us to test a few things. $\endgroup$ – rhermans Jun 19 '18 at 18:01
  • $\begingroup$ @ rhermans Data has been added. $\endgroup$ – Giovanni Baez Jun 19 '18 at 18:07
3
$\begingroup$

It is best to avoid sending such large amounts of data to a ListPlot command, because it does not by default do any downsampling. The size of the resulting Graphics expression will contain every point you feed it, and if you feed it a million points then the front end will have a hard time rendering it.

First import the data,

data = Import["~/Downloads/specup.csv"];

Next delete those elements with duplicate {x,y} values,

data2 = DeleteDuplicatesBy[data, Most];

Dimensions /@ {data, data2}
(* {{1506006, 3}, {1503501, 3}} *)

Next, convert the array into a matrix of z values instead of a list of {x, y, z} tuples. Mathematica will always plot the matrix better than the list of tuples, this is described in more detail here and here.

array = Module[
    {
        xvalues = AssociationThread[#->Range[Length@#]]&@Union[data2[[All,1]]],
        yvalues = AssociationThread[#->Range[Length@#]]&@Union[data2[[All,2]]],
        res = ConstantArray[0, {3001, 501}]
    },
    Scan[
        (res[[xvalues@#[[1]],yvalues@#[[2]]]]=#[[3]])&,
        data2
    ];
    res
]; 

Now you still have way too much data to plot efficiently, but it's very easy to downsample your data

data3 = ArrayResample[array, {300, 300}];

ListDensityPlot[data3, PlotRange -> All, 
 DataRange -> {{0, 5}, {-14, 14}}]

enter image description here

I may have gotten the x and y ranges backwards, but that's an easy fix. You can adjust the second argument of ArrayResample to increase the quality of the resulting plot.

I should point out that you could resample your data without first converting to an array, by using Interpolation. But I do not think this is worth the trouble, and I also suspect it will give a lower quality result.

$\endgroup$
  • $\begingroup$ How did you get the numbers in res? $\endgroup$ – Giovanni Baez Jun 19 '18 at 21:53
  • 1
    $\begingroup$ I had a typo there, where no data was actually assigned to array. If you look at the module inside of the definition for array, I scan over all the elements of data2, and assign them to a Part of res. That definition may be too terse, I could expand it to be more readable. $\endgroup$ – Jason B. Jun 19 '18 at 22:03
  • $\begingroup$ @ Jason B. If you could, please. Im going over the code now, trying it out.Thank you. $\endgroup$ – Giovanni Baez Jun 19 '18 at 22:04
  • $\begingroup$ I know understand the reasoning. Suppose I have another array where z is negative, is there a way I can do this to get BOTH datasets in the same plot? I tried making a separate array but I realized I cant Join the arrays. $\endgroup$ – Giovanni Baez Jun 19 '18 at 23:10
  • $\begingroup$ @GiovanniBaez - Do the two datasets cover the same x/y range? when you combine them, do they make a regular grid? Or are they two separate regions? If they combine to make a regular grid, then you combine the datasets first, and then convert to an array. If they are separate regions, then how do you want to combine them graphically? $\endgroup$ – Jason B. Jun 20 '18 at 1:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.